--- Begin Message ---
Well, as long as there is a reasonably easy (new) way to access the full 9-bit
TCP header flags field interactively, and it's documented properly, I don't
care that much how to attain this.
Personally, I like the approach of a new predefined variable which can also be
used as shorthand for the old tcp[tcpflags], tcphf, and used in the very much
the same syntactic fashion as before, the most.
The other approaches suggested further down don't seem to be quite as intuitive.
And retaining tcp[tcpflags] to allow access to the long-term tcp header flags,
while allowing tcphf to access to all IANA defined flags (9 currently, maybe
more in the future) sounds like the best option to me.
Richard Scheffenegger
-----Original Message-----
From: Denis Ovsienko <[email protected]>
Sent: Donnerstag, 13. November 2025 15:35
To: Scheffenegger, Richard <[email protected]>
Cc: [email protected]
Subject: [tcpdump-workers] Re: Accurate ECN support in tcpdump/libpcap
EXTERNAL EMAIL - USE CAUTION when clicking links or attachments
On Thu, 13 Nov 2025 08:17:00 +0000
"Scheffenegger, Richard" <[email protected]> wrote:
> Hi Denis,
>
> Before discussing the various alternate ways - what exactly are you
> referring to with "breaking compatibility" when tcp[tcpflags] maps to
> 12:2 instead of 13:1?
>
> Is there an expectation that people use "tcpflags" as a "shorthand"
> for 13:1? Or that is being used in contexts outside of the tcp header
> flags?
>
> Because within the context of the tcp header, the flags were always
> defined to be 12 bits wide, since 1981, or 2003 at the latest.
Hello Richard.
Please note that as far as the specifications define it, they never were.
RFC 793 (published in September 1981) Section 3.1 says:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
[...]
Reserved: 6 bits
Reserved for future use. Must be zero.
RFC 3168 (published in September 2001) Section 23.2 says:
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| | | C | E | U | A | P | R | S | F |
| Header Length | Reserved | W | C | R | C | S | S | Y | I |
| | | R | E | G | K | H | T | N | N |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
RFC 9293 (published in August 2022) Section 3.1 says:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |C|E|U|A|P|R|S|F| |
| Offset| Rsrvd |W|C|R|C|S|S|Y|I| Window |
| | |R|E|G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
[...]
Reserved (Rsrvd): 4 bits
A set of control bits reserved for future use. Must be zero in
generated segments and must be ignored in received segments if the
corresponding future features are not implemented by the sending or
receiving host.
In all diagrams you can see the reserved space is a unstructured block rather
than a bitmap pre-allocated into individual 1-bit flags with names such as
ReservedFlag-16, ReservedFlag-15, ReservedFlag-14 etc.
Arguably, RFC 9293 says "a set of control bits", so perhaps the
guess/impression/idea/figure of speech (but not the formally specified norm) is
that the rest of the available bit space will be allocated to more flags later.
But RFC 793 conveyed no such guess, and for 20 years until ECE and CWR were
allocated it was not obvious whether even the rest of the byte 13 would become
more flags, let alone byte 12.
This way, when the named offset "tcpflags" meaning 13 (with the implied load
size of 1 byte) was added to libpcap in what is now known as git commit 4ed1792
(February 2001) and became generally available in release 0.7.1 (October 2001),
the equivalence of "tcp[13:1]" and "tcp[tcpflags]" was a good fit for 20 years
of Internet development before that, and remained a good fit for more than 20
years afterwards, so it seems almost certain "tcp[tcpflags]" has been baked
into some non-interactive software that uses libpcap.
It is conceivable that some of such software trusts "tcp[tcpflags]" to evaluate
to an 8-bit value, and uses it as a part of a more complex arithmetic
expression that would not handle an overflow correctly. Or, for example, the
software captures packets that match "tcp[tcpflags] != 0" and runs them through
a switch block that assumes that at that point at least one of the 8 TCP flags
it knows is set, but this would no longer be the case if tcp-ae matched, but
none of the other flags did.
Or, for example, the software prints to a string buffer an exact 8-bit value
for the specific combination of flags it needs to match, but then one day for
no apparent reason "tcp[tcpflags] == 0x02" no longer matches all packets with
only SYN set in byte 13.
Or this is not a software, but a firewall rule, because some firewalls can
take, via BPF, libpcap filter expressions to match packets. And/or the
matching is offloaded to some sort of network hardware, where problems could
cascade further.
So let's be wise to choose a solution space that does not make the problem
space larger.
> But back to the issue - what compatibility issue is expected to arise?
> As user, who infrequently uses tcpdump with all the functionalities -
> I'd expect there to be only one way to access *all* tcp flags by name;
> and if i need something special, it'll be possible to convert scripts
> that somehow (I don't know how, my imagination fails me) require
> tcp[tcpflags] to return only a 8 bit value, to be redefined tcp[13:1]
> in those scripts as a one-off change after updating tcpdump which has
> proper tcp header flags support...
Interactive use with a relatively short feedback loop is one important use
case, but not the only.
--
Denis Ovsienko
_______________________________________________
tcpdump-workers mailing list -- [email protected] To
unsubscribe send an email to [email protected]
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s
--- End Message ---
_______________________________________________
tcpdump-workers mailing list -- [email protected]
To unsubscribe send an email to [email protected]
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s