This is an old revision of the document!
IPTables Configuration
I went down the route of attempting to configure the firewall using NFtables. NFTables has some nice features that look to make it more user friendly than IPTables. That being said for those already familiar with IPTables this may not be the case. Furthermore, on larger, more complex installs NFTables looks to have some significant technical advantages over IPTables, but these benefits are probably less significant on my smaller undertaking. Unfortunately the package version supplied with Ubuntu 16.04 was released in 2015-11, and during my configuration I found some bugs. Also mss clamping is not supported in this version. I tried the Ubuntu 18.04 development version and the previous noted bugs were no longer apparent and mss clamping was supported.
I have not cross checked this IPTable version against the working NFTables version, and it is definitely out of alignment and untested.
Sample IPTables configuration
Edit iptables configuration file: sudo vim /etc/network/iptables
:
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
# eno1 is WAN interface, br1 is LAN interface (bridged eno2 - eno4),
# ppp1 is the PPPoE connection on eno1, is effectively the WAN
-A POSTROUTING -o ppp1 -j MASQUERADE
# WAN Ports DNAT to LAN
-A PREROUTING -p tcp -m tcp -i ppp1 --dport 80 -j DNAT --to-destination 192.168.1.15:80
-A PREROUTING -p tcp -m tcp -i ppp1 --dport 443 -j DNAT --to-destination 192.168.1.15:443
-A PREROUTING -p tcp -m tcp -i ppp1 --dport 25 -j DNAT --to-destination 192.168.1.18:25
-A PREROUTING -p tcp -m tcp -i ppp1 --dport 993 -j DNAT --to-destination 192.168.1.18:993
-A PREROUTING -p tcp -m tcp -i ppp1 --dport 995 -j DNAT --to-destination 192.168.1.18:995
COMMIT
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
# Service rules
# basic global accept rules - ICMP, loopback, traceroute, established
# all accepted
-A INPUT -s 127.0.0.0/8 -d 127.0.0.0/8 -i lo -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -m state --state ESTABLISHED -j ACCEPT
# enable traceroute rejections to get sent out
-A INPUT -p udp -m udp --dport 33434:33523 -j REJECT --reject-with icmp-port-unreachable
# DNS - accept from LAN
-A INPUT -i br1 -p tcp --dport 53 -j ACCEPT
-A INPUT -i br1 -p udp --dport 53 -j ACCEPT
# SSH - accept from LAN
-A INPUT -i br1 -p tcp --dport 22 -j ACCEPT
# DHCP client requests - accept from LAN
-A INPUT -i br1 -p udp --dport 67:68 -j ACCEPT
# drop all other inbound traffic
-A INPUT -j DROP
# Forwarding rules
# Clamp the MSS to MTU size. Both rules work, this depends on if you specify the MSS or not.
#-A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
-A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1452
# forward packets along related/established connections
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# Syn-flood protection
-A FORWARD -p tcp --syn -m limit --limit 1/s --limit-burst 5 -j ACCEPT
# Furtive port scanner
-A FORWARD -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s --limit-burst 5 -j ACCEPT
# Ping attack
-A FORWARD -p icmp --icmp-type echo-request -m limit --limit 2/s --limit-burst 10 -j ACCEPT
# forward from LAN (br1) to PPPoE (ppp0)
-A FORWARD -i br1 -o ppp1 -j ACCEPT
# allow specific WAN traffic to be forwarded to LAN
-A FORWARD -p tcp -d 192.168.1.15 --dport 80,443 -j ACCEPT
-A FORWARD -p tcp -d 192.168.1.18 --dport 25,993,995 -j ACCEPT
# drop all other forwarded traffic
-A FORWARD -j DROP
COMMIT
Additional IPTables setup requirements
Persistent IPTables on Boot and before Network Start-up:
To initialise IPtables on boot, before the networks is brought on line:
#!/bin/sh
/sbin/iptables-restore < /etc/network/iptables
Note that if /etc/network/if-pre-up.d/iptables is not complete the network may not start-up. This is desirable, as router connectivity is dangerous without firewall in place.
Some IPTables Commands
The PPPoE connection have various additional overhead to that in a standard Ethernet data field. The maximum length (MTU) of the data field of a standard Ethernet data field is limited 1500 bytes.
A standard PPPoE connection has an additional overhead of 8 bytes, which limits the MTU to 1492 bytes. However, some ISP (internet service providers) may have additional overheads. To determine the the largest MTU use the ping command. The ping command has a 28 bytes overhead (20 bytes IP header + 8 bytes for ICMP header). So the MTU is the greatest value that can be pinged without a fragmentation error, plus 28 bytes for the ping overhead. For a normal PPPoE connection this would be 1492 - 28 = 1464 bytes. (Note that a problem with this method is that it probably uses an existing modem router that sets the MTU, and it is possible that this setting acts as the limiter.) Some command examples:
See references: How to Optimize your Internet Connection using MTU and RWIN, MTU and TCP MSS when using PPPoE, TCP Headers and UDP Headers Explained, Path MTU Discovery and Filtering ICMP Cisco Resolve IP Fragmentation, MTU, MSS, and PMTUD Issues with GRE and IPSEC, Understanding MTU for ADSL, and Wikipedia IPv4, Ethertype, IEEE 802.1Q, Maximum transmission unit, Point-to-point protocol over Ethernet, IPv6 packet, Internet Control Message Protocol version 6, and Path MTU Discovery.
The MSS is normally just 40 bytes less than the MTU. The MSS is used to avoid IP fragmentation at endpoints of TCP connections. The MSS is just the TCP data size and excludes the IP and TCP headers that are normally 20 bytes each. So normal mss would be 1492 - 40 = 1452 bytes
Some Ethernet data field overheads to consider:
The Ethernet datafield (MTU) is limited to 1500 bytes and the maximum Ethernet frame size must be 1536 bytes or greater. The following overheads in the Ethernet frame, over the MTU are given for information:
To set the PPPoE connection mtu edit the following file sudo vim /etc/ppp/ip-up
and append the following to the end of the file: /sbin/ifconfig ppp0 mtu 1492
.
There seems to be a lot of conflicting information on filtering ICMP, too much!. ICMP is a fundamental component of IP protocal suite and simply blocking it in entirety is poor practice. In fact IPv6 will not function correctly without ICMP. Some judicious filtering and rate limiting seems the correct solution. The following is some reading on ICMP: