Building Linux L3 switch/router on x86 - Part6 - Connecting Box to the Internet - NAT and Firewall Configuration

This is another tutorial from the series of tutorials that describe building Linux Layer 3 switch on x86 hardware. In a previous tutorial we connected our switch to the Internet via routed port. To connect LAN users to the Internet we have to configure NAT and firewall on the switch.

The article shows firewall and NAT configuration. It does not explain how IP packets filtering or IP masquerade are working, for more information visit these websites:

http://en.wikipedia.org/wiki/Firewall_%28computing%29
http://en.wikipedia.org/wiki/Network_address_translation

1. Check if service itables is running

[root@swouter-x86 ~]# etc/init.d/iptables status
iptables: Firewall is not running.

The warning message "iptables: Firewall is not running" tells us that iptables service is not running. We have to start iptables service with the command:

[root@swouter-x86 ~]#/etc/init.d/iptables start
iptables: Applying firewall rules: [  OK  ]

Check iptables status again:

[root@swouter-x86 ~]#/etc/init.d/iptables status
Table: nat
Chain PREROUTING (policy ACCEPT)
num  target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
num  target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination

Table: filter
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination
1    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED
2    ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0
3    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
4    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:22
5    REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination
1    REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination

From the output above we can see that two tables are loaded - NAT and Filter table. We need them both - table NAT for masquerading and table filter for firewalling.
If table is not presented you can easily load it to Linux kernel with the command.

[root@swouter-x86 ~]#modprobe iptable_filter
[root@swouter-x86 ~]#modprobe iptable_nat

The third table is Mangle table and it is not shown in the output. This table is used for Quality Of Service (QOS) and we are not going to use it. If it is loaded and you are not going to use QoS unload it with the command:

[root@swouter-x86 ~]#rmmod iptable_mangle

2. Flush rules from table filter and nat

This is the list of options that we are going to use.  Both options are correct, use one of them for writing rules.

--flush     = -F
--table     = -t
--append   = -A
--out-interface = -o
--in-interface  = -i
--jump        = -j

a) Flush Filter table

If you do not specify the concrete table,  your changes will always be done on Filter table as it is considered as the default iptable. For example:

[root@swouter-x86 ~]#iptables --flush

meaning the same as:

[root@swouter-x86 ~]#iptables -t filter --flush

but we can use a shorter version as well:

[root@swouter-x86 ~]#iptables  -F

b) Flush NAT table

[root@swouter-x86 ~]#iptables -t nat -F

3. NAT configuration

Outside NAT interface is ppp0.
Inside NAT interface is vlan1.

[root@swouter-x86 ~]#iptables --table nat -A POSTROUTING -o ppp0 --jump MASQUERADE

Save iptables:

[root@swouter-x86 ~]#/etc/init.d/iptables save
iptables: Saving firewall rules to /etc/sysconfig/iptables: [  OK  ]

Check NAT table configuration in detail:

[root@swouter-x86 ~]#iptables -t nat -L -v

Chain PREROUTING (policy ACCEPT 2 packets, 528 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  --  any    ppp0    anywhere             anywhere

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

Traffic coming from any inside interface with any source IP address via outside interface ppp0 will be translated. So far any translation has been done  because - pkts counter is null.

4. Firewal configuration

a) Check default filter policy

[root@swouter-x86 ~]#iptables -L -v

Chain INPUT (policy ACCEPT 140 packets, 14016 bytes)
pkts bytes target     prot opt in     out     source               destination

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

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

Default configured policy is set to ACCEPT for all the chains. Assuming NAT is working you should be able to ping from LAN to the Internet. If you do that, counter pkts for POSTROUTING policy in NAT table should increased every time translation of source IP address in packet is performed.

b) Change default filter policy

As long as default filter policy is set to ACCEPT all traffic is allowed, if it is not explicitly denied. The Cisco IOS ACLs work in different way - what is not explicitly allowed, it is denied by default. It is more secure way and we are going to implement it. This method allows us to explicitly define each type of traffic that should be allowed to pass through firewall.

First we need to change default filter policy to DENY for all the chains in firewall iptable.

Note:  During playing with iptable filter it is recommended to be connected to box via serial port. It is very like to be disconnected if something goes wrong.

[root@swouter-x86 ~]#iptables -P INPUT DROP
[root@swouter-x86 ~]#iptables -P OUTPUT DROP
[root@swouter-x86 ~]#iptables -P FORWARD DROP

You might notice that now you cannot ping local interface of the router from the host in LAN, because INPUT chain is set as DROP. Yo cannot ping from the router to the Internet because OUTPUT chain is set to DROP.  Also ping from the host in LAN to the Internet is not working due to DROP policy for FORWARD chain.

c) Allow ssh connection from LAN to router and vice versa

We need to allow traffic from subnet 172.18.0.0/16 with destination TCP port 22 (ssh) coming to interface vlan1

[root@swouter-x86 ~]#iptables -A INPUT -i vlan1 -s 172.18.0.0/16 -p tcp --dport ssh -j ACCEPT

Packet coming from LAN to VLAN1 interface, with destination TCP port 22 (ssh) can reach vlan1 interface but ssh connection cannot be established. The default DROP policy in OUPUT chain blocks traffic originating from local interface of router. We need to add command to allow connection with source TCP port 22 from vlan1 interface to the hosts on LAN

[root@swouter-x86 ~]#iptables -A OUTPUT -p tcp --sport 22 -o vlan1 -d 172.18.0.0/16 -j ACCEPT

Now hosts on LAN can connect to the router using ssh. If we want to allow establish ssh connection from vlan1 of router to the hosts on LAN we have to to add following two commands.

[root@swouter-x86 ~]#iptables -A INPUT -i vlan1 -s 172.18.0.0/16 -p tcp --sport ssh -j ACCEPT
[root@swouter-x86 ~]#iptables -A OUTPUT -o vlan1 -d 172.18.0.0/16 -p tcp --dport ssh -j ACCEPT

d) Allow ping from hosts on LAN to default gateway and vice versa

Ping is kind of ICMP message. Following rule allows  icmp request coming from the subnet 172.18.0.0/16 to VLAN1 interface.

[root@swouter-x86 ~]#iptables -A INPUT -i vlan1 -s 172.18.0.0/16 -p icmp -j ACCEPT

We need also add the rule which allows to send ICMP echo message from VLAN1 interface to the host on 172.18.0.0/16 subnet.

[root@swouter-x86 ~]#iptables -A OUTPUT -o vlan1 -d 172.18.0.0/16 -p icmp -j ACCEPT

e) Allow ping, DNS, http/https, ssh originating on router's ppp0 interface to reach the Internet

ICMP

[root@swouter-x86 ~]#iptables -A OUTPUT -o ppp0 -p icmp -j ACCEPT
[root@swouter-x86 ~]#iptables -A INPUT -i ppp0 -p icmp -m state --state ESTABLISHED -j ACCEPT

We can ping hosts on the Internet but they cannot ping ppp0 ineterface. Only established icmp connection are allowed on ppp0 interface.

ICMP localhost

[root@swouter-x86 /]#iptables -A OUTPUT -o lo -p icmp -j ACCEPT
[root@swouter-x86 /]#iptables -A INPUT -i lo -p icmp -j ACCEPT

This rule allows to ping loopback interface itself and ping local interfaces from router.

DNS client

[root@swouter-x86 ~]#iptables -A OUTPUT -o ppp0 -p udp --dport 53 -j ACCEPT
[root@swouter-x86 ~]#iptables -A INPUT -i ppp0 -p udp --sport 53 -m state --state ESTABLISHED -j ACCEPT

The rule allows to send DNS query to provider's DNS server.

Local DNS server - access from LAN

[root@swouter-x86 ~]#iptables -A INPUT -i vlan1 -p udp --dport 53 -j ACCEPT
[root@swouter-x86 ~]#iptables -A OUTPUT -o vlan1 -p udp --sport 53 -j ACCEPT

The rule allows DNS request coming from LAN to reach local DNS server running on router.

DNS server - router's own queries of local DNS server

[root@swouter-x86 /]#iptables -A INPUT -i lo -p udp -j ACCEPT
[root@swouter-x86 /]#iptables -A OUTPUT -o lo -p udp -j ACCEPT

DNS queries originating on router to local DNS server will be allowed.

HTTP/HTTPS

We need to allow http traffic originating on router to receive CentOS updates.

[root@swouter-x86 ~]#iptables -A OUTPUT -o ppp0 -p tcp --dport 80 -j ACCEPT
[root@swouter-x86 ~]#iptables -A OUT PUT -o ppp0 -p tcp --dport 443 -j ACCEPT

[root@swouter-x86 ~]#iptables -A INPUT -i ppp0 -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
[root@swouter-x86 ~]#iptables -A INPUT -i ppp0 -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT

SSH to the Internet

[root@swouter-x86 ~]#iptables -A OUTPUT -o ppp0 -p tcp --dport 22 -j ACCEPT
[root@swouter-x86 ~]#iptables -A INPUT -i ppp0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT

f) NTP client and server rules

Allow NTP client running on router to be sychronized with public NTP server.

[root@swouter-x86 ~]#iptables -A OUTPUT -o ppp0 -p udp --dport 123 -j ACCEPT
[root@swouter-x86 ~]#iptables -A INPUT -i ppp0 -p udp --sport 123 -j ACCEPT

Allow NTP server to provide service to the hosts on LAN.

[root@swouter-x86 ~]#iptables -A INPUT -i vlan1 -p udp --dport 123 -j ACCEPT
[root@swouter-x86 ~]#iptables -A OUTPUT -o vlan1 -p udp --sport 123 -j ACCEPT

g) Allow DHCP requests from LAN to to reach DHCP server and vice versa

[root@swouter-x86 ~]#iptables -A INPUT -i vlan1 -p udp --dport 67 -j ACCEPT
[root@swouter-x86 ~]#iptables -A INPUT -i vlan1 -p udp --dport 68 -j ACCEPT

[root@swouter-x86 ~]#iptables -A OUTPUT -o vlan1 -p udp --sport 67 -j ACCEPT
[root@swouter-x86 ~]#iptables -A OUTPUT -o vlan1 -p udp --sport 68 -j ACCEPT

h) Allow host on LAN to access Samba server

[root@swouter-x86 ~]#iptables -A INPUT -i vlan1 -p tcp -m multiport --dport 137,138,139,445 -j ACCEPT
[root@swouter-x86 ~]#iptables -A INPUT -i vlan1 -p udp -m multiport --dport 137,138,139,445 -j ACCEPT

[root@swouter-x86 ~]#iptables -A OUTPUT -o vlan1 -p tcp -m multiport --sport 137,138,139,445 -j ACCEPT
[root@swouter-x86 ~]#iptables -A OUTPUT -o vlan1 -p udp -m multiport --sport 137,138,139,445 -j ACCEPT

i) Allow only established sessions coming from the Internet to be forwarded to LAN

[root@swouter-x86 ~]#/sbin/iptables -A FORWARD -i ppp0 -o vlan1 -m state --state RELATED,ESTABLISHED -j ACCEPT

j) Allow any traffic originating on LAN to be forwarded to the Internet

[root@swouter-x86 ~]#/sbin/iptables -A FORWARD -i vlan1 -o ppp0 -j ACCEPT

k) Check filter table

[root@swouter-x86 ~]#iptables -L -v

Chain INPUT (policy DROP 56 packets, 7156 bytes)
pkts bytes target     prot opt in     out     source               destination
0     0 ACCEPT     icmp --  vlan1  any     172.18.0.0/16        anywhere
145 12353 ACCEPT     tcp  --  vlan1  any     172.18.0.0/16        anywhere            tcp dpt:ssh
0     0 ACCEPT     tcp  --  vlan1  any     172.18.0.0/16        anywhere            tcp spt:ssh
0     0 ACCEPT     icmp --  ppp0   any     anywhere             anywhere            state ESTABLISHED
401 54442 ACCEPT     udp  --  ppp0   any     anywhere             anywhere            udp spt:domain state ESTABLISHED
8   948 ACCEPT     tcp  --  ppp0   any     anywhere             anywhere            tcp spt:http state ESTABLISHED
7  1837 ACCEPT     tcp  --  ppp0   any     anywhere             anywhere            tcp spt:https state ESTABLISHED
0     0 ACCEPT     tcp  --  ppp0   any     anywhere             anywhere            tcp spt:ssh state ESTABLISHED
20  1552 ACCEPT     icmp --  lo     any     anywhere             anywhere
11   836 ACCEPT     udp  --  vlan1  any     anywhere             anywhere            udp dpt:ntp
37  2812 ACCEPT     udp  --  ppp0   any     anywhere             anywhere            udp spt:ntp
304 19672 ACCEPT     udp  --  vlan1  any     anywhere             anywhere            udp dpt:domain
20  1559 ACCEPT     udp  --  lo     any     anywhere             anywhere
4   200 ACCEPT     tcp  --  lo     any     anywhere             anywhere
1   328 ACCEPT     udp  --  vlan1  any     anywhere             anywhere            udp dpt:bootps
0     0 ACCEPT     udp  --  vlan1  any     anywhere             anywhere            udp dpt:bootpc
65 11009 ACCEPT     tcp  --  vlan1  any     anywhere             anywhere            multiport dports netbios-ns,netbios-dgm,netbios-ssn,microsoft-ds
139 13812 ACCEPT     udp  --  vlan1  any     anywhere             anywhere            multiport dports netbios-ns,netbios-dgm,netbios-ssn,microsoft-ds

Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target     prot opt in     out     source               destination
1800 1232K ACCEPT     all  --  ppp0   vlan1   anywhere             anywhere            state RELATED,ESTABLISHED
2481  305K ACCEPT     all  --  vlan1  ppp0    anywhere             anywhere

Chain OUTPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target     prot opt in     out     source               destination
90 10749 ACCEPT     tcp  --  any    vlan1   anywhere             172.18.0.0/16       tcp spt:ssh
0     0 ACCEPT     icmp --  any    vlan1   anywhere             172.18.0.0/16
0     0 ACCEPT     tcp  --  any    vlan1   anywhere             172.18.0.0/16       tcp dpt:ssh
16  1488 ACCEPT     icmp --  any    ppp0    anywhere             anywhere
401 27246 ACCEPT     udp  --  any    ppp0    anywhere             anywhere            udp dpt:domain
10   718 ACCEPT     tcp  --  any    ppp0    anywhere             anywhere            tcp dpt:http
8   933 ACCEPT     tcp  --  any    ppp0    anywhere             anywhere            tcp dpt:https
0     0 ACCEPT     tcp  --  any    ppp0    anywhere             anywhere            tcp dpt:ssh
20  1552 ACCEPT     icmp --  any    lo      anywhere             anywhere
11   836 ACCEPT     udp  --  any    vlan1   anywhere             anywhere            udp spt:ntp
37  2812 ACCEPT     udp  --  any    ppp0    anywhere             anywhere            udp dpt:ntp
304 39665 ACCEPT     udp  --  any    vlan1   anywhere             anywhere            udp spt:domain
20  1559 ACCEPT     udp  --  any    lo      anywhere             anywhere
4   200 ACCEPT     tcp  --  any    lo      anywhere             anywhere
0     0 ACCEPT     udp  --  any    vlan1   anywhere             anywhere            udp spt:bootpc
0     0 ACCEPT     udp  --  any    vlan1   anywhere             anywhere            udp spt:bootps
74  9590 ACCEPT     tcp  --  any    vlan1   anywhere             anywhere            multiport sports netbios-ns,netbios-dgm,netbios-ssn,microsoft-ds
0     0 ACCEPT     udp  --  any    vlan1   anywhere             anywhere            multiport sports netbios-ns,netbios-dgm,netbios-ssn,microsoft-ds

5. Allow forwarding between interfaces

[root@swouter-x86]#sysctl -w net.ipv4.ip_forward=1
[root@swouter-x86]#sysctl -w net.ipv6.conf.all.forwarding=1

To enable forwarding at boot time, you edit /etc/sysctl.conf and change/add the following line.

net.ipv4.ip_forward = 1
net.ipv6.conf.default.forwarding=1

6.  Save and restart iptables

[root@swouter-x86 ~]#/etc/init.d/iptables save
iptables: Saving firewall rules to /etc/sysconfig/iptables: [  OK  ]

[root@swouter-x86 ~]# /etc/init.d/iptables restart
iptables: Flushing firewall rules: [  OK  ]
iptables: Setting chains to policy ACCEPT: filter nat [  OK  ]
iptables: Unloading modules: [  OK  ]
iptables: Applying firewall rules: [  OK  ]

Make iptables to be started after boot.

[root@swouter-x86 ~]# chkconfig iptables on

END.

Here is the list of articles I intensively used during writing.

http://www.yolinux.com/TUTORIALS/LinuxTutorialIptablesNetworkGateway.html
http://www.bctes.com/nat-linux-iptables.html
http://billauer.co.il/ipmasq-html.html
https://help.ubuntu.com/community/IptablesHowTo
http://www.gentoo.org/doc/en/home-router-howto.xml
http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers

3 thoughts on “Building Linux L3 switch/router on x86 - Part6 - Connecting Box to the Internet - NAT and Firewall Configuration

Leave a comment

Your email address will not be published. Required fields are marked *