Proxy - firewalld on the lab host
Proxy Solution · Config document · referenced from Interfaces and firewalld zones and firewalld rich rules
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.
| Item | Value |
|---|---|
| Host | proxy.lab.example.net, RHEL 7.5, a VMware guest |
| Interfaces | ens32 external 10.90.0.102/24, ens33 internal 10.90.114.114/24 |
| Run as | root |
| Zones | external for ens32, internal for ens33, public the default zone with no interface; all three target DROP |
| Services removed | mdns, samba-client, dhcpv6-client from internal; dhcpv6-client from public |
| Masquerade | removed from external |
| Log denied | all |
Rich rules on internal | TCP 3128 to 10.90.114.114 from anywhere; ICMP |
| Reload | firewall-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.
$ firewall-cmd --get-active-zonesoutput 2 lines
public interfaces: ens32 ens33
List the zones that RHEL 7.5 defines by default.
$ firewall-cmd --get-zonesoutput 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).
$ 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.
$ firewall-cmd --get-active-zonesoutput 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).
$ 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.
$ firewall-cmd --get-active-zonesoutput 4 lines
internal interfaces: ens33 external interfaces: ens32
What is the default target of zone internal?
$ firewall-cmd --permanent --zone=internal --get-targetoutput 1 line
default
And of zone external?
$ firewall-cmd --permanent --zone=external --get-targetoutput 1 line
default
Set the target of internal, external and public (the firewalld default zone) to DROP.
$ 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.
$ firewall-cmd --zone=external --list-alloutput 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.
$ firewall-cmd --zone=internal --list-alloutput 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.
$ firewall-cmd --zone=public --list-alloutput 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.
$ 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.
$ firewall-cmd --permanent --zone=external --remove-masquerade $ firewall-cmd --reload
Show the logging configuration of firewalld.
$ firewall-cmd --get-log-deniedoutput 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.
$ 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.
$ 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.
$ 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 line | Meaning |
|---|---|
--get-active-zones | the zones that have an interface or a source bound to them, with the bindings |
--permanent | changes 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=DROP | the 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-all | the 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-masquerade | takes a predefined service, or the address translation, out of the zone |
--set-log-denied=all | a 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 accept | accept 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 accept | accept 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 built | Today |
|---|---|
firewalld-0.4.4.4-14.el7 on RHEL 7.5, iptables backend | Upstream 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 network | ifcfg 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=external | Unchanged. 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 zones | The 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-client | The 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=DROP | In 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 --permanent | Unchanged: 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 accept | Grammar 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 accept | Unchanged; 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=all | Unchanged: 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-masquerade | Unchanged meanings; --remove-masquerade disables IPv4 masquerading |
ifconfig for the addresses | Red 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.