iptables firewall exercise


This exercise will involve 3 machines. Choose 3 IP addresses for them. In my lab I used

machine 1: 192.168.3.4 (we use as a client)
machine 2: 192.168.3.7 (we use as a server)
machine 3: 192.168.3.2

The above are example addresses, and the ones encoded in the commands below. However you can choose any common-subnet addresses you want (perhaps the ones your machines have already). Make sure those are the addresses in use by the machines (use ifconfig if needed). And that you replace my addresses with yours in the commands.

Initial firewall clearing

On all machines, remove existing firewall rules. If you like, view them first:

iptables -nL
iptables -t nat -nL


Then remove them:

iptables -F
iptables -t nat -nL


And make sure the default policies on the main chains are all ACCEPT:

iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT

We'll use machine 1 to run the client program, and machine 2 as the server platform. On machine 2 run the simple server "server3.c" on port 9999. Then on machine 1 edit client3.c to point to machine 1's port 9999. Run it and make sure the response appears.

Blocking at different chokepoints

Now we will experiment with firewall rules to inhibit operations. We'll put a rule in place, examine its effect, then remove it. On machine 1, use 2 virtual terminals or terminal windows. In one, run tcpdump:

tcpdump -nti eth0 host 192.168.3.4

Now run the client in the other window and watch the flurry of several packets that pass between the client and server. Now block the client request going out, with:

iptables -A OUTPUT -p tcp --dport 9999 -j DROP

Note that tcpdump shows no activity. Run iptables -nL to see your rule reflected. Now let's remove it, with:

iptables -D OUTPUT -p tcp --dport 9999 -j DROP

Again, client3 should be operational. Test it to verify. Now block the serer response coming in:

iptables -A INPUT -p tcp --sport 9999 -j DROP

Run the client. What's going on in the tcpdump window? Can tcpdump tell whether or not the server responds? Can the client program?

Interrupt the client program (ctrl-C). Remove the rule

iptables -D INPUT -p tcp --sport 9999 -j DROP

and verify that the client returns to full functionality. Now add 2 rules like the 2 you have used already, but switch the "sport" and "dport" references around:

iptables -A OUTPUT -p tcp --sport 9999 -j DROP
iptables -A INPUT -p tcp --dport 9999 -j DROP


Run the client and note that it's fully functional. Interpret. Then remove the 2 rules.

Go now to the server machine. There, block incoming packets to port 9999:

iptables -A INPUT -p tcp --dport 9999 -j DROP

Back on the the client machine, run the client and observe the tcpdump window. Can tcpdump tell whether or not the server responds? Can the client program?

On the server machine, rescind the rule:

iptables -D INPUT -p tcp --dport 9999 -j DROP

Put in its place a rule that's based on IP address:

iptables -A INPUT -s 192.168.3.4 -j DROP

Run the client from the client machine, machine 1, and note it's no longer functional. Then run it from machine 3 and note that, from there, it still is.

On the server machine, rescind the latest rule:

iptables -D INPUT -s 192.168.3.4 -j DROP

and replace it with one that REJECTs instead of DROPs.

iptables -A INPUT -s 192.168.3.4 -j REJECT

At the client machine, run the client and watch tcpdump. What's the difference between the client's behavior; what's the difference between DROP and REJECT?

Port forwarding

Now we are going to interact the client with the 3rd machine. On the client, edit and recompile client3.c to point to the 3rd machine as its server, instead of the 2nd. As if server3.c were running on machine 3. On the 3rd machine, however, don't run any such thing. Rather, set the following rule:

iptables -t nat -A PREROUTING -d 192.168.3.2 -j DNAT --to 192.168.3.7

Operate tcpdump on all 3 machines. Run client3.c (which now runs against the 3rd machine) from the client (1st) machine. You will observe a triangular interaction. Explain what happens in the 3rd machine. Explain how the 2nd (server) machine responds. Identify the 1st (client) machine's complaint and explain why it is dissatisfied. Remove the rule:

iptables -t nat -D PREROUTING -d 192.168.3.2 -j DNAT --to 192.168.3.7

We got some address translation working here, but that wasn't enough to get the entire client3/server3 transaction to work. We'll do that in the next section.

Network Address Translation

We want to separate machines 1 and 2 (the client and server), and put machine 3 between them in a special role. We separate the server from the client by giving it a new IP address in a different subnet. So, on the server:

ifconfig eth0 down
ifconfig eth0 192.168.4.7

This will automatically remove the routing table's previous entry stating that the old subnet was to be reached via the eth0 NIC. The server has amnesia about that entire old subnet. You need to re-connect the server with machine 3 by explicitly telling it that machine 3 is out there via eth0. On the server:

route add -host 192.168.3.2 eth0

In order for them to inter-communicate, not only must the server know about machine 3, machine 3 must know about the server. However, machine 3 has never heard of this new subnet. So, on machine 3:

route add -net 192.168.4.0 netmask 255.255.255.0 eth0

Make sure the server and machine 3 can ping each other. Try to ping the client from the server, or vice versa, and note the "disconnection" between them. On the client, edit and recompile client3.c to point to the server's new address. Similar to ping, when you run it you won't get satisfaction. Good.

Now let's get machine 3 to intermediate in a way that will reconnect the client and server. First, it needs to be the client's default gateway. That way, when the client has packets it wants to send to IP addresses of whose location it has no idea, it'll send them to machine 3 instead. So on the client:

route del default
route add default gw 192.168.3.2

Then we want to get machine 3, when it gets the packets the client wanted to send to the server, to conduct a similar conversation with the server bu t under its own name. That is, replacing the client's address with its own. This is called network address translation (NAT). On machine 3:

iptables -t nat -A POSTROUTING -d 192.168.4.7 -j SNAT --to 192.168.3.2

If the client has a packet for 192.168.4.7 it will hand it over to the machine 3 gateway. Machine 3, unlike the client knowing how to reach the server, would normally push it back out onto the wire to the server because that's what its routing table says to do. The packet, addressed from the client, would get to the server. Any response produced by the server would be addressed back to the client, which is futile since the server and client have "lost track" of each other. So the above machine 3 rule says, after processing the packet and deciding to put it back on the wire to the server, edit the destination address field to replace the client's address with the machine 3 gateway's own. That way, the server will be responding to the gateway which it does know how to reach instead of to the client which it doesn't. The above rule also causes machine 3 to reverse-translate any reply packets received from the server, readdressing them to the client and putting them on the wire to him.

Run client3 on the client machine again. It should work now. Capture the packet traffic on each machine while doing so. Study both the IP and hardware addresses in the packets to analyze what happened.

This is similar to what happens in the real world except usually the gateway has 2 interfaces and the client and server are connected to opposite ones. Here there is only 1 physical network but by subnetting 2 logical ones.

 

Here is the capture of activity on the client:

 

 

Here is the capture of activity on the gateway (note the 2-packets-for-1 pattern, reflecting the translation's incoming "before" and outgoing "after"):

 

 

Here is the capture of activity on the server: