Objective

Learn the basic concepts behind firewalld and how to interact with it using the firewall-cmd utility

Requirements

  • Root permissions

Difficulty

EASY

Conventions

  • # - requires given linux commands to be executed with root privileges either directly as a root user or by use of sudo command
  • $ - requires given linux commands to be executed as a regular non-privileged user

Introduction

firewalld - firewall-cmdSince version 7 of Rhel and CentOS and version 18 of Fedora, firewalld is the default firewall system. One of its more distinctive traits is its modularity: it works on the concept of connection zones. In this tutorial we will learn more about it, and how to interact with it using the firewall-cmd utility.

A firewall based on zones

Firewalld is a zone-based firewall: each zone can be configured to accept or deny some services or ports, and therefore with a different level of security. Zones can be associated with one or more network interfaces. Usually firewalld comes with a set of preconfigured zones: to list this zones, and more generally to interact with the firewall, we will use the firewall-cmd utility. I am running on a Fedora 27 system, let's check what the available zones are:
$ firewall-cmd --get-zones
FedoraServer FedoraWorkstation block dmz drop external home internal public trusted work

SUBSCRIBE TO NEWSLETTER
Subscribe to Linux Career NEWSLETTER and receive latest Linux news, jobs, career advice and tutorials.


As you can see, the above command returns a list of all available interfaces in my system. Their name is quite indicative of their purpose, but we need to know what services and ports are available through them: the general default rule is that every service or port are denied. Each interface is then configured with some exceptions, depending on the services that must be allowed. If we want to have a list of all services associated with a zone we can run firewall-cmd with the --get-services option. If a zone is not explicitly passed to the command, the default zone will be queried:
# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens5f5
  sources:
  services: ssh mdns dhcpv6-client
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
The command returned a summary of the state of the zone (in this case the default one, "public"). Among the other things you can clearly see what network interfaces are associated with this zone (ens5f5 in this case) and what services are allowed (ssh, mdns, dhcpv6-client) in it. If we want to retrieve information about a specific, non-default zone, we should pass the zone name as an argument to the --zone option. For example, to retrieve information about the external zone, we would run:
# firewall-cmd --zone=external --list-all
external
  target: default
  icmp-block-inversion: no
  interfaces:
  sources:
  services: ssh
  ports:
  protocols:
  masquerade: yes
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:


Zones manipulation

As said before, when using the firewall-cmd tool, if no zone is specified, the default one is referenced. We may want to change what the default zone is. Say for example we want to set the external zone as the default:
# firewall-cmd --set-default=external
Preatty easy, isn't it?. Now let's see how we can add or remove services or ports to a specific zone. First of all services are a preconfigured set of ports associated with specific protocol. For example: the ssh service will include the TCP port 22, while the samba service will comprehend the set of ports 139 and 445 TCP and 137 and 138 UDP. Using services we can avoid having to remember specific ports each time. Let's say that we want to add the samba service to the external zone, all we would do is:
# firwall-cmd --zone=external --add-service=samba
success
The firewalld daemon responded with success, that means that the execution was successfull. To verify it, let's check the zone services:
$ sudo firewall-cmd --zone=external --list-services
ssh samba
As you can see we used the --list-services option for the purpose. The result of the command clearly means that the samba service has been added to the zone. However, modifications made this way are temporary and won't survive a reboot of the firewalld daemon. Let's verify it. First we reload the service:
 # firewall-cmd --reload
Then we check again the services allowed in the external zone:
# firewall-cmd --zone=external --list-services
ssh
As you can see, the only service allowed in the external zone is ssh. To make a persistent modification to a zone we must use the --permanent option:
 # firewall-cmd --permanent --zone=external --add-service=samba
Permanent modifications will need a firewall reload to become effective.

If we want to make the reverse operation, and so remove a service from a zone, we would execute:
 # firewall-cmd --permanent --zone=external --remove-service=samba
The syntax is very intuitive and doesn't need any further explanation. But what if we want to add a specific port instead of service? The syntax would slightly change:
 # firewall-cmd --permanent --zone=external --add-port=139/tcp
To verify that the port has been added to the zone:
# firewall-cmd --zone=external --list-ports
139/tcp
The operation has been successful. In the same way, to remove a port we would do:
# firewall-cmd --permanent --zone=external --remove-port=139/tcp


Creating a custom zone

Until now, we only saw how to modify existing zones. It's also possible to create some new ones, and it's just as easy. Let's suppose we want to create a custom zone called linuxconfig:
# firewall-cmd --permanent --new-zone=linuxconfig
A new empty zone has been created: by default no services or ports are allowed in it. It's also possible to create a zone by loading a configuration file:
# firewall-cmd --permanent --new-zone-from-file=file --name=linuxconfig
Where file is the path to the file containing the zone definition. Notice that when creating or deleting a zone the --permanent option is mandatory: an error will be raised if it is not provided.

Associate a zone with an interface

Creating a zone is just the first step: we now must associate it with a network interface. Let's say we want to use our new created zone, associating it with the ens5f5 ethernet interface: here is the command that let us accomplish the task:
# firewall-cmd --permanent --zone=linuxconfig --add-interface=ens5f5
if we query the zone for the interfaces assigned to it, we should see:
# firewall-cmd --zone=linuxconfig --list-interfaces
ens5f5
Removing the interface from the zone is just as easy as:
# firewall-cmd --remove-interface=ens5f5 --zone=linuxconfig

SUBSCRIBE TO NEWSLETTER
Subscribe to Linux Career NEWSLETTER and receive latest Linux news, jobs, career advice and tutorials.


Rich rules

In certain situations we may need to create more complex rule, and not just allow some ports or services in a zone. For example we may want to create a rule to block some type of traffic from a specific machine. That's what rich rules are for. A rule basically consist of two parts: in the first we specify the conditions that must be met for the rule to be applied, and in the second the action to be executed: accept, drop, or reject.

Let's say we want to block the traffic from the machine with ip 192.168.0.37 in the local network: here is how we would compose our rule:
# firewall-cmd --zone=linuxconfig --add-rich-rule="rule \
    family="ipv4" \
    source address=192.168.0.37 \
    service name=ssh \
    reject \
To add a rich rule we used the --add-rich-rule option, describing the rule as its argument. The rule starts with rule keyword. With family we specified that the rule it's applied only to ipv4 packets: if this keyword is not provided the rule is applied both to ipv4 and ipv6. We then provided the source address that the packets must have for the rule to be triggered with source address. With service we specified the type of service for the rule, in this case ssh. Finally, we provided the action to be executed if a packet matches the rule, in this case reject. If we now try to establish an ssh connection from the machine with the 192.168.0.37 ip, we receive:
ssh 192.168.0.35
ssh: connect to host 192.168.0.35 port 22: Connection refused
The one above is a really simple one, but a rule can become really complex. You should check the firewalld documentation to see all the range of available settings and options.

The panic mode

The panic mode is a mode that should be used only in situations where there are really serious problems with the network environment. When this mode is active, all existing connections are discarded, and all incoming and outgoing packets are be dropped. It can be enabled running:
# firewall-cmd --panic-on
To exit panic mode, the command is:
# firewall-cmd --panic-off
It's even possible to query the panic mode status, running:
# firewall-cmd --query-panic
Those options are valid only at runtime and cannot be used with --permanent.
ARE YOU LOOKING FOR A LINUX JOB?
Submit your RESUME, create a JOB ALERT or subscribe to RSS feed on LinuxCareers.com.
LINUX CAREER NEWSLETTER
Subscribe to NEWSLETTER and receive latest news, jobs, career advice and tutorials.
DO YOU NEED ADDITIONAL HELP?
Get extra help by visiting our LINUX FORUM or simply use comments below.

You may also be interested in: