Skip to content

hm2_eth: add nftables firewall backend#4111

Open
grandixximo wants to merge 1 commit into
LinuxCNC:masterfrom
grandixximo:feature/nftables-support
Open

hm2_eth: add nftables firewall backend#4111
grandixximo wants to merge 1 commit into
LinuxCNC:masterfrom
grandixximo:feature/nftables-support

Conversation

@grandixximo
Copy link
Copy Markdown
Contributor

Follow-up to #3964. That PR added automatic interface isolation via iptables; @NTULINUX noted nftables-only systems have no iptables binary at all, so the auto-skip just leaves them unprotected.

This adds an nft backend alongside the existing one.

What changed

  • New firewall=auto|iptables|nft|none module parameter. no_iptables=1 kept as a deprecated alias for firewall=none.
  • auto (default) prefers iptables when usable, preserving current behavior, and falls back to nft. Pure-nftables systems get isolation out of the box.
  • nft rules live in a private table inet hm2_eth with an output-hook chain. Because the table is dedicated, flush and delete never touch the user's other rules. The inet family handles IPv4 and IPv6 in one chain.
  • Rules mirror the iptables set: board accept (saddr/daddr/sport/dport), per-interface ICMP drop, admin-prohibited reject, and IPv6 drop.
  • hm2_eth(9) updated: new parameter, backend notes, and a manual nft recipe matching the existing iptables one.

Tested

Configured --with-realtime=uspace and built; hm2_eth compiles and links clean. Not hardware-tested, I do not have a Mesa ethernet card. The iptables path is unchanged, so existing setups see no difference.

cc @NTULINUX, @hdiethelm

Comment thread src/hal/drivers/mesa-hostmot2/hm2_eth.c Outdated
Comment thread src/hal/drivers/mesa-hostmot2/hm2_eth.c Outdated
Comment thread src/hal/drivers/mesa-hostmot2/hm2_eth.c Outdated
Comment thread src/hal/drivers/mesa-hostmot2/hm2_eth.c Outdated
Comment thread src/hal/drivers/mesa-hostmot2/hm2_eth.c Outdated
Comment thread src/hal/drivers/mesa-hostmot2/hm2_eth.c Outdated
@grandixximo grandixximo force-pushed the feature/nftables-support branch from 259d203 to 8772107 Compare June 3, 2026 08:06
@hdiethelm
Copy link
Copy Markdown
Contributor

As always, while looking trough the code, I found some things that where not subject to your change. Thanks for fixing.

@hdiethelm
Copy link
Copy Markdown
Contributor

From your side, it is ready? So I will do some testing later today. It will take some time, many options to test... Three firewall variants / vs. root/nonroot so 6 combinations.

@grandixximo
Copy link
Copy Markdown
Contributor Author

grandixximo commented Jun 3, 2026

Yes, ready, I cannot test, waiting on feedback, probably will pick this up tomorrow, addressing test results ;-)

@hdiethelm
Copy link
Copy Markdown
Contributor

So, i tested all combinations: suid / setcap vs. auto iptables installed / auto iptables not installed / nft / iptables
Looks all good and I can not ping the board when linuxcnc is running. All is cleaned up well.

Below the tables when linuxcnc is running to verify. Looks good to me but I don't know this well enought to properly verify it.

Rules iptables:
sudo iptables -S

-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N hm2-eth-rules-output
-A OUTPUT -j hm2-eth-rules-output
-A hm2-eth-rules-output -s 192.168.1.120/32 -d 192.168.1.121/32 -p udp -m udp --sport 43361 --dport 27181 -j ACCEPT
-A hm2-eth-rules-output -o enp2s0f0 -p icmp -j DROP
-A hm2-eth-rules-output -o enp2s0f0 -j REJECT --reject-with icmp-admin-prohibited

sudo ip6tables -S

-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N hm2-eth-rules-output
-A OUTPUT -j hm2-eth-rules-output
-A hm2-eth-rules-output -o enp2s0f0 -j DROP

Rules nft:
sudo nft list ruleset

table ip filter {
	chain OUTPUT {
		type filter hook output priority filter; policy accept;
	}
}
table ip6 filter {
	chain OUTPUT {
		type filter hook output priority filter; policy accept;
	}
}
table inet hm2_eth {
	chain output {
		type filter hook output priority filter; policy accept;
		ip saddr 192.168.1.120 ip daddr 192.168.1.121 udp sport 54897 udp dport 27181 accept
		oifname "enp2s0f0" ip protocol icmp drop
		oifname "enp2s0f0" reject with icmp admin-prohibited
		oifname "enp2s0f0" ip6 version 6 drop
	}
}

@BsAtHome
Copy link
Copy Markdown
Contributor

BsAtHome commented Jun 3, 2026

Can someone also, please, cleanup the cppcheck mess caused by the hm2_eth.c changes?
(somehow, I don't think that ignoring it would be the appropriate solution)

hal/drivers/mesa-hostmot2/hm2_eth.c:542:8: portability: Passing NULL after the last typed argument to a variadic function leads to undefined behaviour. [varFuncNullUB]
    if(IPT(1, "-n", "-L", "INPUT") != 0)
       ^
hal/drivers/mesa-hostmot2/hm2_eth.c:545:8: portability: Passing NULL after the last typed argument to a variadic function leads to undefined behaviour. [varFuncNullUB]
    if(IPT(1, "-n", "-L", CHAIN) != 0) {
       ^
...

@NTULINUX
Copy link
Copy Markdown
Contributor

NTULINUX commented Jun 3, 2026

Is this accurate?

#define IPT(quiet, ...)  run_cmd(IPTABLES_BIN,  (quiet), __VA_ARGS__, (char *)0)
#define IP6T(quiet, ...) run_cmd(IP6TABLES_BIN, (quiet), __VA_ARGS__, (char *)0)
#define NFT(quiet, ...)  run_cmd(NFT_BIN,       (quiet), __VA_ARGS__, (char *)0)

@hdiethelm
Copy link
Copy Markdown
Contributor

hdiethelm commented Jun 3, 2026

This was introduced here:
#3964
https://github.com/LinuxCNC/linuxcnc/actions/runs/26539292778/job/78176412787

@grandixximo If @NTULINUX version does not work, I would just pass the arguments as a single string and split by spaces.

@BsAtHome Recurring issue. It probably would make sense to maintain a list of wontfixnow files in cppcheck.sh / shellcheck.sh and fail the CI if any other files have issues. So no new issues are introduced in any other files than in this list.

@BsAtHome
Copy link
Copy Markdown
Contributor

BsAtHome commented Jun 3, 2026

@BsAtHome Recurring issue. It probably would make sense to maintain a list of wontfixnow files in cppcheck.sh / shellcheck.sh and fail the CI if any other files have issues. So no new issues are introduced in any other files than in this list.

No, we have to be more careful when changing stuff. Ignoring files or difficult issues sets a precedent that "it is ok to be sloppy". No, it is not and things need to get fixed (the proper way). That is also how we were able to add -Werror to the CI build. We just need some continuous stability here too and then we'll enforce it in CI.

With respect to shellcheck,... almost there. Still pondering some options. But my attention is already spread thin by doing all the review work in the necessary docs build reorg and fixes (while working on hal getter/setter and pondering other issues too).

@hdiethelm
Copy link
Copy Markdown
Contributor

@BsAtHome Recurring issue. It probably would make sense to maintain a list of wontfixnow files in cppcheck.sh / shellcheck.sh and fail the CI if any other files have issues. So no new issues are introduced in any other files than in this list.

No, we have to be more careful when changing stuff. Ignoring files or difficult issues sets a precedent that "it is ok to be sloppy". No, it is not and things need to get fixed (the proper way). That is also how we were able to add -Werror to the CI build. We just need some continuous stability here too and then we'll enforce it in CI.

With respect to shellcheck,... almost there. Still pondering some options. But my attention is already spread thin by doing all the review work in the necessary docs build reorg and fixes (while working on hal getter/setter and pondering other issues too).

Of course, this list should be as small as possible and disappear soon. I just discovered that cppcheck is now passing normally (except the new issue introduced). So we could fail the CI if cppcheck fails. I can look into this.

Right now the CI always passes on cppcheck / shellcheck issues which is even worse, so new issues get introduced when you are not checking this CI stage manually.

@grandixximo
Copy link
Copy Markdown
Contributor Author

grandixximo commented Jun 4, 2026

Fixed the cppcheck varFuncNullUB findings too: the IPT/IP6T/NFT sentinel is now (char *)NULL. Local cppcheck is clean for hm2_eth.c.
NTULINUX's nft commands work, so no split needed. Args go as discrete argv tokens straight to posix_spawn, no shell or space-splitting.

@hdiethelm
Copy link
Copy Markdown
Contributor

Thanks for fixing cppckeck. Hmm, while looking at this:
Why not directly pass argv?

I don't have time to test this right now, but this compiles. It could be simplified with the matching define.

static int run_iptables(const char *bin, int quiet, char **argv) {
...
}
run_iptables(IPTABLES_BIN, 1, (char *[]){IPTABLES_BIN_NAME, "-n", "-L", "INPUT", NULL});
//or
char *argv[] = {IPTABLES_BIN_NAME, "-n", "-L", "INPUT", NULL};
run_iptables(IPTABLES_BIN, 1, argv);

@grandixximo grandixximo force-pushed the feature/nftables-support branch from 9339f6e to 0543c7a Compare June 4, 2026 06:19
@grandixximo
Copy link
Copy Markdown
Contributor Author

grandixximo commented Jun 4, 2026

Thanks for fixing cppckeck. Hmm, while looking at this: Why not directly pass argv?

I don't have time to test this right now, but this compiles. It could be simplified with the matching define.

static int run_iptables(const char *bin, int quiet, char **argv) {
...
}
run_iptables(IPTABLES_BIN, 1, (char *[]){IPTABLES_BIN_NAME, "-n", "-L", "INPUT", NULL});
//or
char *argv[] = {IPTABLES_BIN_NAME, "-n", "-L", "INPUT", NULL};
run_iptables(IPTABLES_BIN, 1, argv);

Good call, done. run_cmd now takes char *const argv[] and the IPT/IP6T/NFT macros build it as a compound literal, so no varargs and the varFuncNullUB is gone at the root. Call sites unchanged.

@hdiethelm
Copy link
Copy Markdown
Contributor

Nice! And now you also can not anymore pass an 1 instead of an "1" to the macos. Before, that probably would have generated a segfault / ub. Now the compiler should catch it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants