#863802 systemd unit breaks ferm in some setups in jessie->stretch upgrade

Package:
ferm
Source:
ferm
Submitter:
Moritz Muehlenhoff
Date:
2026-06-20 13:39:01 UTC
Severity:
wishlist
Tags:
#863802#5
Date:
2017-05-31 11:55:18 UTC
From:
To:
Ferm is broken in stretch for any rule set which contains resolve() statements.
(There might be others relying on network, didn't check). This got introduced
in 2.3-2, which now uses a Wants:/Before: network-pre.target

In jessie, no systemd unit was provided and the sysvinit script translated to

# systemctl cat ferm
# /run/systemd/generator.late/ferm.service
# Automatically generated by systemd-sysv-generator

[Unit]
SourcePath=/etc/init.d/ferm
Description=LSB: ferm firewall configuration
DefaultDependencies=no
Before=sysinit.target
After=network-online.target remote-fs.target
Wants=network-online.target

But since ferm.service is now executed before the network is up, any rule
containing a resolve() statement now leads to a ferm startup failure:

# journalctl -u ferm
-- Logs begin at Wed 2017-05-31 10:53:35 UTC, end at Wed 2017-05-31 11:40:57 UTC. --
May 31 10:53:38 ms-be2001 ferm[1038]: Starting Firewall: fermError in /etc/ferm/conf.d/10_example line 4:
May 31 10:53:38 ms-be2001 ferm[1038]:                 just.example.org
May 31 10:53:38 ms-be2001 ferm[1038]:             )
May 31 10:53:38 ms-be2001 ferm[1038]:
May 31 10:53:38 ms-be2001 ferm[1038]:         )
May 31 10:53:38 ms-be2001 ferm[1038]:         <--
May 31 10:53:38 ms-be2001 ferm[1038]: DNS query for 'just.example.org' failed: query timed out
May 31 10:53:38 ms-be2001 ferm[1038]:  failed!
May 31 10:53:38 ms-be2001 systemd[1]: ferm.service: Main process exited, code=exited, status=101/n/a
May 31 10:53:38 ms-be2001 systemd[1]: Failed to start ferm firewall configuration.
May 31 10:53:38 ms-be2001 systemd[1]: ferm.service: Unit entered failed state.
May 31 10:53:38 ms-be2001 systemd[1]: ferm.service: Failed with result 'exit-code'.

I'm setting severity to "grave" since this breaks existing setups during the update
from jessie to stretch.

Possible fixes:
- Revert to the status quo from jessie by reverting the changes from 2.3-2 (ugly)
- Split into two services, e.g. ferm-base.service loading a base rule set which runs on
network-pre.target and ferm-extended.service which runs on nss-lookup.target or
network.target

Cheers,
        Moritz

#863802#10
Date:
2017-05-31 12:08:35 UTC
From:
To:
Which is funny. We had a bunch of bugs about ferm starting late where
everyone stated it should be up before the network is up.

Someone should decide, which is not me. Therefore I don't think this is
grave.

Alex

#863802#15
Date:
2017-05-31 12:08:35 UTC
From:
To:
Which is funny. We had a bunch of bugs about ferm starting late where
everyone stated it should be up before the network is up.

Someone should decide, which is not me. Therefore I don't think this is
grave.

Alex

#863802#22
Date:
2017-06-06 11:36:27 UTC
From:
To:
Feel free to downgrade. I've only marked it RC due to possible jessie->
stretch upgrade problems.

I'm attaching a service unit which waits for name resolution (for people
rebuilding the package or dropping that one into /etc/systemd/system)

Cheers,
        Moritz

#863802#27
Date:
2017-06-07 21:50:24 UTC
From:
To:
severity 863802 wishlist
thanks

As discussed, I don't this is a bug.

#863802#34
Date:
2018-03-05 09:18:39 UTC
From:
To:
How can this be not a bug?

It changed from having no firewall for a fraction of a second to having
no running firewall at all. 

I think this is a serious bug.

Roman

#863802#39
Date:
2024-11-08 08:56:46 UTC
From:
To:
Dear Alex,

The similar problem arises in bookworm.
After intensive debugging I found that when ferm starts the
(statically configured) network interfaces have no IP address yet.
I was forced to override the unit file to get ferm working after boot.

The others say: for security reasons traffic filtering must be functional
before the first network packet arrives. That is a laudable conception
but unfortunately it is not operable in every situation.
The result: the host has no protection at all.

Okay, that is ME who decides. :-) Ferm MUST wait the networking
to be fully up.
A host without protection for half a seconds is far better than
an unprotected host.

At least README.Debian should discuss this problem and should
give a recipe for admins in the same situation.

Sorry if I was too pushy.

Cheers

Gabor

#863802#44
Date:
2026-05-27 06:19:02 UTC
From:
To:
Hi,

this topic is recurring for every firewall package I have seen. There
are two factions, both of which having a point, and going after one
solution causes breakage on the other side.

If we start the firewall early, firewall building fails when the
firewall building needs the network, for example when the firewall admin
writes hostnames in their firewall config (which I consider a
not-so-goodidea) or when the ruleset takes IP addresses and routes as
input for rule building.

Starting the firewall late will leave the host unprotected for a
possibly two-digit number of seconds, up to "indefinetely" when the boot
process stalls.

There is also an issue with service dependencies (see #1137531, where a
cyclic dependency with NetworkManager was reported). This probably needs
an avalanche of coordination and testing to finally fix.

Moritz writes:

This might be a solution. Would somebody help with the necessary
dependencies of the units?

In the current version, ferm stars early again, which will break setups
needing the network on initialization.

I am actually planning myself to migrate away from ferm and to give nft
another try, so I am kind of relutcant to implement a two-stage init at
the current point. I definetely need help with the systemd dependencies,
especially with the different kinds of network initialization stacks.

My idea would be to augment the regular firewall set /etc/ferm/ferm.conf
with /etc/ferm/ferm.d as include directory with a second set
/etc/ferm/ferm-early.conf and /etc/ferm/ferm-early.d, documenting the
fact that ferm-early can't rely on the network being functional.

This can probably be done easily enough, but I don't have time to test
the service dependency hell.

Greetings
Marc

#863802#51
Date:
2026-05-27 06:19:02 UTC
From:
To:
Hi,

this topic is recurring for every firewall package I have seen. There
are two factions, both of which having a point, and going after one
solution causes breakage on the other side.

If we start the firewall early, firewall building fails when the
firewall building needs the network, for example when the firewall admin
writes hostnames in their firewall config (which I consider a
not-so-goodidea) or when the ruleset takes IP addresses and routes as
input for rule building.

Starting the firewall late will leave the host unprotected for a
possibly two-digit number of seconds, up to "indefinetely" when the boot
process stalls.

There is also an issue with service dependencies (see #1137531, where a
cyclic dependency with NetworkManager was reported). This probably needs
an avalanche of coordination and testing to finally fix.

Moritz writes:

This might be a solution. Would somebody help with the necessary
dependencies of the units?

In the current version, ferm stars early again, which will break setups
needing the network on initialization.

I am actually planning myself to migrate away from ferm and to give nft
another try, so I am kind of relutcant to implement a two-stage init at
the current point. I definetely need help with the systemd dependencies,
especially with the different kinds of network initialization stacks.

My idea would be to augment the regular firewall set /etc/ferm/ferm.conf
with /etc/ferm/ferm.d as include directory with a second set
/etc/ferm/ferm-early.conf and /etc/ferm/ferm-early.d, documenting the
fact that ferm-early can't rely on the network being functional.

This can probably be done easily enough, but I don't have time to test
the service dependency hell.

Greetings
Marc

#863802#56
Date:
2026-05-27 07:22:45 UTC
From:
To:
Control: severity -1 important
thanks
are some thoughts.

Splitting into ferm-early.service and ferm.service seems feasible.

Specifying dependencies to other network-related things will be a
challenge.

The current After=remote-fs.target is clearly wrong, as this specifies
ferm _after_network initialization. The current intention is to start
ferm early in the absense of a ferm-early.service.

I would like to encourage people who have rulesets needing network to
try the split locally and report their experiences (and to show their
units).

The idea is: ferm-early.service > network-pre.target > Network
Management Stack > interfaces configured > remote-fs | network-online >
ferm.service

A first idea is:
ferm-early.service:
[Unit]
DefaultDependencies=no
Before=network-pre.target
Wants=network-pre.target
ConditionPathExists=!/run/ferm-loaded
RefuseManualStart=yes
RefuseManualStop=yes

would it make sense to explicitly specify
Before=systemd-networkd.service
Before=NetworkManager.service
Before=networking.service?

[Service]
Environment=CONFIG=/etc/ferm/ferm-early.conf CACHE_DIR=/var/cache/ferm-early
Type=oneshot
RemainAfterExit=yes
ExecStart=ferm-systemd activate
ExecStartPost=touch /run/ferm-loaded
ExecReload=ferm-systemd activate
ExecStop=ferm-systemd deactivate

[Install]
WantedBy=sysinit.target

This relys on all network management daemons saying
[Unit]
After=network-pre.target

We should probable establish the early ruleset in dedicated chains
input-early, output-early, forward-early and then just add one catch-all
rule in the INPUT, OUTPUT and FORWARD chain. The early ruleset should be
liberal, allowing outgoing DNS, incoming and outgoing ICMP (and ICMPv6
including SLAAC), allow the local host to act as DHCP client and NTP
client, to establish VPN connections, PPP, bridges, Wifi.

Then, the real ferm.service would be:
[Unit]
After=network-online.target
Wants=network-online.target

would it make sense to explicitly specify
Before=systemd-networkd.service
Before=NetworkManager.service
Before=networking.service?

[Service]
Environment=CONFIG=/etc/ferm/ferm.conf CACHE_DIR=/var/cache/ferm
Type=oneshot
RemainAfterExit=yes
# optionally check whether we have working DNS
ExecStartPre=getent ahostsv4 debian.org
ExecStart=ferm-systemd activate
ExecReload=ferm-systemd activate
ExecStop=ferm-systemd deactivate

[Install]
WantedBy=multi-user.target

What do you think? Would that work?

Greetings
Marc

#863802#61
Date:
2026-05-27 07:22:45 UTC
From:
To:
Control: severity -1 important
thanks
are some thoughts.

Splitting into ferm-early.service and ferm.service seems feasible.

Specifying dependencies to other network-related things will be a
challenge.

The current After=remote-fs.target is clearly wrong, as this specifies
ferm _after_network initialization. The current intention is to start
ferm early in the absense of a ferm-early.service.

I would like to encourage people who have rulesets needing network to
try the split locally and report their experiences (and to show their
units).

The idea is: ferm-early.service > network-pre.target > Network
Management Stack > interfaces configured > remote-fs | network-online >
ferm.service

A first idea is:
ferm-early.service:
[Unit]
DefaultDependencies=no
Before=network-pre.target
Wants=network-pre.target
ConditionPathExists=!/run/ferm-loaded
RefuseManualStart=yes
RefuseManualStop=yes

would it make sense to explicitly specify
Before=systemd-networkd.service
Before=NetworkManager.service
Before=networking.service?

[Service]
Environment=CONFIG=/etc/ferm/ferm-early.conf CACHE_DIR=/var/cache/ferm-early
Type=oneshot
RemainAfterExit=yes
ExecStart=ferm-systemd activate
ExecStartPost=touch /run/ferm-loaded
ExecReload=ferm-systemd activate
ExecStop=ferm-systemd deactivate

[Install]
WantedBy=sysinit.target

This relys on all network management daemons saying
[Unit]
After=network-pre.target

We should probable establish the early ruleset in dedicated chains
input-early, output-early, forward-early and then just add one catch-all
rule in the INPUT, OUTPUT and FORWARD chain. The early ruleset should be
liberal, allowing outgoing DNS, incoming and outgoing ICMP (and ICMPv6
including SLAAC), allow the local host to act as DHCP client and NTP
client, to establish VPN connections, PPP, bridges, Wifi.

Then, the real ferm.service would be:
[Unit]
After=network-online.target
Wants=network-online.target

would it make sense to explicitly specify
Before=systemd-networkd.service
Before=NetworkManager.service
Before=networking.service?

[Service]
Environment=CONFIG=/etc/ferm/ferm.conf CACHE_DIR=/var/cache/ferm
Type=oneshot
RemainAfterExit=yes
# optionally check whether we have working DNS
ExecStartPre=getent ahostsv4 debian.org
ExecStart=ferm-systemd activate
ExecReload=ferm-systemd activate
ExecStop=ferm-systemd deactivate

[Install]
WantedBy=multi-user.target

What do you think? Would that work?

Greetings
Marc

#863802#66
Date:
2026-06-09 02:31:32 UTC
From:
To:
I've played around with this and I've come up with this:

# /usr/lib/systemd/system/ferm-early.service
[Unit]
Description=Early firewall configuration with ferm
Documentation=man:ferm(1)
Before=network-pre.target
Wants=network-pre.target
After=local-fs.target
ConditionFileIsExecutable=/usr/sbin/ferm
ConditionPathExists=/etc/ferm/ferm.conf

[Service]
Type=oneshot
RemainAfterExit=yes

# Set defaults for variables not in environment file
# (EnvironmentFile takes precedence, see systemd.exec(5)
Environment="CACHE=no"
Environment="OPTIONS="

EnvironmentFile=-/etc/default/ferm

# Execute wrapper
ExecStart=-/bin/sh -c '/usr/libexec/ferm/ferm-systemd activate && touch /run/ferm-early-success'

UMask=0077

# Security hardening
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/cache/ferm /run
NoNewPrivileges=no

# Required capabilities for firewall management
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_MODULE

[Install]
WantedBy=multi-user.target



The important parts being:
  Before=network-pre.target
  Wants=network-pre.target
  After=local-fs.target
  ConditionFileIsExecutable=/usr/sbin/ferm

(Note, ConditionFileIsExecutable, not ConditionPathIsExecutable,
see systemd.directives)


And, more importantly:
  ExecStart=-/bin/sh -c '/usr/libexec/ferm/ferm-systemd activate && touch /run/ferm-early-success'

The "=-" means this will be a best-effort attempt and won't
error out on failure (like if hostnames have been used in the
ferm scripts, not something I'd endorse, but I know there's
people who have different opinions).


Then:

# /usr/lib/systemd/system/ferm.service
[Unit]
Description=Firewall configuration with ferm
Documentation=man:ferm(1)
After=network-online.target nss-lookup.target
Wants=network-online.target
ConditionFileIsExecutable=/usr/sbin/ferm
ConditionPathExists=/etc/ferm/ferm.conf

[Service]
Type=oneshot
RemainAfterExit=yes

# Set defaults for variables not in environment file
# (EnvironmentFile takes precedence, see systemd.exec(5)
Environment="CACHE=no"
Environment="OPTIONS="

EnvironmentFile=-/etc/default/ferm

# Execute wrapper
ExecCondition=/bin/sh -c 'if [ -f /run/ferm-early-success ]; then rm -f /run/ferm-early-success; exit 1; else exit 0; fi'
ExecStart=/usr/libexec/ferm/ferm-systemd activate
ExecReload=/usr/libexec/ferm/ferm-systemd activate
ExecStop=/usr/libexec/ferm/ferm-systemd deactivate

UMask=0077

# Security hardening
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/cache/ferm /run
NoNewPrivileges=no

# Required capabilities for firewall management
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_MODULE

[Install]
WantedBy=multi-user.target



Rationale:
ferm.service is the *real* service that'll run unless ferm-early.service
succeeded. It'll run at a point where the network is up and nss-lookup
is finished. It'll only run if ferm-early.service failed, and do another
attempt. If it fails, that'll be a hard fail in the output from e.g.
"systemctl status". ferm-early.service errors will be ignored.

Also, this ensures that people who are used to "ferm.service" being the
"real" service can do things like "systemctl restart ferm.service" long
after the system has booted, and it'll do the right thing.

Finally, it removes the need for separate "early" and "late" ferm scripts.
Instead, we do a best-effort early firewall setup (will work for ferm
configurations without hostnames), and then an optional second pass
(where DNS should be available).



Things left to consider:
* Should ferm-early.service have DefaultDependencies=no?
* This might still not be enough on servers providing DNS services, since
  I don't think it'll ensure the DNS server is up before ferm.service kicks in
  (I'd argue that DNS servers should not have hostnames in ferm scripts).




(Sorry if the formatting is weird, had to do this via a web client).

#863802#69
Date:
2026-06-09 02:31:32 UTC
From:
To:
I've played around with this and I've come up with this:

# /usr/lib/systemd/system/ferm-early.service
[Unit]
Description=Early firewall configuration with ferm
Documentation=man:ferm(1)
Before=network-pre.target
Wants=network-pre.target
After=local-fs.target
ConditionFileIsExecutable=/usr/sbin/ferm
ConditionPathExists=/etc/ferm/ferm.conf

[Service]
Type=oneshot
RemainAfterExit=yes

# Set defaults for variables not in environment file
# (EnvironmentFile takes precedence, see systemd.exec(5)
Environment="CACHE=no"
Environment="OPTIONS="

EnvironmentFile=-/etc/default/ferm

# Execute wrapper
ExecStart=-/bin/sh -c '/usr/libexec/ferm/ferm-systemd activate && touch /run/ferm-early-success'

UMask=0077

# Security hardening
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/cache/ferm /run
NoNewPrivileges=no

# Required capabilities for firewall management
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_MODULE

[Install]
WantedBy=multi-user.target



The important parts being:
  Before=network-pre.target
  Wants=network-pre.target
  After=local-fs.target
  ConditionFileIsExecutable=/usr/sbin/ferm

(Note, ConditionFileIsExecutable, not ConditionPathIsExecutable,
see systemd.directives)


And, more importantly:
  ExecStart=-/bin/sh -c '/usr/libexec/ferm/ferm-systemd activate && touch /run/ferm-early-success'

The "=-" means this will be a best-effort attempt and won't
error out on failure (like if hostnames have been used in the
ferm scripts, not something I'd endorse, but I know there's
people who have different opinions).


Then:

# /usr/lib/systemd/system/ferm.service
[Unit]
Description=Firewall configuration with ferm
Documentation=man:ferm(1)
After=network-online.target nss-lookup.target
Wants=network-online.target
ConditionFileIsExecutable=/usr/sbin/ferm
ConditionPathExists=/etc/ferm/ferm.conf

[Service]
Type=oneshot
RemainAfterExit=yes

# Set defaults for variables not in environment file
# (EnvironmentFile takes precedence, see systemd.exec(5)
Environment="CACHE=no"
Environment="OPTIONS="

EnvironmentFile=-/etc/default/ferm

# Execute wrapper
ExecCondition=/bin/sh -c 'if [ -f /run/ferm-early-success ]; then rm -f /run/ferm-early-success; exit 1; else exit 0; fi'
ExecStart=/usr/libexec/ferm/ferm-systemd activate
ExecReload=/usr/libexec/ferm/ferm-systemd activate
ExecStop=/usr/libexec/ferm/ferm-systemd deactivate

UMask=0077

# Security hardening
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/cache/ferm /run
NoNewPrivileges=no

# Required capabilities for firewall management
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_MODULE

[Install]
WantedBy=multi-user.target



Rationale:
ferm.service is the *real* service that'll run unless ferm-early.service
succeeded. It'll run at a point where the network is up and nss-lookup
is finished. It'll only run if ferm-early.service failed, and do another
attempt. If it fails, that'll be a hard fail in the output from e.g.
"systemctl status". ferm-early.service errors will be ignored.

Also, this ensures that people who are used to "ferm.service" being the
"real" service can do things like "systemctl restart ferm.service" long
after the system has booted, and it'll do the right thing.

Finally, it removes the need for separate "early" and "late" ferm scripts.
Instead, we do a best-effort early firewall setup (will work for ferm
configurations without hostnames), and then an optional second pass
(where DNS should be available).



Things left to consider:
* Should ferm-early.service have DefaultDependencies=no?
* This might still not be enough on servers providing DNS services, since
  I don't think it'll ensure the DNS server is up before ferm.service kicks in
  (I'd argue that DNS servers should not have hostnames in ferm scripts).




(Sorry if the formatting is weird, had to do this via a web client).

#863802#74
Date:
2026-06-19 19:59:19 UTC
From:
To:
Thank you.

I am not sure whether After=local-fs.target is needed. According to
bootup(7) that comes _before_ sysinit.target and all services depend on
that. I think that is redundant.

Is that any different than having the touch in an ExecStartPost?

So you would recommend to use the same rule set and just come up with
the rule set in some degraded form if it needs network?

I think that nss-lookup.target is important here, yes. Thanks.

What is the rationale behind this?

Will ferm still establish a filter when a name lookup fails? I THINK it
may error out itself and not establish anything?

My gut feeling prefers a real two-step approach with two distinct rule
sets.

Greetings
Marc

#863802#77
Date:
2026-06-19 19:59:19 UTC
From:
To:
Thank you.

I am not sure whether After=local-fs.target is needed. According to
bootup(7) that comes _before_ sysinit.target and all services depend on
that. I think that is redundant.

Is that any different than having the touch in an ExecStartPost?

So you would recommend to use the same rule set and just come up with
the rule set in some degraded form if it needs network?

I think that nss-lookup.target is important here, yes. Thanks.

What is the rationale behind this?

Will ferm still establish a filter when a name lookup fails? I THINK it
may error out itself and not establish anything?

My gut feeling prefers a real two-step approach with two distinct rule
sets.

Greetings
Marc

#863802#82
Date:
2026-06-20 13:07:29 UTC
From:
To:
June 19, 2026 at 9:59 PM, "Marc Haber" <mh+debian-packages@zugschlus.de mailto:mh+debian-packages@zugschlus.de?to=%22Marc%20Haber%22%20%3Cmh%2Bdebian-packages%40zugschlus.de%3E > wrote:

I'm not at home, so can't check right now, but if I remember correctly,
my thinking was that we might want:

  DefaultDependencies=no

To e.g. prevent the firewall from being torn down on shutdown.

Yeah, the "=-" means "ignore failure", but we only want the touch to run
on success. With ExecStartPost I think the touch would always be executed.

Yeah, my draft approach would mean one rule set.

I agree with what you said earlier in the bug report - (i.e. I'd recommend
that people don't specify firewall rules with hostnames at all). But if
they insist, this means that the firewall rules will at least be loaded
(just later).

I means that "ferm.service" won't do anything the first time it's executed
(i.e. during boot) if "ferm-early.service" was successful. And after the
first time "ferm.service" has been started, it'll behave like a normal
systemd .service (so admins that change rules can do e.g. "systemctl
restart ferm", and it'll work as expected).

Yeah, when name lookup fails, ferm will (IIRC) just error out.

That's the trade-off. If the rules contain hostnames, the firewall will only
come up after the network is up and name resolution works (but I'd argue that
people using hostnames in their rules have kind of opted into that behaviour).

The advantage is that there's no need to define two distinct rule sets.

Conceptually cleaner, but the question is how many people would be willing
to rewrite their firewall config for that (especially given that ferm seems
to be kind of EOL; personally I still have the long-term goal to transition
to "pure" NFT).

Cheers,
David

#863802#85
Date:
2026-06-20 13:07:29 UTC
From:
To:
June 19, 2026 at 9:59 PM, "Marc Haber" <mh+debian-packages@zugschlus.de mailto:mh+debian-packages@zugschlus.de?to=%22Marc%20Haber%22%20%3Cmh%2Bdebian-packages%40zugschlus.de%3E > wrote:

I'm not at home, so can't check right now, but if I remember correctly,
my thinking was that we might want:

  DefaultDependencies=no

To e.g. prevent the firewall from being torn down on shutdown.

Yeah, the "=-" means "ignore failure", but we only want the touch to run
on success. With ExecStartPost I think the touch would always be executed.

Yeah, my draft approach would mean one rule set.

I agree with what you said earlier in the bug report - (i.e. I'd recommend
that people don't specify firewall rules with hostnames at all). But if
they insist, this means that the firewall rules will at least be loaded
(just later).

I means that "ferm.service" won't do anything the first time it's executed
(i.e. during boot) if "ferm-early.service" was successful. And after the
first time "ferm.service" has been started, it'll behave like a normal
systemd .service (so admins that change rules can do e.g. "systemctl
restart ferm", and it'll work as expected).

Yeah, when name lookup fails, ferm will (IIRC) just error out.

That's the trade-off. If the rules contain hostnames, the firewall will only
come up after the network is up and name resolution works (but I'd argue that
people using hostnames in their rules have kind of opted into that behaviour).

The advantage is that there's no need to define two distinct rule sets.

Conceptually cleaner, but the question is how many people would be willing
to rewrite their firewall config for that (especially given that ferm seems
to be kind of EOL; personally I still have the long-term goal to transition
to "pure" NFT).

Cheers,
David

#863802#90
Date:
2026-06-20 13:37:06 UTC
From:
To:
That also breaks a lot of implicit dependencies on startup, for example
the sysinit dependency that we need here. I am not too fond of that
idea, but ...

... that is an aspect that I didn't cover i my thoughts before.
specified in ExecStart= have been invoked successfully

You have a point here, my gut feeling still says that people are going
to yell at me because I left their system unprotected for a few seconds.

I see.

The early rule set is rather simply spelled out, I think.

That's as well my long-term goal. Sadly nft sucks when it comes to
dual stack networking.

Greetings
Marc

#863802#93
Date:
2026-06-20 13:37:06 UTC
From:
To:
That also breaks a lot of implicit dependencies on startup, for example
the sysinit dependency that we need here. I am not too fond of that
idea, but ...

... that is an aspect that I didn't cover i my thoughts before.
specified in ExecStart= have been invoked successfully

You have a point here, my gut feeling still says that people are going
to yell at me because I left their system unprotected for a few seconds.

I see.

The early rule set is rather simply spelled out, I think.

That's as well my long-term goal. Sadly nft sucks when it comes to
dual stack networking.

Greetings
Marc