Linux: Firewall, iptables Tutorial

By Xah Lee. Date: . Last updated: .

This is a tutorial of Linux's iptables command. You need to have a basic understanding of TCP/IP. If not, see: TCP/IP Tutorial for Beginner .

firewall 21570
image source

iptables is a advanced firewall for Linux. It can {drop, redirect, modify/NAT} packets based on {IP address, port, …}. For a short intro of what it can do, see: Linux: What's Netfilter, iptables, Their Differences?

you need to be root to use iptables. So, sudo su root first, or precede all your commands by sudo.

A Simple Example

first, do this to first see that your network is working:

# check network
ping -c 3 google.com

Now, do:

# add a rule to drop ALL incoming packets
sudo iptables --table filter --append INPUT --jump DROP

now, all packets coming to your computer are dropped. Now try ping google.com again. It won't work.

you can look at the packet filtering rules you've added:

# show a list of rules
sudo iptables --list

sample output:

Chain INPUT (policy ACCEPT)
target     prot opt source               destination
DROP       all  --  anywhere             anywhere

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

now, clear the rules you've created.

# remove all filtering rules
sudo iptables --flush

now, try ping -c 3 google.com again. It works again.

Basic Concepts and Terminology

iptables is a complex software, and the man page is badly written and hard to understand. You need to understand the following basic concepts first, then, you'll be able to read the man page as reference.

firewall works by matching packets with rules. When a rule match, a specified action is done, such as blocking the packet or letting it pass or alter some info in the packet or redirect. The rules can be checking on IP address, port number, protocol, number of packets, a particular network interface the packet is from or to, or connection state, etc.

The iptables command is used to set the rules and actions.

tables, chain, target

The rules are grouped into “table”, then “chain”. A action to be done on a packet is called “target”.

table
A table is a name of a collection of “chain”.
chain
A “chain” is a name for a set of rules.
rule
A rule is used to match packet. For example, match port number, match protocol, ….
target
Action. A “target” is a name for a action. When a rule matches a packet, the “target” (action) is executed. Example of target: {ACCEPT, DROP, QUEUE, RETURN}.
policy
The default action when no rules match. Only builtin chains can have policy. And its value must be one of {ACCEPT, DROP}. (todo: can it be RETURN? Or QUEUE?).

Basic Syntax

Example:

# list current rules for filter table
sudo iptables --table filter --list

here's a sample output:

# iptables --list

Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED
ACCEPT     icmp --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ssh
REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

On your machine, you'll probably see no rules, because, you haven't set any rules yet.

The general syntax is this:

iptables --table table --append/delete/rename/… CHAIN rule --jump TARGET

It means, work with table named table, then append/delete/rename the rule rule to the chain named CHAIN, when match, do TARGET.

here's one example:

sudo iptables --table filter --append INPUT --match conntrack --ctstate ESTABLISHED,RELATED --jump ACCEPT

here's what it means, broken down in parts:

iptables --table filter …
Work with the “filter” table.
--append INPUT …
Append (a rule) to the INPUT chain.
--match conntrack --ctstate ESTABLISHED,RELATED
Turn on match connection state tracking, and, with condition that the connection is established, or is related to another connection already permitted.
--jump ACCEPT
Goto the action of target “ACCEPT”.

iptables Tables

The possible table names are:

filter
generic table for filtering packets. This is the most commonly used table.
nat
for packets that creates a new connection. (this is related to NAT (Network Address Translation))
mangle
for specialized packet alteration.
raw
mainly for configuring exemptions from connection tracking in combination with the NOTRACK target. It registers at the netfilter hooks with higher priority and is thus called before ip_conntrack, or any other IP tables.
security
for Mandatory Access Control (MAC (not MAC address)) networking rules, such as those enabled by the SECMARK and CONNSECMARK targets. Mandatory Access Control is implemented by Linux Security Modules such as SELinux. The security table is called after the filter table, allowing any Discretionary Access Control (DAC) rules in the filter table to take effect before MAC rules.

For example, you can see the list of rules in a table:

sudo iptables -table filter --list
sudo iptables -table nat --list

Builtin Chains

Each table has several builtin chains (name for a list of rules) defined by default.

“filter” Table Builtin Chains

INPUT
for packets destined to local sockets (that is, packets that goes to local host.).
FORWARD
for packets being routed through the box.
OUTPUT
for locally-generated packets (that is, packets generated by host).

“nat” Table Builtin Chains

PREROUTING
for modifying packets as soon as they come in.
OUTPUT
for modifying locally-generated packets before routing.
POSTROUTING
for modifying packets as they are about to go out.

“mangle” Table Builtin Chains

PREROUTING
for altering incoming packets before routing.
INPUT
for packets coming into the box itself.
OUTPUT
for altering locally-generated packets before routing.
FORWARD
for altering packets being routed through the box.
POSTROUTING
for altering packets as they are about to go out.

“raw” Table Builtin Chains

PREROUTING
for packets arriving via any network interface.
OUTPUT
for packets generated by local processes.

“security” Table Builtin Chains

INPUT
for packets coming into the box itself.
OUTPUT
for altering locally-generated packets before routing.
FORWARD
for altering packets being routed through the box.

the “filter” table is the most useful table.

Predefined Actions (buildin targets)

Remember: “target” is a name for a defined action. By default, the following are defined:

The above are the most basic ones. There are many others that comes with iptables but are considered “extension modules”. For example, there's also REJECT that is like DROP but also send back a error packet. There's also LOG, which doesn't do anything to the packet but writes to log.

Print Options

shortcommand syntaxpurpose
-L--list chain rulenumList the rules in a chain or all chains. Default table is “filter”
-S--list-rules chain rulenumPrint the rules in a chain or all chains
-n--numericnumeric output of addresses and ports
-v--verboseprint more info
--line-numbersprint line numbers when listing rules
-x--exactdisplay exact values for numerical values

Commands to Edit Chain

Here are the commands to edit “chain”. The “chain” here is a name.

Rule in chain are ordered, and can be identified by their number, starting with 1.

shortcommand syntaxpurpose
-A--append chain ruleAppend to chain
-D--delete chain ruleDelete matching rule from chain
-D--delete chain rulenumDelete rule rulenum (1 = first) from chain
-I--insert chain rulenumInsert in chain as rulenum (rulenum defaults to 1)
-R--replace chain rulenumReplace rule rulenum (1 = first) in chain
-X--delete-chain chainDelete a user-defined chain, or all user-defined chains.
-E--rename-chain old_chain new_chainChange chain name, (moving any references)
-N--new chainCreate a new user-defined chain
-C--check chain ruleCheck for the existence of a rule
shortcommand syntaxpurpose
-F--flush chain]Delete all rules in chain. If not specified, delete all chains
-Z--zero chain rulenumclear packet counters and byte counter in chain or all chains
shortcommand syntaxpurpose
-P--policy chain targetChange policy on chain to target. (chain must be a builtin one only, and target can only be one of {ACCEPT, DROP, QUEUE}.)

Syntax for Rules

Some rules can be preceded by !, meaning boolean inverse. That is, changing “matching” to “not matching”. These are marked by a star ★.

shortoption syntaxpurpose
-p--proto protoprotocol. proto is protocol number or one of {tcp, udp, udplite, icmp, esp, ah, sctp} or one in “/etc/protocols” or “all”. “all” is default.
-4--ipv4Nothing (line is ignored by ip6tables-restore)
-6--ipv6Error (line is ignored by iptables-restore)
-s--source address/masksource IP address
-d--destination address/maskdestination IP address
-m--match matchturn on extended match named match. (may load extension)
-f--fragmentmatch second or further fragmented packets only
-i--in-interface name[+]set rule to match only incoming packets on network interface name ([+] for wildcard)
-o--out-interface name[+]set rule to match only out going packets on network interface name ([+] for wildcard)
--set-counters packets bytesturn on packet counter for --insert, --append, --replace

Options for Action (target)

shortoption syntaxpurpose
-j--jump targetgoto action named target (may load target extension)
-g--goto chaingoto rule set named chain

General Options

shortoption syntaxpurpose
-t--table tableuse rules in table table (default is “filter”)
--modprobe=cmdtry to insert modules using command cmd
shortoption syntaxpurpose
-V--versionprint version number.

The above are general options. If you work with iptables a lot, you basically have to memorize all of the above. There are MANY MORE options, for specifying port, protocol, network adaptor, TCP packet detail, …. See man iptables.

Examples

when --table table is not specified, the “filter” table is used by default.

# ban a MAC address
sudo iptables --table filter --append INPUT --match mac --mac-source 00:0f:b4:ac:a0:58 --jump DROP
# redirect all HTTP traffic to a specific server
sudo iptables --table nat --append PREROUTING --protocol tcp --dport 80 --jump REDIRECT --to-port 127.0.0.1:80
# ban a ip address
sudo /sbin/iptables --table filter --append INPUT --source $ipAddr --jump DROP
# set default action to drop
sudo iptables --policy INPUT DROP

Clean Your Tables, Rules, Chains

When testing, you can use --flush to clear out the rules. You need to flush every table if you have added rules in them.

You can save the following as iptables-flush.sh and run them in one shot sudo bash iptables-flush.sh.

# remove all filtering rules, remove all user created chains

iptables -t filter --flush
iptables -t filter --delete-chain

iptables -t nat --flush
iptables -t nat --delete-chain

iptables -t mangle --flush
iptables -t mangle --delete-chain

iptables -t raw --flush
iptables -t raw --delete-chain

iptables -t security --flush
iptables -t security --delete-chain

If you have created a “policy” (default action), the flush won't clean it. You'll need to set policy yourself.

# set policy to accept
sudo iptables --policy INPUT ACCEPT

# you need to set policy for every table's chain too, if you've changed them.

# reset SOME default policies
iptables -t filter --policy INPUT ACCEPT
iptables -t filter --policy FORWARD ACCEPT
iptables -t filter --policy OUTPUT ACCEPT
iptables -t nat --policy PREROUTING ACCEPT
iptables -t nat --policy POSTROUTING ACCEPT
iptables -t nat --policy OUTPUT ACCEPT
iptables -t mangle --policy PREROUTING ACCEPT
iptables -t mangle --policy OUTPUT ACCEPT

# there's also table raw and security.
# there's might be other chains too.

More Examples

# accept incoming packet that's bound to tcp and destined for ssh port
sudo iptables --append INPUT --protocol tcp --dport ssh --jump ACCEPT
# accept incoming packet that's bound to tcp and destined for port 80
sudo iptables --append INPUT --protocol tcp --dport 80 --jump ACCEPT
# block all traffic
sudo iptables --append INPUT --jump DROP
# accept rule to INPUT ruleset in filter table, for traffic bound to loopback address

# add rule to filter table,
# as 1st rule
# in the INPUT set
# for traffic bound to loopback address, accept

sudo iptables --insert INPUT 1 --in-interface lo --jump ACCEPT
# log dropped packets

sudo iptables --insert INPUT 5 --match limit --limit 5/min --jump LOG --log-prefix "dropped: " --log-level 7
# allow max of 2 telnet connections
sudo iptables --append INPUT --proto tcp --syn --dport 23 --match connlimit --connlimit-above 2 --jump REJECT
# limit the number of parallel HTTP requests to 16 per class C sized source network (24 bit netmask)
sudo iptables --proto tcp --syn --dport 80 --match connlimit --connlimit-above 16 --connlimit-mask 24 --jump REJECT
# the following allows one way traffic

# Create chain which blocks new connections, except if coming from inside.
sudo iptables --new myblock
sudo iptables --append myblock --match state --state ESTABLISHED,RELATED --jump ACCEPT
sudo iptables --append myblock --match state --state NEW --in-interface ! ppp0 --jump ACCEPT
sudo iptables --append myblock --jump DROP

# Jump to that chain from INPUT and FORWARD chains.
sudo iptables --append INPUT --jump myblock
sudo iptables --append FORWARD --jump myblock

source http://www.netfilter.org/documentation/HOWTO//packet-filtering-HOWTO-5.html

the following is from http://wiki.centos.org/HowTos/Network/IPTables

sudo iptables --policy INPUT ACCEPT
sudo iptables --flush
sudo iptables --accept INPUT -i lo -j ACCEPT
sudo iptables --accept INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
sudo iptables --accept INPUT -p tcp --dport 22 -j ACCEPT
sudo iptables --policy INPUT DROP
sudo iptables --policy FORWARD DROP
sudo iptables --policy OUTPUT ACCEPT

here's the result after above. sudo iptables --list --verbose

Chain INPUT (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     all  --  lo     any     anywhere             anywhere
    0     0 ACCEPT     all  --  any    any     anywhere             anywhere            state RELATED,ESTABLISHED
    0     0 ACCEPT     tcp  --  any    any     anywhere             anywhere            tcp dpt:ssh
Chain FORWARD (policy DROP 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

ipv6

# Limit the number of connections to a particular host:
ip6tables --proto tcp --syn --dport 49152:65535 -d 2001:db8::1 --match connlimit --connlimit-above 100 --jump REJECT
# limit the number of parallel HTTP requests to 16 for the link local network (ipv6)

ip6tables --proto tcp --syn --dport 80 --source fe80::/64 --match connlimit --connlimit-above 16 --connlimit-mask 64 --jump REJECT

Saving and Restoring Firewall Config

sudo iptables-save → dump iptables rules to stdout

sudo iptables-restore → Restore IP Tables

Reference

Related Reference

StackOverflow ServerFault

Related Tools

Networking Tutorial