The Upcoming v1.0.0

Introduction and Motivations

Firewalld is about to have its first major version bump. This signifies that there are non-compatible (breaking) changes being introduced. There are many motivations for these changes. Each of which will be outlined in this post.

Many of these changes are about strengthening the zone concept in firewalld. There were many cases were zones almost, but not quite behaved as expected. The end result is that features enabled in a zone now apply almost exclusively to traffic that is destined to the host running firewalld. For anything else, e.g. forward filtering, a policy should be used.

Dropped python2 support

Python2 is no longer supported. This support has been dropped everywhere: source code, documentation, build, CI, packaging, etc. Python2 went EOL as of January 1, 2020.

Dropping python2 allows us to take advantage of some python3 only features:

Most distributions were already building firewalld for use with python3.

Reduced dependencies

These are the new set of dependencies:

  • ebtables (optional)
  • ipset (optional)
  • iptables (optional)
  • linux >= 5.3
  • python3-dbus
  • python3-gobject
  • python3-nftables >= 0.9.4

Note that ebtables, ipset, and iptables are now optional. firewalld builds and runs without their existence. If iptables is not present then the iptables backend and direct interface will not be usable.

Additionally, the following dependencies have been removed:

Intra-zone forwarding by default

Intra-zone forwarding has been around since v0.9.0. However, it was disabled by default. In v1.0.0 it will be enabled by default for all shipped and newly created zones. This includes zones: public, block, trusted, internal, etc.

This change aligns firewalld with one of the axioms of zone based firewalls. That is, the zone defines the trust level and packets can freely move between interfaces and sources with in the same zone.

This feature can be disabled on a per zone basis.

# firewall-cmd --permanent --zone public --remove-forward

NAT rules moved to inet family

Prior to v1.0.0, firewalld had to duplicate NAT rules in both the ip and ip6 families. Enabled by a bump in the minimal Linux requirement, 5.3+, these have been combined into the inet family. There is no longer rule duplication.

This is very significant for ipsets. Prior to this change each ipset and ipset entry had to be duplicated three times. Now there is a single copy. This improves both rule application and execution times.

Note: This change only affects the nftables backend. The iptables backend continues to have rule duplication, but does not have set duplication.

Default target is now similar to reject

In the past users have been confused about the differences between default and reject values for the --set-target zone option. This option defines a catch-all rule for packets at the end of the zone’s rule set. default was subtly different and caused all kinds of unexpected behavior like zone drifting. It also caused some zones to be unexpectedly publicly accessible.

Now default is identical to reject with one caveat: default allows ICMP packets.

If you desire the old behavior in which the trusted zone is publicly accessible it can be reintroduced via policies.

# firewall-cmd --permanent --new-policy allowForward
# firewall-cmd --permanent --policy allowForward --set-target ACCEPT
# firewall-cmd --permanent --policy allowForward --add-ingress-zone public
# firewall-cmd --permanent --policy allowForward --add-egress-zone trusted
# firewall-cmd --reload

See the commit, f2896e43, for further details.

Policies with positive priority values

Prior to v1.0.0, policies with a positive priority value would apply if and only if the relevant zones used a --set-target of default. With the above change of “Default target is now similar to reject” these policies are no longer reachable due to the zone’s chains being terminal. Rule execution no longer returns to the top-level chains, e.g. forward.

As such, policies with a positive value have been moved. They now execute immediately before a zone’s --set-target catch-all rule. Or said differently, they are the last thing before the catch-all drop, reject, or accept rule.

This also has the benefit that policies with a positive priority value are effective for zones with a --set-target of drop, reject, or accept. Prior to v1.0.0 they were not.

ICMP blocks and block inversion only apply to input, not forward

ICMP blocks and ICMP block inversion were a bit odd in that they applied to traffic destined to the host (input) and to any other zone (forward). This is violation of zone concepts. Features added the zone should affect the zone and only the zone. It should not allow packets to propagate to other zones.

Now the following behavior applies:

ICMP blocks can be applied to forward traffic by using a policy.

# firewall-cmd --permanent --new-policy blockICMP
# firewall-cmd --permanent --policy blockICMP --add-ingress-zone public
# firewall-cmd --permanent --policy blockICMP --add-egress-zone internal
# firewall-cmd --permanent --policy blockICMP --add-icmp-block echo-request
# firewall-cmd --reload

ICMP block inversion can be simulated for forward traffic with a policy as well.

# firewall-cmd --permanent --new-policy blockInversion
# firewall-cmd --permanent --policy blockInversion --add-ingress-zone public
# firewall-cmd --permanent --policy blockInversion --add-egress-zone internal
# firewall-cmd --permanent --policy blockInversion --add-rich-rule='rule priority=100 icmp-type echo-request allow'
# firewall-cmd --permanent --policy blockInversion --add-rich-rule='rule priority=32000 protocol value=icmp drop'
# firewall-cmd --reload

tftp-client service has been removed

Firewalld has support for connection tracker helpers. Helpers are designed to handle protocols that may, as part of the protocol, result in traffic on ports different than the original flow of traffic. Without helpers this traffic would look like a completely new and independent flow of traffic. A canonical example of this is TFTP.

Unfortunately the tftp-client service never actually worked due to the connection tracker helper assignment occurring in the wrong place. The solution is to use the non-client service definition in combination with a policy for outbound traffic. Then the outbound filtering will assign the connection tracker helper and TFTP will work as expected.

# firewall-cmd --permanent --new-policy hostTftpTraffic
# firewall-cmd --permanent --policy hostTftpTraffic --add-ingress-zone HOST
# firewall-cmd --permanent --policy hostTftpTraffic --add-egress-zone ANY
# firewall-cmd --permanent --policy hostTftpTraffic --add-service tftp
# firewall-cmd --reload

Due to the fact that it never worked and can never work, the tftp-client service has been removed. The above should be used instead.

iptables backend is deprecated

Firewalld has had nftables support since v0.6.0. nftables is the actively developed Linux firewall implementation. iptables is stable, but does not receive new features. For this reason the iptables backend has been marked deprecated.

Don’t fret. Deprecation is not removal. iptables support won’t be removed for a long time. It just means the iptables backend is not the primary focus.

Direct interface is deprecated

Policy objects have largely made the direct interface obsolete. The direct interface was mainly used because firewalld lacked forward and output filtering. Since v0.9.0 firewalld has native support for those using a familiar interface. As such the direct interface has limited usefulness.

If the firewalld is lacking features that force you to use the direct interface then please file an issue. Many things can be added with minimal effort via rich rules.

Don’t fret. Deprecation is not removal. The direct interface will not be removed for a long time. It just means its use is discouraged because in most cases policy objects are a better choice.

CleanupModulesOnExit defaults to no

A new configuration option CleanupModulesOnExit was introduced to avoid unloading kernel modules when firewalld shuts down. This was done to avoid issues caused by the module unloading.

Because CleanupModulesOnExit defaults to no it is considered a breaking change. To get the old behavior it can be set to yes.

The Exceptions

In the introduction it was mentioned that many of these changes were strengthening the zone concept in firewalld. This section is about the exceptions to the effort. These are are largely in order to maintain compatibility with long standing expectations of other software that integrates with firewalld. For example, libvirt and podman.

With the exception of the following all features added to a zone apply to traffic destined to the host (input).

  • --set-target value accept allows forwarding to other zones
    • zones like trusted will allow traffic to be forwarded to other zones
    • libvirt and podman rely upon this to give virtual machines and containers access to the internet
  • forward-port
    • may affect traffic that ingresses a given zone, but is destined for a machine in a different zone. That is, traffic that would be forwarded.
    • forward ports are a type of DNAT. They occur in the NAT table during prerouting. At this point in packet processing it’s undetermined if the packet is destined to the host or any other zone. As such the DNAT action may apply to both types of traffic.
  • masquerade
    • affects traffic egressing a given zone
    • this is the only feature that when added to a zone applies to the traffic leaving via the zone
  • rich rule mark and tcp-mss-clamp actions
    • similar to forward ports these occur on zone ingress and apply to traffic destined to the host or any other zone.

It’s suggested that new configurations use policies to make use of these features. Using a policy makes it explicit to what kind of traffic the feature is applied.

For example:

# firewall-cmd --permanent --new-policy pppTcpClamp
# firewall-cmd --permanent --policy pppTcpClamp --add-ingress-zone internal
# firewall-cmd --permanent --policy pppTcpClamp --add-egress-zone external
# firewall-cmd --permanent --policy pppTcpClamp --add-rich-rule='rule tcp-mss-clamp'
# firewall-cmd --reload

Conclusion

The firewalld developers are confident that the above changes are necessary to improve the predictability and reliability of firewalld. None of the breaking changes were made lightly. Many are years in the making.