Analysis of Firewalld created IPTables

Let's talk about IPtables and Firewalld.

IPtables is Unix' defacto firewall solution.  Super powerful, get's the job done, you can roll this solution out immediately.  You can incorporate scripting elements into implementation of IPTables to automate/simplify the job.  IPtables have been around a while, since 1998.

Many sysadmins utilize IPtables, honestly I don't see it going away anytime soon.  With a single line including arguments you can direct traffic between networks(forwarding) and control all traffic in and out of a system. 

Getting started with IPtables is not for the faint of heart however.  When you first get started you quickly realize that you have to think about everything when designing rules, "how does the traffic flow?" "What exactly is happening when the user does _____?""How do I appropriately administer 'Deny first-then allow'?"

Studying IPtables is an important part of fully understanding how FW work.  All this being said, a lot of smart people have worked on solutions to simplify tools.  Here we see Firewalld.

Firewalld is a application that is based on IPtables.  It provides the user with a terminal interface that allows the user to completely manipulate the FW.  Firewalld also brings in useful elements such as zones which are helpful for FW solution building.  For those who would rather use a gui, they can install "firewall-config" and get a very nice gui that makes the job that much easier.

Goal:  If both solutions utilize IPtables how if at all do the IPtables look different from one another.

Scenario: Target set to DROP, and only allowing user access to the internet.

Because IPtables ship with the default policy of ACCEPT(allowing everything) we need to turn everything to DROP (disallow everything)
 
iptables –-policy INPUT DROP
iptables –-policy OUTPUT DROP
iptables –-policy FORWARD DROP 

Now our user is only allowed to connect to the internet.  We know that http is over port 80 and https is over port 443.  Also keep in mind that our user will need to resolve with DNS, port 53.

-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -P TCP -m tcp --dport 443 -j ACCEPT

-A OUTPUT -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT

-A OUTPUT -p tcp --dport 80 --syn -m state --state NEW -j ACCEPT

-A OUTPUT -p tcp --dport 443 --syn -m state --state NEW -j ACCEPT

-A OUTPUT -p tcp --dport 53 --syn -m state --state NEW -j ACCEPT


Let's look at a few of these lines and see what is happening.

-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -P TCP -m tcp --dport 443 -j ACCEPT

Here we have rules for packets coming in. Hence INPUT, we are setting the protocol to tcp, choosing a destination port (80 and 443) and accepting packets through these ports.

Keep in mind that everything IN/OUT is set to DROP.  So packets will only come in on port 80 and 443.

Next lets look at OUTPUT.  With IPtables if you have a rule for INPUT you have to have a similar/equal rule for OUTPUT (unless OUTUT is set to ACCEPT)

For the most part things are operating in a similar fashion, so lets highlight a few key differences. 

We can see that we are working with the same ports 80 and 443,
with the addition of:
--syn -m state --state NEW We are setting "--syn" which can also be interpreted as
--tcp-flags FIN,SYN,RST,ACK SYN

Next is "-m state --state NEW"  we are matching the state NEW.

Finally we are including the port 53.  We need to be able to resolve addresses.

Seems simple enough right?  Let's see how Firewalld handles the exact same scenario. (#iptables -S ) output below.

-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N INPUT_direct
-N INPUT_ZONES
-N FORWARD_direct
-N FORWARD_IN_ZONES
-N FORWARD_OUT_ZONES
-N OUTPUT_direct
-N IN_security
-N IN_security_pre
-N IN_security_log
-N IN_security_deny
-N IN_security_allow
-N IN_security_post
-N FWDI_security
-N FWDI_security_pre
-N FWDI_security_log
-N FWDI_security_deny
-N FWDI_security_allow
-N FWDI_security_post
-N FWDO_security
-N FWDO_security_pre
-N FWDO_security_log
-N FWDO_security_deny
-N FWDO_security_allow
-N FWDO_security_post
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED,DNAT -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -j INPUT_direct
-A INPUT -j INPUT_ZONES
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED,DNAT -j ACCEPT
-A FORWARD -i lo -j ACCEPT
-A FORWARD -j FORWARD_direct
-A FORWARD -j FORWARD_IN_ZONES
-A FORWARD -j FORWARD_OUT_ZONES
-A FORWARD -m conntrack --ctstate INVALID -j DROP
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -j OUTPUT_direct
-A INPUT_ZONES -i wlan0 -g IN_security
-A INPUT_ZONES -g IN_security
-A FORWARD_IN_ZONES -i wlan0 -g FWDI_security
-A FORWARD_IN_ZONES -g FWDI_security
-A FORWARD_OUT_ZONES -o wlan0 -g FWDO_security
-A FORWARD_OUT_ZONES -g FWDO_security
-A IN_security -j IN_security_pre
-A IN_security -j IN_security_log
-A IN_security -j IN_security_deny
-A IN_security -j IN_security_allow
-A IN_security -j IN_security_post
-A IN_security -j DROP
-A IN_security_allow -p tcp -m tcp --dport 53 -m conntrack --ctstate NEW,UNTRACKED -j ACCEPT
-A IN_security_allow -p udp -m udp --dport 53 -m conntrack --ctstate NEW,UNTRACKED -j ACCEPT
-A IN_security_allow -p tcp -m tcp --dport 80 -m conntrack --ctstate NEW,UNTRACKED -j ACCEPT
-A IN_security_allow -p tcp -m tcp --dport 443 -m conntrack --ctstate NEW,UNTRACKED -j ACCEPT
-A FWDI_security -j FWDI_security_pre
-A FWDI_security -j FWDI_security_log
-A FWDI_security -j FWDI_security_deny
-A FWDI_security -j FWDI_security_allow
-A FWDI_security -j FWDI_security_post
-A FWDI_security -j DROP
-A FWDO_security -j FWDO_security_pre
-A FWDO_security -j FWDO_security_log
-A FWDO_security -j FWDO_security_deny
-A FWDO_security -j FWDO_security_allow
-A FWDO_security -j FWDO_security_post
-A FWDO_security -j DROP


The first thing you should notice is that all three policies are set to ACCEPT.  From a security standpoint this goes completely against "deny first - then allow."  However if we take a step back and look at how Firewalld functions, we will see that it uses on zones.  Some zones come prepackaged with Firewalld and you can guess that some of the default zones are a lot less restrictive than what we are going for here.  Hence why everything is open(ACCEPT).  Firewalld accepts all input then filters it to the required zone specified set to default.  Since our zone is set to DROP everything, then we are ok.

Next we see a bunch of lines beginning with "-N."  Basically what is happening here is that our zone "security" exists and all the direct rules that pertain to this zone are in place.

Now the really interesting part, how firewalld is handling INPUT

-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED,DNAT -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -j INPUT_direct
-A INPUT -j INPUT_ZONES
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED,DNAT -j ACCEPT
-A FORWARD -i lo -j ACCEPT
-A FORWARD -j FORWARD_direct
-A FORWARD -j FORWARD_IN_ZONES
-A FORWARD -j FORWARD_OUT_ZONES
-A FORWARD -m conntrack --ctstate INVALID -j DROP
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -j OUTPUT_direct
-A INPUT_ZONES -i wlan0 -g IN_security
-A INPUT_ZONES -g IN_security
-A FORWARD_IN_ZONES -i wlan0 -g FWDI_security
-A FORWARD_IN_ZONES -g FWDI_security
-A FORWARD_OUT_ZONES -o wlan0 -g FWDO_security
-A FORWARD_OUT_ZONES -g FWDO_security
-A IN_security -j IN_security_pre
-A IN_security -j IN_security_log
-A IN_security -j IN_security_deny
-A IN_security -j IN_security_allow
-A IN_security -j IN_security_post
-A IN_security -j DROP
-A IN_security_allow -p tcp -m tcp --dport 53 -m conntrack --ctstate NEW,UNTRACKED -j ACCEPT
-A IN_security_allow -p udp -m udp --dport 53 -m conntrack --ctstate NEW,UNTRACKED -j ACCEPT
-A IN_security_allow -p tcp -m tcp --dport 80 -m conntrack --ctstate NEW,UNTRACKED -j ACCEPT
-A IN_security_allow -p tcp -m tcp --dport 443 -m conntrack --ctstate NEW,UNTRACKED -j ACCEPT
-A FWDI_security -j FWDI_security_pre
-A FWDI_security -j FWDI_security_log
-A FWDI_security -j FWDI_security_deny
-A FWDI_security -j FWDI_security_allow
-A FWDI_security -j FWDI_security_post
-A FWDI_security -j DROP
-A FWDO_security -j FWDO_security_pre
-A FWDO_security -j FWDO_security_log
-A FWDO_security -j FWDO_security_deny
-A FWDO_security -j FWDO_security_allow
-A FWDO_security -j FWDO_security_post
-A FWDO_security -j DROP


Very similar to our original IPtables where we are matching state.  Firewalld is utilizing conntrack-tools , a free software that interacts with the in-kernel Connection Tracking System. 

As you can see at the beginning we are matching for various states that will allow our user to have connections outside of their machine.

I want to draw your attention to a specific rule.

"-A INPUT -m conntrack --ctstate INVALID -j DROP"

This is a very useful rule, which should be included in every FW solution.  Essentially what is happening here is that if a packet that was not intended to be received occurs, DROP it.  For example your system receives a random SYN-ACK, first of all it is out of order in regards to the three-way-handshake.  It.is.just.not normal.  Another example, what if your machine receives an RST packet randomly.  Not a typical out-of-the-blue situation. 

Both of these examples could show that potentially your system is being scanned, or potentially a DOS is occurring.

Now we can see a few lines down some content that I selected myself. 

When I created the zone 'security' I had manually set my target to DROP

-A IN_security -j DROP

The line above is saying "in the zone 'security' drop everything"


-A IN_security_allow -p tcp -m tcp --dport 53 -m conntrack --ctstate NEW,UNTRACKED -j ACCEPT
-A IN_security_allow -p udp -m udp --dport 53 -m conntrack --ctstate NEW,UNTRACKED -j ACCEPT
-A IN_security_allow -p tcp -m tcp --dport 80 -m conntrack --ctstate NEW,UNTRACKED -j ACCEPT
-A IN_security_allow -p tcp -m tcp --dport 443 -m conntrack --ctstate NEW,UNTRACKED -j ACCEPT

These next 4 are ports that I specificed --> DNS/HTTP/HTTPS.  Notice that we are looking for NEW (referring to the first packet of a connection) and UNTRACKED ("UNTRACKED: Any packets exempted from connection tracking in the raw table with the NOTRACK target end up in this state." See references at end)

Finally the IPtables finishes with how traffic is to be forwarded inside our zone.  Since our scenario does not call for any forwarding, these rules are effectively empty.  They exists here only because they are part of the 'zone' template.

So there you have it, we have taken a closer look at how Firewalld uses IPtables.  Zones are a useful aspect to the FW solution.  The fact that Firewalld automatically includes some very useful IPTables rules, without the user even needing to specify is also very helpful. 

IPtables are powerful for filtering and directing traffic, Firewalld takes an already powerful solution and removes some of the complexity and makes FW management more available to the masses.


References:








Popular Posts