Redhat Firewall configuration: from iptables to firewalld

Tools to manage firewall

Packet filter rules in Linux Kernel is managed by an user-space application named iptables in CentOS and RedHat. Since CentOS 7, firewalld is introduced as an alternative to iptables. Firewalld can be installed and executed as a systemd service, and it is supposed to replace iptables. This article describes how to configure both.

There are several advantages in firewalld. One is is the support of zones. Here are some useful information. Also, iptables involves three different services for IPv4(iptables), IPv6(ip6tables), and software bridging (ebtables), whereas firewalld only involves a single service to manage all three. Firewalld allows user to add or remove rules/ports from running firewall, without restarting firewall. Unless you have specific reason to use iptables, always use firewalld service to manage firewall. Here is an instruction to firewalld service. In this posting however, we will be focusing on iptables to understand firewall managment. We also go through an example of opening a TCP port.

How does iptables work

When working with iptables, it is important to understand that its related concepts (tables->chains->rules->criteria and targets) and how the order of rules plays a factor. There are five independent tables, each contains a number of chains, either built-in or user-defined. Administrators mostly deals with built-in chains in filter and nat tables. The five tables are:

  • filter: If -t isn’t specified, this is the default table. It contains built-in chains:
    • INPUT: for packet destined to local sockets
    • FORWARD: for packets being routed through the box
    • OUTPUT: for locally-generated packets
  • nat: this table is consulted when a packet that creates a new connection is encountered. It has three built-in chains:
    • PREROUTING: for altering packets as soon as they come in
    • OUTPUT: for altering locally generated packets before routing
    • POSTROUTING: for altering packets as they are about to go out
  • mangle: this table is used for specialized packet alternation, with five built-in chains (since kernel 2.4.18): PREROUTING and OUTPUT, INPUT, FORWARD, and POSTROUTING
  • raw: this table is mainly for configuring exceptions from connection tracking with two built-in chains: PREROUTING and OUTPUT
  • security: for Mandatory Access Control (MAC) networking rules, with three built-in chains: INPUT, OUTPUT, and FORWARD.

Under the table (e.g. filter, nat), each chain (e.g. INPUT, OUTPUT, etc) consists of list of firewall rules. Each rule is made up of two parts defined for the packets:

  • Criteria: if the packet does not match the criteria, the next rule in the chain is examined; if it does match, then the next rule is specified by the value of the target.
  • Target: what to do if criteria is met. The target can be:
    • user-defined chain,
    • one of the target described in iptables-extensions, or
    • in most cases, one of the special values ACCEPT, DROP or RETURN
      • ACCEPT – let the packet through
      • DROP – drop the packet on the floor
      • RETURN – stop traversing this chain, and resume at next rule in the previous (calling) chain

The rules, defined in each chain under their tables, can be found in file /etc/sysconfig/iptables. You can find tables (prefix with asterisk *), chains (prefix with colon :), rules under their chains and a statement COMMIT after each table. The iptables process flow illustrates how a packet interact with all these rules under different chains and tables defined in this file:

IPTables and Docker. In this post I will be talking about… | by Edouard  Buschini | Medium
iptables Process Flow

Although this big picture looks formidable, an administrator commonly only deals with the green and purple blocks (filter and nat), with the big picture in mind. Here is an example of /etc/sysconfig/iptables file from a newly installed system:

# Generated by iptables-save v1.4.21 on Fri Sep 11 23:15:32 2017
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [132:17200]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
# Completed on Fri Sep 11 23:15:32 2017

The rule simply allows SSH traffic. This file will be loaded up on every reboot (specifically, restart of iptables service). So if you have made some changes to rules and you want the change picked up on reboot. The rules should be saved to this file:

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

Other than saving rule for reboot, if you simply want to edit the rules (e.g. order of rules is incorrect), you can save the rules to file, modify the file and restore the rule from file:

$ sudo iptables-save > ~/iptables.txt
$ sudo vi ~/iptables.txt
$ sudo iptables-restore < ~/iptables.txt

Here is some further reading about iptables architecture.

Anatomy of a rule

The man page for iptables species the following synopsis:

iptables [-t table] {-A|-C|-D} chain rule-specification
rule-specification = [matches...] [target]
match = -m matchname [per-match-options]
target = -j targetname [per-target-options]

So when you append (-A), delete (-D), insert (-I) or replace (-R) a rule, you need to specify rule specification. The man page further explains that the following parameters make up a rule specification:

  • protocol (-p): the protocol of the rule of the packet to check. value can be tcp, udp, icmp, all or any name defined in /etc/protocols.
  • match (-m): specifies the name of a match to use and is followed by match options. The match refers to an extension module that tests for a specific property. Those extension modules are documented in the man page of iptables-extensions. You may specify -m multiple times for different match names, which together make up the condition under which a target is invoked. Matches are evaluated first to last as specified. We often use extensions tcp and state. According to iptables-extensions man page, we can specify –dport followed by port number for the tcp extension, and –state followed by value such as NEW or ESTABLISHED for the state extension.
  • jump (-j): specifies the target of the rule, such as ACCEPT, REJECT or DROP.
  • source and destination (-s and -d): source and destination IP address or masks. Hostname will work but not recommended since resolution is needed.
  • inbound and outbound interface (-i and -o): name of interface via which the packet was received and is going to be sent.
  • goto (-g): processing should continue in a user specified chain
  • Other parameters: -4/–ipv4, -6/–ipv6, -c/–set-counters, -f/–fragment

When we run iptables command to view rules, we need to specify the table (e.g. filter, nat, etc) followed by -S or –list-rules:

$ iptables -t nat -S

If you do not specify -t switch, the default (-t filter) is applied. Be aware that in this case, you’re only seeing rules under filter table, and not all rules under tall tables!

In the result, for example one line from command “iptables -S” may say:

-A INPUT -p tcp -m state --state NEW -m tcp --dport 9200 -j ACCEPT

The interpretation: appending a rule to INPUT chain of filter table (implicitly specified). The protocol is tcp. The first match extension is state, and the state value shall be NEW. The second match extension is tcp, and the dport value shall be 9200. If the packet is a match, then the target (action) is ACCEPT.

Managing rules

As mentioned earlier, rules can be dumped to any file or /etc/sysconfig/iptables, in which the rules are assessed in order. Below is a real life iptables file with a nat table as well.

# Generated by iptables-save v1.4.21 on Wed Jan 15 13:58:39 2017
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [4:208]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -s 10.100.160.56/32 -p tcp -m state --state NEW -m tcp --dport 7000:7001 -j ACCEPT
-A INPUT -s 10.100.160.56/32 -p tcp -m state --state NEW -m tcp --dport 7199 -j ACCEPT
-A INPUT -s 10.100.160.56/32 -p tcp -m state --state NEW -m tcp --dport 9042 -j ACCEPT
-A INPUT -s 10.100.160.56/32 -p tcp -m state --state NEW -m tcp --dport 9160 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 8080 -j ACCEPT
-A INPUT -p udp -m state --state NEW -m udp --dport 161 -j ACCEPT
-A INPUT -p udp -m state --state NEW -m udp --dport 162 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

*nat
:PREROUTING ACCEPT [1:328]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING -p tcp -m tcp --dport 2392 -j REDIRECT --to-ports 2398
-A PREROUTING -p tcp -m tcp --dport 2393 -j REDIRECT --to-ports 2398
-A OUTPUT -o lo -p tcp -m tcp --dport 2392 -j REDIRECT --to-ports 2398
-A OUTPUT -o lo -p tcp -m tcp --dport 2393 -j REDIRECT --to-ports 2398
COMMIT
# Completed on Wed Jan 15 13:58:39 2017

In this example, the nat table defines traffic forwarding: traffic arriving at TCP port 2392 and 2393 are forwarded to port 2398; outgoing traffic to port 2392 and 2393 are also redirected to port 2398. These rules do not overlap each other so the rules probably don’t matter.

On the other hand, the tcp filter table lists the rules to open certain TCP and UDP ports. Its block starts with a couple accepting rules and ends with a couple reject rules (regardless of protocols or ports). This is a good way to close a chain of rules with security. However, if you need to add additional rules to open more TCP ports, the new rule should not be appended after the reject rules at the bottom since the order matter here!

Correct way to open a TCP port

It’s a common task for developers to open a TCP port simply for the purpose of bring up a web service and make it accessible to client. If we simply add a new rule to existing list, for example:

# iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 9870 -j ACCEPT
# iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A INPUT -p tcp -m state --state NEW -m tcp --dport 9870 -j ACCEPT
-A FORWARD -j REJECT --reject-with icmp-host-prohibited

# systemctl reload iptables

You will notice that the rule is appended to the end of INPUT block, below the INPUT REJECT rule, which will never take effect.

To address this, you can use iptables-save and iptables-restore to export, edit to correct order and reload the rule, as illustrated above, instead of using iptables command to modify the rule directly.

# iptables-save > /tmp/rule.list
# vi /tmp/rule.list
# iptables-restore < /tmp/rule.list
# iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 9870 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited

Alternatively, you could use some advanced iptables command switches to add the new rule to certain line number with –line-number switch. Here is more information.