LINUXOR.SK ... open source notes ...

Proxy - firewalld on the lab host

category: solutionz/proxy · date: 2019-12-31 · updated: 2026-10-03 · author: LALA

Proxy Solution · Config document · referenced from Interfaces and firewalld zones and firewalld rich rules

noteThis is the lab, with the dead end kept in: the first zone method (ZONE= in the ifcfg files) produced a listing with the interfaces in the wrong zones, and the note under it says it is fine. The second method, --change-interface, is the one to copy. The ssh service was left in zone external, and the final --list-rich-rules has no output in the notes.

The whole firewalld command set of the lab proxy proxy.lab.example.net, in the order it was run: the zones as found, the two ways of binding the interfaces, the targets, the inventory of the three zones, the services and the masquerading taken away, the logging of denied traffic and the two rich rules of zone internal. Everything ran as root on the lab host. The ifconfig output and the yum install of net-tools, bind-utils, mc and nc that precede it in the notes are left out here; the addresses are in the table.

ItemValue
Hostproxy.lab.example.net, RHEL 7.5, a VMware guest
Interfacesens32 external 10.90.0.102/24, ens33 internal 10.90.114.114/24
Run asroot
Zonesexternal for ens32, internal for ens33, public the default zone with no interface; all three target DROP
Services removedmdns, samba-client, dhcpv6-client from internal; dhcpv6-client from public
Masqueraderemoved from external
Log deniedall
Rich rules on internalTCP 3128 to 10.90.114.114 from anywhere; ICMP
Reloadfirewall-cmd --reload after the services, after the masquerade and after each rich rule; systemctl restart firewalld after the bindings

The commands

Which zones are active? The note says this is wrong because both interfaces are in the same zone.

bash
$ firewall-cmd --get-active-zones
output 2 lines
public
  interfaces: ens32 ens33

List the zones that RHEL 7.5 defines by default.

bash
$ firewall-cmd --get-zones
output 1 line
block dmz drop external home internal public trusted work

First method. Add the zone to the network configuration of each interface, ZONE=external in ifcfg-ens32 and ZONE=internal in ifcfg-ens33, then restart the network. The two files as written are Config documents: ifcfg-ens32, external and ifcfg-ens33, internal. Two notes stand above the step: after executing these commands you can cut yourself from the system, be careful; and the method works only when NetworkManager is enabled and used (NM_CONTROLLED=yes).

bash
$ vi /etc/sysconfig/network-scripts/ifcfg-ens32
$ vi /etc/sysconfig/network-scripts/ifcfg-ens33
$ systemctl restart network

Which zones are active now? The notes say this is OK because the zones are now on separate interfaces, and repeat that the method needs NetworkManager. The listing is the reverse of the files: ens32 was given ZONE=external and is listed in internal.

bash
$ firewall-cmd --get-active-zones
output 4 lines
internal
  interfaces: ens32
external
  interfaces: ens33

Second method. Assign ens32 to zone external and ens33 to zone internal with firewall-cmd, then restart firewalld. The note says this method also works when NetworkManager is disabled (NM_CONTROLLED=no).

bash
$ firewall-cmd --permanent --change-interface=ens32 --zone=external
$ firewall-cmd --permanent --change-interface=ens33 --zone=internal
$ systemctl restart firewalld

Which zones are active now? This time as intended.

bash
$ firewall-cmd --get-active-zones
output 4 lines
internal
  interfaces: ens33
external
  interfaces: ens32

What is the default target of zone internal?

bash
$ firewall-cmd --permanent --zone=internal --get-target
output 1 line
default

And of zone external?

bash
$ firewall-cmd --permanent --zone=external --get-target
output 1 line
default

Set the target of internal, external and public (the firewalld default zone) to DROP.

bash
$ firewall-cmd --permanent --zone=internal --set-target=DROP
$ firewall-cmd --permanent --zone=external --set-target=DROP
$ firewall-cmd --permanent --zone=public --set-target=DROP

Show what is allowed for each zone. The step titles say internal, external, public; the commands ran external, internal, public, as below. The listing already shows target: DROP although there was no reload after the --permanent change; the datacenter 2 note shows target: default at the same point, see Interfaces and firewalld zones. Zone external first: the ssh service and masquerade: yes are the zone's defaults.

bash
$ firewall-cmd --zone=external --list-all
output 13 lines
external (active)
  target: DROP
  icmp-block-inversion: no
  interfaces: ens32
  sources:
  services: ssh
  ports:
  protocols:
  masquerade: yes
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

Zone internal: four default services.

bash
$ firewall-cmd --zone=internal --list-all
output 13 lines
internal (active)
  target: DROP
  icmp-block-inversion: no
  interfaces: ens33
  sources:
  services: ssh mdns samba-client dhcpv6-client
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

Zone public: no interface, so not marked active.

bash
$ firewall-cmd --zone=public --list-all
output 13 lines
public
  target: DROP
  icmp-block-inversion: no
  interfaces:
  sources:
  services: ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

Remove the services mdns, samba-client and dhcpv6-client from zone internal and dhcpv6-client from zone public, then reload. The step titles write the service dhcp6-client; the commands use the right name.

bash
$ firewall-cmd --permanent --zone=internal --remove-service=mdns
$ firewall-cmd --permanent --zone=internal --remove-service=samba-client
$ firewall-cmd --permanent --zone=internal --remove-service=dhcpv6-client
$ firewall-cmd --permanent --zone=public --remove-service=dhcpv6-client
$ firewall-cmd --reload

Disable masquerading for zone external, with the reason given in the step title: we are not firewall, but proxy. Then reload.

bash
$ firewall-cmd --permanent --zone=external --remove-masquerade
$ firewall-cmd --reload

Show the logging configuration of firewalld.

bash
$ firewall-cmd --get-log-denied
output 1 line
off

Enable logging of all (unicast, broadcast, multicast) denied traffic and show the setting again. The double space in the second command is as typed.

bash
$ firewall-cmd  --set-log-denied=all
$ firewall-cmd --get-log-denied
output 1 line
all

Rich rules of zone internal. Allow access to the proxy address and port from any IPv4 source, reload, and list the rich rules of the zone.

bash
$ firewall-cmd --permanent --zone=internal --add-rich-rule='rule family=ipv4 source address=0.0.0.0/0 destination address=10.90.114.114/32 port port=3128 protocol=tcp accept'
$ firewall-cmd --reload
$ firewall-cmd --permanent --zone=internal --list-rich-rules
output 1 line
rule family="ipv4" source address="0.0.0.0/0" destination address="10.90.114.114/32" port port="3128" protocol="tcp" accept

Allow ICMP in zone internal, reload, and list the rich rules. The notes hold no output for this last listing; two rules should have been printed.

bash
$ firewall-cmd --permanent --zone=internal --add-rich-rule='rule protocol value=icmp accept'
$ firewall-cmd --reload
$ firewall-cmd --permanent --zone=internal --list-rich-rules

The lines

Command or lineMeaning
--get-active-zonesthe zones that have an interface or a source bound to them, with the bindings
--permanentchanges the saved configuration, which becomes the running one at the next reload or restart; without it a change is runtime only
--change-interface=<if> --zone=<zone>moves the interface into the zone, taking it out of whatever zone it was in
--get-target, --set-target=DROPthe zone's target, what happens to a packet no rule in the zone accepts; default rejects, DROP discards silently, as I understand the two
--list-allthe zone's state: target, interfaces, sources, services, ports, protocols, masquerade, forwarded ports, source ports, ICMP blocks, rich rules; without --permanent it is the running state
--remove-service, --remove-masqueradetakes a predefined service, or the address translation, out of the zone
--set-log-denied=alla global setting, not a zone one: log packets the firewall denies, for unicast, broadcast and multicast alike
rule family=ipv4 source address=0.0.0.0/0 destination address=10.90.114.114/32 port port=3128 protocol=tcp acceptaccept TCP 3128 to the proxy's internal address from any IPv4 source; the production rules narrow the source to the client ranges
rule protocol value=icmp acceptaccept all ICMP in the zone; no family is given, and the notes do not say whether that covered IPv6; datacenter 2 added a separate direct rule for ICMPv6, and its listing prints this rule without a family even though one was typed

The two rich rules are the lab counterpart of the production rule sets in firewalld on dc1-a-vcprx001 and firewalld on dc2-a-vcprx001, described in firewalld rich rules.

Checked against firewalld 2.5.2 and RHEL 10

As builtToday
firewalld-0.4.4.4-14.el7 on RHEL 7.5, iptables backendUpstream firewalld 2.5.2 (2026-09-17); RHEL 7.9 ended with 0.6.3, RHEL 8 ships 0.9.x, RHEL 9 1.3.4, RHEL 10 2.3.1 and later 2.4.3. nftables has been the default backend since 0.6.0, and 1.0.0 marked the iptables backend deprecated. RHEL 7 left maintenance support on 2024-06-30
ZONE= in the ifcfg files, systemctl restart networkifcfg files and network-scripts are gone from RHEL 9 and 10; the zone of a NetworkManager profile is set with nmcli connection modify <profile> connection.zone <zone>, applied with nmcli connection reload and nmcli connection up <profile>
--permanent --change-interface=ens32 --zone=externalUnchanged. firewall-cmd(1): it is --remove-interface followed by --add-interface, and if the interface is under NetworkManager's control, firewalld first asks NetworkManager to change the zone of the connection; for other interfaces firewalld.zones(5) says it tries to change the ZONE= setting in an existing ifcfg file
--get-zones lists nine zonesThe same nine predefined zones with the same descriptions; external is still "for use on external networks with masquerading enabled especially for routers"
external found with ssh and masquerade: yes, internal with ssh mdns samba-client dhcpv6-client, public with ssh and dhcpv6-clientThe shipped zone files have the same services and the masquerade flag; all three now also carry forward, because 1.0.0 switched intra-zone forwarding on by default for every shipped zone (--remove-forward turns it off)
--get-target answered default; --permanent --set-target=DROPIn 0.4.4.4 --set-target existed only for the permanent configuration, and its man page said a zone without a target rejects everything not matched. Today firewall-cmd(1) says default "is similar to REJECT, but it implicitly allows ICMP packets"; 1.0.0 changed default, which had been "subtly different" and caused zone drifting, to exactly that. DROP is unchanged
--list-all without --permanentUnchanged: the running configuration. --reload still means that the permanent configuration becomes the running one and runtime-only changes are lost
rule family=ipv4 source address=0.0.0.0/0 destination address=10.90.114.114/32 port port=3128 protocol=tcp acceptGrammar unchanged; a rule with a source or destination address must still name its family. New since: priority= on a rule, and sctp and dccp as port protocols
rule protocol value=icmp acceptUnchanged; since 1.0.0 a zone with the default target accepts ICMP anyway, so the rule matters only on a DROP or REJECT zone as here
firewall-cmd --set-log-denied=allUnchanged: logging rules before the final reject and drop rules, values all, unicast, broadcast, multicast, off, default off (LogDenied=off in firewalld.conf)
--get-active-zones, --remove-service, --remove-masqueradeUnchanged meanings; --remove-masquerade disables IPv4 masquerading
ifconfig for the addressesRed Hat's documentation replaced ifconfig with ip from RHEL 7 on; net-tools is still packaged in RHEL 9 and 10

The firewalld part of this lab would run unchanged on firewalld 2.5 except for the way the interfaces are bound: --change-interface still works, but the ifcfg method does not exist any more. A reader who repeats the target check should know that default now means "reject, but let ICMP through", which is not what it meant on 0.4.4.4.

← solutionz/proxy