Well known is the use of Iptables (read here) with Linux as a secure and effective firewall for your network connections, to customize and regulate all incoming, forwarded, and outgoing network traffic, and as a router or gateway for an internal LAN (Local Area Network). In addition to these and many more functions, Iptables can also be used to mangle, modify or alter parameters within the IP Header of a given Network Packet when necessary. The packets can be mangled in the built-in chains of PREROUTING (altering incoming packets prior to routing), INPUT (for packets coming into the box itself), FORWARD (for altering packets being routed through the box), and OUTPUT (for altering locally-generated packets before routing) and POSTROUTING (for altering packets as they are about to go out).
Set-up and Subsequent Issue: No LAN Internet Connection
Initially, never having had to use Iptables other than as a state of the art firewall to protect my system from various questionable external network factors, a particular event relating to my ISP’s ‘odd’ internet connection prompted me to engage in some in-depth troubleshooting one day. This occurred when I decided to set up an internal LAN connecting several other laptops and desktops in my home based office. What better tool (and free) was up to the task other than Iptables coupled with Linux to function as my primary router and gateway for the other machines?
The task of customizing my firewall / router includes enabling packet forwarding for IPv4 permanently in my router machine by editing the /etc/sysctrl.conf file and indicating net.ipv4.ip_forward=1 (the default value ‘0’ would disable it), and setting the appropriate ‘FORWARD’ and ‘nat POSTROUTING’ lines in Iptables. Here is what the basic firewall / router rules looked like assuming eth1 is connected to the internet and eth0 is connected to a private LAN via a Switch branching to 5 additional machines:
#!/bin/bash iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT ACCEPT iptables -F iptables -t nat -F iptables -t mangle -F iptables -X iptables -t nat -X iptables -t mangle -X iptables -Z iptables -t nat -Z iptables -t mangle -Z # Firewall Rules: iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -i lo -j ACCEPT iptables -A INPUT -p udp -j ACCEPT iptables -A INPUT -i eth1 -m limit --limit 100/hour -j LOG --log-prefix "*Filter BLKD INPUT GTW:*" iptables -A INPUT -j DROP iptables -A FORWARD -i eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT iptables -A FORWARD -i eth0 -j ACCEPT iptables -A FORWARD -o eth0 -i eth1 -m limit --limit 100/hour -j LOG --log-prefix "*Filter BLKD INPUT LAN:*" iptables -A FORWARD -o eth0 -i eth1 -j DROP iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE # Save iptables (/etc/conf.d/iptables) and Rules (/etc/iptables/iptables_direct.rules) echo iptables-save > /etc/iptables_direct.rules echo "Saved Current Rules Using \"iptables-save>/etc/iptables_direct.rules\""
With all necessary modifications completed, my rule set was refreshed and the computers on my LAN were tested for an internet connection. Surprisingly, there was none! I verified the rules several times and made sure there was a connection coming into the router machine. Everything was positive, what could have possibly gone wrong? It was a complete mystery.
Troubleshooting and IP Packet Header
After troubleshooting for many hours, I ran the handy tcpdump command and examined the output once more and something caught my eye immediately:
# tcpdump -vvv -n -i eth1 dst 192.168.44.9 -c10 ... 00:31:07.957241 IP (tos 0x0, ttl 1, id 8504, offset 0, flags [none], proto UDP (17), length 127) 220.127.116.11.53 > 192.168.44.9.49827: [udp sum ok] 47450 q: A? s0.2mdn.net. 3/0/0 s0.2mdn.net. [2m44s] CNAME s0-2mdn-net.l.google.com., s0-2mdn-net.l.google.com. [4m47s] A 18.104.22.168, s0-2mdn-net.l.google.com. [4m47s] A 22.214.171.124 (99) ...
The culprit was the TTL (Time to Live) parameter, it was only “1”! The TTL field in the packet header determines how many hops (routers) a packet can traverse. With each router the packet encounters, the TTL value is decreased by “1” and halts when “0”. So, after the packet traversed the primary router, it no longer went further into the LAN, which explains why there was only an internet connection with the primary router machine, however, none existing further within the LAN.
Diagram of typical Network Packet IP Header
[Diagram Source: RFC 791]
The Simple and Convenient Iptables Solution
Unfortunately, some ISPs deliberately set the TTL value to a minimal value of “1” to prevent their clients from sharing the internet connection with more than one machine. Their business philosophy is, they lose money if their connection is shared with multiple computers. It’s quite sad this is done. Luckily, there is Linux with Iptables, which contains a feature to correct this! This is where packet ‘mangling’ comes into play, especially in the PREROUTING chain. By adding the following rule, a packet is able to traverse further:
iptables -t mangle -A PREROUTING -j TTL --ttl-inc 5
The above rule increments the existing TTL value by “5”, thus allowing the packet to traverse an additional 5 routers or machines. For my LAN, this is sufficient. After adding this rule and refreshing them, all computers in the LAN had a fully functional internet connection!
Self-Tests to Perform
If you wish to perform an interesting test with the above rule on Iptables with one computer which has an internet connection, try the following:
Run the ‘ping’ command without any ‘mangle’ line in your Iptables rule set.
$ ping www.google.com -c2 PING www.google.com (126.96.36.199) 56(84) bytes of data. 64 bytes from 188.8.131.52: icmp_req=1 ttl=58 time=9.78 ms 64 bytes from 184.108.40.206: icmp_req=2 ttl=58 time=9.83 ms --- www.google.com ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1001ms rtt min/avg/max/mdev = 9.783/9.808/9.833/0.025 ms
Notice, the ttl value is “58”. Now add the previous ‘mangle’ rule, incrementing the TTL value by ‘5’, refresh, and in root, type “iptables -t mangle -nvL” to list your Iptables mangle rules. If it looks good, run ‘ping’ again.
$ ping www.google.com -c2 PING www.google.com (220.127.116.11) 56(84) bytes of data. 64 bytes from node18.ggc.rd.tp.pl (18.104.22.168): icmp_req=1 ttl=63 time=8.97 ms 64 bytes from node18.ggc.rd.tp.pl (22.214.171.124): icmp_req=2 ttl=63 time=9.58 ms --- www.google.com ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1001ms rtt min/avg/max/mdev = 8.972/9.277/9.582/0.305 ms
There you go! The TTL value is now “63”, a difference of “5”, verifying the rule is properly modifying the TTL parameter.
There are many more instances when you can utilize ‘mangle’, for example, in the POSTROUTING chain as well, if you wish to send packets with a constant TTL value. A reason for this is, by setting all TTL values to the same value, it will effectively make it more difficult for an ISP or anyone else to notice that you have a LAN with multiple computers enabled. You may then reset the TTL value for all outgoing packets to a standardized value, such as 64.
Have fun experimenting, and please use caution [when setting the incoming TTL parameter to a low value, such as 0 or 1, you may very well prevent an internet connection to the existing LAN or even your primary gateway]!
Author’s System Details
Linux Distribution: Debian 7.0 (Wheezy-Testing) 64-Bit
$ uname -a
Linux Galicja 3.8.0-rc5-git-6abb7c2-Pogorze-Karpackie-CUSTOM-KERNEL #1 Tue Jan 29 15:57:55 CET 2013 x86_64 GNU/Linux