Using iptables, shorewall, firewalld, ufw and ipset to block, masquerade (SNAT) and port forward (DNAT) in Linux

Firewall is a network security system that controls the incoming and outgoing network traffic based on an applied rule set. Some common usage is to block incomming traffic by port, do source NAT / masquerading and destination NAT / port forward.

  • iptables@man/iptables@wiki is a user-space application program that allows a system administrator to configure the tables provided by the Linux kernel firewall netfilter@wiki kernel modules and the chains and rules it stores. Will probably be replaced by Nftables@wiki, a VM able to execute bytecode to inspect network packets and make decisions.
## display status
$ iptables -L -n -v

## flush/delete and default policy
'-F' deleting (flushing) all the rules
'-X' delete chain
'-t table_name' select table
'-P' set the default policy (such as DROP, REJECT, or ACCEPT)
$ iptables -F -X
$ iptables -P INPUT ACCEPT ; iptables -P OUTPUT ACCEPT ; iptables -P FORWARD ACCEPT

## delete rules
'-D' delete one or more rules from the selected chain (by line number or source)
$ iptables -D INPUT 4
$ iptables -D INPUT -s -j DROP

## insert rules
# insert rule between 1 and 2
$ iptables -I INPUT 2 -s -j DROP

## save/restore rules 
$ service iptables save
$ iptables-save > /root/
$ iptables-restore < /root/
$ service iptables restart

## set default policy
# drop all incoming / forwarded packets, but allow outgoing traffic
$ iptables -P INPUT DROP ; iptables -P FORWARD DROP ; iptables -P OUTPUT ACCEPT
$ iptables -A INPUT -m state --state NEW,ESTABLISHED -j ACCEPT

## drop private network address on public interface
$ iptables -A INPUT -i eth1 -s -j DROP
$ iptables -A INPUT -i eth1 -s -j DROP

## block by source IP, destination PORT, destination IP, source MAC address or protocol (ICMP)
$ iptables -A INPUT -s -j DROP
$ iptables -A INPUT -p tcp --dport 80 -j DROP
$ iptables -A OUTPUT -d -j DROP
$ iptables -A INPUT -m mac --mac-source 00:0F:EA:91:04:08 -j DROP
$ iptables -A INPUT -p icmp --icmp-type echo-request -j DROP

## open destination PORT ranges or IP source ranges
$ iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 7000:7010 -j ACCEPT
$ iptables -A INPUT -p tcp --destination-port 80 -m iprange --src-range -j ACCEPT
# SNAT example
$ iptables -t nat -A POSTROUTING -j SNAT --to-source

## allow/block common ports (replace ACCEPT by DROP)
# ssh=tcp/22, http=tcp/80, ntp=udp/123
$ iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
$ iptables -A INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT
$ iptables -A INPUT -m state --state NEW -p udp --dport 123 -j ACCEPT

# restrict parallel connections per source IP
$ iptables -A INPUT -p tcp --syn --dport 22 -m connlimit --connlimit-above 3 -j REJECT
$ iptables -p tcp --syn --dport 80 -m connlimit --connlimit-above 20 --connlimit-mask 24 -j DROP

## IP/PORT REDIRECT: alters the destination IP/PORT address to send to the machine itself
# redirect incomming tcp/25 to 2525
$ iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 25 -j REDIRECT --to-port 2525

# forward incoming $DNS_IP:53 to $DMZ_DNS_IP
$ iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 53 -d $DNS_IP -j DNAT --to-destination $DMZ_DNS_IP

## IP markerading (SNAT)
# source IP for each stream will be allocated randomly from these 'to-source' range
$ iptables -t nat -A POSTROUTING -p tcp -o eth0 -j SNAT --to-source

## log
$ iptables -A INPUT -i eth1 -s -j LOG --log-prefix "IP_SPOOF A: "
$ grep --color 'IP SPOOF' /var/log/messages
# same but limit log entries
$ iptables -A INPUT -i eth1 -s -j LOG --log-prefix "IP_SPOOF A: " -m limit --limit 5/m --limit-burst 7

## debug using ipt_LOG
$ modprobe ipt_LOG
$ iptables -t raw -A OUTPUT -p tcp -j TRACE
$ iptables -t raw -A PREROUTING -p tcp -j TRACE
$ grep DPT=9081 /var/log/kernel.log
$ iptables -t raw -D OUTPUT -p tcp -j TRACE
$ iptables -t raw -D PREROUTING -p tcp -j TRACE

## display natted connections using netstat-nat
$ sudo apt-get install netstat-nat
# display NAT connections with protocol
$ netstat-nat -np
# display SNAT/DNAT connections
$ netstat-nat -S ; netstat-nat -D

from iptable examples, port redirect and netstat-nat. See also iptables HowTo and iptables tutorial

## install
$ sudo apt-get install shorewall | sudo yum install shorewall (EPEL)
# note: you need 2 NICs, see  two-interfaces
$ rpm -ql shorewall | fgrep two-interfaces

## define zones, interfaces and policy
$ cat /etc/shorewall/zones /etc/shorewall/interfaces /etc/shorewall/policy
#ZONE   TYPE    OPTIONS                 IN                      OUT
#                                       OPTIONS                 OPTIONS
fw      firewall
net     ipv4
loc     ipv4
net     eth0            dhcp,tcpflags,nosmurfs,routefilter,logmartians,sourceroute=0
loc     eth1            tcpflags,nosmurfs,routefilter,logmartians
#SOURCE         DEST            POLICY          LOG LEVEL       LIMIT:BURST
loc             net             ACCEPT
net             all             DROP            info
all             all             REJECT          info

## define rules
$ cat /etc/shorewall/rules
# Accept SSH connections from the internet to FW and from FW to local
SSH(ACCEPT)     net             $FW
SSH(ACCEPT)     $FW             loc
# Allow Ping from the local network to firewall
Ping(ACCEPT)    loc             $FW
# Allows DNS,Web,Ping access from your firewall to internet
DNS(ACCEPT)     $FW             net
Web(ACCEPT)     $FW             net
Ping(ACCEPT)    $FW             net
# Forward HTTP from net:9081,80 to local network
DNAT            net             loc:   tcp     9081
DNAT            net             loc:     tcp     9080
# Forward RDP from net:9389 to local network
DNAT            net             loc:   tcp     9389

## check for errors
$ cat /etc/shorewall/shorewall.conf
$ shorewall check

## service start/restart
$ iptables-save > /root/old.firewall.config
$ systemctl stop iptables
$ systemctl enable shorewall
$ systemctl start shorewall

## re-apply rule changes
$ shorewall restart

## list rules, see
$ shorewall show
$ shorewall show nat 
$ iptables -L -v -t nat
# show connections being firewalled
$ shorewall show connections
# show logs
$ shorewall show hits

## show macros, see
$ shorewall show macros
$ shorewall show macro Web

from Shorewall@centos and Shorewall@ubuntu

  • firewalld is the new userland interface in RHEL 7. Its basically an easy way to write iptable rules.
## install
$ yum install firewalld
$ systemctl status firewalld
# activate port forwarding
$ cat /etc/sysctl.conf
$ sysctl -p

## zone management
$ firewall-cmd --get-zones
# change the default zone permanently 
$ firewall-cmd --set-default-zone=home
$ firewall-cmd --get-default-zone
# assign eth0 temporary to the internal zone
$ firewall-cmd --zone=internal --change-interface=eth0
$ firewall-cmd --get-zone-of-interface=eth0
$ firewall-cmd --zone=public --list-all

## source management zone can be bound to a network interface and/or to a network addressing, called source
# add source '' to a zone permanently
$ firewall-cmd --permanent --zone=trusted --add-source=
$ firewall-cmd --permanent --zone=trusted --list-sources
$ firewall-cmd --get-active-zones

## service management: add services to each zone
# allow the http service permanently in the internal zone
$ firewall-cmd --permanent --zone=internal --add-service=http # or '–remove-service=http' to deny the http service
$ firewall-cmd --reload
$ firewall-cmd --list-services --zone=internal

## service firewall configuration: define new services, other then '/usr/lib/firewalld/services'
$ cat /etc/firewalld/services/haproxy.xml
<?xml version="1.0" encoding="utf-8"?>
 <description>HAProxy load-balancer</description>
 <port protocol="tcp" port="80"/>
# assign the correct SELinux context and file permissions
$ cd /etc/firewalld/services ; restorecon haproxy.xml; chmod 640 haproxy.xml

## port management (same as service management)
$ firewall-cmd --zone=internal --add-port=443/tcp # or '–remove-port=443/tcp' to deny the port
$ firewall-cmd --reload
$ firewall-cmd --zone=internal --list-ports

## masquerading: configure masquerading on the external zone to hide internal addresses
$ firewall-cmd --zone=external --add-masquerade # or '–remove-masquerade', or '–query-masquerade'

## port forwarding
$ firewall-cmd --zone=external --add-forward-port=port=22:proto=tcp:toport=3753 # or '–remove-forward-port', or '–query-forward-port'
# same but defines the destination ip address
$ firewall-cmd --zone=external --add-forward-port=port=22:proto=tcp:toport=3753:toaddr=

## direct rules:bypass firewalld
$ firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 9000 -j ACCEPT
$ firewall-cmd --reload
$ firewall-cmd --direct --get-all-rules

from what is firewalld and firewalld@rhel

  • ufw/ufw@wiki Uncomplicated Firewall is a firewall that is designed to be easy to use, best for desktop usage. Its ubuntu’s alternative to firewalld.
## install
$ sudo apt-get install ufw
$ sudo ufw status|enable|disable|show

## configure
# allow access
$ sudo ufw allow ssh | sudo ufw allow ssh/tcp
# deny access
$ sudo ufw deny ftp
# add specific source IP ranges
$ sudo ufw allow from
# add specific source and destination port ranges
$ sudo ufw allow 2290:2300/tcp
$ sudo ufw allow to any port 22
# combine parameters
$ sudo ufw allow from proto tcp to any port 22
# delete rules (by number)
$ sudo ufw status numbered ; sudo ufw delete 1
# reset/delete all rules
$ sudo ufw reset
# basic: deny by default and allow per-application
$ ufw default deny; ufw allow SSH

## application configuration
$ ufw app list
$ ls /etc/ufw/applications.d
$ cat /etc/ufw/applications.d/Deluge-my
description=Deluge BitTorrent client
$ ufw delete allow Deluge ; ufw allow Deluge-my

## rate limiting
# deny connections from an IP address that has attempted to initiate 6 or more connections in the last 30 seconds
$ ufw limit SSH

from How to Install and Configure UFW – An Un-complicated FireWall in Debian/Ubuntu and ufw@arch

  • ipset framework to administer sets of IP addresses, more flexible alternative to CIDR prefixes
## using iptables
$ iptables -A INPUT -s -p TCP -j DROP
# problem is to block ipsets without common CIDR prefix

## using ipset
$ sudo apt-get install ipset | sudo yum install ipset

## define set 'banthis', see
$ ipset create banthis hash:net
$ ipset add banthis ; ipset add banthis
$ ipset list

## use ipsets (to block access to '80')
$ iptables -I INPUT -m set --match-set banthis src -p tcp --destination-port 80 -j DROP

## use public ip block lists, e.g.:
$ sudo pip install iblocklist2ipset | sudo python-pip install iblocklist2ipset
# goto and copy-pate UPDATE-URL
$ iblocklist2ipset generate --ipset banthis $UPDATE-URL banthis.txt
$ ipset restore -f banthis.txt
$ ipset list banthis

from howto block unwanted ip addresses


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s