Network Address Translation - iptables
Lab Setup
- We will be using a virtual machine in the faculty's cloud.
 - When creating a virtual machine in the Launch Instance window:
- Name your VM using the following convention: 
scgc_lab<no>_<username>, where<no>is the lab number and<username>is your institutional account. - Select Boot from image in Instance Boot Source section
 - Select SCGC Template in Image Name section
 - Select a flavor that is at least m1.large.
 
 - Name your VM using the following convention: 
 - The username for connecting to the VM is 
student. - For the following exercises, the resources can be found in the laboratory archive:
 
$ cd work/
$ wget https://repository.grid.pub.ro/cs/scgc/laboratoare/lab-iptables-nat.zip
$ unzip lab-iptables-nat.zip
$ bash runvm.sh
Also run the following commands in you current shell.
$ source ~/.bashrc
$ prepare_lab
Topology
For all the exercises we will use the above topology.
MASQUERADE NAT
The depletion of IPv4 addresses has led to the use of private class IP addresses (e.g. 192.168.0.0/24). In addition to communication between hosts in a network, we also want Internet access. This is why the concept of Network Address Translation (NAT) has been introduced, where several hosts have access to the Internet using the same routable IP address: the gateway address. Enabling address translation (NAT) on the gateway causes the pair <source IP address, source port> (belonging to the station) to be replaced by the pair <gateway IP address, available port>.
Configuring NAT on Linux is done via the iptables command, just like configuring the firewall. Where we used the filter table (the default iptables table) for firewall configuration, we use the nat table for address translation configuration.
So, to enable NAT on a Linux server, run the command
root@host:~# iptables -t nat -A POSTROUTING -j MASQUERADE
In the above command:
-tspecifies the table to which the rule applies, in our case the nat table.-Ameans adding a rule to the end of the rule list.POSTROUTINGrefers to when the address translation process will be performed: after routing. In iptables nomenclature this is also called a chain. Examples of other chains:INPUT,OUTPUT,FORWARD,PREROUTING.-jis the action to be taken,MASQUERADEin this case (simple address translation action). To check and validate the rule, we display thePOSTROUTINGchain entries in thenattable using the command
root@host:~# iptables -t nat -L POSTROUTING -n -v
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 MASQUERADE  all  --  *      *       0.0.0.0/0            0.0.0.0/0
We want to verify that NAT is configured correctly. To do this we will send a packet from the red host to 8.8.8.8. The packet will pass through the gateway (i.e. host) and will be forwarded. On the red host we run the command
root@red:~# ping -c 2 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
From 192.168.1.2 icmp_seq=1 Destination Host Unreachable
From 192.168.1.2 icmp_seq=2 Destination Host Unreachable
--- 8.8.8.8 ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 999ms
We notice that there is no connectivity from the red station to 8.8.8.8:
root@host:~# iptables -t nat -L -n -v
Chain PREROUTING (policy ACCEPT 2 packets, 168 bytes)
 pkts bytes target     prot opt in     out     source               destination
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 MASQUERADE  all  --  *      *       0.0.0.0/0            0.0.0.0/0
We observe that packets arrive in the PREROUTING chain (before routing), but do not arrive in the POSTROUTING chain (after routing). We think there may be a problem with routing on the gateway. We check if routing is enabled:
root@host:~# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 0
Indeed, routing is not enabled. To enable routing on the host we run the command
root@host:~# sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
We log back into the red host and use ping to test connectivity to 8.8.8.8:
root@red:~# ping -c 2 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_req=1 ttl=61 time=92.9 ms
64 bytes from 8.8.8.8: icmp_req=2 ttl=61 time=81.2 ms
--- 8.8.8.8 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 81.272/87.094/92.917/5.829 ms
Now there is connectivity, which can also be observed by the presence of packets processed by the POSTROUTING chain:
root@host:~# iptables -t nat -L POSTROUTING -n -v
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    2   168 MASQUERADE  all  --  *      *       0.0.0.0/0            0.0.0.0/0
Observing NATed packets
We plan to analyze the IP header of packets that are generated by the red, green and blue hosts and destined to a network on the Internet. For this we use the tcpdump capture utility.
On red we start the ping command to 8.8.8.8:
root@red:~# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_req=1 ttl=127 time=42.0 ms
[...]
When running the tcpdump command the sequence to follow is:
- Run the 
tcpdumpcommand with the corresponding options in a terminal, starting packet capture. Thetcpdumputility now waits for packets to be transmitted on the interfaces it is listening on. - In another terminal run a specific network client command that generates traffic.
 - Return to the terminal running the 
tcpdumpcommand and watch for captured packets. - When you no longer need the 
tcpdumputility, stop capturing packets using the Ctrl+c key combination. 
To capture traffic, on the host station we run the command
root@host:~# tcpdump -n -i eth0 ip dst host 8.8.8.8
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
12:59:20.976707 IP host > 8.8.8.8: ICMP echo request, id 625, seq 6, length 64
12:59:21.977708 IP host > 8.8.8.8: ICMP echo request, id 625, seq 7, length 64
We notice that the source IP address is host even though it is the red host that executes the ping command and generates the ICMP echo request packets.
To see the packets as originally generated, we run the tcpdump command on the usernet interface instead of eth0:
root@host:~# tcpdump -n -i usernet ip dst host 8.8.8.8
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on usernet, link-type EN10MB (Ethernet), capture size 65535 bytes
13:01:12.557692 IP red > 8.8.8.8: ICMP echo request, id 626, seq 6, length 64
13:01:13.559726 IP red > 8.8.8.8: ICMP echo request, id 626, seq 7, length 64
To see how traffic is translated we capture traffic on all interfaces (the ones of interest are usernet and eth0)
root@host:~# tcpdump -n -i any ip dst host 8.8.8.8
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
10:23:07.632412 IP red > 8.8.8.8: ICMP echo request, id 707, seq 237, length 64
10:23:07.632430 IP host > 8.8.8.8: ICMP echo request, id 707, seq 237, length 64
10:23:08.633936 IP red > 8.8.8.8: ICMP echo request, id 707, seq 238, length 64
10:23:08.633954 IP host > 8.8.8.8: ICMP echo request, id 707, seq 238, length 64
In the above list we notice both packets that are captured on the usernet interface (generated by the red host) and those captured on the eth0 interface (forwarded by the host).
Also capture the reply packets, which have as their source address 8.8.8.8. Use the ip src host 8.8.8.8 argument string for tcpdump.
Repeat the above tests for the green host.
Observing NATed packets (TCP)
We want to track the contents of TCP packets before and after address translation. In addition to the above exercise, we also want to track ports. For this we will generate TCP (HTTP) packets using wget on the red host and capture the packets using tcpdump on the host station.
On the host station, capture HTTP packets on all interfaces that have cs.pub.ro as destination address.
Use the following command:
root@host:~# tcpdump -n -i any ip dst host cs.pub.ro and tcp dst port 80
On the red host use wget to get the page from cs.pub.ro.
Watch the translation of the source IP address and source port in the packet capture performed with tcpdump on the host.
Notice in the capture that the source port chosen by the red host is the same as the one used after translation by the host station. NAT implementations will generally keep the port after translation. In the rare case that that port is busy on the host station (possibly due to another translation) another port will be assigned.
Do the same, but capture both outgoing and incoming traffic to/from cs.pub.ro port 80.
Port forwarding
In the exercises so far we have used NAT to allow hosts with private IPs on a local network to access the Internet. NAT can also be used to allow a host on the local network to be accessed from the Internet. This process is called port forwarding.
We want to be able to access the red host via SSH from the Internet. This is not possible by default as the red host has a private IP address. The solution is to "open a port" on the gateway (i.e. the host station) and forward this port (port forwarding) to the port corresponding to the SSH service (TCP port 22) on the red station.
We will apply a rule on the host station to forward the traffic coming to the host on port 10022 to port 22 (SSH) of the red station (IP address 10.10.1.2):
root@host:~# iptables -t nat -A PREROUTING -p tcp --dport 10022 -j DNAT --to-destination 10.10.1.2:22
We check the rule by consulting the PREROUTING chain in the NAT table:
root@host:~# iptables -t nat -L PREROUTING -n -v
Chain PREROUTING (policy ACCEPT 1 packets, 474 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:10022 to:192.168.1.2:22
To check that the rule works, from fep.grid.pub.ro we open a new terminal and connect via SSH using port 10022 to the host station:
user.name@fep:~$ ssh -l student 10.9.X.Y -p 10022
student@10.10.1.2's password:
[...]
student@red:~#
We notice that after authentication we are on the red host. Port forwarding worked.
Now, let's use SSH to connect to the host station from the green host:
student@green:~# ssh -l student host -p 10022
[...]
student@red:~#
We notice that from the green station we can also access the red station via port forwarding. We want to limit port forwarding only for connections from the Internet. For this we need to update the port forwarding rule.
Delete the port forwarding rule and add a new rule that only allows connections from the Internet to port forward to the red host.
Apply the rule only for packets arriving on the eth0 interface. Use the -i option of iptables to specify the incoming interface.
Then perform the SSH connection again on port 10022 of the host station from fep.grid.pub.ro and the green host. If you have configured it correctly, the SSH connection from the green host will not work but it will still work from fep.grid.pub.ro.
Port forwarding again
We want to access the green and blue hosts from the Internet/outside via SSH using the host station. We'll use:
- port 20022 on the 
hoststation to port forward to port 22 of thegreenhost; - port 30022 on the 
hoststation to port forward to port 22 on thebluehost. 
Similar to the previous exercise, perform the necessary configurations for this port forwarding. Verify by connecting from fep.grid.pub.ro (Internet/outdoor equivalent) on ports 20022 and 30022 on the host station.
Observing NATed packets (Port Forwarding)
We will capture SSH traffic initiated from the outside to the red host through port 10022 of the host station. This is traffic before port forwarding. For this, on the host station we use the command
root@host:~# tcpdump -n -i eth0 tcp dst port 10022
On another terminal, also on the host station, we capture the traffic after port forwarding, on the usernet interface to the SSH port (22) of the red host. On the host station we use the command
root@host:~# tcpdump -n -i usernet tcp dst port 22
In order to generate traffic, connect from fep.grid.pub.ro using SSH to the host station on port 10022, which will be redirected to port 22 of the red host:
user.name@fep:~$ ssh -l student 10.9.X.Y -p 10022
student@red's password:
[...]
student@red:~#
In the captures above, we see the IP address and destination port being translated from the <10.9.X.Y, 10022> pair to the <10.10.1.2, 22> pair.
Telnet port forwarding
In previous exercises we enabled port forwarding for the SSH service. We want the red, green and blue hosts to be accessible via telnet from the Internet as well so:
redcan be accessed using port 10023greencan be accessed using port 20023bluecan be accessed using port 30023
Make the necessary configurations to enable port forwarding for telnet as described above.
Test from fep.grid.pub.ro using the telnet command:
user.name@fep:~# telnet 10.9.X.Y 10023