Custom Search

Tuesday, July 22, 2014

iptables example DNAT SNAT and MASQUERADE with network namespace

1)
Create a network namespace and run a simple webserver inside it and make it accessible from global namespace. I am using a VirtualBox Virtual Machine (Ubuntu 14.04) to run this test.


a)
Add a namespace

#sudo ip netns add myns1

b)
List all namespaces

#ip netns list

c)
Execute commands in a namespace

#sudo ip netns exec myns1

d)
Check all the interfaces and their IP in the namespace "myns1"

#sudo ip netns exec myns1 ifconfig -a
#sudo ip netns exec myns1 ip link list


e)
Create veth interface pairs (veth0 and veth1) in global namespace

#ip link add veth0 type veth peer name veth1

f)
List and check veth pairs created in the global namespace

#ip link list
OR
#ifconfig -a


* At this point the interface veth0 and "veth1" don't have any IP,So don't belongs to any network.

g)
If you want to connect the global namespace to the "myns1" namespace, you will need to move one of the veth interfaces to the "myns1" namespace using this command.

#sudo ip link set veth1 netns myns1

h)
Check namespace "myns1", there you can see the moved interface "veth1".

#sudo ip netns exec myns1 ip link
OR
#sudo ip netns exec myns1 ifconfig -a


* At this point the interface "veth1" doesn't have any IP, So doesn't belongs to any network.
* If you run "#ip link list" or "#ifconfig -a" in global namespace, you can't see the "veth1" interface, since it moved to namespace "myns1".

i)
List routing table in the namespace "myns1"

#sudo ip netns exec myns1 route -n
OR
#sudo ip netns exec myns1 ip route list


* At this point, this will be empty.

j)
Assign an IP "10.1.1.2" to "veth1" interface OR Add the interface "veth1" to a network "10.1.1.2/24 or 10.1.1.x".

#sudo ip netns exec myns1 ifconfig veth1 10.1.1.2/24 up

k)
List routing table in the namespace "myns1"

#sudo ip netns exec myns1 route -n
OR
#sudo ip netns exec myns1 ip route list


* At this point you can see the network "10.1.1.2/24 or 10.1.1.x" with interface "veth1" in the routing table.

l)
List routing table in the global namespace

#route -n
OR
#ip route list


* You can see the "veth0" not there in the routing table. So we need to add it.

m)
Assign an IP "10.1.1.3" to "veth0" interface OR Add the interface "veth0" to the same network "10.1.1.2/24 or 10.1.1.x" of "veth1".

#sudo ifconfig veth0 10.1.1.3/24 up

* Note: "veth0" and "veth1" should be in same network "10.1.1.2/24 or 10.1.1.x".

n)
List routing table in the global namespace

#route -n
OR
#ip route list


* At this point you can see the network "10.1.1.2/24 or 10.1.1.x" with interface "veth0" in the routing table.

o)
Test IPs

* Ping to interface "veth0" in the global namespace from global namespace
#ping 10.1.1.3

*Ping to interface "veth1" in the "myns1" namespace from global namespace
#ping 10.1.1.2

* Ping to interface "veth0" in the global namespace from "myns1" namespace
#sudo ip netns exec myns1 ping 10.1.1.3

p)
Run a simple webserver inside the namespace "myns1"

#vim index.html
Hello World
#sudo ip netns exec myns1 netcat -l 80 < index.html

q)
Access webserver running in the namespace "myns1" from global namespace in the Virtual Machine

#wget http://10.1.1.2:80
OR
#curl http://10.1.1.2:80


2)
Add a rule with
"DNAT" target in the "PREROUTING" chain of NAT iptables table in the global namespace.

* The DNAT target is used to do Destination Network Address Translation, which means that it is used to rewrite the Destination IP address of a packet. If a packet is matched, and this (DNAT) is the target of the rule, the packet, and all subsequent packets in the same stream will be translated, and then routed on to the correct device, host or network.
http://www.iptables.info/en/iptables-targets-and-jumps.html#DNATTARGET

a)
List all rules in the PREROUTING chain of NAT table

#sudo iptables -t nat -L PREROUTING -nv

b)
Check this before adding the rule with
"DNAT" target in the Virtual Machine. curl from your host machine (Ubuntu 13.10).
#curl http://192.168.56.101:8083
curl: (7) Failed to connect to 192.168.56.101 port 8083: Connection refused

c)
Add a rule with port DNAT target to PREROUTING chain of NAT table in the Virtual Machine

#sudo iptables -t nat -A PREROUTING -p tcp -d 192.168.56.101 --dport 8083 -j DNAT --to-destination 10.1.1.2:80
OR
Specify in-interface and remove destination IP
#sudo iptables -t nat -A PREROUTING -p tcp -i eth1 --dport 8083 -j DNAT --to-destination 10.1.1.2:80

* IMP: you should specify destination port with destination IP, like  --to-destination 10.1.1.2:80
* Replace -A with -D to remove this rule
* We can't test ping, since we specified "-p tcp" in the rule. If you want test ping, please remove "-p tcp" from the rule or replace "-p tcp" with "-p icmp".

d)
List all rules in the PREROUTING chain of NAT table

#sudo iptables -t nat -L PREROUTING -nv

e)
Just check this.(Optional)

#sudo netstat -ntlp | grep 80
tcp6       0      0 :::80                   :::*                    LISTEN      2084/apache2

f)
curl from your host machine
(Ubuntu 13.10) after adding the rule with DNAT target in the Virtual Machine
#curl http://192.168.56.101:8083

Here curl will not work.
http://www.iptables.info/en/iptables-targets-and-jumps.html#DNATTARGET

f,a)
How to debug.

Goto the Virtual Machine and inspect the "veth1" interface in the namespace "myns1" using tshark and check the SYN packet.
In the output below, you can see that SYN signals are comming to "veth1" interface (10.1.1.2) from 192.168.56.1 (This means DNAT is working), but ACK signals not going back (you can see TCP Retransmission).

#sudo ip netns exec myns1 tshark -i veth1 -f "not port 22"

1   0.000000 192.168.56.1 -> 10.1.1.2     TCP 74 41491 > http [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=40849675 TSecr=0 WS=128
1   2   0.996335 192.168.56.1 -> 10.1.1.2     TCP 74 [TCP Retransmission] 41491 > http [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=40849925 TSecr=0 WS=128
2   3   3.000209 192.168.56.1 -> 10.1.1.2     TCP 74 [TCP Retransmission] 41491 > http [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=40850426 TSecr=0 WS=128
3   4   5.000510 52:14:8c:a0:4f:ea -> 8e:a6:de:48:bf:a2 ARP 42 Who has 10.1.1.2?  Tell 10.1.1.3
4   5   5.000586 8e:a6:de:48:bf:a2 -> 52:14:8c:a0:4f:ea ARP 42 10.1.1.2 is at 8e:a6:de:48:bf:a2

g)
Add a rule with SNAT target in POSTROUTING chain of NAT table in the Virtual Machine

#sudo iptables -t nat -A POSTROUTING -p tcp --dst 10.1.1.2 --dport 80 -j SNAT --to-source 10.1.1.3
OR
Add a rule with MASQUERADE target (for out interface veth0) in POSTROUTING chain of NAT table in the Virtual Machine

#sudo iptables -t nat -A POSTROUTING -p TCP -o veth0 -j MASQUERADE --to-ports 80
*This will auto SNAT the packets going to the interface veth0 or network 10.1.1.x 

http://www.iptables.info/en/iptables-targets-and-jumps.html#MASQUERADETARGET

* Note: Here i am used the match "-p tcp --dst 10.1.1.2 --dport 80", because DNAT in the PREROUTING chain already changed the destination IP and port on the packet.
* Replace -A with -D to remove this rule
* We can't test ping, since we specified "-p tcp" in the rule. If you want test ping, please remove "-p tcp" from the rule or replace "-p tcp" with "-p icmp". 

h)
curl from your host machine
(Ubuntu 13.10) after adding the rule with DNAT target in the Virtual Machine
#curl http://192.168.56.101:8083

This will work.
http://www.iptables.info/en/iptables-targets-and-jumps.html#DNATTARGET

h,a)
How to debug.

Goto the Virtual Machine and inspect the "veth1" interface in the namespace "myns1" using tshark and check the SYN packet.
In the output below, you can see that http SYN signals are comming to "veth1" interface (10.1.1.2) from 10.1.1.3 (line-1) and http ACK signal going back from 10.1.1.2 to 10.1.1.3 (line-2) and final http ACK signal from 10.1.1.3 to 10.1.1.2 (line-3). Yoy can also see the HTTP GET request from 10.1.1.3 to 10.1.1.2 (line-5).

#sudo ip netns exec myns1 tshark -i veth1 -f "not port 22"

1   0.000000     10.1.1.3 -> 10.1.1.2     TCP 74 41538 > http [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=41139563 TSecr=0 WS=128
2   0.000154     10.1.1.2 -> 10.1.1.3     TCP 74 http > 41538 [SYN, ACK] Seq=0 Ack=1 Win=28960 Len=0 MSS=1460 SACK_PERM=1 TSval=40860573 TSecr=41139563 WS=128
3   0.000458     10.1.1.3 -> 10.1.1.2     TCP 66 41538 > http [ACK] Seq=1 Ack=1 Win=29312 Len=0 TSval=41139563 TSecr=40860573
4   0.001053     10.1.1.2 -> 10.1.1.3     HTTP 79 Continuation or non-HTTP traffic
5   0.001376     10.1.1.3 -> 10.1.1.2     HTTP 149 GET / HTTP/1.1
6   0.001398     10.1.1.3 -> 10.1.1.2     TCP 66 41538 > http [ACK] Seq=84 Ack=14 Win=29312 Len=0 TSval=41139564 TSecr=40860573
7   0.001548     10.1.1.2 -> 10.1.1.3     TCP 66 http > 41538 [ACK] Seq=14 Ack=84 Win=29056 Len=0 TSval=40860573 TSecr=41139563
8   0.007233     10.1.1.2 -> 10.1.1.3     TCP 66 http > 41538 [FIN, ACK] Seq=14 Ack=84 Win=29056 Len=0 TSval=40860575 TSecr=41139564
9   0.007576     10.1.1.3 -> 10.1.1.2     TCP 66 41538 > http [FIN, ACK] Seq=84 Ack=15 Win=29312 Len=0 TSval=41139565 TSecr=40860575

i)
curl from Virtual Machine or please where we added this iptables rules (firewall machine).


#curl http://192.168.56.101:8083
curl: (7) Failed to connect to 192.168.56.101 port 8083: Connection refused

* This will not work.
http://www.iptables.info/en/iptables-targets-and-jumps.html#DNATTARGET

j)
Add a rule with DNAT target to OUTPUT chain

http://www.iptables.info/en/iptables-targets-and-jumps.html#DNATTARGET

#sudo iptables -t nat -A OUTPUT --dst 192.168.56.101 -p tcp --dport 8083 -j DNAT --to-destination 10.1.1.2:80

* IMP: you should specify destination port with destination IP, like  --to-destination 10.1.1.2:80

* We can't test ping, since we specified "-p tcp" in the rule. If you want test ping, please remove "-p tcp" from the rule or replace "-p tcp" with "-p icmp". 

* Please check the attached figure, you can see that the packets originated from local process/system are passing through OUTPUT and then POSTROUTING chain. So here, for locally generated packets, OUTPUT chain will do DNAT and then POSTROUTING chain will do SNAT.








k)
curl from Virtual Machine or please where we added this iptables rules (firewall machine).


#curl http://192.168.56.101:8083


* This will work.
http://www.iptables.info/en/iptables-targets-and-jumps.html#DNATTARGET

k,a)
How to debug.

Goto the Virtual Machine and inspect the "veth1" interface in the namespace "myns1" using tshark and check the SYN packet.
In the output below, you can see that http SYN signals are comming to "veth1" interface (10.1.1.2) from 10.1.1.3 (line-1) and http ACK signal going back from 10.1.1.2 to 10.1.1.3 (line-2) and final http ACK signal from 10.1.1.3 to 10.1.1.2 (line-3). Yoy can also see the HTTP GET request from 10.1.1.3 to 10.1.1.2 (line-7).

#sudo ip netns exec myns1 tshark -i veth1 -f "not port 22"

1   0.000000     10.1.1.3 -> 10.1.1.2     TCP 74 37848 > http [SYN] Seq=0 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=43099616 TSecr=0 WS=128
2   0.000033     10.1.1.2 -> 10.1.1.3     TCP 74 http > 37848 [SYN, ACK] Seq=0 Ack=1 Win=28960 Len=0 MSS=1460 SACK_PERM=1 TSval=43099616 TSecr=43099616 WS=128
3   0.000051     10.1.1.3 -> 10.1.1.2     TCP 66 37848 > http [ACK] Seq=1 Ack=1 Win=43776 Len=0 TSval=43099616 TSecr=43099616
4   0.000131     10.1.1.2 -> 10.1.1.3     HTTP 79 Continuation or non-HTTP traffic
5   0.000144     10.1.1.3 -> 10.1.1.2     TCP 66 37848 > http [ACK] Seq=1 Ack=14 Win=43776 Len=0 TSval=43099616 TSecr=43099616
6   0.000158     10.1.1.2 -> 10.1.1.3     TCP 66 http > 37848 [FIN, ACK] Seq=14 Ack=1 Win=29056 Len=0 TSval=43099616 TSecr=43099616
7   0.000208     10.1.1.3 -> 10.1.1.2     HTTP 149 GET / HTTP/1.1
8   0.000218     10.1.1.2 -> 10.1.1.3     TCP 66 http > 37848 [ACK] Seq=15 Ack=84 Win=29056 Len=0 TSval=43099616 TSecr=43099616
9   0.002479     10.1.1.3 -> 10.1.1.2     TCP 66 37848 > http [FIN, ACK] Seq=84 Ack=15 Win=43776 Len=0 TSval=43099617 TSecr=43099616
10   0.002490     10.1.1.2 -> 10.1.1.3     TCP 66 http > 37848 [ACK] Seq=15 Ack=85 Win=29056 Len=0 TSval=43099617 TSecr=43099617













1 comment:

  1. http://www.thegeekstuff.com/2011/01/iptables-fundamentals/

    http://www.sysresccd.org/Sysresccd-Networking-EN-Iptables-and-netfilter-load-balancing-using-connmark

    http://en.wikibooks.org/wiki/Communication_Networks/IP_Tables <== IMP

    http://www.garron.me/en/linux/iptables-manual.html

    http://content.hccfl.edu/pollock/AUnixSec/IptablesOverview.htm

    ReplyDelete