Firewalled Up (Part 2) 

December 14, 2018
Firewall , iptables
Deluxe company -

Continuing with our previous article on firewalls, it is time to put the theory to practice. Today’s article is going to talk about how we can set up common rules using iptables. All commands below are as a non-root user with superuser privileges. Since you are working on controlling access to your VPS, it is recommended to not close all connections without testing the added rules. Open a SSH connection and keep it running in a separate window while making these changes in a new window. If something goes wrong, you can undo the change or start over from scratch

$ sudo iptables -F             # Flush all existing rules and start over

The Starting Point

Let us begin by listing the current rules on the system

$ sudo iptables -L

Here is the output from a new VPS

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

The three chains – INPUT, FORWARD and OUTPUT, are currently accepting all connections. We will start with a simple internal rule, allowing the loopback interface to forward connections to itself. This is particularly useful when the web server connects to the database server (e.g. MySQL) on a port on the “localhost” instead of using unix sockets.

$ sudo iptables -A INPUT -i lo -j ACCEPT

$ sudo iptables -A OUTPUT -o lo -j ACCEPT

A quick run down of the parameters, -A is to append, INPUT/OUTPUT specify the chain to which the rule is added. The -i and -o options specify input and output interfaces respectively. In both cases we are referring to the loopback interface “lo”. -j specifies what needs to be done to the packets that meet the criteria. We want to ACCEPT such packets

We have made this rule without specifying any protocols (TCP/UDP) or ports. This makes our lives easier as we don’t have to add more rules when new changes come in. A common example is you may choose to run FastCGI for your PHP in port 9000. If your earlier rule was setup only for port 3306 (MySQL), the time FastCGI is installed you will run into errors.

The next rule we need to add is to allow all established and related incoming connections.

$ sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

The new parameters you see here are -m which stands for match the subsystem connection tracking (conntrack) where the connection state (–ctstate) is established or related. The -j ACCEPT is to accept traffic (as we saw before)

Similarly, we will allow all established outgoing connections

$ sudo iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT

Note the chain we are referring to is the OUTPUT chain to reference outgoing connections.

Port & Protocols

To add rules specific to a protocol and port, we will start by adding a rule that allows SSH connections

$ sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

This accepts all TCP connections on port 22. If you have made changes to your SSH settings to connect to a different port, change it after the –dport parameter

To allow your web server to accept connections, the rule is similar, the port changes

$ sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT # HTTP requests

$ sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT # HTTPS requests

The above can be also setup as

$ sudo iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT

If your server is not going to send email, you will REJECT all outgoing traffic on port 25 like this

$ sudo iptables -A OUTPUT -p tcp --dport 25 -j REJECT

If you have installed MOSH, you will need to open a range of ports using the UDP protocol

$ sudo iptables -I INPUT -p udp --dport 60000:61000 -j ACCEPT

The -I switch indicates, INSERT and in the above case inserts this rule at the top of the INPUT table

If things change and you want to delete a rule (for e.g., your application now is starting to send emails and will require access to the SMTP port), you can delete the particular rule. The flag is -D and the rest of the rule remains the same as when you appended it.

$ sudo iptables -D OUTPUT -p tcp --dport 25 -j REJECT

Restricting & Blocking

Sometimes you want to restrict connections based on where the originate from. If you have a fixed IP and want to ensure that SSH connections are only accepted from your known IP address, your “allow SSH” rule would look like this

$ sudo iptables -A INPUT -p tcp -s 123.456.7.8 --dport 22 -j ACCEPT

Only SSH connection requests from the IP 123.456.7.8 will be accepted and all other connections rejected

If you think that certain IP addresses are causing trouble for your node (such as by constant pinging/port scanning etc.), you can DROP all connections from that IP address

$ sudo iptables -A INPUT -s 123.456.8.9 -j DROP

The source IP 123.456.8.9 will have all packets dropped. If you want to send a “Connection Refused” response back to this IP, change -j DROP to -j REJECT

If you have two network interfaces on your machine, one internal and one external. You can add a rule that allows your internal network to access the external network. Assuming eth0 is your external network and eth1 is the internal one, we will add a rule to the FORWARD chain

$ sudo iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT

Saving Your Rules

So far, all the rules we have established are valid as long as the server is on. Once rebooted, the rules get cleared out. You can make the rules persistent by using the iptables-save command. On the common Linux flavors, you can invoke it as

$ sudo iptables-save > /etc/iptables/rules.v4 # Ubuntu/Debian

$ sudo iptables-save > /etc/sysconfig/iptables # CentOS

Here is how the iptables list looks like after executing the commands above

Chain INPUT (policy ACCEPT)

target prot opt source destination

ACCEPT udp -- anywhere anywhere udp dpts:60000:61000

ACCEPT all -- anywhere anywhere

ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED

ACCEPT tcp -- anywhere anywhere tcp dpt:ssh

ACCEPT tcp -- anywhere anywhere multiport dports http,https

Chain FORWARD (policy ACCEPT)

target prot opt source destination

Chain OUTPUT (policy ACCEPT)

target prot opt source destination

ACCEPT all -- anywhere anywhere

ACCEPT all -- anywhere anywhere ctstate ESTABLISHED

In our next and final part, we will talk about other interfaces that connect with iptables such as ufw and firewalld and see how we can setup rules using those tools.


Ramesh Vishveshwar
Ramesh Vishveshwar

Ramesh Vishveshwar is a tech blogger who is always on the lookout for the next big thing. Having discovered his infatuation for various flavors of Linux, he spends his time tinkering with VPS nodes installing and trying out new applications. His interest in coding spans across multiple languages from PHP, shell scripting to remote old generation languages such as COBOL.