Priyanka Saggu I speak here {^_^}

Let's get started with iptables!

August 8, 2019

[ After procastinating to write for a whole long day due to a number of xyz reasons, here I am finally writing about what I did in past 2 days. ]

It's about iptables!

Whatever we do on any network, it includes exchange of huge number of incoming and outgoing network packets. Now, it's not necessarily bound that whatever is coming to our end (our host/ server/machine), has to be accepted. Same goes for the outgoing traffic as well (like not everything has to be transferred outside). And there is another thing called forwarding which means, there is some traffic created from some network node (suppose A) and it is intended for some another network node (suppose B). Between them, our node is acting as a forwarding node i.e it will direct/forward the incoming traffic from node A to node B (for instance, routers are meant for forwarding packets or routing). And yes, this forwarding process also requires some levels of restrictions.

Thus, there has to be something to monitor & regulate this network activity.

And Firewall is that component which ensures that this incoming, outgoing, and forwarding of network packets is happening according to a certain defined set of rules.

The linux distributions are shipped with a few different firewall tools, that could be used for the above purpose. One among them (that we are gonna discuss here) is iptables firewall.

Iptables is a standard firewall included in most Linux distributions by default (a modern variant called nftables will begin to replace it). It is actually a front end to the kernel-level netfilter hooks that can manipulate the Linux network stack. It works by matching each packet that crosses the networking interface against a set of rules to decide what to do.

Justin Ellingwood

Now that we have a good introduction to "what Firewall is and why it is required". Also, we know that iptables can be used to fulfil the requirement. Let's quickly get introduced with the basic terminologies used in iptables as well.

  • Rules: These are certain validations against which the network packets are compared, so that, they can be marked whether to accept or drop or queue or log or something else. The comparision can be done on many things like the packet protocol type, the source or destination address or port, the interface that is being used, its relation to previous packets, etc. (Don't worry if it sounds complicated right now, we will see all these later in the post with simple examples. :) )
  • Target: If the network traffic is validated (matched) against a rule, the follow up action is known as Target. The target could be accepting, dropping, or moving the packet to a different chain, or logging the validation, etc.
  • Chains: These are simply a sequential set of rules (that we have talked above). A packet is checked sequentially along this chain of rules, and if it matches with a certain rule, the corresponding action is performed. No further comparision of the packet will be there, with rest of the rules left. A user can create these chain(s) of rules as per the requirement. By default, there are 5 chains available ( if you have read the introduction carefully, then you can easily imagine about what the rules defined in the first three chains will do. :) )
    1. INPUT
    2. OUTPUT
    3. FORWARD
    4. PREROUTING (This chain include rules for modifying the packets as they arrive.)
    5. POSTROUTING (This chain include rules for modifying packets as they are leaving.)

Each chain can contain zero or more rules, and has a default policy. The policy determines what happens when a packet drops through all of the rules in the chain and does not match any rule. You can either drop the packet or accept the packet if no rules match.

Justin Ellingwood

  • Tables: And moving along the hierarchy, the set of chains is known as a Table. There could be five possible tables:
    1. filter (the default table for packet filtering)
    2. nat (meant for Network Address Translation(NAT))
    3. mangle (associated with specialised packet alteration)
    4. raw (configures exemptions from connection tracking)
    5. security (associated with Mandatory Access Control)

And here, I end the boring (though necessary :) ) theoretical part. Let's have a hands-on now on writing some basic iptables rules.


REQUIREMENT:

A separate, non-root superuser account i.e a user with sudo privileges.

[NOTE: For most part below, we will be working on the "INPUT" chain inside the default "filter" table. You can always try to write new rules for other chains in different tables as you feel a bit confident about your concepts. ]

  • Launch a new terminal. (I am using a new VM, so it will be all from scratch.)
  • Run the following command to confirm if "iptables" is installed in your system by default or not. If it gives you a number (something like shown), then you are good to go.

$ sudo iptables --version
//OUTPUT
iptables v1.6.1

  • In case, if it throws an error of "command not found", install it using:

$ sudo apt-get install iptables

  • Now, that we have our setup ready. Let's write our first command to see what are the default chains available to us in "filter" table.

$ sudo iptables -L

// If you want to see what chains are there in other tables, use the general syntax
// Syntax: sudo iptables -t <table_name> -L
//for example:
$ sudo iptables -t nat -L

list iptables
output of "sudo iptables -L"

As you see, we have 3 default chains, "INPUT, FORWARD, and OUTPUT" with zero rules by default. The default policy (I'll be discussing in a second about this) is ACCEPT for all three of the above chains. And right below these three chains, we have headers to indicate various components of the rules.

Each chain can contain zero or more rules, and has a default policy. The policy determines what happens when a packet drops through all of the rules in the chain and does not match any rule. You can either drop the packet or accept the packet if no rules match.

Justin Ellingwood

  • If you want to change the default policy of these chains, it can be done as following ( ⚠️ I am changing it to DROP to show you an example, but it is not recommended to change the default policy to DROP before adding any specific rules to ACCEPT packets. ⚠️)

//syntax: sudo iptables -P <chain_name> Policy
//Or, sudo iptables --policy <chain_name> Policy

$ sudo iptables -P INPUT DROP

  • And if by mistake you have ran the above command before adding any rules, or anyway in any case, you want to flush/dump all your existing rules (if you have any) at once. Use the command:

$ sudo iptables -F

  • let's write/append our very basic first rule in the INPUT chain of the "filter" table. This rule will block all connections from a specific IP address 10.0.0.1.

// syntax: sudo iptables -t <table_name> -A <chain_name> [parameters]

$ sudo iptables -t filter -A INPUT -s 10.0.0.1 -j DROP

// As filter is a default table, we can re-write it as
$ sudo iptables -A INPUT -s 10.0.0.1 DROP

"-t" flag is used to determine the name of the table in while the rule is being written.

"-A" flag (or it can be "--append" as well) determines the chain in which the rule will be appended (or added at the end).

"-s" flag is used to match with the source address of the packet.

"-j" flag specifies the target of matching packets. So, here the packets that match the preceding criteria should be accepted and allowed through.

  • The next rule will accept all the network packets coming from a range of IP address "10.0.0.0" to "10.0.0.255". ("/24" means a subnet mask of 255.255.255.0)

// The "slash" or "/" notations or the netmask specifies the range of the IP addresses.
$ sudo iptables -A INPUT -s 10.0.0.0/24 ACCEPT

  • Similarly, the next rule will block all the network packets destined for the IP address range "23.220.0.0" to "23.220.255.255" (Don't worry, these are just random IPs).

$ sudo iptables -A INPUT -d 23.220.0.0/16

"-d" flag is to match with the destination address of the packet.

  • Let's move a little forward and try to write rules for specific ports. The next rule will block all the SSH conncetions coming from 192.168.192.21. (Assuming SSH is at the default port 22)

$ sudo iptables -A INPUT -p tcp --dport 22 -s 192.168.192.21 -j DROP

"-p" flag tells about which protocol is used. Here we have defined the rule for TCP. If it was for some other protocol like udp, icmp etc., it would have been like "-p udp" or "-p icmp".

"--dport" determines the destination port number. As here, we are blocking the packet destined for port 22 on our machine. So, port 22 is a destination port for the incoming packet. (The just opposite flag will be "--sport" to determine the source port number.)

  • The next iptables rule will block SSH connections from any IP address. ( ⚠️ Don't run it though unless you have a specific ACCEPT rule defined for your particular address which you use to join this intended IP address, or you yourself would be locked outside. ⚠️)

$ sudo iptables -A INPUT -p tcp --dport ssh -j DROP

  • We can delete the already defined rules as well. The following command will delete the above command if you mistakenly ran that. :)

$ sudo iptables -D INPUT -p tcp --dport ssh -j DROP

//If you know the index of the rule in the chain, you can delete the rule by the index number.
//suppose the index of the above rule(at what index, the above rule is in sequence of rules in the chain) is 5.
//syntax: sudo iptables -t <table_name> -D <chain_name> <index_number>
$ sudo iptables -D INPUT 5

"-D" (or "--delete") flag determines which rule is to be deleted.

Another thing to keep in mind is that the order of the rules in each chain matter. A packet must not come across a more general rule that it matches if it is meant to match a more specific rule. Because of this, rules near the top of a chain should have a higher level of specificity than rules at the bottom. You should match specific cases first, and then provide more general rules to match broader patterns. If a packet falls through the entire chain (doesn't match any rules), it will hit the most general rule, the default policy.

Justin Ellingwood

  • So, keeping the above thought in mind, you may want to insert a rule at a particular index in the sequence. The next rule will be inserted at index 2 in the INPUT chain of filter table. (The following rule specifies to drop all the udp packets. )

//syntax: sudo iptables -t <table_name> -I <chain_name> <index_number> [parameters]

$ sudo iptables -I INPUT 2 -p udp -j DROP

"-I" (or "--insert") flag is paired with a index number (like in our case, "2" ) to determine at what particular index the rule is to be inserted in the chain.

  • let's quickly see one more iptables rule to drop all packets destined for wireless (wlan0) interface.

$ sudo iptables -A INPUT -i wlan0 -j DROP

"-i" flag matches the network packets with the specific in-interface. (The just opposite flag is "-o" for out-interface)


We have covered some basic iptables rule. Before discussing a few complex iptables examples, let's quickly see how to make user-defined chains.

  • The following command is to add a user-defined chain in an iptables table.

// syntax: sudo iptables -t <table_name> -N <new_chain_name>

$ sudo iptables -t filter -N sampleChain

Note that these user-defined chains don't have any default policy.

  • To remove a user-defined table, use the following command.

//syntax: sudo iptables -t <table_name> -X <user-defined_chain_to_be_deleted>
$ sudo iptables -t filter -X sampleChain

  • Like "-L" is used to list all the chains and rules in a table, we can output them in a format which reflects the commands required/used to enable each of them.

//syntax: sudo iptables -t <table_name> filter -S
$ sudo iptables -t filter -S

//The output will be somewhat like
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT


Before we conclude this article, let's try to write a more complex iptables rule with a more realistic approach.

  • This next iptables rule will explicitly accepts your current SSH connection.

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

"-m" flag is to determine "conntrack" module which is one among the set of extensions/modules that provides extra capabilities to iptables core functionality.

conntrack  module gives access to commands that can be used to make decisions based on the packet's relationship to previous connections. 

Justin Ellingwood

"--ctstate" is one of the commands provided under conntrack module. It is used to match network packets based on how they were related the previous packets seen by the host.

The value "ESTABLISHED" specifies to allow packets that are part of an existing connection. While the value "RELATED" specifies to allow packets that are associated with an established connection. These two values are the determining part for our current SSH session.


Pheww, I think this was a good basic intro to iptables. Now that these iptables rules are ephemeral i.e. everything will go away once we reboot our machine/host/server.

So, in order to sabe the iptables cofiguration tables, you need to install another iptables package from the Ubuntu's default repositories.

$ sudo apt-get update
$ sudo apt-get install iptables-persistent

And finally run this command to save the configuration, so that it remains intact after reboot of the machine.

$ sudo service netfilter-persistent save


That's all from my end for iptables. I have read a bit more for myself though. So, adding pointers to the references down below.

Till next time. o/

REFERENCES: