Skip to content

libpcap uses stub ether_hostton() from musl libc #1462

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
infrastation opened this issue Feb 14, 2025 · 7 comments
Open

libpcap uses stub ether_hostton() from musl libc #1462

infrastation opened this issue Feb 14, 2025 · 7 comments
Assignees

Comments

@infrastation
Copy link
Member

Linux with GNU libc:

$ grep -F eth-noipv4-noipv6.host1.libpcap.test /etc/ethers
aa:00:04:00:14:0e eth-noipv4-noipv6.host1.libpcap.test
$ ./testprogs/filtertest EN10MB 'ether src host eth-noipv4-noipv6.host1.libpcap.test'
(000) ld       [8]
(001) jeq      #0x400140e       jt 2	jf 5
(002) ldh      [6]
(003) jeq      #0xaa00          jt 4	jf 5
(004) ret      #262144
(005) ret      #0

Linux with musl libc:

$ grep -F eth-noipv4-noipv6.host1.libpcap.test /etc/ethers 
aa:00:04:00:14:0e eth-noipv4-noipv6.host1.libpcap.test
$ ./testprogs/filtertest EN10MB 'ether src host eth-noipv4-noipv6.host1.libpcap.test'
filtertest: unknown ether host 'eth-noipv4-noipv6.host1.libpcap.test'

This is because musl libc implements ether_hostton() as follows:

int ether_hostton(const char *hostname, struct ether_addr *e)
{
	return -1;
}

This is good enough to be detected by the build system:

checking for ether_hostton... yes
checking whether ether_hostton is declared... no
checking whether ether_hostton is declared... yes
[...]
$ grep ETHER config.h
/* #undef ARPA_INET_H_DECLARES_ETHER_HOSTTON */
#define HAVE_DECL_ETHER_HOSTTON 1
#define HAVE_ETHER_HOSTTON 1
/* #undef HAVE_STRUCT_ETHER_ADDR */
/* #undef HAVE_STRUCT_RTE_ETHER_ADDR */
#define NETINET_ETHER_H_DECLARES_ETHER_HOSTTON 1
/* #undef NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON */
/* #undef NET_ETHERNET_H_DECLARES_ETHER_HOSTTON */
/* #undef SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON */

Then libpcap nametoaddr.c uses that instead of its substitute implementation.

A potential solution could be adding a "this is musl" factor into the decision process. This isn't straightforward because musl libc, unlike GNU libc, does not identify itself in headers (see the FAQ, no comments). However, it does, like GNU libc, identify itself if one executes the libc shared library:

$ /lib/x86_64-linux-gnu/libc.so.6 
GNU C Library (Debian GLIBC 2.36-9+deb12u9) stable release version 2.36.
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 12.2.0.
libc ABIs: UNIQUE IFUNC ABSOLUTE
Minimum supported kernel: 3.2.0
For bug reporting instructions, please see:
<http://www.debian.org/Bugs/>.

$ /usr/lib/libc.so 
musl libc (aarch64)
Version 1.2.5
Dynamic Program Loader
Usage: /usr/lib/libc.so [options] [--] pathname [args]

So perhaps the build process could translate this into something such as HAVE_MUSL_LIBC and then nametoaddr.c could use that to disregard HAVE_ETHER_HOSTTON.

@guyharris
Copy link
Member

However, it does, like GNU libc, identify itself if one executes the libc shared library:

A little tricky for cross-compilation, but maybe we can't do any more for people doing cross-builds (building for some embedded Linux, probably).

@infrastation
Copy link
Member Author

An alternative could be a build option such as --disable-ether-hostton or --enable-musl-workarounds. Possibly something else. This problem isn't new and this part of the syntax is not especially popular, so there is time to think about it.

@infrastation
Copy link
Member Author

Another potential solution could be combining the above two means. Cross-compilation does not start spontaneously, so whoever is rigging it up it could add --enable-musl-workarounds to the arguments. When the build matrix script runs, there is no cross-compilation so it can interrogate the binaries and add the flag as necessary.

And yet another one would be to use defined(__linux__) && ! defined (__GLIBC__) as the grounds to disregard HAVE_ETHER_HOSTTON.

@infrastation
Copy link
Member Author

The latter works and exposes a bug in libpcap's pcap_ether_hostton(), which after reading /etc/ethers compares the hostname in a case-sensitive manner. The fix is trivial and exposes the fact musl libc after reading /etc/hosts compares the hostname in a case-sensitive manner:

$ ping -n -c1 tcpdump.org
PING tcpdump.org (195.22.157.118): 56 data bytes

$ ping -n -c 1 TCPDUMP.ORG
PING TCPDUMP.ORG (195.22.157.118): 56 data bytes

$ ping -n -c 1 eth-ipv4-noipv6.host1.libpcap.test
PING eth-ipv4-noipv6.host1.libpcap.test (10.20.30.40): 56 data bytes

$ ping -n -c 1 ETH-IPV4-NOIPV6.HOST1.LIBPCAP.TEST
ping: bad address 'ETH-IPV4-NOIPV6.HOST1.LIBPCAP.TEST'

All three BSD platforms also implement ether_hostton() case-sensitive. GNU libc implementation is case-insensitive (which makes the most sense to me).

@infrastation
Copy link
Member Author

For the original problem there is a simple bug fix in my working copy, it is going to be a part of a pull request when other changes become ready.

Case-sensitivity of pcap_ether_hostton() seems to be common with other BSD implementations of ether_hostton(), for this my current work includes a workaround anyway and including pcap_ether_hostton() into that workaround is trivial.

Case-sensitivity of getaddrinfo() in musl libc is a separate matter, which still remains to be reported, and for which my working copy includes a workaround.

@infrastation infrastation self-assigned this Feb 14, 2025
infrastation added a commit to infrastation/libpcap that referenced this issue Feb 15, 2025
When libpcap compiles with musl libc, the "ether host HOSTNAME" syntax
cannot resolve any hostnames:

$ grep -F host.example /etc/ethers
12:34:56:78:9a:bc host.example

$ ./testprogs/filtertest EN10MB 'ether src host.example'
filtertest: unknown ether host 'host.example'

$ /usr/lib/libc.so
musl libc (aarch64)
Version 1.2.5
Dynamic Program Loader
Usage: /usr/lib/libc.so [options] [--] pathname [args]

This is because the functions always returns -1, so if it is Linux and
the libc does no identify, assume musl libc and compile the "no system
ether_hostton()" code path:

$ ./testprogs/filtertest EN10MB 'ether src host.example'
(000) ld       [8]
(001) jeq      #0x56789abc      jt 2	jf 5
(002) ldh      [6]
(003) jeq      #0x1234          jt 4	jf 5
(004) ret      #262144
(005) ret      #0

See also GitHub bug report the-tcpdump-group#1462.
@infrastation
Copy link
Member Author

The workaround is in the master branch, keeping open until the follow-ups are done.

@infrastation
Copy link
Member Author

musl libc bug report about case-sensitive getaddrinfo()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

2 participants