Central to securing a Linux server that’s connected to the Internet is having a good firewall and specific policies in place. Numerous options exist for those considering firewalls for Linux, however, a free and included solution is onoffer through Netfilter and iptables.
As of Linux kernel 2.4 and above, Netfilter has been included as a kernel extension by the majority of (if not all) Linux distributors. iptables is its counterpart and the tool for managing firewall rules. The duo, which I call simply "iptables", creates a stateful firewall on a Linux desktop or server. "Stateful" refers to the firewall’s ability to track the state of packets moving in and out of a server and/or network.
This is an improvement on the former ipchains, through which packet state was not available. Thus, iptables can distinguish between new and existing connections and keep track of traffic. iptables recognizes four kinds of packet states: new, established, related and invalid.
The developer can take any number of routes and options when deploying an iptables firewall: via prepackaged solutions like APF, from within a control panel such as Webmin, which has an iptables module, or by way of a GUI configuration tool such as Firestarter.
For the purpose of this article, we’ll focus on securing a single development Web server environment where multiple services are offered. This will be accomplished via configuring iptables manually in a command line text editor (which is traditionally stored at /etc/sysocnfig/iptables).
This also means we will only be discussing the filter table, which is one of three tables in the firewall system (others include Mangle, which manages quality of services issues with packet traffic, and the NAT (network address translation) table).
How iptables Works
iptables executes its rules based on the TCP protocol handshake. When a remote device connects to your server, a packet is sent with a SYN (short for synchronization) bit, which is generally acknowledged with a SYN/ACK (synchronization acknowledged) sent from your server back to the client. The client then acknowledges receipt of this with an ACK, and the network relationship is established.
This terminology has also become more familiar to non-network administrators in recent years due to some well-publicized cases of SYN flooding, which is used to execute denial-of-service attacks. This occurs when a remote malicious host (or hosts) repeatedly sends SYN packets to multiple ports on a server, which the server acknowledges. However, instead of sending an ACK back to open a legitimate connection, the remote malicious host(s) continues sending SYN packets and the server repeatedly attempts to acknowledge them, ultimately clogging bandwidth and system resources, and either severely hampering or blocking all other traffic.
We will look at an option to protect against SYN flooding later, when we configure our server’s firewall.
Only the root user can manage iptables, so the usual precautions — taking action as root — can cause damage to your server’s health if a user is not careful.
iptables may or may not be running on your system. You can check by issuing
'/etc/rc.d/init.d/iptables status', which will either list the status of your firewall rules, or return something along the lines of ‘firewall is stopped’.
Controlling iptables operations is simple, with options such as start, stop, status and others using the above command.
At this point, we’ll assume that you don’t have an iptables configuration, and we’ll build the rules file from scratch. First, we need to identify the services you wish to enable (i.e. FTP, SSH, mail and HTTP), identify areas of concern (i.e. like SYN flooding) and potentially note any IP addresses whose access you may seek to ban.
If you are using a Red Hat-flavored system, as I am (Fedora Core 3 on a development server), you may find some generic rules in the /etc/sysconfig/iptables file. You will want to back up an existing iptables file if it has been in use. This can be done on the command line via
'cp /etc/sysconfig/iptables /etc/sysconfig/iptables.backup'.
To start building your rules, open that file in your favorite command line editor. I issue
'vi /etc/sysconfig/iptables'; you will press the Insert key or letter I key to start editing. Remember that when you’re finished editing, you’ll want to press the ESC key and type ‘:wq’ to save the file in Vi.
Allowing Targeted Access
Let’s build a set of firewall rules that will allow ftp, and allow ssh only to the IP addresses you specify and some additional ports you may need for other services. We’ll break each section down and discuss the details as we go.
One caveat: this firewall example will not be a completely hardened overview for the truly paranoid production box; it’s meant to serve as a primer to help you get used to handling basic rules with a solid level of packet filtering.
With the iptables file open in your favorite text editor, begin by setting some basic parameters. Use the following entry:
#My firewall config in /etc/sysconfig/iptables #It is good practice to comment, initial, and date your config files for the sake of shared #administrative environments and, also, so you remember what has been done in a file. *filter :OUTPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :FWALL-INPUT - [0:0] :INPUT ACCEPT [0:0] -A INPUT -j FWALL-INPUT
This allows outgoing access from your server, and allows forwarding as well as accepting all incoming traffic (if passing packets through your server is not needed, simply change the
DROP). However, this code forwards all incoming traffic to our firewall rules (
FWALL-INPUT) for filtering.
As SSH is a critical factor for system management, user access and other options such as requiring SFTP from your clients, let’s enable this service. Depending on how you manage your clients/users, you may simply allow all incoming SSH traffic:
#accept all incoming ssh traffic -A FWALL-INPUT -p tcp -m tcp -s 0/0 --dport 22 -j ACCEPT
Alternatively, SSH can be restricted to identified static IP address hosts:
#accept incoming ssh traffic from user John Doe -A FWALL-INPUT -p tcp -m tcp -s x.x.x.x --dport 22 -j ACCEPT #end specific ssh access â€“ this commenting is handy of you have multiple users here as #you can start and end sections if users have multiple IPs from which they can access
In breaking down those lines of code, we see:
-Aappends the rule to the firewall rule set
-prepresents protocol (which can be
icmpin varying cases)
-mis for match and opens up options for extending packet management, for example to have granular control over
SYNbits, defining destination and source ports. This is better explained at length in ‘man iptables’ than here, as multiple levels of options are available.
-ssignifies the source address, where
0/0stands for any host, a specific host IP address can be used (as in the example above), or a network segment can be denoted, such as
--dportpoints to the destination port; in the case of SSH, it’s
-jselects the target (or jump target), which may be a custom target, or one of the common built-in targets such as
Next, let’s consider FTP, an entry for the Webmin control panel, and a host of commonly used ports that are important to your server’s operation on the Internet.
# manage ftp port traffic
-A FWALL-INPUT-p tcp -m tcp --dport 21 -j ACCEPT
# end ftp port
#My webmin custom port
-A FWALL-INPUT-p tcp -m tcp --dport 42009 -j ACCEPT
# end webmin
#SNMP monitoring so I can use a remote monitoring tool
-A FWALL-INPUT-p udp -m udp --dport 161 -j ACCEPT
-A FWALL-INPUT-p udp -m udp --sport 1023:2999 -j ACCEPT
A quick security note: when enabling remote access to SNMP, please be sure to have invested time in securing your SNMP configuration file(s), including changing community strings and using authentication.
# some standard out ports with port definition #POP mail -A FWALL-INPUT-p tcp -m tcp --dport 110 -j ACCEPT --syn #HTTPS -A FWALL-INPUT-p tcp -m tcp --dport 443 -j ACCEPT --syn #SMTP Traffic -A FWALL-INPUT-p tcp -m tcp --dport 25 -j ACCEPT --syn #HTTP -A FWALL-INPUT-p tcp -m tcp --dport 80 -j ACCEPT --syn #In my case - Urchin -A FWALL-INPUT-p tcp -m tcp --dport 9999 -j ACCEPT --syn #MySQL database server -A FWALL-INPUT-p tcp -m tcp --dport 3306 -j ACCEPT --syn -A FWALL-INPUT-p udp -m udp --dport 3306 -j ACCEPT #IMAP mail services -A FWALL-INPUT-p tcp -m tcp --dport 143 -j ACCEPT --syn #DNS -A FWALL-INPUT-p tcp -m tcp --dport 53 -j ACCEPT --syn -A FWALL-INPUT-p udp -m udp --dport 53 -j ACCEPT -A FWALL-INPUT-p udp -m udp -s 0/0 -d 0/0 --sport 53 -j ACCEPT #Localhost traffic -A FWALL-INPUT-i lo -j ACCEPT #The below commits the rules to production for iptables to execute COMMIT
You will notice we added the
--syn flag. This is part of the previously mentioned
-m (for matching) option in iptables. Here, we are specifically ensuring that only new connections with a
SYN bit, and for which no
ACK is set, are accepted.
At this point, you have a working development firewall. You can add and remove services to meet your own requirements. However, we can make some additional entries. We can add a final rule that drops all packets that do not qualify for any of our preceding ports.
#Drop all other new requests not meeting any existing rule requirements applied to traffic -A FWALL-INPUT -p tcp -m tcp -j REJECT --syn -A FWALL-INPUT -p udp -m udp -j REJECT
SYN Flood Protection
For some added protection, we can also seek to prevent the flooding of new requests (packets with the
SYN bit set and no
ACK, as discussed earlier in the article) by limiting the amount of requests to 5 seconds, which allows the system time to apply the rules.
-A FWALL-INPUT â€“p tcp --syn -m limit --limit 5/second -j ACCEPT
This should appear at the top of your rules, just above the first SSH entry.
If there are troublesome hosts you have discovered in your logs, these can be banned via iptables; however, be cautious in light of IP masquerading. Do some research on the IP address you wish to block, to ensure it is not a legitimate SMTP server, or worse: one of your clients who has been spoofed.
To block a specific host:
#Block malicious system -A FWALL-INPUT -p tcp -m tcp -s x.x.x.x -j DROP
Checking Firewall Logs
iptables traditionally logs basic entries to
/var/log/messages. However, specific logging needs to be noted in your firewall rules if you’d like to track and research traffic. Many prefer to log only
drop/reject actions, as this allows them to see any potential malicious behavior that’s being attempted.
This can be handled with an entry like the following:
#Option 1 logging drop/reject actions -A FWALL-INPUT -j LOG --log-level alert #Option 2 logging with a prefix for easy search/grep of log file -A FWALL-INPUT -j LOG --log-prefix "Dropped: "
Finally, a nice open source iptables log analyzer is available; it provides an interface similar to those commonly used to view Web traffic statistics. Found online at gege.org, this daemon can be implemented into a LAMP (specifically PHP and MySQL) environment and used to log all iptables actions in place of the default
Setup and configuration is straightforward and only a minor edit to your iptables file will start the reporting process.
The man pages for iptables are extensive and it is recommended to spend some time getting accustomed to the various options before moving a firewall into production. For example, options exist for using the -m (matching) option to manage packet states – i.e. allowing only new and established connections for specific services.
There are endless documents related to iptables on the Web, however, the best place to start is at the source: Netfilter’s Website. Tutorials range from basic networking concepts and packet filtering to setting up network address translation and advanced connection tracking options.
Finally, as noted before, this firewall does not represent the be-all and end-all configuration. It is a great place to start when exploring your options with iptables. Administrators, based on their environment, will have varying levels of paranoia to accommodate. Some systems I manage are locked as tight as possible, while others have fairly open doors for testing and development.