All of lore.kernel.org
 help / color / mirror / Atom feed
* nft numeric output translates tcp flags rule so it cannot be loaded again
@ 2021-10-22 13:51 Benno
  2021-10-22 15:20 ` Pablo Neira Ayuso
  0 siblings, 1 reply; 5+ messages in thread
From: Benno @ 2021-10-22 13:51 UTC (permalink / raw)
  To: netfilter

Hi,

the following ruleset was written manually:

#!/sbin/nft -f
flush ruleset
table inet firewall {

  chain inbound {
    type filter hook input priority 0; policy drop;
    ct state vmap { 0x1 : drop, 0x2 : accept, 0x4 : accept }
    tcp flags & (fin|syn|rst|ack) != syn ct state new counter drop
    iifname "lo" accept
    meta protocol vmap { 0x0800 : jump inbound_ipv4, 0x86dd : jump
inbound_ipv6 }
    tcp dport { 22, 80, 443 } accept
    udp dport 1900 meta pkttype 2 limit rate 4/second burst 20 packets
accept comment "Accept UPnP IGD port mapping reply"

    log prefix "[nftables] Inbound Denied: " counter packets 0 bytes 0 drop
  }
}

The ruleset should drop anything except it is allowed. Loading this
through nft -f <file> does exactly what it should. Adding or removing
for example more ports for dport rule does exactly what it should:
provide access to more or less services, e.g. 631 for CUPS or 8883 to a
TLS-wrapped mosquitto/ MQTT broker.

The last line flawlessly controls logging. Without port 631 but
connection attempts to CUPS print the messages accordingly. Adding port
631 again makes CUPS work again and no messages anymore.

The operating system stores this to a file when shutting down and uses
option -n for numeric output. This translates all the rules and the tcp
flags rule turns into this:

tcp flags 0x2 / 0x1,0x2,0x4,0x10 ct state 0x8 counter packets 0 bytes 0 drop

When the rules saved like this are re-loaded TCP port rules are broken.
For example connections to sshd on port 22 is not possible anymore.
There are also no logs about the dropped traffic.

I can fix this by replacing the numeric variant with the verbose tcp
flags rule. When reverting this change to the numeric variant connection
attempts are fruitless again. Logging never returns correctly. With the
numeric variant and connection attempts causing only timeouts no
messages show up that it was denied.

1) Should I re-write this rule so the numeric variant also changes to
something working?
2) Is the translation to the numeric variant broken and should this
become a bug report?
3) Is -n a bad idea to save current rule set to restore it later?
4) None of the above but something with a funny twist?

Thanks in advance.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: nft numeric output translates tcp flags rule so it cannot be loaded again
  2021-10-22 13:51 nft numeric output translates tcp flags rule so it cannot be loaded again Benno
@ 2021-10-22 15:20 ` Pablo Neira Ayuso
  2021-10-22 18:10   ` Benno
  0 siblings, 1 reply; 5+ messages in thread
From: Pablo Neira Ayuso @ 2021-10-22 15:20 UTC (permalink / raw)
  To: Benno; +Cc: netfilter

On Fri, Oct 22, 2021 at 03:51:04PM +0200, Benno wrote:
> Hi,
> 
> the following ruleset was written manually:
> 
> #!/sbin/nft -f
> flush ruleset
> table inet firewall {
> 
>   chain inbound {
>     type filter hook input priority 0; policy drop;
>     ct state vmap { 0x1 : drop, 0x2 : accept, 0x4 : accept }
>     tcp flags & (fin|syn|rst|ack) != syn ct state new counter drop
>     iifname "lo" accept
>     meta protocol vmap { 0x0800 : jump inbound_ipv4, 0x86dd : jump
> inbound_ipv6 }
>     tcp dport { 22, 80, 443 } accept
>     udp dport 1900 meta pkttype 2 limit rate 4/second burst 20 packets
> accept comment "Accept UPnP IGD port mapping reply"
> 
>     log prefix "[nftables] Inbound Denied: " counter packets 0 bytes 0 drop
>   }
> }
> 
> The ruleset should drop anything except it is allowed. Loading this
> through nft -f <file> does exactly what it should. Adding or removing
> for example more ports for dport rule does exactly what it should:
> provide access to more or less services, e.g. 631 for CUPS or 8883 to a
> TLS-wrapped mosquitto/ MQTT broker.
> 
> The last line flawlessly controls logging. Without port 631 but
> connection attempts to CUPS print the messages accordingly. Adding port
> 631 again makes CUPS work again and no messages anymore.
> 
> The operating system stores this to a file when shutting down and uses
> option -n for numeric output. This translates all the rules and the tcp
> flags rule turns into this:
> 
> tcp flags 0x2 / 0x1,0x2,0x4,0x10 ct state 0x8 counter packets 0 bytes 0 drop
> 
> When the rules saved like this are re-loaded TCP port rules are
> broken.

What nftables version are you using there? Using nftables 1.0.0.

Reload works fine here:

# nft -f ruleset.nft
# nft -n list ruleset > /tmp/ruleset2.nft
# nft flush ruleset
# nft -f /tmp/ruleset2.nft
# nft list ruleset
table inet firewall {
        chain inbound_ipv4 {
        }

        chain inbound_ipv6 {
        }

        chain inbound {
                type filter hook input priority filter; policy drop;
                ct state vmap { invalid : drop, established : accept, related : accept }
                tcp flags != syn / fin,syn,rst,ack ct state new counter packets 0 bytes 0 drop
                iifname "lo" accept
                meta protocol vmap { ip : jump inbound_ipv4, ip6 : jump inbound_ipv6 }
                tcp dport { 22, 80, 443 } accept
                udp dport 1900 meta pkttype multicast limit rate 4/second burst 20 packets accept comment "Accept UPnP IGD port mapping reply"
                log prefix "[nftables] Inbound Denied: " counter packets 20 bytes 6180 drop
        }
}

> For example connections to sshd on port 22 is not possible anymore.
> There are also no logs about the dropped traffic.

Works also fine here.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: nft numeric output translates tcp flags rule so it cannot be loaded again
  2021-10-22 15:20 ` Pablo Neira Ayuso
@ 2021-10-22 18:10   ` Benno
  2021-10-23  5:42     ` Benno
  2021-10-26 22:52     ` Pablo Neira Ayuso
  0 siblings, 2 replies; 5+ messages in thread
From: Benno @ 2021-10-22 18:10 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter

Am 22.10.21 um 17:20 schrieb Pablo Neira Ayuso:
> On Fri, Oct 22, 2021 at 03:51:04PM +0200, Benno wrote:
[…]
> 
> What nftables version are you using there? Using nftables 1.0.0.
> 
> Reload works fine here:
> 
> # nft -f ruleset.nft
> # nft -n list ruleset > /tmp/ruleset2.nft
> # nft flush ruleset
> # nft -f /tmp/ruleset2.nft
> # nft list ruleset
> table inet firewall {
>         chain inbound_ipv4 {
>         }
> 
>         chain inbound_ipv6 {
>         }
> 
>         chain inbound {
>                 type filter hook input priority filter; policy drop;
>                 ct state vmap { invalid : drop, established : accept, related : accept }
>                 tcp flags != syn / fin,syn,rst,ack ct state new counter packets 0 bytes 0 drop
>                 iifname "lo" accept
>                 meta protocol vmap { ip : jump inbound_ipv4, ip6 : jump inbound_ipv6 }
>                 tcp dport { 22, 80, 443 } accept
>                 udp dport 1900 meta pkttype multicast limit rate 4/second burst 20 packets accept comment "Accept UPnP IGD port mapping reply"
>                 log prefix "[nftables] Inbound Denied: " counter packets 20 bytes 6180 drop
>         }
> }
> 
>> For example connections to sshd on port 22 is not possible anymore.
>> There are also no logs about the dropped traffic.
> 
> Works also fine here.
> 
I fast forwarded to (not yet stable 1.0 on Gentoo) and tried a restart
with same result. But restoring the working rule set, saving through the
init script and restarting yields a working rule set.

And instead of numeric variant of 0.9.9 which was

tcp flags 0x2 / 0x1,0x2,0x4,0x10 ct state 0x8 counter packets 0 bytes 0 drop

it looks now different with 1.0:

tcp flags != 0x2 / 0x1,0x2,0x4,0x10 ct state 0x8 counter packets 0 bytes
0 drop

Interestingly both variants are syntactically correct according to nft
-c but I'm not experienced enough to interprete the consquences of the
missing operator != for 0.9.9.

Replacing the now working 1.0 variant of tcp flags with the broken
variant from 0.9.9 causes failed connections again.

It'd be great if you could explain the effects of the subtle change of
the rule. Since I'd like to use nftables to be verbose/ easier to
maintain. Both numeric variants look complicated to the untrained eye.

I can match the different string tcp flags to their numeric values. But
I'm unable to get the difference between tcp flags 0x2 and tcp flags !=
0x2… It looks like a not-equal-operator that clearly lacks in the 0.9.9
variant. Is it because of polish notation/ operator first?

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: nft numeric output translates tcp flags rule so it cannot be loaded again
  2021-10-22 18:10   ` Benno
@ 2021-10-23  5:42     ` Benno
  2021-10-26 22:52     ` Pablo Neira Ayuso
  1 sibling, 0 replies; 5+ messages in thread
From: Benno @ 2021-10-23  5:42 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter

>> […]
> And instead of numeric variant of 0.9.9 which was
> 
> tcp flags 0x2 / 0x1,0x2,0x4,0x10 ct state 0x8 counter packets 0 bytes 0 drop
> 
> it looks now different with 1.0:
> 
> tcp flags != 0x2 / 0x1,0x2,0x4,0x10 ct state 0x8 counter packets 0 bytes
> 0 drop
> 
> […]
> 
> It'd be great if you could explain the effects of the subtle change of
> the rule. Since I'd like to use nftables to be verbose/ easier to
> maintain. Both numeric variants look complicated to the untrained eye.
> 
> I can match the different string tcp flags to their numeric values. But
> I'm unable to get the difference between tcp flags 0x2 and tcp flags !=
> 0x2… It looks like a not-equal-operator that clearly lacks in the 0.9.9
> variant. Is it because of polish notation/ operator first?
> 
I've been through the documentation and found only a single occurence of
the expression with no explanation.

*
https://wiki.nftables.org/wiki-nftables/index.php/Matching_packet_headers#Matching_TCP.2FUDP.2FUDPlite_traffic
– the only occurrence
* https://www.netfilter.org/projects/nftables/manpage.html – man page
does not list round braces (except for side notes or additions)
* https://wiki.nftables.org/wiki-nftables/index.php/Sets – sets use
curly braces instead
* https://wiki.nftables.org/wiki-nftables/index.php/Verdict_Maps_(vmaps)
– like maps, also curly
*
https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes
– quick reference also lacks a sample (despite the widespread use of
such a rule/ expression)

Would it be correct to call the sub expression

( syn | ack )

combination? Would it be more precise to name it binary combination?
Deducing from the sample (syn | ack) merges all the bits set into a sort
of bit mask that is used for comparison? Why is it necessary then to
preceed the binary combination with an '&'? What is the second operator
if the binary combination is followed by not equal to syn? Is it the
header value? Do I fix my explanation by labelling tcp flags the left
hand side of the bit mask operation and the binary combination right
hand side? Is it interpreted correctly if described as:

1. create bitmask from OR-ing syn 0x02 and ack 0x10
2. flag value of header must match the bitmask exactly (preceeding &)
3. must evaluate to true applying comparison operator and bit mask right
of it

What other prefixes to a combination are valid except &? I tried ! ( syn
| fin ) != syn which failed at the != operator. But | ( syn | fin ) !=
syn works and nft -c accepts this. I didn't try it out with traffic.
Also accepted by nft -c:

# binary combination should evalute to 0x00 -> always true
tcp flags & (fin & syn & ack) != syn ct state new counter drop

# binary combination should evaluate to 0x00, too -> always true
tcp flags & (fin & (syn | ack)) != syn ct state new counter drop

# get a little bit crazy and have a binary combination on both sides
# and use literal greater than instead of >
tcp flags & (fin & (syn | ack)) gt (syn | fin) ct state new counter drop

I'd appreciate if this would be added to the wiki. I'd say a short on
the example and link in the 10min-guide? (Not every firewall maintainer
knows about syntax trees or is fond of de Morgan.)

Just for the records/ side notes:

I also had no success using nft describe. It complained about syntax
errors in too many occasions. For example

nft describe "add rule ip { tcp flags 0x2 / 0x1,0x2,0x4,0x10 ct state
0x8 counter packets 0 bytes 0 drop }"

yields

Error: syntax error, unexpected add
describe add rule ip { tcp flags 0x2 / 0x1,0x2,0x4,0x10 ct state 0x8
counter packets 0 bytes 0 drop }
         ^^^

If it weren't explicitely binary expressions one could take the detour
through POSIX syntax[1]. The vertical bar is interpreted as
»arguments…mutually exclusive«. And ellipses »denote […] one or more
occurrences«.

[1] https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: nft numeric output translates tcp flags rule so it cannot be loaded again
  2021-10-22 18:10   ` Benno
  2021-10-23  5:42     ` Benno
@ 2021-10-26 22:52     ` Pablo Neira Ayuso
  1 sibling, 0 replies; 5+ messages in thread
From: Pablo Neira Ayuso @ 2021-10-26 22:52 UTC (permalink / raw)
  To: Benno; +Cc: netfilter

On Fri, Oct 22, 2021 at 08:10:07PM +0200, Benno wrote:
> Am 22.10.21 um 17:20 schrieb Pablo Neira Ayuso:
> > On Fri, Oct 22, 2021 at 03:51:04PM +0200, Benno wrote:
> […]
> > 
> > What nftables version are you using there? Using nftables 1.0.0.
> > 
> > Reload works fine here:
> > 
> > # nft -f ruleset.nft
> > # nft -n list ruleset > /tmp/ruleset2.nft
> > # nft flush ruleset
> > # nft -f /tmp/ruleset2.nft
> > # nft list ruleset
> > table inet firewall {
> >         chain inbound_ipv4 {
> >         }
> > 
> >         chain inbound_ipv6 {
> >         }
> > 
> >         chain inbound {
> >                 type filter hook input priority filter; policy drop;
> >                 ct state vmap { invalid : drop, established : accept, related : accept }
> >                 tcp flags != syn / fin,syn,rst,ack ct state new counter packets 0 bytes 0 drop
> >                 iifname "lo" accept
> >                 meta protocol vmap { ip : jump inbound_ipv4, ip6 : jump inbound_ipv6 }
> >                 tcp dport { 22, 80, 443 } accept
> >                 udp dport 1900 meta pkttype multicast limit rate 4/second burst 20 packets accept comment "Accept UPnP IGD port mapping reply"
> >                 log prefix "[nftables] Inbound Denied: " counter packets 20 bytes 6180 drop
> >         }
> > }
> > 
> >> For example connections to sshd on port 22 is not possible anymore.
> >> There are also no logs about the dropped traffic.
> > 
> > Works also fine here.
> > 
> I fast forwarded to (not yet stable 1.0 on Gentoo) and tried a restart
> with same result. But restoring the working rule set, saving through the
> init script and restarting yields a working rule set.
> 
> And instead of numeric variant of 0.9.9 which was
> 
> tcp flags 0x2 / 0x1,0x2,0x4,0x10 ct state 0x8 counter packets 0 bytes 0 drop
> 
> it looks now different with 1.0:
> 
> tcp flags != 0x2 / 0x1,0x2,0x4,0x10 ct state 0x8 counter packets 0 bytes
> 0 drop
> 
> Interestingly both variants are syntactically correct according to nft
> -c but I'm not experienced enough to interprete the consquences of the
> missing operator != for 0.9.9.
> 
> Replacing the now working 1.0 variant of tcp flags with the broken
> variant from 0.9.9 causes failed connections again.
> 
> It'd be great if you could explain the effects of the subtle change of
> the rule. Since I'd like to use nftables to be verbose/ easier to
> maintain. Both numeric variants look complicated to the untrained eye.
> 
> I can match the different string tcp flags to their numeric values. But
> I'm unable to get the difference between tcp flags 0x2 and tcp flags !=
> 0x2… It looks like a not-equal-operator that clearly lacks in the 0.9.9
> variant. Is it because of polish notation/ operator first?

0.9.9 listing is buggy for tcp flags !=.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-10-26 22:52 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-22 13:51 nft numeric output translates tcp flags rule so it cannot be loaded again Benno
2021-10-22 15:20 ` Pablo Neira Ayuso
2021-10-22 18:10   ` Benno
2021-10-23  5:42     ` Benno
2021-10-26 22:52     ` Pablo Neira Ayuso

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.