IPTables is a command-line utility that is the standard interface for controlling the firewall netfilter for Linux kernels. To use the IPTables utility you need superuser privileges (root).

netfilter is a set of system messages within the Linux kernel that allows kernel modules to register callback functions from the network stack. The registered callback function handles every packet passing through the network stack.

The firewall in Linux is controlled by iptables, which has IPv4 filtering functions

The # sign means that the command is executed as root. Open a console with root privileges beforehand - sudo -i on Debian-based systems or su on others.

*Show status.

# iptables -L -n -v

Sample output of the command for an inactive firewall:

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

For an active firewall:

Chain INPUT (policy DROP 0 packets, 0 bytes)  
 pkts bytes target prot opt in out source destination
    0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 state INVALID
  394 43586 ACCEPT all -- * * 0.0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
   93 17292 ACCEPT all -- br0 * 0.0.0.0.0/0 0.0.0.0/0
    1 142 ACCEPT all -- lo * 0.0.0.0/0/0 0.0.0.0/0
Chain FORWARD (policy DROP 0 packets, 0 bytes)  
 pkts bytes target prot opt in out source destination
    0 0 0 ACCEPT all -- br0 br0 0.0.0.0/0 0.0.0.0/0
    0 0 0 DROP all -- * * 0.0.0.0/0 0.0.0/0 state INVALID
    0 0 0 TCPMSS tcp -- * * * 0.0.0.0/0 0.0.0.0/0 tcp flags:0x06/0x02 TCPMSS clamp to PMTU
    0 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0/0 state RELATED,ESTABLISHED
    0 0 0 wanin all -- -- vlan2 * 0.0.0.0/0 0.0.0.0/0
    0 0 0 wanout all -- * vlan2 0.0.0.0/0 0.0.0.0/0
    0 0 0 ACCEPT all -- br0 * 0.0.0.0/0 0.0.0.0/0
Chain OUTPUT (policy ACCEPT 425 packets, 113K bytes)  
 pkts bytes target prot opt in out source destination
Chain wanin (1 references)  
 pkts bytes target prot opt in out source destination
Chain wanout (1 references)  
 pkts bytes target prot opt in out source destination

Where:

  • L : Show list of rules.
  • v : Show additional information. This option shows the interface name, options, TOS mask. It also displays suffixes 'K', 'M' or 'G'.
  • n : Display IP address and port as numbers (without using a DNS server to define names. This will speed up the display).

**Display rule list with line numbers

# iptables -n -L -v --line-numbers

Approximate output:

Chain INPUT (policy DROP)  
num target prot prot opt source destination  
1 DROP all -- 0.0.0.0/0 0.0.0.0/0 state INVALID  
2 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED  
3 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0  
4 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0  
Chain FORWARD (policy DROP)  
num target prot opt source destination  
1 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0  
2 DROP all -- 0.0.0.0/0 0.0.0.0/0 state INVALID  
3 TCPMSS tcp -- 0.0.0.0/0 0.0.0.0/0 tcp flags:0x06/0x02 TCPMSS clamp to PMTU  
4 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED  
5 wanin all -- 0.0.0.0/0 0.0.0.0/0  
6 wanout all -- 0.0.0.0/0 0.0.0.0/0  
7 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0  
Chain OUTPUT (policy ACCEPT)  
num target prot opt source destination  
Chain wanin (1 references)  
num target prot opt source destination  
Chain wanout (1 references)  
num target prot opt source destination  

You can use line numbers to add new rules.

**Display the INPUT or OUTPUT of a rule chain

# iptables -L INPUT -n -v
# iptables -L OUTPUT -n -v --line-numbers

*# Stop, start, restart the firewall

By the system itself:

# service ufw stop
# service ufw start

You can also use iptables commands to stop the firewall and remove all rules:

# iptables -F
# iptables -X
# iptables -t nat -F
# iptables -t nat -X
# iptables -t mangle -F
# iptables -t mangle -X
# iptables -P INPUT ACCEPT
# iptables -P OUTPUT ACCEPT
# iptables -P FORWARD ACCEPT

Where:

  • F : Remove (flush) all rules.
  • X : Remove the chain.
  • t table_name : Select a table (nat or mangle) and delete all rules.
  • P : Select the default action (such as DROP, REJECT, or ACCEPT).

*Remove firewall rules

To display the line number with existing rules:

# iptables -L INPUT -n --line-numbers
# iptables -L OUTPUT -n --line-numbers
# iptables -L OUTPUT -n --line-numbers | less
# iptables -L OUTPUT -n --line-numbers | grep 202.54.1.1

We get a list of IP addresses. Just look at the number on the left and remove the corresponding line. For example for number 3:

# iptables -D INPUT 3

Or find the source IP address (202.54.1.1) and remove it from the rule:

# iptables -D INPUT -s 202.54.1.1 -j DROP

Where:

  • D : Remove one or more rules from the chain.

Add rule to the firewall.

To add one or more rules to a chain, we start by displaying a list using line numbers:

# iptables -L INPUT -n --line-numbers

Sample output:

Chain INPUT (policy DROP)  
num target prot opt source destination  
1 DROP all -- 202.54.1.1 0.0.0/0  
2 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state NEW,ESTABLISHED  

To insert a rule between line 1 and line 2:

# iptables -I INPUT 2 -s 202.54.1.2 -j DROP

Check if the rule has been updated:

# iptables -L INPUT -n --line-numbers

The output will go like this:

Chain INPUT (policy DROP)  
num target prot prot opt source destination  
1 DROP all -- 202.54.1.1 0.0.0/0  
2 DROP all -- 202.54.1.2 0.0.0/0  
3 ACCEPT all -- 0.0.0.0/0 0.0.0/0 state NEW,ESTABLISHED  

**Save firewall rules

Through iptables-save:

# iptables-save > /etc/iptables.rules

*# Restore rules

Through iptables-restore

# iptables-restore < /etc/iptables.rules

*# Set default policies

To reset all traffic:

# iptables -P INPUT DROP
# iptables -P OUTPUT DROP
# iptables -P FORWARD DROP
# iptables -L -v -n

After the above commands no packets will leave this host.

# ping google.com

**Block only incoming connections

To drop all incoming packets not initiated by you, 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
# iptables -L -v -n

Outgoing packets and those that have been remembered within established sessions are allowed.

# ping google.com

*# Reset isolated network addresses on the public network

# iptables -A INPUT -i eth1 -s 192.168.0.0/24 -j DROP
# iptables -A INPUT -i eth1 -s 10.0.0.0/8 -j DROP

List of IP addresses for isolated networks:
10.0.0.0/8 -j (A)
172.16.0.0/12 (B)
192.168.0.0/16 ©
224.0.0.0/4 (MULTICAST D)
240.0.0.0/5 (E)
127.0.0.0/8 (LOOPBACK)

** Blocking a specific IP address

To block burglar address 1.2.3.4:

# iptables -A INPUT -s 1.2.3.4 -j DROP
# iptables -A INPUT -s 192.168.0.0/24 -j DROP

Block incoming port requests.

To block all incoming port 80 requests:

# iptables -A INPUT -p tcp --dport 80 -j DROP
# iptables -A INPUT -i eth1 -p tcp --dport 80 -j DROP

To block a port 80 request from address 1.2.3.4:

# iptables -A INPUT -p tcp -s 1.2.3.4 --dport 80 -j DROP
# iptables -A INPUT -i eth1 -p tcp -s 192.168.1.0/24 --dport 80 -j DROP

**Block outgoing IP address requests

To block a certain domain, find out its address:

# host -t a facebook.com

Conclusion: facebook.com has address 69.171.228.40
Find the CIDR for 69.171.228.40:

# whois 69.171.228.40 | grep CIDR

Output:
CIDR: 69.171.224.0/19

Block access to 69.171.224.0/19:

# iptables -A OUTPUT -p tcp -d 69.171.224.0/19 -j DROP

You can also use the domain to block:

# iptables -A OUTPUT -p tcp -d www.fаcebook.com -j DROP
# iptables -A OUTPUT -p tcp -d  -j DROP

Record the event and reset it.

To log packet traffic before resetting, let's add a rule:

# iptables -A INPUT -i eth1 -s 10.0.0.0/8 -j LOG --log-prefix "IP_SPOOF A: "
# iptables -A INPUT -i eth1 -s 10.0.0.0/8 -j DROP

Check the log (by default /var/log/messages):

# tail -f /var/log/messages
# grep -i --color 'IP SPOOF' /var/log/messages

# Record the event and reset it (with a limit on the number of entries).*

To avoid overfilling the partition with a bloated log, we will limit the number of entries using -m. For example, to record every 5 minutes a maximum of 7 lines:

# iptables -A INPUT -i eth1 -s 10.0.0.0/8 -m limit --limit 5/m --limit-burst 7 -j LOG --log-prefix "IP_SPOOF A: "
# iptables -A INPUT -i eth1 -s 10.0.0.0/8 -j DROP

**Reset or allow traffic from certain MAC addresses

# iptables -A INPUT -m mac --mac-source 00:0F:EA:91:04:08 -j DROP
## *allow only for TCP port # 8080 with mac address 00:0F:EA:91:04:07 ##
# iptables -A INPUT -p tcp --destination-port 22 -m mac --mac-source 00:0F:EA:91:04:07 -j ACCEPT

*Allow or deny ICMP Ping requests

Deny Icmp messages.
It is also good practice to forbid ICMP messages which might give out additional information about the host or be used to perform various malicious actions (e.g., modifying the routing table). Below is a table with a list of possible ICMP message types:

ICMP message types.

0 - echo reply (echo ping)  
3 - destination unreachable  
4 - source quench  
5 - redirect  
8 - echo request  
9 - router advertisement  
10 - router solicitation  
11 - time-to-live exceeded  
12 - IP header bad  
13 - timestamp request (timestamp value request)  
14 - timestamp reply (request for timestamp value)  
15 - information request  
16 - information reply (request for information)  
17 - address mask request  
18 - address mask reply (request for netmask)  

As you can see, replying to some ICMP messages may lead to disclosure of some host information, while others may lead to modification of the routing table, so they should be forbidden.

Typically, ICMP messages 0, 3, 4, 11, and 12 are allowed out to the outside world, while only 3, 8, and 12 are allowed in. This is how it is implemented in different firewalls:

Deny dangerous ICMP messages.

iptables -A INPUT -p icmp --icmp-type 3,8,12 -j ACCEPT  
iptables -A OUTPUT -p icmp --icmp-type 0,3,4,11,12 -j ACCEPT  

To prohibit:

# iptables -A INPUT -p icmp --icmp-type echo-request -j DROP
# iptables -A INPUT -i eth1 -p icmp --icmp-type echo-request -j DROP

Allow for certain networks/hosts:

# iptables -A INPUT -s 192.168.1.0/24 -p icmp --icmp-type echo-request -j ACCEPT

Allow only part of the ICMP requests:

### ** it is assumed that the default policy for inbound is set to DROP ** ###
# iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT
# iptables -A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT
# iptables -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT
## ** let us respond to the request ** ##
# # iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
  • iptables -A INPUT -p icmp --icmp-type 3 -j ACCEPT
  • iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT
  • iptables -A INPUT -p icmp --icmp-type 12 -j ACCEPT

  • iptables -A OUTPUT -i eth0 -p icmp --icmp-type 0 -j ACCEPT

**Open port range

# iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 7000:7010 -j ACCEPT

*Open a range of addresses

## allow connection to port 80 (Apache) if address range is 192.168.1.100 to 192.168.1.200 ##
# iptables -A INPUT -p tcp --destination-port 80 -m iprange --src-range 192.168.1.100-192.168.1.200 -j ACCEPT

## example for nat ##
# iptables -t nat -A POSTROUTING -j SNAT --to-source 192.168.1.20-192.168.1.25

Close or open standard ports.

Replace ACCEPT with DROP to block the port.

## ssh tcp port 22 ##
iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT  
iptables -A INPUT -s 192.168.1.0/24 -m state --state NEW -p tcp --dport 22 -j ACCEPT  

## cups (printing service) udp/tcp port 631 for local network ##
iptables -A INPUT -s 192.168.1.0/24 -p udp -m udp --dport 631 -j ACCEPT  
iptables -A INPUT -s 192.168.1.0/24 -p tcp -m tcp --dport 631 -j ACCEPT  

## time sync via NTP for local network (udp port 123) ##
iptables -A INPUT -s 192.168.1.0/24 -m state --state NEW -p udp --dport 123 -j ACCEPT  

## tcp port 25 (smtp) ##
iptables -A INPUT -m state --state NEW -p tcp --dport 25 -j ACCEPT  

# dns server ports ##
iptables -A INPUT -m state --state NEW -p udp --dport 53 -j ACCEPT  
iptables -A INPUT -m state --state NEW -p tcp --dport 53 -j ACCEPT  

## http/https www server port ##
iptables -A INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT  
iptables -A INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT  

## tcp port 110 (pop3) ##
iptables -A INPUT -m state --state NEW -p tcp --dport 110 -j ACCEPT  

## tcp port 143 (imap) ##
iptables -A INPUT -m state --state NEW -p tcp --dport 143 -j ACCEPT  

## Samba file server for local network ##
iptables -A INPUT -s 192.168.1.0/24 -m state --state NEW -p tcp --dport 137 -j ACCEPT  
iptables -A INPUT -s 192.168.1.0/24 -m state --state NEW -p tcp --dport 138 -j ACCEPT  
iptables -A INPUT -s 192.168.1.0/24 -m state --state NEW -p tcp --dport 139 -j ACCEPT  
iptables -A INPUT -s 192.168.1.0/24 -m state --state NEW -p tcp --dport 445 -j ACCEPT  

## proxy server for local network ##
iptables -A INPUT -s 192.168.1.0/24 -m state --state NEW -p tcp --dport 3128 -j ACCEPT  

## mysql server for local network ##
iptables -I INPUT -p tcp --dport 3306 -j ACCEPT  

*Limit the number of concurrent connections to the server for one address

The connlimit module is used for restrictions. To allow only 3 ssh connections per client:

# iptables -A INPUT -p tcp --syn --dport 22 -m connlimit --connlimit-above 3 -j REJECT

Set the number of HTTP requests to 20:

# iptables -p tcp --syn --dport 80 -m connlimit --connlimit-above 20 -connlimit-mask 24 -j DROP

Where:

  • connlimit-above 3 : Specifies that the rule is valid only if the number of connections exceeds 3.
  • connlimit-mask 24 : Specifies the network mask.
Updated Jan. 2, 2019