Score:1

nftables: getting a per-port whitelist to work

uz flag

Setup: Ubuntu 20.04, created a bridge "br0" with brctl, added three physical ports to it: enp10s0, enp7s0 and enp5s0.

The desire: enp5s0 and enp7s0 should be able to talk to each other on the bridge unimpeded (in the end, there will be more than these two, so I'm trying to keep the rules as simple as possible). enp10s0 is the "outside world" link and I want to whitelist what I let into the bridge, but only from that port. I have a blacklist working fine but whitelist is thwarting me.

flush ruleset

table bridge drawbridge {
    chain input {
        type filter hook input priority 0;
    }
    chain forward {
        type filter hook forward priority 0;
        iifname "enp10s0" tcp dport 3389 ct state new,established accept
        iifname "enp10s0" drop
    }
    chain output {
        type filter hook output priority 0;
    }
}

This should (I thought) allow Windows remote desktop (tcp 3389) plugged in on enp10s0 to talk to any laptop on the bridge, but drop everything else. If I flush the ruleset, it's working, so the bridge works, the laptops are configured, but as soon as I apply the above rule, it stops working.

A blacklist of:

iifname "enp10s0" tcp dport 3389 drop

...worked fine. I can still ping it but I can't remote desktop. Doing icmp as a blacklist also works fine. I can remote desktop but I can't ping. So my nftables seems to be fine, just not as a whitelist.

(To eliminate "windows remote desktop" as an issue, I also tried the same thing with ping: whitelist iifname "enp10s0" icmp type echo-request accept and iifname "enp10s0" icmp type echo-reply accept with a iifname "enp10s0" drop , but that didn't work either. Works as a blacklist, though -- policy accept, and drop only those two icmp things. Works as expected there.)

How can I give "enp10s0" the whitelist treatment, but only "enp10s0"?

Score:1
cl flag
A.B

The problem is about ARP rather than IPv4.

If anything (except TCP destination port 3389) coming from enp10s0 is dropped, then any frame of type ARP is dropped. Thus a system on enp10s0 side won't be able to send ARP queries to systems on other ports, and will never discover the correct MAC address associated to an IPv4 address it needs to send traffic to. Usually it would receive a No route to host error within 3 seconds.

So a rule to allow ARP traffic should be inserted before the generic drop rule.

flush ruleset

table bridge drawbridge {
    chain input {
        type filter hook input priority 0;
    }
    chain forward {
        type filter hook forward priority 0;
        iifname "enp10s0" tcp dport 3389 ct state new,established accept
        iifname "enp10s0" ether type arp accept
        iifname "enp10s0" drop
    }
    chain output {
        type filter hook output priority 0;
    }
}

I also think related traffic should be enabled. But as this related traffic won't be on port 3389 (but would likely be a related ICMP error if it ever happens), the ruleset should be rewritten a bit. With some factorization, for example like this:

table bridge drawbridge
delete table bridge drawbridge

table bridge drawbridge {
    chain from_enp10s0 {
        ct state established,related accept
        tcp dport 3389 accept
        ether type arp accept
        drop
    }

    chain forward {
        type filter hook forward priority 0; policy accept;
        iifname "enp10s0" jump from_enp10s0
    }
}

Note: for similar reasons, IPv6 will fail, unless also allowing ICMPv6 with meta l4proto ipv6-icmp accept, or at least the subset needed for NDP, IPv6's equivalent of ARP.

JamieB avatar
uz flag
That was it! I had given up on making whitelist work but after adding arp for ipv4, the whole whitelist works as expected. Good tip on ipv6 too, in case we end up needing that as well (it's a private ipv4 network....for now).
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.