Netfilter IPTables is Linux kernel implementation of software firewall. Let build a basic minimal firewall.
Let start by assuming we have a server where we have a web server listening on port 80 and 443 and SSH on port 22. We want to allow incoming connection to only these ports, traffic to any other port is denied.
With iptables we can do this by running these rules
iptables -P INPUT DROP # set default policy to drop all incoming connections # allow unrestricted traffic to loopback interface iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT # we want to allow all established and related connections iptables -A INPUT -j ACCEPT -m state --state RELATED,ESTABLISHED # Allow incoming traffic to SSH iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -p tcp --sport 22 -m conntrack --ctstate ESTABLISHED -j ACCEPT # Allow incoming traffic to HTTP iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -p tcp --sport 80 -m conntrack --ctstate ESTABLISHED -j ACCEPT # Allow incoming traffic to HTTPS iptables -A INPUT -p tcp --dport 443 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -p tcp --sport 443 -m conntrack --ctstate ESTABLISHED -j ACCEPT # finally make sure nothing comes in, this should be the last rule. iptables -A INPUT -j DROP
We have got out basic firewall ready, ssh is still open to public, what if we want to restrict access to ssh from specific IPs only say 1.1.1.1 and 2.2.2.2, the new rules for SSH will be like
iptables -A INPUT -s 1.1.1.1/32 -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT iptables -A INPUT -s 2.2.2.2/32 -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -p tcp --sport 22 -m conntrack --ctstate ESTABLISHED -j ACCEPT
FTP is a special case, it uses port 20(ftp data), 21(ftp control) and passive ports above 1023.
We will allow passive ports 22000-24000 for data transfer
iptables -A INPUT -p tcp -m tcp --dport 21 -j ACCEPT iptables -A OUTPUT -p tcp -m tcp --sport 21 -j ACCEPT # Assuming we use port 22000 - 24000 for passive ftp iptables -A INPUT -p tcp -m tcp --dport 22000:24000 -j ACCEPT iptables -A OUTPUT -p tcp -m tcp --sport 22000:24000 -j ACCEPT
We are now ready accept FTP connections.
So far we have mostly firewalled TCP traffic, let now check DNS which listens on both TCP and UDP port 53. The rules for this will be
iptables -A INPUT -p tcp -m tcp --dport 53 -j ACCEPT iptables -A INPUT -p udp -m udp --dport 53 -j ACCEPT iptables -A OUTPUT -p tcp -m tcp --sport 53 -j ACCEPT iptables -A OUTPUT -p udp -m udp --sport 53 -j ACCEPT
Our basic firewall is now ready which allow traffic to only restricted ports. The final rules will be like
iptables -P INPUT DROP # set default policy to drop all incoming connections # allow unrestricted traffic to loopback interface iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT # we want to allow all established and related connections iptables -A INPUT -j ACCEPT -m state --state RELATED,ESTABLISHED # Allow incoming traffic to SSH iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -p tcp --sport 22 -m conntrack --ctstate ESTABLISHED -j ACCEPT # Allow incoming traffic to HTTP iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -p tcp --sport 80 -m conntrack --ctstate ESTABLISHED -j ACCEPT # Allow incoming traffic to HTTPS iptables -A INPUT -p tcp --dport 443 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -p tcp --sport 443 -m conntrack --ctstate ESTABLISHED -j ACCEPT # FTP traffic iptables -A INPUT -p tcp -m tcp --dport 21 -j ACCEPT iptables -A OUTPUT -p tcp -m tcp --sport 21 -j ACCEPT # Assuming we use port 22000 - 24000 for passive ftp iptables -A INPUT -p tcp -m tcp --dport 22000:24000 -j ACCEPT iptables -A OUTPUT -p tcp -m tcp --sport 22000:24000 -j ACCEPT # Allow DNS iptables -A INPUT -p tcp -m tcp --dport 53 -j ACCEPT iptables -A INPUT -p udp -m udp --dport 53 -j ACCEPT iptables -A OUTPUT -p tcp -m tcp --sport 53 -j ACCEPT iptables -A OUTPUT -p udp -m udp --sport 53 -j ACCEPT # finally make sure nothing comes in, this should be the last rule. iptables -A INPUT -j DROP