FIREWALL-CMD(1)
π FIREWALL-CMD(1) β the firewall-cmd era π
okay bestie, welcome to firewall-cmd(1), aka the manual page for the firewalld command line client. pull up a chair, grab a strawberry π, and let's get into it.
β¨ NAME β¨
firewall-cmd β firewalld command line client
πΈ SYNOPSIS πΈ
firewall-cmd [OPTIONS...]
π¦ DESCRIPTION π¦
So. firewall-cmd is the command line client of the firewalld daemon. She's basically the interface that lets you manage your runtime configuration and your permanent configuration. Two worlds, one icon. π
And here's the thing you have to internalize, fr fr: in firewalld, the runtime configuration is separated from the permanent configuration. What does that mean for you? It means things can get changed in the runtime configuration or in the permanent configuration. Separate places, separate vibes, and you get to pick which one you're messing with.
π OPTIONS π
First, let's talk about sequence options, because this is one of those things that's giving "important and also easy to misunderstand."
Sequence options are the ones you can specify multiple times. The exit code is 0 if there's at least one item that succeeded. And listen β the ALREADY_ENABLED (11), NOT_ENABLED (12) and also ZONE_ALREADY_SET (16) errors are treated as succeeded. Yes, really. They're not the enemy.
If there are issues while parsing the items, those get treated as warnings and they will not change the result, as long as there's one that succeeded. But if there's no succeeded item at all, then the exit code depends on the error codes:
- If there's exactly one error code, that one gets used.
- If there's more than one, then
UNKNOWN_ERROR(254) gets used.
The following options are supported, and yes, we're doing all of them, no skips, no cap π
π§ General Options
-h,--helpβ prints a short help text and then dips. help text says bye, exits.-V,--versionβ prints the version string of firewalld. heads up bestie: this option is not combinable with other options. she's a solo act.-q,--quietβ do not print status messages. silence is golden, periodt.
π©Ί Status Options
--stateβ check whether the firewalld daemon is active (i.e. running). Returns an exit code0if it is active,RUNNING_BUT_FAILEDif failure occurred on startup,NOT_RUNNINGotherwise. See the section called βEXIT CODESβ. It will also print the state toSTDOUT. double duty, we love that.--reloadβ reload firewall rules and keep state information. The current permanent configuration will become the new runtime configuration. iykyk: all runtime-only changes you made up until reload are lost with reload if they have not also been in the permanent configuration. π that's just how she is.
Note: IfFlushAllOnReload=no, runtime changes applied via the direct interface are not affected and will therefore stay in place until the firewalld daemon is restarted completely. ForFlushAllOnReload, seefirewalld.conf(5).
--complete-reloadβ reload firewall completely, even netfilter kernel modules. This will most likely terminate active connections, because state information is lost. This option should only be used in case of severe firewall problems. For example if there are state information problems that no connection can be established with correct firewall rules. it's giving "nuclear option, use with respect" π
Note: IfFlushAllOnReload=no, runtime changes applied via the direct interface are not affected and will therefore stay in place until the firewalld daemon is restarted completely. ForFlushAllOnReload, seefirewalld.conf(5).
--runtime-to-permanentβ save the active runtime configuration and overwrite the permanent configuration with it. The way this is supposed to work is that when you're configuring firewalld you do runtime changes only, and once you're happy with the configuration and you tested that it works the way you want, you save the configuration to disk. this is the "test drive first, commit later" pipeline and honestly? main character energy. β¨--check-configβ run checks on the permanent configuration. This includes XML validity and semantics. vibe check for your config files, literally.--reset-to-defaultsβ reset configuration to firewalld's default configuration. factory reset moment.
π Log Denied Options
--get-log-deniedβ print thelog deniedsetting.--set-log-denied=valueβ add logging rules right before reject and drop rules in theINPUT,FORWARDandOUTPUTchains for the default rules, and also final reject and drop rules in zones for the configured link-layer packet type. The possible values are:all,unicast,broadcast,multicastandoff. The default setting isoff, which disables the logging.
This is a runtime and permanent change and will also reload the firewall to be able to add the logging rules. two things at once, she's efficient.
π Permanent Options
--permanentβ the permanent option--permanentcan be used to set options permanently. These changes are not effective immediately β only after service restart/reload or system reboot. Without the--permanentoption, a change will only be part of the runtime configuration.
If you want to make a change in runtime and permanent configuration, use the same call with and without the --permanent option. yep, twice. that's the move.
The --permanent option can be optionally added to all options further down where it is supported.
π Zone Options
--get-default-zoneβ print default zone for connections and interfaces.--set-default-zone=zoneβ set default zone for connections and interfaces where no zone has been selected. Setting the default zone changes the zone for the connections or interfaces that are using the default zone.
This is a runtime and permanent change.
--get-active-zonesβ print currently active zones altogether with interfaces and sources used in these zones. Active zones are zones that have a binding to an interface or source. The output format is:
zone1
interfaces: interface1 interface2 ..
sources: source1 ..
zone2
interfaces: interface3 ..
zone3
sources: source2 ..
If there are no interfaces or sources bound to the zone, the corresponding line will be omitted. no empty filler, she's tidy. π
[--permanent] --get-zonesβ print predefined zones as a space separated list.[--permanent] --get-servicesβ print predefined services as a space separated list.[--permanent] --get-icmptypesβ print predefined icmptypes as a space separated list.[--permanent] --get-zone-of-interface=interfaceβ print the name of the zone the interface is bound to, orno zone.[--permanent] --get-zone-of-source=source[/mask]|MAC|ipset:ipsetβ print the name of the zone the source is bound to, orno zone.[--permanent] --info-zone=zoneβ print information about the zone zone. The output format is:
zone
interfaces: interface1 ..
sources: source1 ..
services: service1 ..
ports: port1 ..
protocols: protocol1 ..
forward-ports:
forward-port1
..
source-ports: source-port1 ..
icmp-blocks: icmp-type1 ..
rich rules:
rich-rule1
..
[--permanent] --list-all-zonesβ list everything added for or enabled in all zones. The output format is:
zone1
interfaces: interface1 ..
sources: source1 ..
services: service1 ..
ports: port1 ..
protocols: protocol1 ..
forward-ports:
forward-port1
..
icmp-blocks: icmp-type1 ..
rich rules:
rich-rule1
..
..
--permanent --new-zone=zoneβ add a new permanent and empty zone.
Zone names must be alphanumeric and may additionally include characters: '_' and '-'.
--permanent --new-zone-from-file=filename [--name=zone]β add a new permanent zone from a prepared zone file, with an optional name override.--permanent --delete-zone=zoneβ delete an existing permanent zone. bye bestie π«Ά--permanent --load-zone-defaults=zoneβ load zone default settings or reportNO_DEFAULTSerror.--permanent --path-zone=zoneβ print path of the zone configuration file.
π§ Policy Options
[--permanent] --get-policiesβ print predefined policies as a space separated list.[--permanent] --info-policy=policyβ print information about the policy policy.[--permanent] --list-all-policiesβ list everything added for or enabled in all policies.--permanent --new-policy=policyβ add a new permanent policy.
Policy names must be alphanumeric and may additionally include characters: '_' and '-'.
--permanent --new-policy-from-file=filename [--name=policy]β add a new permanent policy from a prepared policy file, with an optional name override.--permanent --path-policy=policyβ print path of the policy configuration file.--permanent --delete-policy=policyβ delete an existing permanent policy.--permanent --load-policy-defaults=policyβ load the shipped defaults for a policy. Only applies to policies shipped with firewalld. Does not apply to user defined policies. read that again, it matters. π
π Options to Adapt and Query Zones and Policies
Ok so this next group is a little different β options in this section affect only one particular zone or policy. If used with the --zone=zone or --policy=policy option, they affect the specified zone or policy. If both options are omitted, they affect the default zone (see --get-default-zone).
[--permanent] [--zone=zone] [--policy=policy] --list-allβ list everything added or enabled.--permanent [--zone=zone] [--policy=policy] --get-targetβ get the target.--permanent [--zone=zone] [--policy=policy] --set-target=targetβ set the target.
For zones, target is one of: default, ACCEPT, DROP, REJECT
For policies, target is one of: CONTINUE, ACCEPT, DROP, REJECT
default is similar to REJECT, but it implicitly allows ICMP packets.
ACCEPT allows traffic to be forwarded from the zone, either to the same zone or other zones.
--permanent [--zone=zone] [--policy=policy] --set-description=descriptionβ set description.--permanent [--zone=zone] [--policy=policy] --get-descriptionβ print description.--permanent [--zone=zone] [--policy=policy] --set-short=descriptionβ set short description.--permanent [--zone=zone] [--policy=policy] --get-shortβ print short description.[--permanent] [--zone=zone] [--policy=policy] --list-servicesβ list services added as a space separated list.[--permanent] [--zone=zone] [--policy=policy] --add-service=service [--timeout=timeval]β add a service. This option can be specified multiple times (sequence option representation π ). If a timeout is supplied, the rule will be active for the specified amount of time and will be removed automatically afterwards.timevalis either a number (of seconds) or a number followed by one of the characterss(seconds),m(minutes),h(hours), for example20mor1h.
The service is one of the firewalld provided services. To get a list of the supported services, use firewall-cmd --get-services.
The--timeoutoption is not combinable with the--permanentoption. pick a lane, bestie. π«
okay quick note bestie β some services come with connection tracking helpers. And the ones that can operate in client mode (looking at you, tftp π
) have to be added to an outbound policy, not a zone, or they will literally never kick in for your clients. Like, the helper just won't apply to the outbound traffic. The related traffic β the stuff the connection tracking helper defines on the return path (ingress) β that part gets allowed by the stateful firewall rules, so you're covered there. π«Ά
Here's what an outbound policy for connection tracking helpers looks like:
# firewall-cmd --permanent --new-policy clientConntrack
# firewall-cmd --permanent --policy clientConntrack --add-ingress-zone HOST
# firewall-cmd --permanent --policy clientConntrack --add-egress-zone ANY
# firewall-cmd --permanent --policy clientConntrack --add-service tftp
[--permanent] [--zone=zone] [--policy=policy] --remove-service=serviceβ takes a service out. You can say this option more than once, no cap.[--permanent] [--zone=zone] [--policy=policy] --query-service=serviceβ asks the universe "is this service in here or not?" Returns0if yeah,1if nope.[--permanent] [--zone=zone] [--policy=policy] --list-portsβ spills out every port you've added as a space-separated list. A port looks likeportid[-portid]/protocolβ so it's either a port-and-protocol pair, or a whole port range with a protocol attached. Cute and simple. β¨[--permanent] [--zone=zone] [--policy=policy] --add-port=portid[-portid]/protocol [--timeout=timeval]β adds a port. Say it multiple times if you want, go off. And if you hand it a timeout, the rule stays live for exactly that long and then dips out automatically. timeval is either just a plain number (seconds, boo boring) or a number with one of these letters:s(seconds),m(minutes),h(hours) β like20mor1h. π
The port is either one single port number, or a range written portid-portid. The protocol is one of tcp, udp, sctp or dccp.
π¨ heads up: --timeout and --permanent cannot be combined. Pick a lane.
[--permanent] [--zone=zone] [--policy=policy] --remove-port=portid[-portid]/protocolβ bye bye port. Multiple times? Totally allowed.[--permanent] [--zone=zone] [--policy=policy] --query-port=portid[-portid]/protocolβ returns whether that port got added.0= true,1= otherwise.[--permanent] [--zone=zone] [--policy=policy] --list-protocolsβ shows every protocol you've added, space-separated, all lined up pretty. πΈ[--permanent] [--zone=zone] [--policy=policy] --add-protocol=protocol [--timeout=timeval]β adds a protocol. Stack it as many times as you need. If a timeout is supplied, the rule is active for that amount of time and then removes itself, dramatic exit. timeval is a number (seconds) or a number followed by one ofs(seconds),m(minutes),h(hours) β20m,1h, you know the drill.
Your protocol can be literally any protocol the system supports. Go peek at /etc/protocols for the roster. π
And again: --timeout is not combinable with --permanent.
[--permanent] [--zone=zone] [--policy=policy] --remove-protocol=protocolβ removes a protocol. Repeatable, of course.[--permanent] [--zone=zone] [--policy=policy] --query-protocol=protocolβ did the protocol get added?0if yes,1if no.[--permanent] [--zone=zone] [--policy=policy] --list-source-portsβ lists the source ports you added, space-separated. Port format isportid[-portid]/protocol. Slay. π[--permanent] [--zone=zone] [--policy=policy] --add-source-port=portid[-portid]/protocol [--timeout=timeval]β adds a source port. Specify it multiple times if your heart desires. With a timeout, the rule lives for that long and then auto-dips. timeval = a number (seconds), or a number plus one ofs(seconds),m(minutes),h(hours), e.g.20mor1h.
Port: single port number or a range portid-portid. Protocol: tcp, udp, sctp or dccp.
One more time for the people in the back: --timeout is not combinable with --permanent. π
[--permanent] [--zone=zone] [--policy=policy] --remove-source-port=portid[-portid]/protocolβ removes the source port. Yeah, you can run it multiple times.[--permanent] [--zone=zone] [--policy=policy] --query-source-port=portid[-portid]/protocolβ returns whether the source port has been added.0= true,1= otherwise.[--permanent] [--zone=zone] [--policy=policy] --list-icmp-blocksβ lists all the Internet Control Message Protocol (ICMP) type blocks that have been added, as one space-separated list. π¦[--permanent] [--zone=zone] [--policy=policy] --add-icmp-block=icmptype [--timeout=timeval]β adds an ICMP block for icmptype. Specify it multiple times, iconic. With a timeout supplied, the rule is active for that stretch and then removes itself automatically. timeval is a number (seconds) or a number followed by one ofs(seconds),m(minutes),h(hours) β20m,1h, whatever.
The icmptype is one of the ICMP types firewalld supports. Want the full list of supported ICMP types? Run firewall-cmd --get-icmptypes and β¨ behold β¨.
Also (say it with me): --timeout is not combinable with --permanent.
[--permanent] [--zone=zone] [--policy=policy] --remove-icmp-block=icmptypeβ removes the ICMP block for icmptype. Multiple times, sure.[--permanent] [--zone=zone] [--policy=policy] --query-icmp-block=icmptypeβ returns whether an ICMP block for icmptype has been added.0if true,1otherwise.[--permanent] [--zone=zone] [--policy=policy] --list-forward-portsβ lists IPv4 forward ports, space-separated. π
For IPv6 forward ports? Bestie, go use the rich language.
[--permanent] [--zone=zone] [--policy=policy] --add-forward-port=port=portid[-portid]:proto=protocol[:toport=portid[-portid]][:toaddr=address[/mask]] [--timeout=timeval]β adds the IPv4 forward port. Can be specified multiple times. With a timeout, the rule stays active for the specified amount of time and is then removed automatically. timeval is a number (seconds) or a number followed by one ofs(seconds),m(minutes),h(hours) β for example20mor1h.
The port is a single port number portid or a port range portid-portid. The protocol is tcp, udp, sctp or dccp. The destination address is a simple IP address.
--timeout is not combinable with --permanent. π«
For IPv6 forward ports, please use the rich language.
Note: IP forwarding will be implicitly enabled if toaddr is specified. Not a suggestion, it just happens.
Note: When this option is used with --policy, the firewall backend cannot determine the egress zone. See section UNKNOWN DESTINATIONS for the whole saga. π
[--permanent] [--zone=zone] [--policy=policy] --remove-forward-port=port=portid[-portid]:proto=protocol[:toport=portid[-portid]][:toaddr=address[/mask]]β removes the IPv4 forward port. Specify it multiple times, no problem.
IPv6 forward ports: rich language, bestie. That's the way.
[--permanent] [--zone=zone] [--policy=policy] --query-forward-port=port=portid[-portid]:proto=protocol[:toport=portid[-portid]][:toaddr=address[/mask]]β returns whether that IPv4 forward port has been added.0if true,1otherwise.
(IPv6 forward ports β rich language. You know the vibe by now. π)
[--permanent] [--zone=zone] [--policy=policy] --add-masquerade [--timeout=timeval]β turns on IPv4 masquerade. If you supply a timeout, masquerading stays active for that amount of time. timeval is a number (seconds) or a number followed by one ofs(seconds),m(minutes),h(hours), e.g.20mor1h. Masquerading is the move when your machine is a router and machines hooked up over an interface in another zone should be able to use that first connection. Main character routing energy, honestly. π
--timeout is not combinable with --permanent.
For IPv6 masquerading, please use the rich language.
Note: IP forwarding gets implicitly enabled. Automatically. Surprise.
Note (Linux < 5.5): with theiptablesbackend, a policy may not enable masquerade if an ingress zone has assigned interfaces. Thenftablesbackend doesn't have that restriction, but it does need Linux v5.5+ to actually function properly β otherwise it will silently fail. Silent. Failure. The worst kind. π
[--permanent] [--zone=zone] [--policy=policy] --remove-masqueradeβ turns IPv4 masquerade off. And if masquerading had been enabled with a timeout, this disables it too.
For IPv6 masquerading, please use the rich language.
[--permanent] [--zone=zone] [--policy=policy] --query-masqueradeβ returns whether IPv4 masquerading has been enabled.0= true,1= otherwise.
For IPv6 masquerading, please use the rich language.
[--permanent] [--zone=zone] [--policy=policy] --list-rich-rulesβ lists the rich language rules you've added, one per line (newline-separated). π§[--permanent] [--zone=zone] [--policy=policy] --add-rich-rule='rule' [--timeout=timeval]β adds the rich language rule'rule'. This option can be specified multiple times. Supply a timeout and the rule will be active for that amount of time before it removes itself automatically. timeval is a number (seconds) or a number followed by one ofs(seconds),m(minutes),h(hours) β20mor1h, take your pick.
For the rich language rule syntax, go read firewalld.richlanguage(5).
And yes β --timeout is not combinable with --permanent. π
[--permanent] [--zone=zone] [--policy=policy] --remove-rich-rule='rule'β removes the rich language rule'rule'. Can be specified multiple times.
For the rich language rule syntax, hit up firewalld.richlanguage(5).
[--permanent] [--zone=zone] [--policy=policy] --query-rich-rule='rule'β returns whether a rich language rule'rule'has been added.0if true,1otherwise.
For the rich language rule syntax, please have a look at firewalld.richlanguage(5).
β Options to Adapt and Query Zones β
Okay so everything in this lil section only touches one particular zone. Use it with the --zone=zone option and it affects that specified zone. Leave the option out and it hits the default zone instead (go check --get-default-zone if you forgot which one that is π).
[--permanent] [--zone=zone] --add-icmp-block-inversionβ enables ICMP block inversion.[--permanent] [--zone=zone] --remove-icmp-block-inversionβ ok so turn ICMP block inversion OFF bestie, it's giving "let the pings through" energy π«[--permanent] [--zone=zone] --query-icmp-block-inversionβ asks the universe "is ICMP block inversion on?" and reports back. Returns0if true,1otherwise. no cap π«Ά[--permanent] [--zone=zone] --add-forwardβ switch on intra zone forwarding, slay β¨[--permanent] [--zone=zone] --remove-forwardβ switch off intra zone forwarding, bye bestie π[--permanent] [--zone=zone] --query-forwardβ is intra zone forwarding enabled?? Returns0if true,1otherwise πΈ--permanent [--zone=zone] --get-priorityβ grab the priority of the zone, pulling up π--permanent [--zone=zone] --set-priorityβ set the zone's priority for packet classification. this sets BOTH the ingress and the egress priority at once, two birds one stone fr fr π¦--permanent [--zone=zone] --get-ingress-priorityβ get the ingress priority of the zone π--permanent [--zone=zone] --set-ingress-priorityβ set the zone's ingress priority for packet classification π--permanent [--zone=zone] --get-egress-priorityβ get the egress priority of the zone π¦--permanent [--zone=zone] --set-egress-priorityβ set the zone's egress priority for packet classification π
π Options to Adapt and Query Policies π
okay so these options are like, super into ONE particular policy only. you literally HAVE to pass --policy=policy with them or it's not gonna work. it's giving "commitment issues but make it firewalld" π
--permanent --policy=policy --get-priorityβ get the priority, periodt π--permanent --policy=policy --set-priority=priorityβ set the priority. this priority thing decides the relative ordering of policies, it's the vibe check for who goes first. it's an integer value between-32768and32767where-1is the default value for new policies and0is reserved for internal use. lowkey important!! π¨
if a priority is < 0, then the policy's rules will execute before all rules in all zones. it's jumping the line bestie π¨
if a priority is > 0, then the policy's rules will execute after all rules in all zones. fashionably late π
[--permanent] --policy=policy --list-ingress-zonesβ list ingress zones that were added, as a space separated list πΈ[--permanent] --policy=policy --add-ingress-zone=zoneβ add an ingress zone. you can specify this option multiple times, go off π₯
the ingress zone is one of the firewalld provided zones OR one of the pseudo-zones: HOST, ANY.
HOST is used for traffic originating from the host machine, i.e. the host running firewalld.
ANY is used for traffic originating from any zone. think of it like a wild card for zones. BUT it does not include traffic originating from the host machine β use HOST for that. this distinction is so real, iykyk π
[--permanent] --policy=policy --remove-ingress-zone=zoneβ remove an ingress zone. also can be specified multiple times π[--permanent] --policy=policy --query-ingress-zone=zoneβ return whether the zone has been added. Returns0if true,1otherwise π«Ά[--permanent] --policy=policy --list-egress-zonesβ list egress zones added, as a space separated list β¨[--permanent] --policy=policy --add-egress-zone=zoneβ add an egress zone. can be specified multiple times, no cap π«
the egress zone is one of the firewalld provided zones OR one of the pseudo-zones: HOST, ANY.
for clarification on HOST and ANY see option --add-ingress-zone. (spoiler: it's up there β¬οΈ)
[--permanent] --policy=policy --remove-egress-zone=zoneβ remove an egress zone. yep, can be specified multiple times π[--permanent] --policy=policy --query-egress-zone=zoneβ return whether the zone has been added. Returns0if true,1otherwise. slay π[--permanent] --policy=policy|--policy-set=policy-set --add-disableβ administratively disable a policy. a disabled policy will not activate. it's on do-not-disturb mode fr π΄[--permanent] --policy=policy|--policy-set=policy-set --remove-disableβ remove the administratively disable from a policy. lets a policy activate again, welcome back bestie π₯³[--permanent] --policy=policy --query-disableβ return if the policy is administratively disabled πΈ
π¦ Options to Handle Bindings of Interfaces π¦
okay so binding an interface to a zone means the zone settings get used to restrict traffic via that interface. that's the whole vibe β¨
periodt, these options affect only ONE particular zone. if you use them with the --zone=zone option, they affect the zone zone. if you skip the option, they affect the default zone (see --get-default-zone).
for a list of predefined zones use firewall-cmd --get-zones.
an interface name is a string up to 16 characters long, and it may NOT contain ' ', '/', '!' and '*'. so no wild shenanigans bestie π«
[--permanent] [--zone=zone] --list-interfacesβ list interfaces bound to zone zone, as a space separated list. if zone is omitted, default zone will be used π[--permanent] [--zone=zone] --add-interface=interfaceβ bind interface interface to zone zone. if zone is omitted, default zone will be used π
if the interface is under control of NetworkManager, it is at first connected to change the zone for the connection that is using the interface. if this fails, the zone binding is created in firewalld and the limitations below apply. for interfaces that are not under control of NetworkManager, firewalld tries to change the ZONE setting in the ifcfg file, if the file exists.
as an end user you don't need this in most cases, because NetworkManager (or legacy network service) adds interfaces into zones automatically (according to the ZONE= option from the ifcfg-interface file) if NM_CONTROLLED=no is not set. you should only do it if there's no /etc/sysconfig/network-scripts/ifcfg-interface file. if there IS such a file and you add interface to zone with this --add-interface option, make sure the zone is the same in both cases, otherwise the behavior would be undefined. π please also have a look at the firewalld(1) man page in the Concepts section. for permanent association of interface with a zone, see also 'How to set or change a zone for a connection?' in firewalld.zones(5).
[--permanent] [--zone=zone] --change-interface=interfaceβ if the interface is under control of NetworkManager, it is at first connected to change the zone for the connection that is using the interface. if this fails, the zone binding is created in firewalld and the limitations below apply. for interfaces that are not under control of NetworkManager, firewalld tries to change theZONEsetting in the ifcfg file, if the file exists.
change the zone that interface interface is bound to, to zone zone. it's basically --remove-interface followed by --add-interface, glow up moment β¨. if the interface has not been bound to a zone before, it behaves like --add-interface. if zone is omitted, default zone will be used.
[--permanent] [--zone=zone] --query-interface=interfaceβ query whether interface interface is bound to zone zone. Returns0if true,1otherwise π«Ά[--permanent] --remove-interface=interfaceβ if the interface is under control of NetworkManager, it is at first connected to change the zone for the connection that is using the interface. if this fails, the zone binding is created in firewalld and the limitations below apply.
for the addition or change of interfaces that are not under control of NetworkManager: firewalld tries to change the ZONE setting in the ifcfg file, if an ifcfg file exists that is using the interface.
only for the removal of interfaces that are not under control of NetworkManager: firewalld is NOT trying to change the ZONE setting in the ifcfg file. this is needed to make sure that an ifdown of the interface will not result in a reset of the zone setting to the default zone. only the zone binding is then removed in firewalld then.
removes the binding of interface interface from the zone it was previously added to. it's out girlie π
πΈ Options to Handle Bindings of Sources πΈ
binding a source to a zone means the zone settings will be used to restrict traffic from that source. that's the tea β
a source address or address range is either an IP address or a network IP address with a mask for IPv4 or IPv6 or a MAC address or an ipset with the ipset: prefix. for IPv4, the mask can be a network mask or a plain number. for IPv6 the mask is a plain number. the use of host names is not supported. soz, no cute domain names here π
these options affect only ONE particular zone. if you use them with the --zone=zone option, they affect the zone zone. if the option is omitted, they affect the default zone (see --get-default-zone).
for a list of predefined zones use firewall-cmd [--permanent] --get-zones.
[--permanent] [--zone=zone] --list-sourcesβ list sources bound to zone zone, as a space separated list. if zone is omitted, default zone will be used π[--permanent] [--zone=zone] --add-source=source[/mask]|MAC|ipset:ipsetβ bind the source to zone zone. if zone is omitted, default zone will be used π«[--zone=zone] --change-source=source[/mask]|MAC|ipset:ipsetβ change the zone that the source is bound to, to zone zone. it's basically--remove-sourcefollowed by--add-source. if the source has not been bound to a zone before, it behaves like--add-source. if zone is omitted, default zone will be used β¨[--permanent] [--zone=zone] --query-source=source[/mask]|MAC|ipset:ipsetβ query whether the source is bound to the zone zone. Returns0if true,1otherwise π[--permanent] --remove-source=source[/mask]|MAC|ipset:ipsetβ remove the binding of the source from the zone it was previously added to π¦
π IPSet Options π
--get-ipset-typesβ print the supported ipset types, pulling up the menu π--permanent --new-ipset=ipset --type=type [--family=inet|inet6] [--option=key[=value]]β add a new permanent and empty ipset, specifying the type and optionally the family and options like timeout, hashsize and maxelem. for more information please have a look at theipset(8)man page π
ipset names must be alphanumeric and may additionally include characters: '_' and '-'. so cute but rules are rules π
--permanent --new-ipset-from-file=filename [--name=ipset]β add a new permanent ipset from a prepared ipset file, with an optional name override π--permanent --delete-ipset=ipsetβ delete an existing permanent ipset. bye bestie π--permanent --load-ipset-defaults=ipsetβ load ipset default settings or reportNO_DEFAULTSerror π¨[--permanent] --info-ipset=ipsetβ print information about the ipset ipset. the output format is:
ipset
type: type
options: option1[=value1] ..
entries: entry1 ..
[--permanent] --get-ipsetsβ print predefined ipsets as a space separated list π₯--permanent --ipset=ipset --set-description=descriptionβ set a new description to the ipset π--permanent --ipset=ipset --get-descriptionβ print description for the ipset π«Ά--permanent --ipset=ipset --set-short=descriptionβ set short description to the ipset βοΈ--permanent --ipset=ipset --get-shortβ prints the short description for the ipset, bestie β¨[--permanent] --ipset=ipset --add-entry=entryβ drops a shiny newentryinto the ipset π
Adding an entry to an ipset that has the timeout option is allowed, but heads up: firewalld does not track those entries. Not it being sneaky about it π
[--permanent] --ipset=ipset --remove-entry=entryβ yeetsentryout of the ipset π«Ά[--permanent] --ipset=ipset --query-entry=entryβ tells you whetherentryhas been added to the ipset. Returns0if true,1otherwise.
Careful bestie π β querying an ipset that has a timeout will straight up error. Entries are not tracked for ipsets with a timeout. Periodt.
[--permanent] --ipset=ipset --get-entriesβ lists every entry in the ipset π[--permanent] --ipset=ipset --add-entries-from-file=filenameβ loads a whole batch of new entries into the ipset from a file. For every entry that's in the file but already in the ipset, you get a warning printed. She's just letting you know π
The file should have one entry per line. Lines starting with a hash or a semicolon are ignored. Empty lines too. Clean girl aesthetic β¨
[--permanent] --ipset=ipset --remove-entries-from-file=filenameβ removes existing entries from the ipset, usingfilenameas the source. For every entry that's listed in the file but not in the ipset, a warning gets printed.
Same file rules, bestie: one entry per line, lines starting with a hash or semicolon ignored, empty lines ignored too πΈ
--permanent --path-ipset=ipsetβ prints the path of the ipset configuration file π
π Service Options π
Options in this section affect only one particular service. One service, one little universe π
[--permanent] --info-service=serviceβ prints info about the serviceservice. The output format is:
service
ports: port1 ..
protocols: protocol1 ..
source-ports: source-port1 ..
helpers: helper1 ..
destination: ipv1:address1 ..
The following options are only usable in the permanent configuration. So lock in π
--permanent --new-service=serviceβ adds a brand new permanent and empty service. Blank canvas energy π¨
Service names must be alphanumeric and may additionally include the characters '_' and '-'. No funny business β
--permanent --new-service-from-file=filename [--name=service]β adds a new permanent service from a prepared service file, with an optional name override. Slay, reuse the template π--permanent --delete-service=serviceβ deletes an existing permanent service. Gone, bye, no notes π--permanent --load-service-defaults=serviceβ loads service default settings, or reports aNO_DEFAULTSerror. Sometimes the defaults just aren't there, and that's the vibe check π--permanent --path-service=serviceβ prints the path of the service configuration file ποΈ--permanent --service=service --set-description=descriptionβ sets a new description on the service βοΈ--permanent --service=service --get-descriptionβ prints the description for the service π--permanent --service=service --set-short=descriptionβ sets the short description on the service πΈ--permanent --service=service --get-shortβ prints the short description for the service β¨--permanent --service=service --add-port=portid[-portid]/protocolβ adds a new port to the permanent service π₯--permanent --service=service --remove-port=portid[-portid]/protocolβ removes a port from the permanent service π«Ά--permanent --service=service --query-port=portid[-portid]/protocolβ returns whether that port has been added to the permanent service. Yes or no bestie π--permanent --service=service --get-portsβ lists the ports added to the permanent service π--permanent --service=service --add-protocol=protocolβ adds a new protocol to the permanent service π--permanent --service=service --remove-protocol=protocolβ removes a protocol from the permanent service π--permanent --service=service --query-protocol=protocolβ returns whether that protocol has been added to the permanent service π--permanent --service=service --get-protocolsβ lists the protocols added to the permanent service β¨--permanent --service=service --add-source-port=portid[-portid]/protocolβ adds a new source port to the permanent service π--permanent --service=service--remove-source-port=portid[-portid]/protocolβ removes a source port from the permanent service π--permanent --service=service--query-source-port=portid[-portid]/protocolβ returns whether that source port has been added to the permanent service π--permanent --service=service --get-source-portsβ lists the source ports added to the permanent service πΈ--permanent --service=service --add-helper=helperβ adds a new helper to the permanent service π§--permanent --service=service --remove-helper=helperβ removes a helper from the permanent service π«Ά--permanent --service=service --query-helper=helperβ returns whether that helper has been added to the permanent service π--permanent --service=service --get-service-helpersβ lists the helpers added to the permanent service β¨--permanent --service=service --set-destination=ipv:address[/mask]β sets the destination foripvtoaddress[/mask]in the permanent service π―--permanent --service=service --remove-destination=ipvβ removes the destination foripvfrom the permanent service ποΈ--permanent --service=service --query-destination=ipv:address[/mask]β returns whether the destinationipvtoaddress[/mask]has been set in the permanent service π--permanent --service=service --get-destinationsβ lists the destinations added to the permanent service π--permanent --service=service --add-include=serviceβ adds a new include to the permanent service π--permanent --service=service --remove-include=serviceβ removes an include from the permanent service π«Ά--permanent --service=service --query-include=serviceβ returns whether that include has been added to the permanent service π--permanent --service=service --get-includesβ lists the includes added to the permanent service β¨
π¦ Helper Options π¦
Options in this section affect only one particular helper. Just the one, she's the main character π
[--permanent] --info-helper=helperβ prints info about the helperhelper. The output format is:
helper
family: family
module: module
ports: port1 ..
The following options are only usable in the permanent configuration. Permanent mode only, bestie π
--permanent --new-helper=helper --module=nf_conntrack_module [--family=ipv4|ipv6]β adds a new permanent helper withmoduleand optionallyfamilydefined. Build-a-helper workshop π§Έ
Helper names must be alphanumeric and may additionally include the character '-'. That's it, that's the rule β
--permanent --new-helper-from-file=filename [--name=helper]β adds a new permanent helper from a prepared helper file, with an optional name override π--permanent --delete-helper=helperβ deletes an existing permanent helper π--permanent --load-helper-defaults=helperβ loads helper default settings, or reports aNO_DEFAULTSerror π--permanent --path-helper=helperβ prints the path of the helper configuration file ποΈ[--permanent] --get-helpersβ prints the predefined helpers as a space separated list β¨--permanent --helper=helper --set-description=descriptionβ sets a new description on the helper βοΈ--permanent --helper=helper --get-descriptionβ prints the description for the helper π--permanent --helper=helper --set-short=descriptionβ sets the short description on the helper πΈ--permanent --helper=helper --get-shortβ prints the short description for the helper β¨--permanent --helper=helper --add-port=portid[-portid]/protocolβ adds a new port to the permanent helper π₯--permanent --helper=helper --remove-port=portid[-portid]/protocolβ removes a port from the permanent helper π«Ά--permanent --helper=helper --query-port=portid[-portid]/protocolβ returns whether that port has been added to the permanent helper π--permanent --helper=helper --get-portsβ lists the ports added to the permanent helper π--permanent --helper=helper --set-module=descriptionβ sets the module description for the helper π§©--permanent --helper=helper --get-moduleβ prints the module description for the helper π--permanent --helper=helper --set-family=descriptionβ sets the family description for the helper π¨βπ©βπ§--permanent --helper=helper --get-familyβ prints the family description of the helper π
π Internet Control Message Protocol (ICMP) type Options π
Options in this section affect only one particular icmptype. One icmptype and only one π
[--permanent] --info-icmptype=icmptypeβ prints info about the icmptypeicmptype. The output format is:
icmptype
destination: ipv1 ..
The following options are only usable in the permanent configuration. Permanent only, no cap π
--permanent --new-icmptype=icmptypeβ adds a brand new permanent and empty icmptype β¨
ICMP type names must be alphanumeric and may additionally include the characters '_' and '-'. Stay in your lane, names π
--permanent --new-icmptype-from-file=filename [--name=icmptype]β adds a new permanent icmptype from a prepared icmptype file, with an optional name override π--permanent --delete-icmptype=icmptypeβ deletes an existing permanent icmptype π--permanent --load-icmptype-defaults=icmptypeβ loads icmptype default settings, or reports aNO_DEFAULTSerror π--permanent --icmptype=icmptype --set-description=descriptionβ sets a new description on the icmptype βοΈ--permanent --icmptype=icmptype --get-descriptionβ prints the description for the icmptype π--permanent --icmptype=icmptype --set-short=descriptionβ sets the short description on the icmptype πΈ--permanent --icmptype=icmptype --get-shortβ prints the short description for the icmptype β¨--permanent --icmptype=icmptype --add-destination=ipvβ enables the destination foripvin the permanent icmptype.ipvis one ofipv4oripv6. Pick one bestie, there are only two π--permanent --icmptype=icmptype --remove-destination=ipvβ disables the destination foripvin the permanent icmptype.ipvis one ofipv4oripv6.--permanent --icmptype=icmptype --query-destination=ipvβ returns whether the destination foripvis enabled in the permanent icmptype.ipvis one ofipv4oripv6.--permanent --icmptype=icmptype --get-destinationsβ lists the destinations in the permanent icmptype π--permanent --path-icmptype=icmptypeβ prints the path of the icmptype configuration file ποΈ
π Direct Options π
DEPRECATED
The direct interface has been deprecated. It will be removed in a future release. It is superseded by policies, see firewalld.policies(5).
Not me being the bearer of bad news π but yeah, she's on her way out. Use policies instead, bestie.
The direct options give a more direct access to the firewall. These options require the user to know basic iptables concepts, i.e. table (filter/mangle/nat/...), chain (INPUT/OUTPUT/FORWARD/...), commands (-A/-D/-I/...), parameters (-p/-s/-d/-j/...) and targets (ACCEPT/DROP/REJECT/...). So like, hard mode iptables lore π§ β¨
Direct options should be used only as a last resort when it's not possible to use, for example, --add-service=service or --add-rich-rule='rule'. Last resort only, she said what she said π
β οΈ Warning: Direct rules behavior is different depending on the value ofFirewallBackend. See CAVEATS infirewalld.direct(5).
Okay bestie, listen β the first argument of each one of these options has to be ipv4, ipv6 or eb. With ipv4 it's for IPv4 (iptables(8)), with ipv6 it's for IPv6 (ip6tables(8)), and with eb it's for ethernet bridges (ebtables(8)). Periodt, that's the rules of the game. π
[--permanent] --direct --get-all-chainsβ grabs every chain that's been added to all the tables. Note bestie: this one only cares about chains you previously added with--direct --add-chain. Nothing else. π[--permanent] --direct --get-chains { ipv4 | ipv6 | eb } tableβ gets every chain added to table as a space separated list. Again, only chains you previously added with--direct --add-chainshow up here. rigorous.[--permanent] --direct --add-chain { ipv4 | ipv6 | eb } table chainβ adds a brand new chain called chain to table. Pls make sure there's no other chain with that name already, okay? don't be messy. π
There are already basic chains built for you to use with direct options β for example the INPUT_direct chain (run iptables-save | grep direct and you'll see all of them, iykyk). These chains get jumped into before the chains for zones, which means every rule you put into INPUT_direct gets checked before the rules in zones. priority queen behavior. π
[--permanent] --direct --remove-chain { ipv4 | ipv6 | eb } table chainβ removes the chain named chain from table. Only chains previously added with--direct --add-chaincan be removed this way, no sneaky exceptions. π[--permanent] --direct --query-chain { ipv4 | ipv6 | eb } table chainβ tells you whether a chain named chain exists in table. Returns0if true,1otherwise. And yes, only chains previously added with--direct --add-chaincount here. π¦[--permanent] --direct --get-all-rulesβ gets every rule added to every chain in every table, as a newline separated list of the priority and arguments. Only rules previously added with--direct --add-rule, so don't expect it to manifest anything else. β¨[--permanent] --direct --get-rules { ipv4 | ipv6 | eb } table chainβ gets every rule added to chain in table, as a newline separated list of the priority and arguments. Again: only rules previously added with--direct --add-rule. consistent queen.[--permanent] --direct --add-rule { ipv4 | ipv6 | eb } table chain priority argsβ adds a rule with the arguments args to chain in table, with priority priority. π
The priority is what orders your rules, bestie. Priority 0 means the rule goes on top of the chain, and with a higher priority the rule gets added further down. Rules with the same priority sit on the same level, and the order of those is not fixed and may change. So if you need a rule to definitely land after another one, give the first one a low priority and the following one a higher priority. That's the whole trick, no cap. π
[--permanent] --direct --remove-rule { ipv4 | ipv6 | eb } table chain priority argsβ removes the rule with priority and the arguments args from chain in table. Only rules previously added with--direct --add-rulecan be removed this way. linear, clean, iconic. π[--permanent] --direct --remove-rules { ipv4 | ipv6 | eb } table chainβ removes all rules in the chain named chain that exists in table. This one only concerns rules previously added with--direct --add-rulein this chain. bye bye rules π«Ά[--permanent] --direct --query-rule { ipv4 | ipv6 | eb } table chain priority argsβ returns whether a rule with priority and the arguments args exists in chain in table. Returns0if true,1otherwise. And yes, only rules previously added with--direct --add-ruleare in scope here. π--direct --passthrough { ipv4 | ipv6 | eb } argsβ passes a command straight through to the firewall. args can be alliptables,ip6tablesandebtablescommand line arguments. Heads up bestie: this command is untracked, which means firewalld is not able to provide information about this command later on β not even a listing of the untracked passthroughs. it's giving mystery π΅οΈββοΈ (there is no--permanenthere, so don't try it.)[--permanent] --direct --get-all-passthroughsβ gets all passthrough rules as a newline separated list of theipvvalue and arguments. β¨[--permanent] --direct --get-passthroughs { ipv4 | ipv6 | eb }β gets all passthrough rules for theipvvalue as a newline separated list of the priority and arguments. πΈ[--permanent] --direct --add-passthrough { ipv4 | ipv6 | eb } argsβ adds a passthrough rule with the arguments args for theipvvalue. π[--permanent] --direct --remove-passthrough { ipv4 | ipv6 | eb } argsβ removes a passthrough rule with the arguments args for theipvvalue. π[--permanent] --direct --query-passthrough { ipv4 | ipv6 | eb } argsβ returns whether a passthrough rule with the arguments args exists for theipvvalue. Returns0if true,1otherwise. π¦
π¨ Panic Options π¨
--panic-onβ enables panic mode. All incoming and outgoing packets are dropped, and active connections will expire. Enable this only if there are serious problems with your network environment β for example if the machine is getting hacked in. π¨π
This is a runtime only change.
--panic-offβ disables panic mode. After disabling it, established connections might work again, if panic mode was enabled for a short period of time. we're so back. π«Ά
This is a runtime only change.
--query-panicβ returns0if panic mode is enabled,1otherwise. vibe check on the panic. π
πΈ EXAMPLES πΈ
π Example 1
Enable the http service in the default zone. This is a runtime only change, i.e. effective until restart.
firewall-cmd --add-service=http
π Example 2
Enable port 443/tcp immediately and permanently in the default zone. To make the change effective immediately and also after restart we need two commands. The first command makes the change in runtime configuration, i.e. makes it effective immediately, until restart. The second command makes the change in permanent configuration, i.e. makes it effective after restart. two commands, one slay. π
firewall-cmd --add-port=443/tcp
firewall-cmd --permanent --add-port=443/tcp
π¦ UNKNOWN DESTINATIONS π¦
Some features occur at a point in the packet processing pipeline when it's impossible to determine the destination of the packet, e.g. prerouting. As a consequence, firewalld can only use the ingress interface/source to dispatch zones and policies, and packets get dispatched without considering the egress. it's giving "where are you going? we don't know her" π
Since the egress cannot be determined, the order of precedence is determined by the policy's priority.
The following features are subject to this behavior:
--add-forward-port--add-rich-rule rule ... forward-port ...--add-rich-rule rule ... mark ...
remember this one, bestie, it will show up in a quiz. πΈ
okay so bestie, exit codes are literally the receipts of what just happened. π
When everything is β¨perfectβ¨, firewall-cmd exits with 0. Zero. Nothing. Clean. Iconic. When it fails tho? The output turns red (dramatic, we love), and the exit code is either 2 if you fumbled the command-line options, or one of the following error codes in all the other cases. Keep this list in your notes app fr fr, iykyk. π
ALREADY_ENABLEDβ code11, aka bestie it's already enabled πNOT_ENABLEDβ code12, it's not enabled, soβ¦COMMAND_FAILEDβ code13, the command just did not eat πNO_IPV6_NATβ code14, no IPv6 NAT happening herePANIC_MODEβ code15, full panic mode activated πZONE_ALREADY_SETβ code16, that zone is already setUNKNOWN_INTERFACEβ code17, the interface is a mystery to usZONE_CONFLICTβ code18, zones are beefingBUILTIN_CHAINβ code19, it's giving builtin chain energyEBTABLES_NO_REJECTβ code20, ebtables said no rejectNOT_OVERLOADABLEβ code21, can't overload it, sorryNO_DEFAULTSβ code22, there are no defaultsBUILTIN_ZONEβ code23, builtin zone momentBUILTIN_SERVICEβ code24, builtin service momentBUILTIN_ICMPTYPEβ code25, builtin icmptype momentNAME_CONFLICTβ code26, name conflict, rudeNAME_MISMATCHβ code27, the names don't matchPARSE_ERRORβ code28, parsing said nopeACCESS_DENIEDβ code29, access denied, bye πUNKNOWN_SOURCEβ code30, unknown sourceRT_TO_PERM_FAILEDβ code31, rt to perm failedIPSET_WITH_TIMEOUTβ code32, ipset with timeoutBUILTIN_IPSETβ code33, builtin ipsetALREADY_SETβ code34, it's already set bestieMISSING_IMPORTβ code35, missing importDBUS_ERRORβ code36, dbus error π΅BUILTIN_HELPERβ code37, builtin helperNOT_APPLIEDβ code38, not appliedINVALID_ACTIONβ code100, that action is invalidINVALID_SERVICEβ code101, that service is invalidINVALID_PORTβ code102, that port is invalidINVALID_PROTOCOLβ code103, that protocol is invalidINVALID_INTERFACEβ code104, that interface is invalidINVALID_ADDRβ code105, that address is invalidINVALID_FORWARDβ code106, that forward is invalidINVALID_ICMPTYPEβ code107, that icmptype is invalidINVALID_TABLEβ code108, that table is invalidINVALID_CHAINβ code109, that chain is invalidINVALID_TARGETβ code110, that target is invalidINVALID_IPVβ code111, that ipv is invalidINVALID_ZONEβ code112, that zone is invalidINVALID_PROPERTYβ code113, that property is invalidINVALID_VALUEβ code114, that value is invalidINVALID_OBJECTβ code115, that object is invalidINVALID_NAMEβ code116, that name is invalidINVALID_FILENAMEβ code117, that filename is invalidINVALID_DIRECTORYβ code118, that directory is invalidINVALID_TYPEβ code119, that type is invalidINVALID_SETTINGβ code120, that setting is invalidINVALID_DESTINATIONβ code121, that destination is invalidINVALID_RULEβ code122, that rule is invalidINVALID_LIMITβ code123, that limit is invalidINVALID_FAMILYβ code124, that family is invalidINVALID_LOG_LEVELβ code125, that log level is invalidINVALID_AUDIT_TYPEβ code126, that audit type is invalidINVALID_MARKβ code127, that mark is invalidINVALID_CONTEXTβ code128, that context is invalidINVALID_COMMANDβ code129, that command is invalidINVALID_USERβ code130, that user is invalidINVALID_UIDβ code131, that uid is invalidINVALID_MODULEβ code132, that module is invalidINVALID_PASSTHROUGHβ code133, that passthrough is invalidINVALID_MACβ code134, that mac is invalidINVALID_IPSETβ code135, that ipset is invalidINVALID_ENTRYβ code136, that entry is invalidINVALID_OPTIONβ code137, that option is invalidINVALID_HELPERβ code138, that helper is invalidINVALID_PRIORITYβ code139, that priority is invalidINVALID_POLICYβ code140, that policy is invalidINVALID_LOG_PREFIXβ code141, that log prefix is invalidINVALID_NFLOG_GROUPβ code142, that nflog group is invalidINVALID_NFLOG_QUEUEβ code143, that nflog queue is invalidINVALID_SOURCEβ code144, that source is invalidMISSING_TABLEβ code200, missing tableMISSING_CHAINβ code201, missing chainMISSING_PORTβ code202, missing portMISSING_PROTOCOLβ code203, missing protocolMISSING_ADDRβ code204, missing addrMISSING_NAMEβ code205, missing nameMISSING_SETTINGβ code206, missing settingMISSING_FAMILYβ code207, missing family
aaaand here's the rest of the exit-code lineup, bestie β the dramatic finale of the table from earlier:
RUNNING_BUT_FAILEDβ251πNOT_RUNNINGβ252πNOT_AUTHORIZEDβ253πUNKNOWN_ERRORβ254π
okay so special tea for the --query-* options: successful queries return 0, unsuccessful ones return 1, and if an actual error happened, then the table above is what applies. periodt. π
π SEE ALSO π
go read these next, they're all iconic:
firewall-applet(1)firewalld(1)firewall-cmd(1)firewall-config(1)firewalld.conf(5)firewalld.direct(5)firewalld.dbus(5)firewalld.icmptype(5)firewall-offline-cmd(1)firewalld.richlanguage(5)firewalld.service(5)firewalld.zone(5)firewalld.zones(5)firewalld.policy(5)firewalld.policies(5)firewalld.ipset(5)firewalld.helper(5)
π NOTES π
- firewalld home page:
http://firewalld.orgππ
π AUTHORS π
- Thomas Woerner
<twoerner@redhat.com>β Developer - Jiri Popelka
<jpopelka@redhat.com>β Developer - Eric Garver
<eric@garver.life>β Developer
and that's a wrap on this absolute saga π« this page comes from firewalld 2.5.2, and it's the FIREWALL-CMD(1) manual. no cap, you made it to the end, ily π«Άβ¨
π¦ where this page comes from
- arch rolling: firewalld 2.5.2-1 Β· GPL-2.0-or-later
- nixpkgs unstable: firewalld 2.5.2
- ubuntu stonking: firewalld 2.5.2-1 Β· GPL-2.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms