2

My pppoe client automatically adds an iptables rule iptables -t mangle -o "$PPP_IFACE" --insert FORWARD 1 -p tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1400:65495 -j TCPMSS --clamp-mss-to-pmtu from /etc/ppp/ip-up.d. However, this rule in nftables looks like

table ip mangle {
    chain FORWARD {
        type filter hook forward priority mangle; policy accept;
        oifname "ppp0" meta l4proto tcp tcp flags & (syn|rst) == syn # tcpmss match 1400:65495 counter packets 714 bytes 42388 tcp option maxseg size set rt mtu
    }
}

Why contents after tcpmss is commented and this rule seems to do nothing?

1 Answer 1

3

Explanation

  • the rule set through iptables-nft is using xtables kernel modules (here: xt_tcpmss and xt_TCPMSS) through the nftables kernel API along a compatibility layer API, even if xtables was initially intended for (legacy kernel API) iptables.

    Native nftables cannot use xtables kernel modules by design: whenever xtables is in use, it's not native anymore, and the userland nft command (or its API) deals only with native nftables. Use of xtables is reserved for the compatibility layer. So when displayed through nft any such unknown module is displayed commented out (but see later).

  • the current version of iptables-nft wasn't yet able to translate automatically the iptables rule into native nftables rule (for this case) or there is no equivalent native nftables rule to translate to (eg: ponder the LED target).

    Here nft sees there are xtables modules that aren't translatable by the common translation engine so considers this part as off limits and adds a comment on the untranslatable part, but still translates what it knowns about. The call to xtables modules can be seen with --debug=netlink:

    # nft -a --debug=netlink list ruleset
    ip mangle FORWARD 2
      [ meta load oifname => reg 1 ]
      [ cmp eq reg 1 0x30707070 0x00000000 ]
      [ meta load l4proto => reg 1 ]
      [ cmp eq reg 1 0x00000006 ]
      [ match name tcp rev 0 ]
      [ match name tcpmss rev 0 ]
      [ counter pkts 0 bytes 0 ]
      [ target name TCPMSS rev 0 ]
    
    table ip mangle { # handle 167
      chain FORWARD { # handle 1
          type filter hook forward priority mangle; policy accept;
          oifname "ppp0" meta l4proto tcp tcp flags & (syn|rst) == syn # tcpmss match 1400:65495 counter packets 0 bytes 0 tcp option maxseg size set rt mtu # handle 2
      }
    }
    

    above: match and target mean xtables modules. Since nftables uses about the same engine as iptables-translate in this regard, one could guess -m tcpmss --mss 1400:65495 got an issue because that's the one which starts with a comment and isn't translated in the output, while the last part was translated. Whatever nft displays back here is only for the display and mustn't be taken as the actual rules.

    The actual rules are the bytecodes shown with --debug=netlink (plus non-visible parts for xtables specific data), so this bytecode is the proof that this rule is doing something. It's just not useful to native nftables.

Native nftables version

For example most of OP's iptables rule can be natively translated:

# iptables-translate -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
nft add rule ip mangle FORWARD tcp flags & (syn|rst) == syn counter tcp option maxseg size set rt mtu

While there's no automatic translation available currently for -m tcpmss --mss , the feature is available: tcp option maxseg size which can be used either as an expression (the equivalent of the match -m tcpmss --mss) or with set as a statement (the equivalent of the target -j TCPMSS). Below would be the result of such translation (and might be in the future once the translation engine is improved):

nft add rule ip mangle FORWARD 'oifname ppp0 tcp flags & (syn|rst) == syn tcp option maxseg size 1400-65495 counter tcp option maxseg size set rt mtu'

The second value 65495 is probably useless (one could just use tcp option maxseg size >= 1400 instead).


Note

nft and iptables-nft can be misleading when trying to abuse translations. For example using iptables v1.8.7 (nf_tables) and nft v1.0.0, one can get this:

# iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
# nft list ruleset | tee /tmp/mss.nft
table ip mangle {
    chain FORWARD {
        type filter hook forward priority mangle; policy accept;
        meta l4proto tcp tcp flags & (syn|rst) == syn counter packets 0 bytes 0 tcp option maxseg size set rt mtu
    }
  }
# nft flush ruleset
# nft -f /tmp/mss.nft
# iptables-save 
# Table `mangle' is incompatible, use 'nft' tool.

That's because while nft was able to translate the whole ruleset when displaying it, the initial compat ruleset was still including an xtables target in the bytecode (the same as seen above: [ target name TCPMSS rev 0 ]): iptables-nft didn't behave as iptables-translate and nft's output hid the difference. Once run again through the nft command, the result is full native nftables with tcp option maxseg size set rt mtu instead of -j TCMPSS --clamp-mss-to-pmtu . But the iptables-save command doesn't recognize the result anymore as iptables-translated code and can't translate it back into iptables format.

Don't dump blindly iptables rules using nftables to reload them with nftables, this can bite later if iptables is still needed.

2
  • Thank you! As the mtu of ppp0 is 1492, perhaps oifname "ppp0" tcp flags & (syn|rst) == syn tcp option maxseg size 1453-65495 counter tcp option maxseg size set rt mtu (or the lower limit should be 1452? I am not sure) can be a better rule. Commented Oct 12, 2021 at 6:14
  • @StevenYang so if it worked, you're supposed to accept my answer to thank me. As for 1453 instead of 1400 it's as you prefer, but I reused the information available in your question where 1400 was used.
    – A.B
    Commented Oct 29, 2021 at 8:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .