Summary
Please extend the VyOS firewall so that any IPv4/IPv6, TCP and UDP header field and any TCP option can be matched from the CLI, as nftables already allows. Right now, mitigating protocol-level vulnerabilities such as the recent MPTCP-related CVE-2026-98432 needs hand-written nft rules outside the VyOS config. With fine-grained matching you could block a single TCP option (e.g. MPTCP) and keep important ones like MSS untouched.
Description
VyOS 1.5 already lets you match some header fields in firewall rules, for example tcp flags, tcp mss, packet-length, dscp, ttl/hop-limit and fragment. Each of these was added one at a time through separate feature requests (e.g. T4622, T4651, T5055). nftables can do much more: it can match almost any field in the L3/L4 headers and any TCP option.
So whenever a new threat shows up, operators have to go around the VyOS CLI and add raw nft rules. Those rules aren’t saved in the config, aren’t covered by commit/rollback or config migrations, and disappear on reboot or on the next firewall commit.
Motivation / real-world case
CVE-2026-98432 (CVSS 9.8) is a critical Linux kernel flaw. Unauthenticated attackers can use it to run commands as root remotely on systems that have MPTCP listeners.
Until a patched kernel/image was available, the practical way to reduce exposure on VyOS was to drop packets carrying the MPTCP TCP option (kind 30) directly in nftables:
nft insert rule ip vyos_filter VYOS_INPUT_filter tcp option mptcp exists drop
From the VyOS CLI you can’t do this. Some options, like MSS, must not be touched. We need fine-grained control: block exactly one option (here MPTCP, or just one MPTCP subtype) and leave everything else as it is, all inside the regular VyOS config.
Proposal
Add generic header-field matching to firewall rules (named rulesets and base chains for ipv4/ipv6/bridge, and ideally policy route too). The CLI should map as directly as possible to nftables expressions.
- TCP options (by name and numeric kind, with exists/missing and field matching)
set firewall ipv4 name WAN-LOCAL rule 10 protocol tcp set firewall ipv4 name WAN-LOCAL rule 10 tcp option mptcp exists set firewall ipv4 name WAN-LOCAL rule 10 action drop set firewall ipv4 name WAN-LOCAL rule 11 tcp option mptcp subtype mp-join set firewall ipv4 name WAN-LOCAL rule 12 tcp option kind 30 exists set firewall ipv4 name WAN-LOCAL rule 13 tcp option sack-perm missing set firewall ipv4 name WAN-LOCAL rule 14 tcp option window count '>14' set firewall ipv4 name WAN-LOCAL rule 15 tcp option timestamp exists
nft equivalents: tcp option mptcp exists, tcp option mptcp subtype mp-join, tcp option sack-perm missing, tcp option window count > 14, etc.
Supported options should include at least: eol, nop, maxseg (already exists as tcp mss), window, sack-perm, sack, timestamp, fastopen, md5sig, mptcp, plus generic numeric kinds.
- TCP header fields
sequence, ackseq, doff, reserved, window, checksum, urgptr (and keep the existing flags/ports).
set firewall ipv4 name WAN-IN rule 20 tcp window '0' set firewall ipv4 name WAN-IN rule 21 tcp urgptr '!=0'
- UDP header fields
length, checksum
set firewall ipv4 name WAN-LOCAL rule 30 udp length '<8' set firewall ipv4 name WAN-LOCAL rule 31 udp checksum '0'
- IPv4 header fields and options
version, hdrlength, ecn, id, frag-off, checksum (in addition to the existing dscp, ttl, length), plus IP options: rr, lsrr, ssrr, ra (exists/missing).
set firewall ipv4 name WAN-LOCAL rule 40 ip option ssrr exists set firewall ipv4 name WAN-LOCAL rule 41 ip hdrlength '!=5'
- IPv6 header fields and extension headers
flowlabel, nexthdr (in addition to the existing dscp, hop-limit, length), and extension headers: hbh, rt (incl. rt type), frag, dst, mh (exists/missing).
set firewall ipv6 name WAN6-LOCAL rule 50 exthdr rt type '0' set firewall ipv6 name WAN6-LOCAL rule 51 exthdr hbh exists
- Optional: raw payload matching as escape hatch
A generic raw matcher for cases the named fields don’t cover (nft @nh,offset,length / @th,offset,length):
set firewall ipv4 name WAN-LOCAL rule 60 raw base transport offset '96' length '16' value '0x1234'
This alone would have been enough to handle the MPTCP case via the CLI and would cover future cases without a new feature request each time.
Expected benefits
- Mitigations for new protocol-level CVEs can be done fast and precisely, without hand-edited nft rules
- Rules live in the VyOS config: persistent, versioned, covered by commit/rollback and config sync
- Useful TCP options (MSS, SACK, window scaling, timestamps) don’t have to be disabled wholesale
- Fewer individual feature requests for single fields over time
Notes
- All new nodes are optional, so existing configs aren’t affected
- Ranges, negation (!=) and comparisons (<, >) should work the same way as existing matchers (packet-length, tcp mss)
- ip option, exthdr and tcp option matching need the nft version VyOS already ships; no new dependencies expected