Linux firewalling¶
Introduction¶
This page is where I keep track of the few things I know about Linux firewalling and port scanning with nftables, Nmap, ss and Fail2ban.
Use what you find on this page at your own risk. I’m not a network security specialist so the firewall configuration provided on this page may not be the best one. And your needs may be different than mine.
Disabling iptables¶
iptables is the predecessor of nftables, and used to be the default network filtering framework in Debian GNU/Linux. Starting with Debian 10 (Buster), the default network filtering framework is nftables.
if iptables is installed on your system, you can list the rules (as root)
with iptables -L
(for the IPv4 protocol) and ip6tables -L
(for the IPv6
protocol). Here is the output you get when iptables is not configured:
Alternatively, you can use iptables -S
and ip6tables -S
(as root).
When iptables is not configured, you get:
You can flush the iptables rules (as root) with:
iptables -F
ip6tables -F
You may also want to uninstall iptables. You can do so (as root) with:
apt-get remove iptables
Finding the open ports on the local network¶
I use Nmap to scan for open ports on hosts of my local network. On a Debian GNU/Linux system, you can install it with:
apt-get install nmap
by default, Nmap scans the 1000 most popular TCP ports (-vv
is for incresed
verbosity):
nmap -vv host_name
-F
option is for a fast scan (only the most popular ports are scanned):
nmap -vv -F host_name
-p
option is to specify a single port (or a port range, e.g. p22-25
):
nmap -p3142 host_name
-sU
is for a UDP scan, --top-ports
is to scan only the most common
ports (here the 100 most common ports). Note that UDP scan requires root
privileges:
nmap -vv -sU -top-ports 100 host_name
Using the command ss
, you can see which process or service uses a specific
port. On a Debian GNU/Linux system, you can
install it with:
apt-get install iproute2
For example, to see which services uses the ports that Nmap has found opened, you can do something like:
ss -ane|awk "NR == 1 || /[0-9\]]:(22 |68 |3142 |5353 )/"
The output obtained on my Debian machines is available for download
(file ss_22_68_3142_5353)
.
Configuring nftables¶
nftables configuration file¶
The configuration file for nftables is the /etc/nftables.conf
script. It’s
not run if the nftables service is not active. You can check the nftables
service status with:
systemctl status nftables
You can start and stop the service as root with:
systemctl start nftables
systemctl stop nftables
The service is started automatically when the machine boots only if it is “enabled”. You can enable the service as root with:
systemctl enable nftables
or:
systemctl enable nftables --now # Start and enable the service.
If /etc/nftables.conf
has changed, you can take the change into account
as root with:
systemctl reload nftables
You can disable the service as root with:
systemctl disable nftables
systemctl disable nftables --now # Stop and disable the service.
nft administration tool¶
nft
is the command line administration tool of the nftables framework that
make it possible to add, delete or change packet filtering rules with immediate
effect.
One way of managing nftables configuration is to configure it using nft
and
then to use nft
to output the rules (using command nft list ruleset
).
The output can be used as content for the /etc/nftables.conf
script. Just
make sure to prepend the shebang and a flush command:
Note also that you can check the validity of the commands in the script
(without actually running them) with the --check
option:
nft --check --file /etc/nftables.conf
Example nftables configuration¶
Once again, use what you find here at your own risk!
All the nft
commands below have to be run as root:
# Remove all rules.
nft flush ruleset
# Add a table named "firewall" for IPv4 and IPv6.
nft add table inet firewall
# Add a chain named "fw_in" in table "firewall" with default policy "drop".
# The chain is attached to the input hook.
nft add chain inet firewall fw_in { \
type filter hook input priority 0\; \
policy drop\; \
}
# Similarly, add chains attached to the forward and output hooks.
nft add chain inet firewall fw_fwd { \
type filter hook forward priority 0\; \
policy drop\; \
}
nft add chain inet firewall fw_out { \
type filter hook output priority 0\; \
policy drop\; \
}
# Drop invalid state connections.
nft add rule inet firewall fw_in ct state invalid drop
# Allow all incoming / outgoing established and related traffic.
nft add rule inet firewall fw_in ct state established, related accept
nft add rule inet firewall fw_out ct state established, related accept
# Allow everything from and to loopback interface.
nft add rule inet firewall fw_in iif lo accept
nft add rule inet firewall fw_out oif lo accept
# Allow some inbound and outbound ICMP types.
nft add rule inet firewall fw_in icmp type {destination-unreachable, \
echo-reply, \
echo-request, \
source-quench, \
time-exceeded} accept
nft add rule inet firewall fw_in icmpv6 type {destination-unreachable, \
echo-reply, \
echo-request, \
nd-neighbor-solicit, \
nd-router-advert, \
nd-neighbor-advert, \
packet-too-big, \
parameter-problem, \
time-exceeded } accept
nft add rule inet firewall fw_out icmp type {destination-unreachable, \
echo-reply, \
echo-request, \
source-quench, \
time-exceeded} accept
nft add rule inet firewall fw_out icmpv6 type {destination-unreachable, \
echo-reply, \
echo-request, \
nd-neighbor-solicit, \
nd-router-advert, \
nd-neighbor-advert, \
packet-too-big, \
parameter-problem, \
time-exceeded } accept
# Allow incoming SSH connections.
nft add rule inet firewall fw_in tcp dport ssh accept
# Allow outgoing DNS queries.
nft add rule inet firewall fw_out tcp dport 53 accept
nft add rule inet firewall fw_out udp dport 53 accept
# Allow outgoing NTP (Network Time Protocol) client requests.
nft add rule inet firewall fw_out udp dport 123 accept
# NOTE: If you just need SSH access to the machine and time synchronization,
# you can stop here.
# Allow outgoing SSH connections.
nft add rule inet firewall fw_out tcp dport ssh accept
# Allow RDP.
nft add rule inet firewall fw_in tcp dport 3389 accept
# Allow outgoing Web (http and https) queries.
nft add rule inet firewall fw_out tcp dport http accept
nft add rule inet firewall fw_out tcp dport https accept
# Allow POP3-SSL client.
nft add rule inet firewall fw_out tcp dport 995 accept
# Allow mDNS.
nft add rule inet firewall fw_in pkttype multicast udp dport 5353 accept
nft add rule inet firewall fw_out udp sport 5353 accept
Allow outgoing Web queries to a set of specific servers¶
On a remote machine, I initially used the configuration above (stopping after
allowing incoming SSH connections), and then realized I couldn’t upgrade the
system anymore (i.e. apt-get update
and of course apt-get dist-upgrade
didn’t work any more) because nftables was blocking the DNS queries, and also
the Web queries to the Debian repositories.
Obviously, I allowed the outgoing DNS queries with the commands provided above,
defined a set of addresses for the servers used by the apt-get update
and
apt-get dist-upgrade
commands, and allowed outgoing Web (http and https)
queries.
Note that the list of servers used depends on your APT configuration.
I used the following commands (as root) to create and populate the set of addresses:
# Create a set named "debian_sources" (in table "firewall") that can store
# multiple individual IPv4 addresses.
nft add set inet firewall debian_sources { type ipv4_addr \; }
# Add some addresses to the set. Both numerical addresses and domain names
# are valid.
nft add element inet firewall debian_sources { XXX.XXX.XXX.XXX, \
YYY.YYY.YYY.YYY, \
ZZZ.ZZZ.ZZZ.ZZZ }
Finally I used the following commands (as root) to allow the Web queries (http and https) to the servers in the set:
nft add rule inet firewall fw_out \
ip daddr @debian_sources tcp dport http accept
nft add rule inet firewall fw_out \
ip daddr @debian_sources tcp dport https accept
Deleting individual rules or sets¶
To delete an nftables rule, you first have to find its handle (a numerical
value). To see the handles of the rules, use option -a
in the nft list
ruleset
command:
nft -a list ruleset
Then delete the rule with a command like the following (example of deletion of a rule in the “fw_out” chain of the “firewall” table):
nft delete rule inet firewall fw_out handle <handle_value>
To delete a set, use a command like (example of deletion of a set in the table “firewall”):
nft delete set inet firewall <set_name>
Deleting the whole ruleset¶
To delete the whole nftables ruleset, do:
nft flush ruleset
Note about DHCP¶
If you have to configure nftables on a machine that is also a DHCP server or client, read the “Firewall rules” section in the DHCP README file.
Updating /etc/nftables.conf¶
Once you have configured nftables using nft
commands, you may want to
update /etc/nftables.conf
so that the configuration is preserved on next
start of nftables. You can do this using the following commands (as root):
printf '#!/usr/sbin/nft -f\n\nflush ruleset\n\n' > /etc/nftables.conf
nft list ruleset >> /etc/nftables.conf
Installing and configuring Fail2ban¶
You can install Fail2ban on a Debian GNU/Linux system with:
apt-get install fail2ban
Assuming you have nftables running, and an SSH server listening on port 22,
creating (as root) file /etc/fail2ban/jail.local
with the following
content and then starting Fail2ban (systemctl start fail2ban
) should be
enough to have Fail2ban prevent brute force attacks on the SSH server.
Make sure you enable Fail2ban so that it starts automatically on next reboot:
systemctl enable fail2ban
You can get some information about the state of Fail2ban using
fail2ban-client
:
fail2ban-client status
fail2ban-client status sshd