From: Guy Harris Date: Fri, 15 Sep 2017 12:14:10 +0000 (-0700) Subject: Don't test for capture devices, test for header files. X-Git-Tag: libpcap-1.9-bp~692 X-Git-Url: https://git.tcpdump.org/libpcap/commitdiff_plain/6865dc7308d5b9a8e5308e6fa7f6ec64695fc15e Don't test for capture devices, test for header files. Testing for /dev/bpf or /dev/bpfN in CMake requires that they be readable. Test for various header files required by various pcap-XXX.c files, and use that to determine what the capture mechanism for the host platform is. Don't look for headers by absolute path, as that could get in the way of cross-development (if any cross-development where the build machine and the host machine are running different OSes works). This means we have to determine whether we have a cloning BPF device at run time; do so. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 197874d4..0763fb40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -303,39 +303,65 @@ else() # what libraries we'd need to link libpcap with, if any. # set(PCAP_LINK_LIBRARIES "") - if(EXISTS /dev/bpf) + + # + # Check for a bunch of headers for various packet capture mechanisms. + # + check_include_file(net/bpf.h HAVE_NET_BPF_H) + check_include_file(net/pfilt.h HAVE_NET_PFILT_H) + check_include_file(net/enet.h HAVE_NET_ENET_H) + check_include_file(net/nit.h HAVE_NET_NIT_H) + check_include_file(sys/net/nit.h HAVE_SYS_NET_NIT_H) + check_include_file(linux/socket.h HAVE_LINUX_SOCKET_H) + check_include_file(net/raw.h HAVE_NET_RAW_H) + check_include_file(sys/dlpi.h HAVE_SYS_DLPI_H) + + if(HAVE_NET_BPF_H) # - # Cloning BPF device. + # BPF. + # Check this before DLPI, so that we pick BPF on + # Solaris 11 and later. # set(PCAP_TYPE bpf) - set(HAVE_CLONING_BPF TRUE) - elseif(EXISTS /dev/bpf0) - set(PCAP_TYPE bpf) - elseif(EXISTS /usr/include/net/pfilt.h) + elseif(HAVE_NET_PFILT_H) # # DEC OSF/1, Digital UNIX, Tru64 UNIX # set(PCAP_TYPE pf) - elseif(EXISTS /dev/enet) + elseif(HAVE_NET_ENET_H) + # + # Stanford Enetfilter. + # set(PCAP_TYPE enet) - elseif(EXISTS /dev/nit) + elseif(HAVE_NET_NIT_H) + # + # SunOS 4.x STREAMS NIT. + # set(PCAP_TYPE snit) - elseif(EXISTS /usr/include/sys/net/nit.h) + elseif(HAVE_SYS_NET_NIT_H) + # + # Pre-SunOS 4.x non-STREAMS NIT. + # set(PCAP_TYPE nit) - elseif(EXISTS /usr/include/linux/socket.h) + elseif(HAVE_LINUX_SOCKET_H) + # + # No prizes for guessing this one. + # set(PCAP_TYPE linux) - elseif(EXISTS /usr/include/net/raw.h) + elseif(HAVE_NET_RAW_H) + # + # IRIX snoop. + # set(PCAP_TYPE snoop) - elseif(EXISTS /usr/include/odmi.h) - # - # On AIX, the BPF devices might not yet be present - they're - # created the first time libpcap runs after booting. - # We check for odmi.h instead. - # - set(PCAP_TYPE bpf) - elseif(/usr/include/sys/dlpi.h) + elseif(HAVE_SYS_DLPI_H) + # + # DLPI on pre-Solaris 11 SunOS 5, HP-UX, possibly others. + # set(PCAP_TYPE dlpi) else() + # + # Nothing we support. + # set(PCAP_TYPE null) endif() endif(WIN32) diff --git a/config.h.in b/config.h.in index d4ab2409..9ba62ee9 100644 --- a/config.h.in +++ b/config.h.in @@ -3,9 +3,6 @@ /* Enable optimizer debugging */ #undef BDEBUG -/* define if you have a cloning BPF device */ -#undef HAVE_CLONING_BPF - /* define if you have the DAG API */ #undef HAVE_DAG_API @@ -82,6 +79,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_NET_TSTAMP_H +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_SOCKET_H + /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_SOCKIOS_H @@ -106,12 +106,27 @@ /* Define to 1 if you have the header file. */ #undef HAVE_NETPACKET_PACKET_H +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_BPF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_ENET_H + /* Define to 1 if you have the header file. */ #undef HAVE_NET_IF_MEDIA_H +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_NIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_PFILT_H + /* Define to 1 if you have the header file. */ #undef HAVE_NET_PFVAR_H +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_RAW_H + /* if there's an os_proto.h for this platform, to use additional prototypes */ #undef HAVE_OS_PROTO_H @@ -178,9 +193,15 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_DLPI_EXT_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_DLPI_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCCOM_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_NET_NIT_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKIO_H diff --git a/configure b/configure index 08614a29..ec86476b 100755 --- a/configure +++ b/configure @@ -5285,71 +5285,98 @@ if test "${with_pcap+set}" = set; then : withval=$with_pcap; fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking packet capture type" >&5 -$as_echo_n "checking packet capture type... " >&6; } if test ! -z "$with_pcap" ; then V_PCAP="$withval" -elif test -r /dev/bpf -o -h /dev/bpf ; then +else # - # Cloning BPF device. + # Check for a bunch of headers for various packet + # capture mechanisms. # - V_PCAP=bpf + for ac_header in net/bpf.h net/pfilt.h net/enet.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF -$as_echo "#define HAVE_CLONING_BPF 1" >>confdefs.h +fi +done - # - # We have BPF, so build valgrindtest with "make test". - # - VALGRINDTEST=valgrindtest -elif test -r /dev/bpf0 ; then - V_PCAP=bpf + for ac_header in net/nit.h sys/net/nit.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF - # - # We have BPF, so build valgrindtest with "make test". - # - VALGRINDTEST=valgrindtest -elif test -r /usr/include/net/pfilt.h ; then - V_PCAP=pf -elif test -r /dev/enet ; then - V_PCAP=enet -elif test -r /dev/nit ; then - V_PCAP=snit -elif test -r /usr/include/sys/net/nit.h ; then - V_PCAP=nit -elif test -r /usr/include/linux/socket.h ; then - V_PCAP=linux +fi - # - # XXX - this won't work with older kernels that have SOCK_PACKET - # sockets but not PF_PACKET sockets. - # - VALGRINDTEST=valgrindtest -elif test -r /usr/include/net/raw.h ; then - V_PCAP=snoop -elif test -r /usr/include/odmi.h ; then - # - # On AIX, the BPF devices might not yet be present - they're - # created the first time libpcap runs after booting. - # We check for odmi.h instead. - # - V_PCAP=bpf -elif test -c /dev/bpf0 ; then # check again in case not readable - V_PCAP=bpf +done - # - # We have BPF, so build valgrindtest with "make test". - # - VALGRINDTEST=valgrindtest -elif test -r /usr/include/sys/dlpi.h ; then - V_PCAP=dlpi -elif test -c /dev/enet ; then # check again in case not readable - V_PCAP=enet -elif test -c /dev/nit ; then # check again in case not readable - V_PCAP=snit -else - V_PCAP=null + for ac_header in linux/socket.h net/raw.h sys/dlpi.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + if test "$ac_cv_header_net_bpf_h" = yes; then + # + # BPF. + # Check this before DLPI, so that we pick BPF on + # Solaris 11 and later. + # + V_PCAP=bpf + + # + # We have BPF, so build valgrindtest with "make test" + # on macOS, FreeBSD, and Linux (add your OS once + # there's a valgrind for it). + # + case "$host_os" in + + freebsd*|darwin*|linux*) + VALGRINDTEST=valgrindtest + ;; + esac + elif test "$ac_cv_header_net_pfilt_h" = yes; then + V_PCAP=pf + elif test "$ac_cv_header_net_enet_h" = yes; then + V_PCAP=enet + elif test "$ac_header_net_nit_h" = yes; then + V_PCAP=snit + elif test "$ac_header_sys_net_nit_h" = yes; then + V_PCAP=nit + elif test "$ac_header_linux_socket_h" = yes; then + V_PCAP=linux + + # + # XXX - this won't work with older kernels that have + # SOCK_PACKET sockets but not PF_PACKET sockets. + # + VALGRINDTEST=valgrindtest + elif test "$ac_header_net_raw_h" = yes; then + V_PCAP=snoop + elif test "$ac_header_sys_dlpi_h" = yes; then + V_PCAP=dlpi + else + V_PCAP=null + fi fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking packet capture type" >&5 +$as_echo_n "checking packet capture type... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $V_PCAP" >&5 $as_echo "$V_PCAP" >&6; } diff --git a/configure.ac b/configure.ac index 5f534f63..77d502f1 100644 --- a/configure.ac +++ b/configure.ac @@ -261,68 +261,85 @@ if test -z "$with_pcap" && test "$cross_compiling" = yes; then fi AC_ARG_WITH(pcap, AC_HELP_STRING([--with-pcap=TYPE],[use packet capture TYPE])) -AC_MSG_CHECKING(packet capture type) if test ! -z "$with_pcap" ; then V_PCAP="$withval" -elif test -r /dev/bpf -o -h /dev/bpf ; then +else # - # Cloning BPF device. + # Check for a bunch of headers for various packet + # capture mechanisms. # - V_PCAP=bpf - AC_DEFINE(HAVE_CLONING_BPF,1,[define if you have a cloning BPF device]) + AC_CHECK_HEADERS(net/bpf.h net/pfilt.h net/enet.h) + AC_CHECK_HEADERS(net/nit.h sys/net/nit.h) + AC_CHECK_HEADERS(linux/socket.h net/raw.h sys/dlpi.h) - # - # We have BPF, so build valgrindtest with "make test". - # - VALGRINDTEST=valgrindtest -elif test -r /dev/bpf0 ; then - V_PCAP=bpf + if test "$ac_cv_header_net_bpf_h" = yes; then + # + # BPF. + # Check this before DLPI, so that we pick BPF on + # Solaris 11 and later. + # + V_PCAP=bpf - # - # We have BPF, so build valgrindtest with "make test". - # - VALGRINDTEST=valgrindtest -elif test -r /usr/include/net/pfilt.h ; then - V_PCAP=pf -elif test -r /dev/enet ; then - V_PCAP=enet -elif test -r /dev/nit ; then - V_PCAP=snit -elif test -r /usr/include/sys/net/nit.h ; then - V_PCAP=nit -elif test -r /usr/include/linux/socket.h ; then - V_PCAP=linux + # + # We have BPF, so build valgrindtest with "make test" + # on macOS, FreeBSD, and Linux (add your OS once + # there's a valgrind for it). + # + case "$host_os" in - # - # XXX - this won't work with older kernels that have SOCK_PACKET - # sockets but not PF_PACKET sockets. - # - VALGRINDTEST=valgrindtest -elif test -r /usr/include/net/raw.h ; then - V_PCAP=snoop -elif test -r /usr/include/odmi.h ; then - # - # On AIX, the BPF devices might not yet be present - they're - # created the first time libpcap runs after booting. - # We check for odmi.h instead. - # - V_PCAP=bpf -elif test -c /dev/bpf0 ; then # check again in case not readable - V_PCAP=bpf + freebsd*|darwin*|linux*) + VALGRINDTEST=valgrindtest + ;; + esac + elif test "$ac_cv_header_net_pfilt_h" = yes; then + # + # DEC OSF/1, Digital UNIX, Tru64 UNIX + # + V_PCAP=pf + elif test "$ac_cv_header_net_enet_h" = yes; then + # + # Stanford Enetfilter. + # + V_PCAP=enet + elif test "$ac_header_net_nit_h" = yes; then + # + # SunOS 4.x STREAMS NIT. + # + V_PCAP=snit + elif test "$ac_header_sys_net_nit_h" = yes; then + # + # Pre-SunOS 4.x non-STREAMS NIT. + # + V_PCAP=nit + elif test "$ac_header_linux_socket_h" = yes; then + # + # No prizes for guessing this one. + # + V_PCAP=linux - # - # We have BPF, so build valgrindtest with "make test". - # - VALGRINDTEST=valgrindtest -elif test -r /usr/include/sys/dlpi.h ; then - V_PCAP=dlpi -elif test -c /dev/enet ; then # check again in case not readable - V_PCAP=enet -elif test -c /dev/nit ; then # check again in case not readable - V_PCAP=snit -else - V_PCAP=null + # + # XXX - this won't work with older kernels that have + # SOCK_PACKET sockets but not PF_PACKET sockets. + # + VALGRINDTEST=valgrindtest + elif test "$ac_header_net_raw_h" = yes; then + # + # IRIX snoop. + # + V_PCAP=snoop + elif test "$ac_header_sys_dlpi_h" = yes; then + # + # DLPI on pre-Solaris 11 SunOS 5, HP-UX, possibly others. + # + V_PCAP=dlpi + else + # + # Nothing we support. + # + V_PCAP=null + fi fi +AC_MSG_CHECKING(packet capture type) AC_MSG_RESULT($V_PCAP) AC_SUBST(VALGRINDTEST) diff --git a/pcap-bpf.c b/pcap-bpf.c index a6403780..e821ff05 100644 --- a/pcap-bpf.c +++ b/pcap-bpf.c @@ -477,12 +477,10 @@ static int bpf_open(char *errbuf) { int fd; -#ifdef HAVE_CLONING_BPF - static const char device[] = "/dev/bpf"; -#else + static const char cloning_device[] = "/dev/bpf"; int n = 0; char device[sizeof "/dev/bpf0000000000"]; -#endif + static int no_cloning_bpf = 0; #ifdef _AIX /* @@ -494,19 +492,32 @@ bpf_open(char *errbuf) return (PCAP_ERROR); #endif -#ifdef HAVE_CLONING_BPF - if ((fd = open(device, O_RDWR)) == -1 && - (errno != EACCES || (fd = open(device, O_RDONLY)) == -1)) { - if (errno == EACCES) - fd = PCAP_ERROR_PERM_DENIED; - else - fd = PCAP_ERROR; - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "(cannot open device) %s: %s", device, pcap_strerror(errno)); + /* + * First, unless we've already tried opening /dev/bpf and + * gotten ENOENT, try opening /dev/bpf. + * If it fails with ENOENT, remember that, so we don't try + * again, and try /dev/bpfN. + */ + if (!no_cloning_bpf && + (fd = open(cloning_device, O_RDWR)) == -1 && + ((errno != EACCES && errno != ENOENT) || + (fd = open(cloning_device, O_RDONLY)) == -1)) { + if (errno != ENOENT) { + if (errno == EACCES) + fd = PCAP_ERROR_PERM_DENIED; + else + fd = PCAP_ERROR; + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "(cannot open device) %s: %s", device, + pcap_strerror(errno)); + return (fd); + } + no_cloning_bpf = 1; } -#else + /* - * Go through all the minors and find one that isn't in use. + * Go through all the /dev/bpfN minors and find one that isn't + * in use. */ do { (void)pcap_snprintf(device, sizeof(device), "/dev/bpf%d", n++); @@ -580,7 +591,6 @@ bpf_open(char *errbuf) break; } } -#endif return (fd); }