Friday, July 10, 2015

Setting Up a Firewall with Iptables on Linux

Since we've already become familiar with Packet Filtering and Iptables, this is going to get right into the iptables commands you need to execute in order to set up rules and manage the packets entering and exiting your server.

Prerequisites: It helps to know a little bit about TCP/IP and Subnets and to ready my introductory guide to iptables. Also, since we're going to be setting up a local virtual machine, you should be familiar with Virtualbox and Vagrant. This guide was written for Mac OS X and Linux users.

Virtual Machine Set Up

We're going to be setting up a multi-machine cluster so that we can see how two servers interact with each other with different firewall settings in place. We'll be setting up the firewall on our machine running off 192.168.33.10 and be sending packets from a secondary machine off 192.168.33.11.

# create a directory for vagrant
mkdir iptables && cd iptables

# create a Vagrantfile
vagrant init

Replace it with the following contents:

# spin it up
vagrant up

# ssh into our main vm
vagrant ssh hostname1

Now, open up a new shell window, ssh into hostname2, and send some packets to our main virtual machine, just to make sure they can communicate.

# make sure you're in the folder we created
cd iptables

# ssh into our secondary vm
vagrant ssh hostname2

# send packets; CTRL-C after a few seconds
ping 192.168.33.10

PING 192.168.33.10 (192.168.33.10) 56(84) bytes of data.
64 bytes from 192.168.33.10: icmp_seq=1 ttl=64 time=0.481 ms
64 bytes from 192.168.33.10: icmp_seq=2 ttl=64 time=0.286 ms
...
64 bytes from 192.168.33.10: icmp_seq=18 ttl=64 time=0.294 ms
--- 192.168.33.10 ping statistics ---
18 packets transmitted, 18 received, 0% packet loss, time 16999ms
rtt min/avg/max/mdev = 0.267/0.368/0.648/0.117 ms

So now that we've confirmed that the secondary virtual machine is able to send packets to the main, let's return to the main session and start configuring the firewall.

Listing

# list the current rules
# it will list the filter table by default
sudo iptables -L -n -v
# OR
sudo iptables --list --numeric --verbose

Chain INPUT (policy ACCEPT 1704 packets, 174K bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 1364 packets, 83708 bytes)
 pkts bytes target     prot opt in     out     source               destination

# or target specific tables
# filter table
sudo iptables -t filter -L

# mangle table
sudo iptables -t mangle -L

# nat table
sudo iptables -t nat -L

# raw table
sudo iptables -t raw -L

Let's explain some of these flags.

  • -L : List rules
  • -n : Show IP address and port number in numeric format without using DNS to resolve the names, speeding up listing.
  • -v : Verbose output that shows the interface nae, rule options, and TOS masks. The packet and byte counters are display with "K"(1,000), "M"(1,000,000), and "G"(1,000,000,000) units.
# display INPUT chain rules
sudo iptables -L INPUT -n -v

# display OUTPUT chain rules
sudo iptables -L OUTPUT -n -v

Starting and Stopping

UFW

The Uncomplicated Firewall, or UFW, is the firewall that uses iptables on Ubuntu.

sudo service ufw stop
sudo service ufw start
sudo service ufw restart

Creating Firewall Rules

Dropping and Accepting Packets

# drop all incoming packets from our secondary vm
sudo iptables -I INPUT -s 192.168.33.11 -j DROP

# accept all local packets...
# ...but insert after our previous rule
sudo iptables -I INPUT 2 -s 0.0.0.0 -j ACCEPT

# view the updated rules
sudo iptables -L INPUT -n --line-numbers

Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination
1    DROP       all  --  192.168.33.11        0.0.0.0/0
2    ACCEPT     all  --  0.0.0.0              0.0.0.0/0

Now, if you return to the secondary session and try pinging the server again with ping 192.168.33.10, you won't see the packets going through at specific intervals. Then, after terminating the ping process, the report will indicate that of the packets transmitted, 0 were received with a 100% packet loss. Let's return to our main session and delete the rule that's dropping these packets and try creating other rules in its place.

Deleting Firewall Rules

Deleting by Line Number

# display line number along with rules
sudo iptables -L INPUT -n --line-numbers
sudo iptables -L OUTPUT -n --line-numbers

Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination
1    DROP       all  --  192.168.33.11        0.0.0.0/0
2    ACCEPT     all  --  0.0.0.0              0.0.0.0/0

# go off of the line number to the left...
# ...and delete our DROP rule
sudo iptables -D INPUT 1

Blocking Ports

# to block http requests from a specific IP
sudo iptables -A INPUT -p tcp -s 192.168.33.11 --dport 80 -j DROP
sudo iptables -A INPUT -i eth1 -p tcp -s 192.168.1.0/24 --dport 80 -j DROP

# list the rules, again
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination
1    ACCEPT     all  --  0.0.0.0              0.0.0.0/0
2    DROP       tcp  --  192.168.33.11        0.0.0.0/0            tcp dpt:80
3    DROP       tcp  --  192.168.1.0/24       0.0.0.0/0            tcp dpt:80

# install a webserver
sudo apt-get install nginx

Now, let's return to the secondary session and make sure this rule is working, properly. Notice you don't get a response when you send a GET request from the secondary shell.

# curl from the secondary vm
curl -v http://192.168.33.10

* Rebuilt URL to: http://192.168.33.10/
* Hostname was NOT found in DNS cache
*   Trying 192.168.33.10...

Your secondary vm will hang there, unable to resolve the URL. End the session with CTRL + C. However, pinging the server is still allowed.

# send packets; CTRL-C after a few seconds
ping 192.168.33.10

PING 192.168.33.10 (192.168.33.10) 56(84) bytes of data.
64 bytes from 192.168.33.10: icmp_seq=1 ttl=64 time=0.481 ms
64 bytes from 192.168.33.10: icmp_seq=2 ttl=64 time=0.286 ms
...
64 bytes from 192.168.33.10: icmp_seq=18 ttl=64 time=0.294 ms
--- 192.168.33.10 ping statistics ---
18 packets transmitted, 18 received, 0% packet loss, time 16999ms
rtt min/avg/max/mdev = 0.267/0.368/0.648/0.117 ms

Let's go back to our main session and delete the rule that's blocking port 80.

# list the rules, again
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination
1    ACCEPT     all  --  0.0.0.0              0.0.0.0/0
2    DROP       tcp  --  192.168.33.11        0.0.0.0/0            tcp dpt:80
3    DROP       tcp  --  192.168.1.0/24       0.0.0.0/0            tcp dpt:80

# delete the rules
sudo iptables -D INPUT 2
sudo iptables -D INPUT 2

Now, run the curl command, again. This time, you'll get the NGiNX welcome page.

# curl from the secondary vm
curl -v http://192.168.33.10

* Rebuilt URL to: http://192.168.33.10/
* Hostname was NOT found in DNS cache
*   Trying 192.168.33.10...
* Connected to 192.168.33.10 (192.168.33.10) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.35.0
> Host: 192.168.33.10
> Accept: */*
>
< HTTP/1.1 200 OK
* Server nginx/1.4.6 (Ubuntu) is not blacklisted
< Server: nginx/1.4.6 (Ubuntu)
< Date: Sun, 12 Jul 2015 01:01:59 GMT
< Content-Type: text/html
< Content-Length: 612
< Last-Modified: Tue, 04 Mar 2014 11:46:45 GMT
< Connection: keep-alive
< ETag: "5315bd25-264"
< Accept-Ranges: bytes

You should have a basic understanding of how to set up a firewall, now. If you'd like to learn about some more commands, check out the Related Resources section, below.

1 comment:

  1. Setting Up a Linux Firewall with Iptables on Linux, following commands to install and add rules:

    # apt-get install iptables
    # iptables -A INPUT -p tcp -s localhost --dport 8080 -j ACCEPT
    # iptables -A INPUT -p tcp --dport 8080 -j DROP

    ReplyDelete