Skip to content

Commit 2c5130e

Browse files
committed
Fix "ip broadcast" netmask byte order with the -f flag.
Let's suppose the interface eth0 has one IPv4 address with a /24 netmask. Without -f tcpdump leaves the netmask variable set to 0, which regardless of the host endianness causes "ip broadcast" to match destination hosts 0.0.0.0 and 255.255.255.255: # tcpdump -i eth0 -d 'ip broadcast' (000) ldh [12] (001) jeq #0x800 jt 2 jf 6 (002) ld [30] (003) jeq #0x0 jt 5 jf 4 (004) jeq #0xffffffff jt 5 jf 6 (005) ret #262144 (006) ret #0 With -f tcpdump calls pcap_lookupnet(), which correctly sets the netmask to 0xFFFFFF00 (in network byte order). Then pcap_compile() receives the same value, but it expects it to be in host byte order, so on a little-endian host the resulting filter program incorrectly tests for a 0x00FFFFFF netmask: # tcpdump -i eth0 -f -d 'ip broadcast' (000) ldh [12] (001) jeq #0x800 jt 2 jf 7 (002) ld [30] (003) jset #0xff000000 jt 4 jf 6 (004) and #0xff000000 (005) jeq #0xff000000 jt 6 jf 7 (006) ret #262144 (007) ret #0 Add two missing ntohl() wrappers to make it right: # tcpdump -i eno1 -f -d 'ip broadcast' (000) ldh [12] (001) jeq #0x800 jt 2 jf 7 (002) ld [30] (003) jset #0xff jt 4 jf 6 (004) and #0xff (005) jeq #0xff jt 6 jf 7 (006) ret #262144 (007) ret #0 Audit the init_print() code path and do not change anything because there the byte order is already correct. Add comments to spell the byte order in every case and update the -f flag description in the man page. See also libpcap commit 1e54958.
1 parent 1e1ec7f commit 2c5130e

File tree

5 files changed

+35
-9
lines changed

5 files changed

+35
-9
lines changed

CHANGES

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ DayOfTheWeek, Month DD, YYYY / The Tcpdump Group
6666
Change Sun RPC code licence to BSD-3-Clause.
6767
Use C99 macros to define 64-bit constants and maximum 64-bit
6868
values.
69+
Fix "ip broadcast" netmask byte order with the -f flag.
6970
Building and testing:
7071
Autoconf: Remove detection of early IPv6 stacks.
7172
Detect OS IPv6 support using AF_INET6 only.

addrtoname.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ ipaddr_string(netdissect_options *ndo, const u_char *ap)
290290
* (2) Address is foreign and -f was given. (If -f was not
291291
* given, f_netmask and f_localnet are 0 and the test
292292
* evaluates to true)
293+
* Both addr and f_netmask and f_localnet are in network byte order.
293294
*/
294295
if (!ndo->ndo_nflag &&
295296
(addr & f_netmask) == f_localnet) {
@@ -1244,7 +1245,7 @@ init_ipxsaparray(netdissect_options *ndo)
12441245
* Initialize the address to name translation machinery. We map all
12451246
* non-local IP addresses to numeric addresses if ndo->ndo_fflag is true
12461247
* (i.e., to prevent blocking on the nameserver). localnet is the IP address
1247-
* of the local network. mask is its subnet mask.
1248+
* of the local network, mask is its subnet mask, both in network byte order.
12481249
*/
12491250
void
12501251
init_addrtoname(netdissect_options *ndo, uint32_t localnet, uint32_t mask)

print.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ static const struct printer printers[] = {
241241
{ NULL, 0 },
242242
};
243243

244+
// Both localnet and mask are in network byte order.
244245
void
245246
init_print(netdissect_options *ndo, uint32_t localnet, uint32_t mask)
246247
{

tcpdump.1.in

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
2121
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2222
.\"
23-
.TH TCPDUMP 1 "30 November 2024"
23+
.TH TCPDUMP 1 "22 February 2025"
2424
.SH NAME
2525
tcpdump \- dump traffic on a network
2626
.SH SYNOPSIS
@@ -417,12 +417,26 @@ Sun's NIS server \(em usually it hangs forever translating non-local
417417
internet numbers).
418418
.IP
419419
The test for `foreign' IPv4 addresses is done using the IPv4 address and
420-
netmask of the interface on that capture is being done. If that
421-
address or netmask are not available, either because the
422-
interface on that capture is being done has no address or netmask or
423-
because it is the "any" pseudo-interface (see the
420+
netmask of the interface on that capture is being done. If the interface
421+
has no IPv4 addresses (which by convention applies to the "any"
422+
pseudo-interface (see the
424423
.B \-i
425-
flag below), this option will not work correctly.
424+
flag below), the IPv4 netmask is assumed to be /0 and any IPv4 address is
425+
considered non-foreign. If the IPv4 netmask is /32, all IPv4 addresses
426+
except the interface's own address are considered foreign. If the
427+
interface has more than one IPv4 address, it is not trivial to predict
428+
which one will be used for the test.
429+
.IP
430+
Without the
431+
.B \-f
432+
flag, or when the netmask is assumed to be /0 (as discussed above), the
433+
.B "ip broadcast"
434+
primitive in the filter expression matches IPv4 packets that have either
435+
0.0.0.0 or 255.255.255.255 as the destination address. With the flag,
436+
the primitive uses the same netmask (but not the network address) to test
437+
the IPv4 destination address as the foreign address test. One exception
438+
is the netmask /32, in which case the primitive is considered invalid for
439+
the interface.
426440
.TP
427441
.BI \-F " file"
428442
Use \fIfile\fP as input for the filter expression.

tcpdump.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2375,7 +2375,11 @@ DIAG_ON_WARN_UNUSED_RESULT
23752375
#ifdef HAVE_PCAP_SET_OPTIMIZER_DEBUG
23762376
pcap_set_optimizer_debug(dflag);
23772377
#endif
2378-
if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
2378+
/*
2379+
* netmask is in network byte order, pcap_compile() takes it
2380+
* in host byte order.
2381+
*/
2382+
if (pcap_compile(pd, &fcode, cmdbuf, Oflag, ntohl(netmask)) < 0)
23792383
error("%s", pcap_geterr(pd));
23802384
if (dflag) {
23812385
bpf_dump(&fcode, dflag);
@@ -2390,6 +2394,7 @@ DIAG_ON_WARN_UNUSED_RESULT
23902394
capdns = capdns_setup();
23912395
#endif /* HAVE_CASPER */
23922396

2397+
// Both localnet and netmask are in network byte order.
23932398
init_print(ndo, localnet, netmask);
23942399

23952400
#ifndef _WIN32
@@ -2793,7 +2798,11 @@ DIAG_ON_ASSIGN_ENUM
27932798
ndo->ndo_if_printer = get_if_printer(dlt);
27942799
/* Free the old filter */
27952800
pcap_freecode(&fcode);
2796-
if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
2801+
/*
2802+
* netmask is in network byte order, pcap_compile() takes it
2803+
* in host byte order.
2804+
*/
2805+
if (pcap_compile(pd, &fcode, cmdbuf, Oflag, ntohl(netmask)) < 0)
27972806
error("%s", pcap_geterr(pd));
27982807
}
27992808

0 commit comments

Comments
 (0)