How to Use Netfilter on Your Linux System: Enabling a Packet-Filtering Firewall

By Emmett Dulaney

The Linux kernel has built-in packet filtering software in the form of something called netfilter. You use the iptables command to set up the rules for what happens to the packets based on the IP addresses in their header and the network connection type.

To find out more about netfilter and iptables, visit the documentation section of the netfilter website.

The built-in packet filtering capability is handy when you don’t have a dedicated firewall between your Linux system and the Internet, such as when you connect your Linux system to the Internet through a DSL or cable modem. Essentially, you can have a packet filtering firewall inside your Linux system sitting between the kernel and the applications.

The security level configuration tool in Linux

Most Linux distributions, such as Fedora and SUSE, now include GUI tools to turn on a packet filtering firewall and simplify the configuration experience for the user.

In some distributions, you need to install ufw (an acronym for Uncomplicated Firewall), which lets you manage a net-filter firewall and simplify configuration. ufw serves as a front end to iptables, which allows you to enter commands in a terminal window directly through it. The command

sudo ufw enable

turns the firewall on, and the command

sudo ufw status verbose

displays such information as the following:

Status: active

Logging: on (low)

Default: deny (incoming), allow (outgoing), disabled (routed)

New profiles: skip

The default settings are exactly what you’re looking for in most cases for a client machine: allowing outgoing traffic and denying incoming traffic.

You can allow incoming packets meant for specific Internet services such as SSH, Telnet, and FTP. If you select a network interface such as eth0 (the first Ethernet card) as trusted, all network traffic over that interface is allowed without any filtering.

In SUSE, to set up a firewall, choose Main Menu→   System→   YaST. In the YaST Control Center window that appears, click Security and Users on the left side of the window and then click Firewall on the right side. YaST opens a window that you can use to configure the firewall.

You can designate network interfaces (by device name, such as eth0, ppp0, and so on) to one of three zones: internal, external, or demilitarized zone. Then, for that zone, you can specify what services (such as HTTP, FTP, and SSH) are allowed. If you have two or more network interfaces, and you use the Linux system as a gateway (a router), you can enable forwarding packets between network interfaces (a feature called masquerading).

You can also turn on different levels of logging, such as logging all dropped packets that attempt connection at specific ports. If you change the firewall settings, choose the Startup category and click Save Settings and Restart Firewall Now.

The iptables command in Linux

The graphical user interface (GUI) firewall configuration tools are just front ends that use the iptables command to implement the firewall. If your Linux system doesn’t have a GUI tool, you can use iptables directly to configure firewalling on your Linux system.

Using the iptables command is somewhat complex. The command uses the concept of a chain, which is a sequence of rules. Each rule says what to do with a packet if the header contains certain information, such as the source or destination IP address. If a rule doesn’t apply, iptables consults the next rule in the chain. By default, there are three chains:

  • INPUT chain: Contains the first set of rules against which packets are tested. The packets continue to the next chain only if the INPUT chain doesn’t specify DROP or REJECT.
  • FORWARD chain: Contains the rules that apply to packets attempting to pass through this system to another system (when you use your Linux system as a router between your LAN and the Internet, for example).
  • OUTPUT chain: Includes the rules applied to packets before they’re sent out (either to another network or to an application).

When an incoming packet arrives, the kernel uses iptables to make a routing decision based on the destination IP address of the packet. If the packet is for this server, the kernel passes the packet to the INPUT chain. If the packet satisfies all the rules in the INPUT chain, the packet is processed by local processes such as an Internet server that’s listening for packets of this type.

If the kernel has IP forwarding enabled, and the packet has a destination IP address of a different network, the kernel passes the packet to the FORWARD chain. If the packet satisfies the rules in the FORWARD chain, it’s sent out to the other network. If the kernel doesn’t have IP forwarding enabled, and the packet’s destination address isn’t for this server, the packet is dropped.

If the local processing programs that receive the input packets want to send network packets out, those packets pass through the OUTPUT chain. If the OUTPUT chain accepts those packets, they’re sent out to the specified destination network.

You can view the current chains, add rules to the existing chains, or create new chains of rules by using the iptables command, which normally requires you to be root to interact with. When you view the current chains, you can save them to a file. If you’ve configured nothing else, and your system has no firewall configured, typing iptables -L should show the following:

Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination

In this case, all three chains — INPUT, FORWARD, and OUTPUT — show the same ACCEPT policy, which means that everything is wide open.

If you’re setting up a packet filter, the first thing you do is specify the packets that you want to accept. To accept packets from the 192.168.0.0 network address, add the following rule to the INPUT chain:

iptables -A INPUT -s 192.168.0.0/24 -j ACCEPT

Now add a rule to drop everything except local loopback (the lo network interface) traffic and stop all forwarding with the following commands:

iptables -A INPUT -i ! lo -j REJECT
iptables -A FORWARD -j REJECT

The first iptables command, for example, appends to the INPUT chain (-A INPUT) the rule that if the packet doesn’t come from the lo interface (-i ! lo), iptables rejects the packet (-j REJECT).

Before rejecting all other packets, you may add more rules to each INPUT chain to allow specific packets in. You can select packets to accept or reject based on many parameters, such as IP addresses, protocol types (TCP, UDP), network interface, and port numbers.

You can do all sorts of specialized packet filtering with iptables. Suppose that you set up a web server and want to accept packets meant for only HTTP (port 80) and SSH services. The SSH service (port 22) is for you to securely log in and administer the server. Also suppose that the server’s IP address is 192.168.0.10. Here’s how you might set up the rules for this server:

iptables -P INPUT DROP
iptables -A INPUT -s 0/0 -d 192.168.0.10 -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -s 0/0 -d 192.168.0.10 -p tcp --dport 22 -j ACCEPT

In this case, the first rulesets up the default policy of the INPUT chain to DROP, which means that if none of the specific rules matches, the packet is dropped. The next two rules say that packets addressed to 192.168.0.10 and meant for ports 80 and 22 are accepted.

Don’t type iptables commands from a remote login session. A rule that begins denying packets from all addresses can also stop what you type from reaching the system; in that case, you may have no way of accessing the system over the network. To avoid unpleasant surprises, always type iptables rules at the console — the keyboard and monitor connected directly to your Linux PC that’s running the packet filter. If you want to delete all filtering rules in a hurry, type iptables -F to flush them. To change the default policy for the INPUT chain to ACCEPT, type iptables -t filter -P INPUT ACCEPT. This command causes iptables to accept all incoming packets by default.

Not every iptables command is discussed here. You can type man iptables to read a summary of the commands. You can also read about netfilter and iptables.

After you define the rules by using the iptables command, those rules are in memory and are gone when you reboot the system. Use the iptables-save command to store the rules in a file. You can save the rules in a file named iptables.rules by using the following command:

iptables-save > iptables.rules

Here’s a listing of the iptables.rules file generated on a Fedora system:

# Generated by iptables-save v1.3.0 on Sun Dec 28 16:10:12 2019
*filter
:FORWARD ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [6:636]
-A FORWARD -j REJECT --reject-with icmp-port-unreachable
-A INPUT -s 192.168.0.0/255.255.255.0 -j ACCEPT
-A INPUT -i ! lo -j REJECT --reject-with icmp-port-unreachable
COMMIT
# Completed on Sun Dec 28 16:10:12 2019

These rules correspond to the following iptables commands used to configure the filter:

iptables -A INPUT -s 192.168.0.0/24 -j ACCEPT
iptables -A INPUT -i ! lo -j REJECT
iptables -A FORWARD -j REJECT

If you want to load these saved rules into iptables, use the following command:

iptables-restore < iptables.rules