Introduction to iptables
iptables is a userspace command
line program used to configure the Linux 2.4 and later kernel
packet filtering ruleset.
Note
Development versions of BLFS may not build or run some packages
properly if LFS or dependencies have been updated since the most
recent stable versions of the books.
Package Information
iptables Dependencies
Optional
libpcap-1.10.5 (required for BPF compiler or
nfsynproxy support), bpf-utils (required for
Berkeley Packet Filter support), libnfnetlink
(required for connlabel support), libnetfilter_conntrack
(required for connlabel support), and nftables
Kernel
Configuration
A firewall in Linux is accomplished through the netfilter
interface. To use iptables to
configure netfilter, the following kernel configuration parameters
are required:
[*] Networking support ---> [NET]
Networking options --->
[*] Network packet filtering framework (Netfilter) ---> [NETFILTER]
[*] Advanced netfilter configuration [NETFILTER_ADVANCED]
Core Netfilter Configuration --->
<*/M> Netfilter connection tracking support [NF_CONNTRACK]
<*/M> Netfilter Xtables support (required for ip_tables)
... [NETFILTER_XTABLES]
<*/M> LOG target support [NETFILTER_XT_TARGET_LOG]
IP: Netfilter Configuration --->
<*/M> IP tables support (required for filtering/masq/NAT)
... [IP_NF_IPTABLES]
Include any connection tracking protocols that will be used, as
well as any protocols that you wish to use for match support under
the "Core Netfilter Configuration" section. The above options are
enough for running Creating a
Personal Firewall With iptables below.
Installation of iptables
Note
The installation below does not include building some specialized
extension libraries which require the raw headers in the
Linux source code. If you wish
to build the additional extensions (if you aren't sure, then you
probably don't), you can look at the INSTALL
file to see an example of how to change
the KERNEL_DIR=
parameter
to point at the Linux source
code. Note that if you upgrade the kernel version, you may also
need to recompile iptables and
that the BLFS team has not tested using the raw kernel headers.
Install iptables by running the
following commands:
./configure --prefix=/usr \
--disable-nftables \
--enable-libipq &&
make
This package does not come with a test suite.
Now, as the root
user:
make install
Command Explanations
--disable-nftables
: This
switch disables building nftables compatibility.
--enable-libipq
: This
switch enables building of libipq.so
which can be used by some packages outside of BLFS.
--enable-nfsynproxy
: This switch
enables installation of nfsynproxy
SYNPROXY configuration tool.
Configuring iptables
Note
In the following example configurations, LAN1 is used for the internal
LAN interface, and WAN1 is used for the external
interface connected to the Internet. You will need to replace
these values with appropriate interface names for your system.
Personal Firewall
A Personal Firewall is designed to let you access all the
services offered on the Internet while keeping your computer
secure and your data private.
Below is a slightly modified version of Rusty Russell's
recommendation from the
Linux 2.4 Packet Filtering HOWTO. It is still applicable to
the Linux 6.x kernels.
install -v -dm755 /etc/systemd/scripts
cat > /etc/systemd/scripts/iptables << "EOF"
#!/bin/sh
# Begin /etc/systemd/scripts/iptables
# Insert connection-tracking modules
# (not needed if built into the kernel)
modprobe nf_conntrack
modprobe xt_LOG
# Enable broadcast echo Protection
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
# Disable Source Routed Packets
echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route
echo 0 > /proc/sys/net/ipv4/conf/default/accept_source_route
# Enable TCP SYN Cookie Protection
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
# Disable ICMP Redirect Acceptance
echo 0 > /proc/sys/net/ipv4/conf/default/accept_redirects
# Do not send Redirect Messages
echo 0 > /proc/sys/net/ipv4/conf/all/send_redirects
echo 0 > /proc/sys/net/ipv4/conf/default/send_redirects
# Drop Spoofed Packets coming in on an interface, where responses
# would result in the reply going out a different interface.
echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
echo 1 > /proc/sys/net/ipv4/conf/default/rp_filter
# Log packets with impossible addresses.
echo 1 > /proc/sys/net/ipv4/conf/all/log_martians
echo 1 > /proc/sys/net/ipv4/conf/default/log_martians
# be verbose on dynamic ip-addresses (not needed in case of static IP)
echo 2 > /proc/sys/net/ipv4/ip_dynaddr
# disable Explicit Congestion Notification
# too many routers are still ignorant
echo 0 > /proc/sys/net/ipv4/tcp_ecn
# Set a known state
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
# These lines are here in case rules are already in place and the
# script is ever rerun on the fly. We want to remove all rules and
# pre-existing user defined chains before we implement new rules.
iptables -F
iptables -X
iptables -Z
iptables -t nat -F
# Allow local-only connections
iptables -A INPUT -i lo -j ACCEPT
# Free output on any interface to any ip for any service
# (equal to -P ACCEPT)
iptables -A OUTPUT -j ACCEPT
# Permit answers on already established connections
# and permit new connections related to established ones
# (e.g. port mode ftp)
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Log everything else.
iptables -A INPUT -j LOG --log-prefix "FIREWALL:INPUT "
# End /etc/systemd/scripts/iptables
EOF
chmod 700 /etc/systemd/scripts/iptables
This script is quite simple, it drops all traffic coming into
your computer that wasn't initiated from your computer, but as
long as you are simply surfing the Internet you are unlikely to
exceed its limits.
If you frequently encounter certain delays at accessing FTP
servers, take a look at BusyBox with iptables example number
4.
Even if you have daemons or services running on your system,
these will be inaccessible everywhere but from your computer
itself. If you want to allow access to services on your machine,
such as ssh or
ping, take a look
at Creating a BusyBox With iptables.
Masquerading Router
A Network Firewall has two interfaces, one connected to an
intranet, in this example LAN1, and one connected to the
Internet, here WAN1.
To provide the maximum security for the firewall itself, make
sure that there are no unnecessary servers running on it such as
X11. As a general principle, the
firewall itself should not access any untrusted service (think of
a remote server giving answers that makes a daemon on your system
crash, or even worse, that implements a worm via a
buffer-overflow).
install -v -dm755 /etc/systemd/scripts
cat > /etc/systemd/scripts/iptables << "EOF"
#!/bin/sh
# Begin /etc/systemd/scripts/iptables
echo
echo "You're using the example configuration for a setup of a firewall"
echo "from Beyond Linux From Scratch."
echo "This example is far from being complete, it is only meant"
echo "to be a reference."
echo "Firewall security is a complex issue, that exceeds the scope"
echo "of the configuration rules below."
echo "You can find additional information"
echo "about firewalls in Chapter 4 of the BLFS book."
echo "https://www.linuxfromscratch.org/blfs"
echo
# Insert iptables modules (not needed if built into the kernel).
modprobe nf_conntrack
modprobe nf_conntrack_ftp
modprobe xt_conntrack
modprobe xt_LOG
modprobe xt_state
# Enable broadcast echo Protection
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
# Disable Source Routed Packets
echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route
# Enable TCP SYN Cookie Protection
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
# Disable ICMP Redirect Acceptance
echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects
# Don't send Redirect Messages
echo 0 > /proc/sys/net/ipv4/conf/default/send_redirects
# Drop Spoofed Packets coming in on an interface where responses
# would result in the reply going out a different interface.
echo 1 > /proc/sys/net/ipv4/conf/default/rp_filter
# Log packets with impossible addresses.
echo 1 > /proc/sys/net/ipv4/conf/all/log_martians
# Be verbose on dynamic ip-addresses (not needed in case of static IP)
echo 2 > /proc/sys/net/ipv4/ip_dynaddr
# Disable Explicit Congestion Notification
# Too many routers are still ignorant
echo 0 > /proc/sys/net/ipv4/tcp_ecn
# Set a known state
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
# These lines are here in case rules are already in place and the
# script is ever rerun on the fly. We want to remove all rules and
# pre-existing user defined chains before we implement new rules.
iptables -F
iptables -X
iptables -Z
iptables -t nat -F
# Allow local connections
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
# Allow forwarding if the initiated on the intranet
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD ! -i WAN1 -m conntrack --ctstate NEW -j ACCEPT
# Do masquerading
# (not needed if intranet is not using private ip-addresses)
iptables -t nat -A POSTROUTING -o WAN1 -j MASQUERADE
# Log everything for debugging
# (last of all rules, but before policy rules)
iptables -A INPUT -j LOG --log-prefix "FIREWALL:INPUT "
iptables -A FORWARD -j LOG --log-prefix "FIREWALL:FORWARD "
iptables -A OUTPUT -j LOG --log-prefix "FIREWALL:OUTPUT "
# Enable IP Forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
# The following sections allow inbound packets for specific examples
# Uncomment the example lines and adjust as necessary
# Allow ping on the external interface
#iptables -A INPUT -p icmp -m icmp --icmp-type echo-request -j ACCEPT
#iptables -A OUTPUT -p icmp -m icmp --icmp-type echo-reply -j ACCEPT
# Reject ident packets with TCP reset to avoid delays with FTP or IRC
#iptables -A INPUT -p tcp --dport 113 -j REJECT --reject-with tcp-reset
# Allow HTTP and HTTPS to 192.168.0.2
#iptables -A PREROUTING -t nat -i WAN1 -p tcp --dport 80 -j DNAT --to 192.168.0.2
#iptables -A PREROUTING -t nat -i WAN1 -p tcp --dport 443 -j DNAT --to 192.168.0.2
#iptables -A FORWARD -p tcp -d 192.168.0.2 --dport 80 -j ACCEPT
#iptables -A FORWARD -p tcp -d 192.168.0.2 --dport 443 -j ACCEPT
# End /etc/systemd/scripts/iptables
EOF
chmod 700 /etc/systemd/scripts/iptables
With this script your intranet should be reasonably secure
against external attacks. No one should be able to setup a new
connection to any internal service and, if it's masqueraded,
makes your intranet invisible to the Internet. Furthermore, your
firewall should be relatively safe because there are no services
running that a cracker could attack.
BusyBox
This scenario isn't too different from the Creating a Masquerading Router With
iptables, but additionally offers some services to your
intranet. Examples of this can be when you want to administer
your firewall from another host on your intranet or use it as a
proxy or a name server.
Note
Outlining specifically how to protect a server that offers
services on the Internet goes far beyond the scope of this
document. See the references in the
section called “Extra Information” for more information.
Be cautious. Every service you have enabled makes your setup more
complex and your firewall less secure. You are exposed to the
risks of misconfigured services or running a service with an
exploitable bug. A firewall should generally not run any extra
services. See the introduction to the Creating a Masquerading Router With
iptables for some more details.
If you want to add services such as internal Samba or name
servers that do not need to access the Internet themselves, the
additional statements are quite simple and should still be
acceptable from a security standpoint. Just add the following
lines into the script before the logging rules.
iptables -A INPUT -i ! WAN1 -j ACCEPT
iptables -A OUTPUT -o ! WAN1 -j ACCEPT
If daemons, such as squid, have to access the Internet
themselves, you could open OUTPUT generally and restrict INPUT.
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -j ACCEPT
However, it is generally not advisable to leave OUTPUT
unrestricted. You lose any control over trojans who would like to
"call home", and a bit of redundancy in case you've
(mis-)configured a service so that it broadcasts its existence to
the world.
To accomplish this, you should restrict INPUT and OUTPUT on all
ports except those that it's absolutely necessary to have open.
Which ports you have to open depends on your needs: mostly you
will find them by looking for failed accesses in your log files.
Have a Look at the Following Examples:
-
Squid is caching the web:
iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --sport 80 -m conntrack --ctstate ESTABLISHED \
-j ACCEPT
-
Your caching name server (e.g., named) does its lookups via
UDP:
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
-
You want to be able to ping your computer to ensure it's
still alive:
iptables -A INPUT -p icmp -m icmp --icmp-type echo-request -j ACCEPT
iptables -A OUTPUT -p icmp -m icmp --icmp-type echo-reply -j ACCEPT
-
If you are
frequently accessing FTP servers or enjoy chatting, you
might notice delays because some implementations of these
daemons query an identd daemon on your system to obtain
usernames. Although there's really little harm in this,
having an identd running is not recommended because many
security experts feel the service gives out too much
additional information.
To avoid these delays you could reject the requests with a
'tcp-reset' response:
iptables -A INPUT -p tcp --dport 113 -j REJECT --reject-with tcp-reset
-
To log and drop invalid packets (packets that came in after
netfilter's timeout or some types of network scans) insert
these rules at the top of the chain:
iptables -I INPUT 0 -p tcp -m conntrack --ctstate INVALID \
-j LOG --log-prefix "FIREWALL:INVALID "
iptables -I INPUT 1 -p tcp -m conntrack --ctstate INVALID -j DROP
-
Anything coming from the outside should not have a private
address, this is a common attack called IP-spoofing:
iptables -A INPUT -i WAN1 -s 10.0.0.0/8 -j DROP
iptables -A INPUT -i WAN1 -s 172.16.0.0/12 -j DROP
iptables -A INPUT -i WAN1 -s 192.168.0.0/16 -j DROP
There are other addresses that you may also want to drop:
0.0.0.0/8, 127.0.0.0/8, 224.0.0.0/3 (multicast and
experimental), 169.254.0.0/16 (Link Local Networks), and
192.0.2.0/24 (IANA defined test network).
-
If your firewall is a DHCP client, you need to allow those
packets:
iptables -A INPUT -i WAN1 -p udp -s 0.0.0.0 --sport 67 \
-d 255.255.255.255 --dport 68 -j ACCEPT
-
To simplify debugging and be fair to anyone who'd like to
access a service you have disabled, purposely or by
mistake, you could REJECT those packets that are dropped.
Obviously this must be done directly after logging as the
very last lines before the packets are dropped by policy:
iptables -A INPUT -j REJECT
These are only examples to show you some of the capabilities of
the firewall code in Linux. Have a look at the man page of
iptables. There you will find much more information. The port
numbers needed for this can be found in /etc/services
, in case you didn't find them by
trial and error in your log file.
Systemd Unit
To set up the iptables firewall at boot, install the iptables.service
unit included in the blfs-systemd-units-20241211 package.
make install-iptables