From 7181ae471345d4e4e85d5edd5341ff7f156de01d Mon Sep 17 00:00:00 2001 From: Guy Harris Date: Mon, 30 Mar 2015 11:21:17 -0700 Subject: Work around a Linux bonding driver bug (and the lack of a libpcap workaround). The bonding driver does not properly handle unknown ioctls; it returns ENODEV rather than ENOTSUP, EOPNOTSUPP, ENOTTY, or a "not supported" error of that type. This causes problems detailed in bug 11058. On Linux, check for bonding devices before checking for monitor-mode support. While we're at it, get rid of a commented-out include of CheckCSourceCompiles (it's presumably already been implicitly included by other functions that use it). Bug: 11058 Change-Id: I13035de0650634c51a52f262829b2b6fb86b39e9 Reviewed-on: https://code.wireshark.org/review/7856 Petri-Dish: Guy Harris Tested-by: Petri Dish Buildbot Reviewed-by: Guy Harris --- ConfigureChecks.cmake | 30 +++++++++++++++++- configure.ac | 11 +++++++ dumpcap.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 124 insertions(+), 2 deletions(-) diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index 69ca619068..de25c64874 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -53,6 +53,35 @@ check_include_file("unistd.h" HAVE_UNISTD_H) check_include_file("windows.h" HAVE_WINDOWS_H) check_include_file("winsock2.h" HAVE_WINSOCK2_H) +# +# On Linux, check for some additional headers, which we need as a +# workaround for a bonding driver bug and for libpcap's current lack +# of its own workaround for that bug. +# +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + # + # Those header files require . + # + check_c_source_compiles( + "#include + #include + int main(void) + { + return 0; + }" + HAVE_LINUX_SOCKIOS_H + ) + check_c_source_compiles( + "#include + #include + int main(void) + { + return 0; + }" + HAVE_LINUX_IF_BONDING_H + ) +endif() + #Functions include(CheckFunctionExists) include(CheckSymbolExists) @@ -107,7 +136,6 @@ check_struct_has_member("struct tm" tm_zone time.h HAVE_TM_ZONE) check_symbol_exists(tzname "time.h" HAVE_TZNAME) # Check for stuff that isn't testable via the tests above -#include(CheckCSourceCompiles) # # *If* we found libnl, check if we can use nl80211 stuff with it. diff --git a/configure.ac b/configure.ac index 857e898089..085b663a52 100644 --- a/configure.ac +++ b/configure.ac @@ -2606,6 +2606,17 @@ AC_CHECK_HEADERS(sys/ioctl.h sys/param.h sys/socket.h sys/sockio.h sys/stat.h sy AC_CHECK_HEADERS(netinet/in.h) AC_CHECK_HEADERS(arpa/inet.h arpa/nameser.h) +# +# On Linux, check for some additional headers, which we need as a +# workaround for a bonding driver bug and for libpcap's current lack +# of its own workaround for that bug. +# +case "$host_os" in +linux*) + AC_CHECK_HEADERS(linux/sockios.h linux/if_bonding.h,,,[#include ]) + ;; +esac + dnl SSL Check SSL_LIBS='' AC_MSG_CHECKING(whether to use SSL library) diff --git a/dumpcap.c b/dumpcap.c index 1bdffabbdc..696f6f706d 100644 --- a/dumpcap.c +++ b/dumpcap.c @@ -63,6 +63,39 @@ #include #endif +/* + * Linux bonding devices mishandle unknown ioctls; they fail + * with ENODEV rather than ENOTSUP, EOPNOTSUPP, or ENOTTY, + * so pcap_can_set_rfmon() returns a "no such device" indication + * if we try to do SIOCGIWMODE on them. + * + * So, on Linux, we check for bonding devices, if we can, before + * trying pcap_can_set_rfmon(), as pcap_can_set_rfmon() will + * end up trying SIOCGIWMODE on the device if that ioctl exists. + */ +#if defined(HAVE_PCAP_CREATE) && defined(__linux__) + +#include + +/* + * If we're building for a Linux version that supports bonding, + * HAVE_BONDING will be defined. + */ + +#ifdef HAVE_LINUX_SOCKIOS_H +#include +#endif + +#ifdef HAVE_LINUX_IF_BONDING_H +#include +#endif + +#if defined(BOND_INFO_QUERY_OLD) || defined(SIOCBONDINFOQUERY) +#define HAVE_BONDING +#endif + +#endif /* defined(HAVE_PCAP_CREATE) && defined(__linux__) */ + #include #include @@ -1117,6 +1150,44 @@ create_data_link_info(int dlt) return data_link_info; } +#ifdef HAVE_BONDING +gboolean +is_linux_bonding_device(const char *ifname) +{ + int fd; + struct ifreq ifr; + ifbond ifb; + + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd == -1) + return FALSE; + + memset(&ifr, 0, sizeof ifr); + g_strlcpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name); + memset(&ifb, 0, sizeof ifb); + ifr.ifr_data = (caddr_t)&ifb; +#if defined(SIOCBONDINFOQUERY) + if (ioctl(fd, SIOCBONDINFOQUERY, &ifr) == 0) { + close(fd); + return TRUE; + } +#else + if (ioctl(fd, BOND_INFO_QUERY_OLD, &ifr) == 0) { + close(fd); + return TRUE; + } +#endif + + return FALSE; +} +#else +static gboolean +is_linux_bonding_device(const char *ifname _U_) +{ + return FALSE; +} +#endif + /* * Get the capabilities of a network device. */ @@ -1177,7 +1248,19 @@ get_if_capabilities(const char *devicename, gboolean monitor_mode g_free(caps); return NULL; } - status = pcap_can_set_rfmon(pch); + if (is_linux_bonding_device(devicename)) { + /* + * Linux bonding device; not Wi-Fi, so no monitor mode, and + * calling pcap_can_set_rfmon() might get a "no such device" + * error. + */ + status = 0; + } else { + /* + * Not a Linux bonding device, so go ahead. + */ + status = pcap_can_set_rfmon(pch); + } if (status < 0) { /* Error. */ if (status == PCAP_ERROR) -- cgit v1.2.1