diff --git a/CHANGES b/CHANGES index 8c72dbe9cd42..89e739c46fa2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,129 @@ -Wednesday, Jan. 25, 2017 guy@alum.mit.edu +Sunday, July 22, 2018 + Summary for 1.9.1 libpcap release + Mention pcap_get_required_select_timeout() in the main pcap man page + Fix pcap-usb-linux.c build on systems with musl + Fix assorted man page and other documentation issues + Plug assorted memory leaks + Documentation changes to use https: + Changes to how time stamp calculations are done + Lots of tweaks to make newer compilers happier and warning-free and + to fix instances of C undefined behavior + Warn if AC_PROG_CC_C99 can't enable C99 support + Rename pcap_set_protocol() to pcap_set_protocol_linux(). + Align pcap_t private data on an 8-byte boundary. + Fix various error messages + Use 64-bit clean API in dag_findalldevs() + Fix cleaning up after some errors + Work around some ethtool ioctl bugs in newer Linux kernels (GitHub + issue #689) + Add backwards compatibility sections to some man pages (GitHub issue + #745) + Fix autotool configuration on AIX and macOS + Don't export bpf_filter_with_aux_data() or struct bpf_aux_data; + they're internal-only and subject to change + Fix pcapng block size checking + On macOS, don't build rpcapd or test programs any fatter than they + need to be + Fix reading of capture statistics for Linux USB + Fix packet size values for Linux USB packets (GitHub issue #808) + Check only VID in VLAN test in filterss (GitHub issue #461) + Fix pcap_list_datalinks on 802.11 devices on macOS + Fix overflows with very large snapshot length in pcap file + Improve parsing of rpcapd configuration file (GitHub issue #767) + Handle systems without strlcpy() or strlcat() better + Fix crashes and other errors with invalid filter expressions + Fix use of uninitialized file descriptor in remote capture + Fix some CMake issues + Fix some divide-by-zero issues with the filter compiler + Work around a GNU libc bug in pcap_nametonetaddr() + Add support for DLT_LINUX_SLL2 + Fix handling of the packet-count argument for Myricom SNF devices + Fix --disable-rdma in configure script (GitHub issue #782) + Fix compilation of TurboCap support (GitHub issue #764) + Constify first argument to pcap_findalldevs_ex() + Fix a number of issues when running rpcapd as an inetd-style daemon + Fix CMake issues with D-Bus libraries + In rpcapd, clean up termination of a capture session + Redo remote capture protocol negotiation + In rpcapd, report the same error for "invalid user name" and + "invalid password", to make brute-forcing harder + For remote captures, add an error code for "the server requires TLS" + Fix pcap_dump_fopen() on Windows to avoid clashes between + {Win,N}Pcap and application C runtimes + Fix exporting of functions from Windows DLLs (GitHub issue #810) + Fix building as part of Npcap + Allow rpcapd to rebind more rapidly + Fix building shared libpcap library on midipix (midipix.org) + Fix hack to detect UTF-16LE adapter names on Windows not to go past + the end of the string + Fix handling of "wireless WAN" (mobile phone network modems) on + Windows with WinPcap/Npcap (GitHub issue #824) + Have pcap_dump_open_append() create the dump file if it doesn't + exists (GitHub issue #247) + Fix the maxmum snapshot length for DLT_USBPCAP + Use -fPIC when building for 64-bit SPARC on Linux (GitHub issue #837) + Fix CMake 64-bit library installation directory on some Linux + distributions + Boost the TPACKET_V3 timeout to the maximum if a timeout of 0 was + specified + Five CVE-2019-15161, CVE-2019-15162, CVE-2019-15163, CVE-2019-15164, CVE-2019-15165 + Fixes for CVE-2018-16301, errors in pcapng reading. + PCAPNG reader applies some sanity checks before doing malloc(). + +Sunday, June 24, 2018, by mcr@sandelman.ca Summary for 1.9.0 libpcap release + Added testing system to libpcap, independent of tcpdump + Changes to how pcap_t is activated + Adding support for Large stream buffers on Endace DAG cards + Changes to BSD 3-clause license to 2-clause licence + Additions to TCP header parsing, per RFC3168 + Add CMake build process (extensive number of changes) + Assign a value for OpenBSD DLT_OPENFLOW. + Support setting non-blocking mode before activating. + Extensive build support for Windows VS2010 and MINGW (many many changes, over many months) + Added RPCAPD support when --enable-remote (default no) + Add the rpcap daemon source and build instructions. + Put back the greasy "save the capture filter string so we can tweak it" + hack, that keeps libpcap from capturing rpcap traffic. + Fixes for captures on MacOS, utun0 + fixes so that non-AF_INET addresses, are not ==AF_INET6 addresses. + Add a linktype for IBM SDLC frames containing SNA PDUs. + pcap_compile() in 1.8.0 and later is newly thread-safe. + bound snaplen for linux tpacket_v2 to ~64k + Make VLAN filter handle both metadata and inline tags + D-Bus captures can now be up to 128MB in size + Added LORATAP DLT value + Added DLT_VSOCK for http://qemu-project.org/Features/VirtioVsock + probe_devices() fixes not to overrun buffer for name of device + Add linux-specific pcap_set_protocol_linux() to allow specifying a specific capture protocol. + RDMA sniffing support for pcap + Add Nordic Semiconductor Bluetooth LE sniffer link-layer header type. + fixes for reading /etc/ethers + Make it possible to build on Windows without packet.dll. + Add tests for large file support on UN*X. + Solaris fixes to work with 2.8.6 + configuration test now looks for header files, not capture devices present + Fix to work with Berkeley YACC. + fixes for DragonBSD compilation of pcap-netmap.c + Clean up the ether_hostton() stuff. + Add an option to disable Linux memory-mapped capture support. + Add DAG API support checks. + Add Septel, Myricom SNF, and Riverbed TurboCap checks. + Add checks for Linux USB, Linux Bluetooth, D-Bus, and RDMA sniffing support. + Add a check for hardware time stamping on Linux. + Don't bother supporting pre-2005 Visual Studio. + Increased minimum autoconf version requirement to 2.64 + Add DLT value 273 for XRA-31 sniffer + Clean up handing of signal interrupts in pcap_read_nocb_remote(). + Use the XPG 4.2 versions of the networking APIs in Solaris. + Fix, and better explain, the "IPv6 means IPv6, not IPv4" option setting. + Explicitly warn that negative packet buffer timeouts should not be used. + rpcapd: Add support inetd-likes, including xinetd.conf, and systemd units + Rename DLT_IEEE802_15_4 to DLT_IEEE802_15_4_WITHFCS. + Add DISPLAYPORT AUX link type + Remove the sunos4 kernel modules and all references to them. + Add more interface flags to pcap_findalldevs(). + Summary for 1.9.0 libpcap release (to 2017-01-25 by guy@alum.mit.edu) Man page improvements Fix Linux cooked mode userspace filtering (GitHub pull request #429) Fix compilation if IPv6 support not enabled diff --git a/CMakeLists.txt b/CMakeLists.txt index ce6915512045..55b93f14d74c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ if(POLICY CMP0042) cmake_policy(SET CMP0042 OLD) endif() -set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) project(pcap) @@ -135,83 +135,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") option(BUILD_WITH_LIBNL "Build with libnl" ON) endif() -# -# By default, build universal with the appropriate set of architectures -# for the OS on which we're doing the build. -# -if(APPLE AND "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "") - # - # Get the major version of Darwin. - # - string(REGEX MATCH "^([0-9]+)" SYSTEM_VERSION_MAJOR "${CMAKE_SYSTEM_VERSION}") - - if(SYSTEM_VERSION_MAJOR LESS 8) - # - # Pre-Tiger. Build only for 32-bit PowerPC. - # - set(CMAKE_OSX_ARCHITECTURES "ppc") - elseif(SYSTEM_VERSION_MAJOR EQUAL 8) - # - # Tiger. Is this prior to, or with, Intel support? - # - # Get the minor version of Darwin. - # - string(REPLACE "${SYSTEM_VERSION_MAJOR}." "" SYSTEM_MINOR_AND_PATCH_VERSION ${CMAKE_SYSTEM_VERSION}) - string(REGEX MATCH "^([0-9]+)" SYSTEM_VERSION_MINOR "${SYSTEM_MINOR_AND_PATCH_VERSION}") - if(SYSTEM_VERSION_MINOR LESS 4) - # - # Prior to Intel support. Build for 32-bit - # PowerPC and 64-bit PowerPC, with 32-bit PowerPC - # first. (I'm guessing that's what Apple does.) - # - set(CMAKE_OSX_ARCHITECTURES "ppc;ppc64") - elseif(SYSTEM_VERSION_MINOR LESS 7) - # - # With Intel support but prior to x86-64 support. - # Build for 32-bit PowerPC, 64-bit PowerPC, and x86, - # with 32-bit PowerPC first. - # (I'm guessing that's what Apple does.) - # - set(CMAKE_OSX_ARCHITECTURES "ppc;ppc64;i386") - else() - # - # With Intel support including x86-64 support. - # Build for 32-bit PowerPC, 64-bit PowerPC, x86, - # and x86-64, with 32-bit PowerPC first. - # (I'm guessing that's what Apple does.) - # - set(CMAKE_OSX_ARCHITECTURES "ppc;ppc64;i386;x86_64") - endif() - elseif(SYSTEM_VERSION_MAJOR EQUAL 9) - # - # Leopard. Build for 32-bit PowerPC, 64-bit - # PowerPC, x86, and x86-64, with 32-bit PowerPC - # first. (That's what Apple does.) - # - set(CMAKE_OSX_ARCHITECTURES "ppc;ppc64;i386;x86_64") - elseif(SYSTEM_VERSION_MAJOR EQUAL 10) - # - # Snow Leopard. Build for x86-64, x86, and - # 32-bit PowerPC, with x86-64 first. (That's - # what Apple does, even though Snow Leopard - # doesn't run on PPC, so PPC libpcap runs under - # Rosetta, and Rosetta doesn't support BPF - # ioctls, so PPC programs can't do live - # captures.) - # - set(CMAKE_OSX_ARCHITECTURES "x86_64;i386;ppc") - else() - # - # Post-Snow Leopard. Build for x86-64 and - # x86, with x86-64 first. (That's probably what - # Apple does, given that Rosetta is gone.) - # XXX - update if and when Apple drops support - # for 32-bit x86 code. - # - set(CMAKE_OSX_ARCHITECTURES "x86_64;i386") - endif() -endif() - # # Additional capture modules. # @@ -233,7 +156,7 @@ option(DISABLE_RDMA "Disable RDMA sniffing support" OFF) option(DISABLE_DAG "Disable Endace DAG card support" OFF) option(DISABLE_SEPTEL "Disable Septel card support" OFF) -set(SEPTEL_ROOT "${CMAKE_SOURCE_DIR}/../septel" CACHE PATH "Path to directory with include and lib subdirectories for Septel API") +set(SEPTEL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../septel" CACHE PATH "Path to directory with include and lib subdirectories for Septel API") option(DISABLE_SNF "Disable Myricom SNF support" OFF) @@ -251,7 +174,7 @@ option(YYDEBUG "Build parser debugging code" OFF) # Get, parse, format and set pcap's version string from [pcap_root]/VERSION # for later use. - + # Get MAJOR, MINOR, PATCH & SUFFIX file(STRINGS ${pcap_SOURCE_DIR}/VERSION PACKAGE_VERSION @@ -264,7 +187,7 @@ string(REGEX MATCH "^([0-9]+)" PACKAGE_VERSION_MAJOR "${PACKAGE_VERSION}") # Get MAJOR, MINOR & PATCH string(REGEX MATCH "^([0-9]+.)?([0-9]+.)?([0-9]+)" PACKAGE_VERSION_NOSUFFIX "${PACKAGE_VERSION}") -if(WIN32) +if(WIN32) # Convert PCAP_VERSION_NOSUFFIX to Windows preferred version format string(REPLACE "." "," PACKAGE_VERSION_PREDLL ${PACKAGE_VERSION_NOSUFFIX}) @@ -289,6 +212,7 @@ include_directories( include(CheckFunctionExists) include(CMakePushCheckState) +include(CheckSymbolExists) if(WIN32) @@ -310,6 +234,14 @@ if(WIN32) cmake_pop_check_state() endif(PACKET_FOUND) + message(STATUS "checking for Npcap's version.h") + check_symbol_exists(WINPCAP_PRODUCT_NAME "../../version.h" HAVE_VERSION_H) + if(HAVE_VERSION_H) + message(STATUS "HAVE version.h") + else(HAVE_VERSION_H) + message(STATUS "MISSING version.h") + endif(HAVE_VERSION_H) + endif(WIN32) if(MSVC) @@ -343,6 +275,11 @@ include(CheckIncludeFiles) include(CheckStructHasMember) include(CheckTypeSize) +# +# Tests are a bit expensive with Visual Studio on Windows, so, on +# Windows, we skip tests for UN*X-only headers and functions. +# + # # Header files. # @@ -395,12 +332,44 @@ endif(NOT WIN32) # check_function_exists(strerror HAVE_STRERROR) check_function_exists(strerror_r HAVE_STRERROR_R) -check_function_exists(strerror_s HAVE_STRERROR_S) +if(HAVE_STRERROR_R) + # + # We have strerror_r; if we define _GNU_SOURCE, is it a + # POSIX-compliant strerror_r() or a GNU strerror_r()? + # + check_c_source_compiles( +"#define _GNU_SOURCE +#include + +/* Define it GNU-style; that will cause an error if it's not GNU-style */ +extern char *strerror_r(int, char *, size_t); + +int +main(void) +{ + return 0; +} +" + HAVE_GNU_STRERROR_R) + if(NOT HAVE_GNU_STRERROR_R) + set(HAVE_POSIX_STRERROR_R YES) + endif(NOT HAVE_GNU_STRERROR_R) +else(HAVE_STRERROR_R) + # + # We don't have strerror_r; do we have strerror_s? + # + check_function_exists(strerror_s HAVE_STRERROR_S) +endif(HAVE_STRERROR_R) check_function_exists(strlcpy HAVE_STRLCPY) check_function_exists(strlcat HAVE_STRLCAT) check_function_exists(snprintf HAVE_SNPRINTF) check_function_exists(vsnprintf HAVE_VSNPRINTF) +check_function_exists(asprintf HAVE_ASPRINTF) +check_function_exists(vasprintf HAVE_VASPRINTF) check_function_exists(strtok_r HAVE_STRTOK_R) +if(NOT WIN32) + check_function_exists(vsyslog HAVE_VSYSLOG) +endif() # # These tests are for network applications that need socket functions @@ -429,7 +398,6 @@ check_function_exists(strtok_r HAVE_STRTOK_R) # set(PCAP_LINK_LIBRARIES "") include(CheckLibraryExists) -include(CheckSymbolExists) if(WIN32) # # We need winsock2.h and ws2tcpip.h. @@ -865,11 +833,61 @@ set(PROJECT_SOURCE_LIST_C ) if(WIN32) - set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} missing/win_snprintf.c) + # + # For now, we assume we don't have snprintf() or that it's not one + # that behaves enough like C99's snprintf() for our purposes (i.e., + # it doesn't null-terminate the string if it truncates it to fit in + # the buffer), so we have to provide our own (a wrapper around + # _snprintf() that null-terminates the buffer). + # + # We also assume we don't have asprintf(), and provide an implementation + # that uses _vscprintf() to determine how big the string needs to be. + # + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} + missing/win_snprintf.c missing/win_asprintf.c) else() + # + # Either: + # + # we have snprintf() and vsnprintf(), and have asprintf() and + # vasprintf(); + # + # we have snprintf() and vsnprintf(), but don't have asprintf() + # or vasprintf(); + # + # we have neither snprintf() nor vsnprintf(), and don't have + # asprintf() or vasprintf(), either. + # + # We assume that if we have asprintf() we have vasprintf(), as well + # as snprintf() and vsnprintf(), and that if we have snprintf() we + # have vsnprintf(). + # + # For the first case, we don't need any replacement routines. + # For the second case, we need replacement asprintf()/vasprintf() + # routines. + # For the third case, we need replacement snprintf()/vsnprintf() and + # asprintf()/vasprintf() routines. + # if(NOT HAVE_SNPRINTF) + # + # We assume we have none of them; missing/snprintf.c supplies + # all of them. + # set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} missing/snprintf.c) - endif(NOT HAVE_SNPRINTF) + elif(NOT HAVE_ASPRINTF) + # + # We assume we have snprintf()/vsnprintf() but lack + # asprintf()/vasprintf(); missing/asprintf.c supplies + # the latter (using vsnprintf()). + # + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} missing/asprintf.c) + endif() + if(NOT HAVE_STRLCAT) + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} missing/strlcat.c) + endif(NOT HAVE_STRLCAT) + if(NOT HAVE_STRLCPY) + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} missing/strlcpy.c) + endif(NOT HAVE_STRLCPY) if(NOT HAVE_STRTOK_R) set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} missing/strtok_r.c) endif(NOT HAVE_STRTOK_R) @@ -931,13 +949,16 @@ else() # as it's a Linux, it should use packet sockets, # instead. # - # # We need: # # sys/types.h, because FreeBSD 10's net/bpf.h # requires that various BSD-style integer types # be defined; # + # sys/time.h, because AIX 5.2 and 5.3's net/bpf.h + # doesn't include it but does use struct timeval + # in ioctl definitions; + # # sys/ioctl.h and, if we have it, sys/ioccom.h, # because net/bpf.h defines ioctls; # @@ -952,9 +973,9 @@ else() # of those headers itself. # if(HAVE_SYS_IOCCOM_H) - check_symbol_exists(BIOCSETIF "sys/types.h;sys/ioctl.h;sys/socket.h;sys/ioccom.h;net/bpf.h;net/if.h" BPF_H_DEFINES_BIOCSETIF) + check_symbol_exists(BIOCSETIF "sys/types.h;sys/time.h;sys/ioctl.h;sys/socket.h;sys/ioccom.h;net/bpf.h;net/if.h" BPF_H_DEFINES_BIOCSETIF) else(HAVE_SYS_IOCCOM_H) - check_symbol_exists(BIOCSETIF "sys/types.h;sys/ioctl.h;sys/socket.h;net/bpf.h;net/if.h" BPF_H_DEFINES_BIOCSETIF) + check_symbol_exists(BIOCSETIF "sys/types.h;sys/time.h;sys/ioctl.h;sys/socket.h;net/bpf.h;net/if.h" BPF_H_DEFINES_BIOCSETIF) endif(HAVE_SYS_IOCCOM_H) endif(HAVE_NET_BPF_H) check_include_file(net/pfilt.h HAVE_NET_PFILT_H) @@ -1436,7 +1457,28 @@ if(NOT DISABLE_DBUS) set(PCAP_SUPPORT_DBUS TRUE) set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-dbus.c) include_directories(${DBUS_INCLUDE_DIRS}) - set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${DBUS_LIBRARIES}) + + # + # This "helpfully" supplies DBUS_LIBRARIES as a bunch of + # library names - not paths - and DBUS_LIBRARY_DIRS as + # a bunch of directories. + # + # CMake *really* doesn't like the notion of specifying "here are + # the directories in which to look for libraries" except in + # find_library() calls; it *really* prefers using full paths to + # library files, rather than library names. + # + # Find the libraries and add their full paths. + # + set(DBUS_LIBRARY_FULLPATHS) + foreach(_lib IN LISTS DBUS_LIBRARIES) + # + # Try to find this library, so we get its full path. + # + find_library(_libfullpath ${_lib} HINTS ${DBUS_LIBRARY_DIRS}) + list(APPEND DBUS_LIBRARY_FULLPATHS ${_libfullpath}) + endforeach() + set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${DBUS_LIBRARY_FULLPATHS}) endif(DBUS_FOUND) endif(NOT DISABLE_DBUS) @@ -1499,7 +1541,7 @@ if(NOT DISABLE_DAG) endif() endif() endif() -endif() +endif() # Check for Septel card support. set(PROJECT_EXTERNAL_OBJECT_LIST "") @@ -1521,7 +1563,7 @@ if(NOT DISABLE_SEPTEL) set(PROJECT_EXTERNAL_OBJECT_LIST ${PROJECT_EXTERNAL_OBJECT_LIST} "${SEPTEL_ROOT}/asciibin.o ${SEPTEL_ROOT}/bit2byte.o ${SEPTEL_ROOT}/confirm.o ${SEPTEL_ROOT}/fmtmsg.o ${SEPTEL_ROOT}/gct_unix.o ${SEPTEL_ROOT}/hqueue.o ${SEPTEL_ROOT}/ident.o ${SEPTEL_ROOT}/mem.o ${SEPTEL_ROOT}/pack.o ${SEPTEL_ROOT}/parse.o ${SEPTEL_ROOT}/pool.o ${SEPTEL_ROOT}/sdlsig.o ${SEPTEL_ROOT}/strtonum.o ${SEPTEL_ROOT}/timer.o ${SEPTEL_ROOT}/trace.o") set(HAVE_SEPTEL_API TRUE) endif() -endif() +endif() # Check for Myricom SNF support. if(NOT DISABLE_SNF) @@ -1542,7 +1584,7 @@ if(NOT DISABLE_SNF) set(HAVE_SNF_API TRUE) set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${SNF_LIBRARIES}) endif() -endif() +endif() # Check for Riverbed TurboCap support. if(NOT DISABLE_TC) @@ -1563,7 +1605,7 @@ if(NOT DISABLE_TC) set(HAVE_TC_API TRUE) set(PCAP_LINK_LIBRARIES "${PCAP_LINK_LIBRARIES} ${TC_LIBRARIES} ${CMAKE_USE_PTHREADS_INIT} stdc++") endif() -endif() +endif() # # Remote capture support. @@ -1582,7 +1624,7 @@ if(ENABLE_REMOTE) # the check. # cmake_push_check_state() - set(CMAKE_REQUIRED_INCLUDES ${CMAKE_SOURCE_DIR}) + set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}) check_struct_has_member("struct msghdr" msg_control "ftmacros.h;sys/socket.h" HAVE_STRUCT_MSGHDR_MSG_CONTROL) check_struct_has_member("struct msghdr" msg_flags "ftmacros.h;sys/socket.h" HAVE_STRUCT_MSGHDR_MSG_FLAGS) cmake_pop_check_state() @@ -1597,7 +1639,7 @@ endif(ENABLE_REMOTE) # # Check and add warning options if we have a .devel file. # -if(EXISTS ${CMAKE_SOURCE_DIR}/.devel OR EXISTS ${CMAKE_BINARY_DIR}/.devel) +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.devel OR EXISTS ${CMAKE_BINARY_DIR}/.devel) # # Warning options. # @@ -1808,10 +1850,12 @@ set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/grammar.c PROPERTIES # # Assume, by default, no support for shared libraries and V7/BSD -# convention for man pages (file formats in section 5, miscellaneous -# info in section 7, administrative commands and daemons in section 8). +# convention for man pages (devices in section 4, file formats in +# section 5, miscellaneous info in section 7, administrative commands +# and daemons in section 8). Individual cases can override this. # Individual cases can override this. # +set(MAN_DEVICES 4) set(MAN_FILE_FORMATS 5) set(MAN_MISC_INFO 7) set(MAN_ADMIN_COMMANDS 8) @@ -1869,6 +1913,7 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "OSF1") # set(MAN_FILE_FORMATS 4) set(MAN_MISC_INFO 5) + set(MAN_DEVICES 7) elseif(CMAKE_SYSTEM_NAME STREQUAL "SunOS" AND CMAKE_SYSTEM_VERSION MATCHES "5[.][0-9.]*") # # SunOS 5.x. @@ -1892,6 +1937,7 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "SunOS" AND CMAKE_SYSTEM_VERSION MATCHES "5[.] set(MAN_ADMIN_COMMANDS 1m) set(MAN_FILE_FORMATS 4) set(MAN_MISC_INFO 5) + set(MAN_DEVICES 7D) endif() endif() @@ -1944,6 +1990,16 @@ if(BUILD_SHARED_LIBS) add_dependencies(${LIBRARY_NAME} SerializeTarget) set_target_properties(${LIBRARY_NAME} PROPERTIES COMPILE_DEFINITIONS BUILDING_PCAP) + # + # No matter what the library is called - it might be called "wpcap" + # in a Windows build - the symbol to define to indicate that we're + # building the library, rather than a program using the library, + # and thus that we're exporting functions defined in our public + # header files, rather than importing those functions, is + # pcap_EXPORTS. + # + set_target_properties(${LIBRARY_NAME} PROPERTIES + DEFINE_SYMBOL pcap_EXPORTS) endif(BUILD_SHARED_LIBS) add_library(${LIBRARY_NAME}_static STATIC @@ -1982,7 +2038,7 @@ if(WIN32) # For compatibility, build the shared library without the "lib" prefix on # MinGW as well. # - set_target_properties(${LIBRARY_NAME} PROPERTIES + set_target_properties(${LIBRARY_NAME} PROPERTIES PREFIX "" OUTPUT_NAME "${LIBRARY_NAME}" ) @@ -2020,6 +2076,118 @@ if(NOT C_ADDITIONAL_FLAGS STREQUAL "") set_target_properties(${LIBRARY_NAME}_static PROPERTIES COMPILE_FLAGS ${C_ADDITIONAL_FLAGS}) endif() +# +# On macOS, build libpcap for the appropriate architectures, if +# CMAKE_OSX_ARCHITECTURES isn't set (if it is, let that control +# the architectures for which to build it). +# +if(APPLE AND "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "") + # + # Get the major version of Darwin. + # + string(REGEX MATCH "^([0-9]+)" SYSTEM_VERSION_MAJOR "${CMAKE_SYSTEM_VERSION}") + + if(SYSTEM_VERSION_MAJOR LESS 8) + # + # Pre-Tiger. Build only for 32-bit PowerPC. + # + set(OSX_LIBRARY_ARCHITECTURES "ppc") + elseif(SYSTEM_VERSION_MAJOR EQUAL 8) + # + # Tiger. Is this prior to, or with, Intel support? + # + # Get the minor version of Darwin. + # + string(REPLACE "${SYSTEM_VERSION_MAJOR}." "" SYSTEM_MINOR_AND_PATCH_VERSION ${CMAKE_SYSTEM_VERSION}) + string(REGEX MATCH "^([0-9]+)" SYSTEM_VERSION_MINOR "${SYSTEM_MINOR_AND_PATCH_VERSION}") + if(SYSTEM_VERSION_MINOR LESS 4) + # + # Prior to Intel support. Build for 32-bit + # PowerPC and 64-bit PowerPC, with 32-bit PowerPC + # first. (I'm guessing that's what Apple does.) + # + set(OSX_LIBRARY_ARCHITECTURES "ppc;ppc64") + elseif(SYSTEM_VERSION_MINOR LESS 7) + # + # With Intel support but prior to x86-64 support. + # Build for 32-bit PowerPC, 64-bit PowerPC, and 32-bit x86, + # with 32-bit PowerPC first. + # (I'm guessing that's what Apple does.) + # + set(OSX_LIBRARY_ARCHITECTURES "ppc;ppc64;i386") + else() + # + # With Intel support including x86-64 support. + # Build for 32-bit PowerPC, 64-bit PowerPC, 32-bit x86, + # and x86-64, with 32-bit PowerPC first. + # (I'm guessing that's what Apple does.) + # + set(OSX_LIBRARY_ARCHITECTURES "ppc;ppc64;i386;x86_64") + endif() + elseif(SYSTEM_VERSION_MAJOR EQUAL 9) + # + # Leopard. Build for 32-bit PowerPC, 64-bit + # PowerPC, 32-bit x86, and x86-64, with 32-bit PowerPC + # first. (That's what Apple does.) + # + set(OSX_LIBRARY_ARCHITECTURES "ppc;ppc64;i386;x86_64") + elseif(SYSTEM_VERSION_MAJOR EQUAL 10) + # + # Snow Leopard. Build for x86-64, 32-bit x86, and + # 32-bit PowerPC, with x86-64 first. (That's + # what Apple does, even though Snow Leopard + # doesn't run on PPC, so PPC libpcap runs under + # Rosetta, and Rosetta doesn't support BPF + # ioctls, so PPC programs can't do live + # captures.) + # + set(OSX_LIBRARY_ARCHITECTURES "x86_64;i386;ppc") + else() + # + # Post-Snow Leopard. Build for x86-64 and 32-bit x86, + # with x86-64 first. (That's what Apple does) + # XXX - update if and when Apple drops support + # for 32-bit x86 code and if and when Apple adds + # ARM-based Macs. (You're on your own for iOS etc.) + # + # XXX - check whether we *can* build for i386 and, if not, + # suggest that the user install the /usr/include headers if + # they want to build fat. + # + cmake_push_check_state() + set(CMAKE_REQUIRED_FLAGS "-arch i386") + check_c_source_compiles( +"int +main(void) +{ + return 0; +} +" + X86_32_BIT_SUPPORTED) + cmake_pop_check_state() + if(X86_32_BIT_SUPPORTED) + set(OSX_LIBRARY_ARCHITECTURES "x86_64;i386") + else() + set(OSX_LIBRARY_ARCHITECTURES "x86_64") + if(SYSTEM_VERSION_MAJOR LESS 18) + # + # Pre-Mojave; the command-line tools should be sufficient to + # enable 32-bit x86 builds. + # + message(WARNING "Compiling for 32-bit x86 gives an error; try installing the command-line tools") + else() + message(WARNING "Compiling for 32-bit x86 gives an error; try installing the command-line tools and, after that, installing the /usr/include headers from the /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg package") + endif() + endif() + endif() + if(BUILD_SHARED_LIBS) + set_target_properties(${LIBRARY_NAME} PROPERTIES + OSX_ARCHITECTURES "${OSX_LIBRARY_ARCHITECTURES}") + endif(BUILD_SHARED_LIBS) + set_target_properties(${LIBRARY_NAME}_static PROPERTIES + OSX_ARCHITECTURES "${OSX_LIBRARY_ARCHITECTURES}") +endif() + ###################################### # Write out the config.h file ###################################### @@ -2079,6 +2247,7 @@ set(MAN3PCAP_EXPAND pcap_list_tstamp_types.3pcap.in pcap_open_dead.3pcap.in pcap_open_offline.3pcap.in + pcap_set_immediate_mode.3pcap.in pcap_set_tstamp_precision.3pcap.in pcap_set_tstamp_type.3pcap.in ) @@ -2114,9 +2283,8 @@ set(MAN3PCAP_NOEXPAND pcap_open_live.3pcap pcap_set_buffer_size.3pcap pcap_set_datalink.3pcap - pcap_set_immediate_mode.3pcap pcap_set_promisc.3pcap - pcap_set_protocol.3pcap + pcap_set_protocol_linux.3pcap pcap_set_rfmon.3pcap pcap_set_snaplen.3pcap pcap_set_timeout.3pcap @@ -2179,11 +2347,13 @@ if(WIN32) endif(NOT MINGW) endif(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8) else(WIN32) - install(TARGETS ${LIBRARY_NAME} ${LIBRARY_NAME_STATIC} DESTINATION lib) + install(TARGETS ${LIBRARY_NAME} ${LIBRARY_NAME_STATIC} DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}) endif(WIN32) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/pcap/ DESTINATION include/pcap) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/pcap.h DESTINATION include) +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/pcap-bpf.h DESTINATION include) +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/pcap-namedb.h DESTINATION include) # On UN*X, and on Windows when not using MSVC, generate libpcap.pc and # pcap-config and process man pages and arrange that they be installed. @@ -2223,8 +2393,8 @@ if(NOT MSVC) foreach(LIB ${PCAP_LINK_LIBRARIES}) set(LIBS "${LIBS} -l${LIB}") endforeach(LIB) - configure_file(${CMAKE_SOURCE_DIR}/pcap-config.in ${CMAKE_CURRENT_BINARY_DIR}/pcap-config @ONLY) - configure_file(${CMAKE_SOURCE_DIR}/libpcap.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libpcap.pc @ONLY) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/pcap-config.in ${CMAKE_CURRENT_BINARY_DIR}/pcap-config @ONLY) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libpcap.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libpcap.pc @ONLY) install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/pcap-config DESTINATION bin) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpcap.pc DESTINATION lib/pkgconfig) @@ -2236,17 +2406,17 @@ if(NOT MSVC) # set(MAN1 "") foreach(MANPAGE ${MAN1_NOEXPAND}) - set(MAN1 ${MAN1} ${CMAKE_SOURCE_DIR}/${MANPAGE}) + set(MAN1 ${MAN1} ${CMAKE_CURRENT_SOURCE_DIR}/${MANPAGE}) endforeach(MANPAGE) install(FILES ${MAN1} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) set(MAN3PCAP "") foreach(MANPAGE ${MAN3PCAP_NOEXPAND}) - set(MAN3PCAP ${MAN3PCAP} ${CMAKE_SOURCE_DIR}/${MANPAGE}) + set(MAN3PCAP ${MAN3PCAP} ${CMAKE_CURRENT_SOURCE_DIR}/${MANPAGE}) endforeach(MANPAGE) foreach(TEMPLATE_MANPAGE ${MAN3PCAP_EXPAND}) string(REPLACE ".in" "" MANPAGE ${TEMPLATE_MANPAGE}) - configure_file(${CMAKE_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY) set(MAN3PCAP ${MAN3PCAP} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE}) endforeach(TEMPLATE_MANPAGE) install(FILES ${MAN3PCAP} DESTINATION ${CMAKE_INSTALL_MANDIR}/man3) @@ -2270,7 +2440,7 @@ if(NOT MSVC) set(MANFILE "") foreach(TEMPLATE_MANPAGE ${MANFILE_EXPAND}) string(REPLACE ".manfile.in" ".${MAN_FILE_FORMATS}" MANPAGE ${TEMPLATE_MANPAGE}) - configure_file(${CMAKE_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY) set(MANFILE ${MANFILE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE}) endforeach(TEMPLATE_MANPAGE) install(FILES ${MANFILE} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_FILE_FORMATS}) @@ -2278,7 +2448,7 @@ if(NOT MSVC) set(MANMISC "") foreach(TEMPLATE_MANPAGE ${MANMISC_EXPAND}) string(REPLACE ".manmisc.in" ".${MAN_MISC_INFO}" MANPAGE ${TEMPLATE_MANPAGE}) - configure_file(${CMAKE_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY) set(MANMISC ${MANMISC} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE}) endforeach(TEMPLATE_MANPAGE) install(FILES ${MANMISC} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_MISC_INFO}) diff --git a/CONTRIBUTING b/CONTRIBUTING.md similarity index 93% rename from CONTRIBUTING rename to CONTRIBUTING.md index a3c2bd68d027..69b597260f79 100644 --- a/CONTRIBUTING +++ b/CONTRIBUTING.md @@ -25,5 +25,5 @@ Please note that if you know exactly how to solve the problem and the solution would not be too intrusive, it would be best to contribute some development time and open a pull request instead. -Still not sure how to do? Feel free to [subscribe](http://www.tcpdump.org/#mailing-lists) +Still not sure how to do? Feel free to [subscribe](https://www.tcpdump.org/#mailing-lists) to the mailing list tcpdump-workers@lists.tcpdump.org and ask! diff --git a/CREDITS b/CREDITS index b959c77c07e8..f7abc1f3222e 100644 --- a/CREDITS +++ b/CREDITS @@ -1,21 +1,18 @@ -This file lists people who have contributed to libpcap: +This file lists people who have contributed to libpcap. -The current maintainers: - Bill Fenner +The current maintainers (in alphabetical order): Denis Ovsienko - Fulvio Risso + Francois-Xavier Le Bail Guy Harris - Hannes Gredler Michael Richardson - Francois-Xavier Le Bail - -Additional people who have contributed patches: +Additional people who have contributed patches (in alphabetical order): Akos Vandra Alan Bawden Albert Chin Alexander 'Leo' Bergolth Alexey Kuznetsov + Ali Abdulkadir Alon Bar-Lev Andres Perera Andrew Brown @@ -62,6 +59,7 @@ Additional people who have contributed patches: Gabor Tatarka Garrett Cooper George Neville-Neil + Gerard Garcia Gianluca Varenni Gilbert Hoyek Gisle Vanem @@ -99,6 +97,7 @@ Additional people who have contributed patches: Koryn Grant Kris Katterjohn Krzysztof Halasa + Lennert Buytenhek Lorenzo Cavallaro Loris Degioanni Love Hörnquist-Ã…strand @@ -114,6 +113,7 @@ Additional people who have contributed patches: Márton Németh Matthew Luckie Max Laier + Michal Kubecek Michal Labedzki Michal Sekletar Mike Frysinger @@ -129,7 +129,7 @@ Additional people who have contributed patches: Olaf Kirch Ollie Wild Onno van der Linden - Paolo Abeni + Paolo Abeni Patrick Marie Patrick McHardy Paul Mundt @@ -145,6 +145,8 @@ Additional people who have contributed patches: Rick Jones Robert Edmonds Roberto Mariani + Rongxi Li + Roland Dreier Romain Francoise Sagun Shakya Scott Barron @@ -167,6 +169,7 @@ Additional people who have contributed patches: Wesley Shields Xianjie Zhang Xin Li + Xue Jiang Qing Yen Yen Lim Yoann Vandoorselaere Yvan Vanhullebus @@ -176,5 +179,8 @@ The original LBL crew: Craig Leres Van Jacobson -Past maintainers: - Jun-ichiro itojun Hagino Also see: http://www.wide.ad.jp/itojun-award/ +Past maintainers (in alphabetical order): + Bill Fenner + Fulvio Risso + Hannes Gredler + Jun-ichiro itojun Hagino Also see: http://www.wide.ad.jp/itojun-award/ diff --git a/INSTALL.txt b/INSTALL.md similarity index 94% rename from INSTALL.txt rename to INSTALL.md index e39c122a341b..3a303fe0a6ce 100644 --- a/INSTALL.txt +++ b/INSTALL.md @@ -69,10 +69,6 @@ before /usr/ucb or else: before running configure. (You might have to do a "make distclean" if you already ran configure once). -Also note that "make depend" won't work; while all of the known -universe uses -M, the SPARCompiler uses -xM to generate makefile -dependencies. - If you are trying to do packet capture with a FORE ATM card, you may or may not be able to. They usually only release their driver in object code so unless their driver supports packet capture, there's not much @@ -258,27 +254,26 @@ ChmodBPF/* - macOS startup item to set ownership and permissions CMakeLists.txt - CMake file CONTRIBUTING - guidelines for contributing CREDITS - people that have helped libpcap along -INSTALL.txt - this file +INSTALL.md - this file LICENSE - the license under which tcpdump is distributed Makefile.in - compilation rules (input to the configure script) -README - description of distribution -README.aix - notes on using libpcap on AIX -README.dag - notes on using libpcap to capture on Endace DAG devices -README.hpux - notes on using libpcap on HP-UX -README.linux - notes on using libpcap on Linux -README.macos - notes on using libpcap on macOS -README.septel - notes on using libpcap to capture on Intel/Septel devices -README.sita - notes on using libpcap to capture on SITA devices -README.tru64 - notes on using libpcap on Digital/Tru64 UNIX -README.Win32 - notes on using libpcap on Win32 systems (with WinPcap) +README.md - description of distribution +doc/README.aix - notes on using libpcap on AIX +doc/README.dag - notes on using libpcap to capture on Endace DAG devices +doc/README.hpux - notes on using libpcap on HP-UX +doc/README.linux.md - notes on using libpcap on Linux +doc/README.macos - notes on using libpcap on macOS +doc/README.septel - notes on using libpcap to capture on Intel/Septel devices +doc/README.sita - notes on using libpcap to capture on SITA devices +doc/README.tru64 - notes on using libpcap on Digital/Tru64 UNIX +doc/README.Win32 - notes on using libpcap on Win32 systems (with Npcap) VERSION - version of this release acconfig.h - support for post-2.13 autoconf aclocal.m4 - autoconf macros arcnet.h - ARCNET definitions atmuni31.h - ATM Q.2931 definitions -bpf/net - copy of bpf_filter.c bpf_dump.c - BPF program printing routines -bpf_filter.c - symlink to bpf/net/bpf_filter.c +bpf_filter.c - BPF filtering routines bpf_image.c - BPF disassembly routine config.guess - autoconf support config.h.in - autoconf input diff --git a/Makefile.in b/Makefile.in index 6fcd3afc4e00..5a6b165da3f0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -69,7 +69,7 @@ INSTALL_RPCAPD=@INSTALL_RPCAPD@ EXTRA_NETWORK_LIBS=@EXTRA_NETWORK_LIBS@ # Standard CFLAGS for building members of a shared library -FULL_CFLAGS = $(CCOPT) $(SHLIB_CCOPT) $(INCLS) $(DEFS) $(CFLAGS) +FULL_CFLAGS = $(CCOPT) @V_LIB_CCOPT_FAT@ $(SHLIB_CCOPT) $(INCLS) $(DEFS) $(CFLAGS) INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ @@ -117,6 +117,7 @@ PUBHDR = \ pcap/nflog.h \ pcap/pcap.h \ pcap/sll.h \ + pcap/socket.h \ pcap/vlan.h \ pcap/usb.h @@ -168,6 +169,7 @@ MAN3PCAP_EXPAND = \ pcap_list_tstamp_types.3pcap.in \ pcap_open_dead.3pcap.in \ pcap_open_offline.3pcap.in \ + pcap_set_immediate_mode.3pcap.in \ pcap_set_tstamp_precision.3pcap.in \ pcap_set_tstamp_type.3pcap.in @@ -203,9 +205,8 @@ MAN3PCAP_NOEXPAND = \ pcap_open_live.3pcap \ pcap_set_buffer_size.3pcap \ pcap_set_datalink.3pcap \ - pcap_set_immediate_mode.3pcap \ pcap_set_promisc.3pcap \ - pcap_set_protocol.3pcap \ + pcap_set_protocol_linux.3pcap \ pcap_set_rfmon.3pcap \ pcap_set_snaplen.3pcap \ pcap_set_timeout.3pcap \ @@ -235,21 +236,13 @@ EXTRA_DIST = \ ChmodBPF/StartupParameters.plist \ CREDITS \ CMakeLists.txt \ - INSTALL.txt \ + INSTALL.md \ LICENSE \ Makefile.in \ Makefile-devel-adds \ - README \ - README.aix \ - README.dag \ - README.hpux \ - README.linux \ - README.macos \ - README.septel \ - README.sita \ - README.tru64 \ - README.Win32 \ - CONTRIBUTING \ + README.md \ + doc \ + CONTRIBUTING.md \ TODO \ VERSION \ aclocal.m4 \ @@ -284,10 +277,14 @@ EXTRA_DIST = \ lbl/os-sunos4.h \ lbl/os-ultrix4.h \ libpcap.pc.in \ + missing/asprintf.c \ missing/getopt.c \ missing/getopt.h \ missing/snprintf.c \ + missing/strlcat.c \ + missing/strlcpy.c \ missing/strtok_r.c \ + missing/win_asprintf.c \ missing/win_snprintf.c \ mkdep \ msdos/bin2c.c \ @@ -355,16 +352,18 @@ EXTRA_DIST = \ rpcapd/fileconf.c \ rpcapd/fileconf.h \ rpcapd/log.h \ - rpcapd/log-stderr.c \ + rpcapd/log.c \ rpcapd/org.tcpdump.rpcapd.plist \ rpcapd/rpcapd.c \ rpcapd/rpcapd.h \ rpcapd/rpcapd.inetd.conf \ rpcapd/rpcapd.manadmin.in \ + rpcapd/rpcapd-config.manfile.in \ rpcapd/rpcapd.rc \ rpcapd/rpcapd.socket \ rpcapd/rpcapd.xinetd.conf \ rpcapd/rpcapd@.service \ + rpcapd/win32-svc.c \ rpcapd/win32-svc.h \ sockutils.c \ sockutils.h \ @@ -424,7 +423,7 @@ libpcap.dylib: $(OBJ) MAJOR_VER=A; \ COMPAT_VER=1; \ CURRENT_VER=`sed 's/[^0-9.].*$$//' $(srcdir)/VERSION`; \ - $(CC) -dynamiclib -undefined error $(LDFLAGS) \ + $(CC) -dynamiclib -undefined error $(LDFLAGS) @V_LIB_LDFLAGS_FAT@ \ -o libpcap.$$VER.dylib $(OBJ) $(ADDLOBJS) $(LIBS) \ -install_name $(libdir)/libpcap.$$MAJOR_VER.dylib \ -compatibility_version $$COMPAT_VER \ @@ -496,9 +495,18 @@ grammar.o: grammar.c scanner.h gencode.o: $(srcdir)/gencode.c grammar.h scanner.h $(CC) $(FULL_CFLAGS) -c $(srcdir)/gencode.c +asprintf.o: $(srcdir)/missing/asprintf.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/asprintf.c + snprintf.o: $(srcdir)/missing/snprintf.c $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/snprintf.c +strlcat.o: $(srcdir)/missing/strlcat.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/strlcat.c + +strlcpy.o: $(srcdir)/missing/strlcpy.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/strlcpy.c + strtok_r.o: $(srcdir)/missing/strtok_r.c $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/strtok_r.c @@ -582,6 +590,9 @@ install: install-shared install-archive libpcap.pc pcap-config @INSTALL_RPCAPD@ rm -f pcap_datalink_val_to_description.3pcap && \ $(LN_S) pcap_datalink_val_to_name.3pcap \ pcap_datalink_val_to_description.3pcap && \ + rm -f pcap_datalink_val_to_description_or_dlt.3pcap && \ + $(LN_S) pcap_datalink_val_to_name.3pcap \ + pcap_datalink_val_to_description_or_dlt.3pcap && \ rm -f pcap_dump_fopen.3pcap && \ $(LN_S) pcap_dump_open.3pcap pcap_dump_fopen.3pcap && \ rm -f pcap_freealldevs.3pcap && \ @@ -751,7 +762,7 @@ tags: $(TAGFILES) releasetar: @cwd=`pwd` ; dir=`basename $$cwd` ; name=$(PROG)-`cat VERSION` ; \ mkdir $$name; \ - tar cf - $(CSRC) $(HDR) $(MAN1) $(MAN3PCAP_EXPAND) \ + tar -c --exclude='*~' -f - $(CSRC) $(HDR) $(MAN1) $(MAN3PCAP_EXPAND) \ $(MAN3PCAP_NOEXPAND) $(MANFILE) $(MANMISC) $(EXTRA_DIST) | \ (cd $$name; tar xf -); \ tar -c -z -f $$name.tar.gz $$name; \ diff --git a/README.Win32 b/README.Win32 deleted file mode 100644 index 0a42dab93d4b..000000000000 --- a/README.Win32 +++ /dev/null @@ -1,46 +0,0 @@ -Under Win32, libpcap is integrated in the WinPcap packet capture system. -WinPcap provides a framework that allows libpcap to capture the packets -under Windows 95, Windows 98, Windows ME, Windows NT 4, Windows 2000 -and Windows XP. -WinPcap binaries and source code can be found at http://winpcap.polito.it: -they include also a developer's pack with all the necessary to compile -libpcap-based applications under Windows. - -How to compile libpcap with Visual Studio ------------------------------------------ - -In order to compile libpcap you will need: - -- version 6 (or higher) of Microsoft Visual Studio -- The November 2001 (or later) edition of Microsoft Platform -Software Development Kit (SDK), that contains some necessary includes -for IPv6 support. You can download it from http://www.microsoft.com/sdk -- the latest WinPcap sources from http://winpcap.polito.it/install - -The WinPcap source code already contains a recent (usually the latest -stable) version of libpcap. If you need to compile a different one, -simply download it from www.tcpdump.org and copy the sources in the -winpcap\wpcap\libpcap folder of the WinPcap distribution. If you want to -compile a libpcap source retrieved from the tcpdump.org Git, you will -have to create the scanner and the grammar by hand (with lex and yacc) -or with the cygnus makefile, since The Visual Studio project is not able -to build them. - -Open the project file winpcap\wpcap\prj\wpcap.dsw with Visual Studio and -build wpcap.dll. wpcap.lib, the library file to link with the applications, -will be generated in winpcap\wpcap\lib\. wpcap.dll will be generated in -winpcap\wpcap\prj\release or winpcap\wpcap\prj\debug depending on the type -of binary that is being created. - -How to compile libpcap with Cygnus ----------------------------------- - -To build wpcap.dll, cd to the directory WPCAP/PRJ of the WinPcap source code -distribution and type "make". libwpcap.a, the library file to link with the -applications, will be generated in winpcap\wpcap\lib\. wpcap.dll will be -generated in winpcap\wpcap\prj. - -Remember, you CANNOT use the MSVC-generated .lib files with gcc, use -libwpcap.a instead. - -"make install" installs wpcap.dll in the Windows system folder. diff --git a/README b/README.md similarity index 88% rename from README rename to README.md index 24fdc80d6989..78cc3c4b41b5 100644 --- a/README +++ b/README.md @@ -2,14 +2,17 @@ To report a security issue please send an e-mail to security@tcpdump.org. To report bugs and other problems, contribute patches, request a feature, provide generic feedback etc please see the file -CONTRIBUTING in the libpcap source tree root. +[CONTRIBUTING](CONTRIBUTING.md) in the libpcap source tree root. + +The directory doc/ has README files about specific operating systems and +options. LIBPCAP 1.x.y Now maintained by "The Tcpdump Group" https://www.tcpdump.org Anonymous Git is available via: - git clone git://bpf.tcpdump.org/libpcap + https://github.com/the-tcpdump-group/libpcap.git formerly from Lawrence Berkeley National Laboratory Network Research Group @@ -67,9 +70,10 @@ kernel source and/or object patches available in: https://www.tcpdump.org/other/bpfext42.tar.Z -Linux, in the 2.2 kernel and later kernels, has a "Socket Filter" -mechanism that accepts BPF filters; see the README.linux file for -information on configuring that option. +Linux has a number of BPF based systems, and libpcap does not support +any of the eBPF mechanisms as yet, although it supports many of the +memory mapped receive mechanisms. +See the [README.linux](doc/README.linux.md) file for more information. Note to Linux distributions and *BSD systems that include libpcap: diff --git a/VERSION b/VERSION index 52c56fe39831..9ab8337f3962 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.9.0-PRE-GIT +1.9.1 diff --git a/aclocal.m4 b/aclocal.m4 index 2b63c8842d5f..aa91e846ed6b 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -266,6 +266,14 @@ dnl Check whether the compiler option specified as the second argument dnl is supported by the compiler and, if so, add it to the macro dnl specified as the first argument dnl +dnl If a third argument is supplied, treat it as C code to be compiled +dnl with the flag in question, and the "treat warnings as errors" flag +dnl set, and don't add the flag to the first argument if the compile +dnl fails; this is for warning options cause problems that can't be +dnl worked around. If a third argument is supplied, a fourth argument +dnl should also be supplied; it's a message desribing what the test +dnl program is checking. +dnl AC_DEFUN(AC_LBL_CHECK_COMPILER_OPT, [ AC_MSG_CHECKING([whether the compiler supports the $2 option]) @@ -287,8 +295,38 @@ AC_DEFUN(AC_LBL_CHECK_COMPILER_OPT, [return 0], [ AC_MSG_RESULT([yes]) + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x$4" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + AC_MSG_CHECKING(whether $2 $4) + AC_COMPILE_IFELSE( + [AC_LANG_SOURCE($3)], + [ + # + # Not a problem. + # + AC_MSG_RESULT(no) + ], + [ + # + # A problem. + # + AC_MSG_RESULT(yes) + can_add_to_cflags=no + ]) + fi CFLAGS="$save_CFLAGS" - $1="$$1 $2" + if test x"$can_add_to_cflags" = "xyes" + then + $1="$$1 $2" + fi ], [ AC_MSG_RESULT([no]) @@ -446,7 +484,7 @@ AC_DEFUN(AC_LBL_SHLIBS_INIT, aix*) ;; - freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*) + freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*|midipix*) # # Platforms where the linker is the GNU linker # or accepts command-line arguments like @@ -463,7 +501,7 @@ AC_DEFUN(AC_LBL_SHLIBS_INIT, sparc64*) case "$host_os" in - freebsd*|openbsd*) + freebsd*|openbsd*|linux*) PIC_OPT=-fPIC ;; esac @@ -840,23 +878,58 @@ AC_DEFUN(AC_LBL_DEVEL, # if test "$ac_lbl_cc_dont_try_gcc_dashW" != yes; then AC_LBL_CHECK_UNKNOWN_WARNING_OPTION_ERROR() + AC_LBL_CHECK_COMPILER_OPT($1, -W) AC_LBL_CHECK_COMPILER_OPT($1, -Wall) - AC_LBL_CHECK_COMPILER_OPT($1, -Wsign-compare) - AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-prototypes) - AC_LBL_CHECK_COMPILER_OPT($1, -Wstrict-prototypes) - AC_LBL_CHECK_COMPILER_OPT($1, -Wshadow) - AC_LBL_CHECK_COMPILER_OPT($1, -Wdeclaration-after-statement) - AC_LBL_CHECK_COMPILER_OPT($1, -Wused-but-marked-unused) - AC_LBL_CHECK_COMPILER_OPT($1, -Wdocumentation) AC_LBL_CHECK_COMPILER_OPT($1, -Wcomma) + AC_LBL_CHECK_COMPILER_OPT($1, -Wdeclaration-after-statement) + AC_LBL_CHECK_COMPILER_OPT($1, -Wdocumentation) + AC_LBL_CHECK_COMPILER_OPT($1, -Wformat-nonliteral) AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-noreturn) + AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-prototypes) + AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-variable-declarations) + AC_LBL_CHECK_COMPILER_OPT($1, -Wshadow) + AC_LBL_CHECK_COMPILER_OPT($1, -Wsign-compare) + AC_LBL_CHECK_COMPILER_OPT($1, -Wstrict-prototypes) + AC_LBL_CHECK_COMPILER_OPT($1, -Wunused-parameter) + AC_LBL_CHECK_COMPILER_OPT($1, -Wused-but-marked-unused) # Warns about safeguards added in case the enums are # extended # AC_LBL_CHECK_COMPILER_OPT($1, -Wcovered-switch-default) - AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-variable-declarations) - AC_LBL_CHECK_COMPILER_OPT($1, -Wunused-parameter) - AC_LBL_CHECK_COMPILER_OPT($1, -Wformat-nonliteral) - AC_LBL_CHECK_COMPILER_OPT($1, -Wunreachable-code) + # + # This can cause problems with ntohs(), ntohl(), + # htons(), and htonl() on some platforms, such + # as OpenBSD 6.3 with Clang 5.0.1. I guess the + # problem is that the macro that ultimately does + # the byte-swapping involves a conditional + # expression that tests whether the value being + # swapped is a compile-time constant or not, + # using __builtin_constant_p(), and, depending + # on whether it is, does a compile-time swap or + # a run-time swap; perhaps the compiler always + # considers one of the two results of the + # conditional expressin is never evaluated, + # because the conditional check is done at + # compile time, and thus always says "that + # expression is never executed". + # + # (Perhaps there should be a way of flagging + # an expression that you *want* evaluated at + # compile time, so that the compiler 1) warns + # if it *can't* be evaluated at compile time + # and 2) *doesn't* warn that the true or false + # branch will never be reached.) + # + AC_LBL_CHECK_COMPILER_OPT($1, -Wunreachable-code, + [ +#include + +unsigned short +testme(unsigned short a) +{ + return ntohs(a); +} + ], + [generates warnings from ntohs()]) fi AC_LBL_CHECK_DEPENDENCY_GENERATION_OPT() # diff --git a/bpf_filter.c b/bpf_filter.c index 615ed3fc3d0f..33872ff4bbda 100644 --- a/bpf_filter.c +++ b/bpf_filter.c @@ -51,7 +51,7 @@ #include #endif /* _WIN32 */ -#include +#include #include @@ -328,11 +328,17 @@ bpf_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p, continue; case BPF_ALU|BPF_LSH|BPF_X: - A <<= X; + if (X < 32) + A <<= X; + else + A = 0; continue; case BPF_ALU|BPF_RSH|BPF_X: - A >>= X; + if (X < 32) + A >>= X; + else + A = 0; continue; case BPF_ALU|BPF_ADD|BPF_K: @@ -378,10 +384,13 @@ bpf_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p, case BPF_ALU|BPF_NEG: /* * Most BPF arithmetic is unsigned, but negation - * can't be unsigned; throw some casts to - * specify what we're trying to do. + * can't be unsigned; respecify it as subtracting + * the accumulator from 0U, so that 1) we don't + * get compiler warnings about negating an unsigned + * value and 2) don't get UBSan warnings about + * the result of negating 0x80000000 being undefined. */ - A = (u_int32)(-(int32)A); + A = (0U - A); continue; case BPF_MISC|BPF_TAX: diff --git a/cmake/Modules/FindPacket.cmake b/cmake/Modules/FindPacket.cmake index 1311cdb94f15..f114875bf873 100644 --- a/cmake/Modules/FindPacket.cmake +++ b/cmake/Modules/FindPacket.cmake @@ -49,9 +49,17 @@ # # The 64-bit Packet.lib is located under /x64 -set(64BIT_SUBDIR "") if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(64BIT_SUBDIR "/x64") + # + # For the WinPcap and Npcap SDKs, the Lib subdirectory of the top-level + # directory contains 32-bit libraries; the 64-bit libraries are in the + # Lib/x64 directory. + # + # The only way to *FORCE* CMake to look in the Lib/x64 directory + # without searching in the Lib directory first appears to be to set + # CMAKE_LIBRARY_ARCHITECTURE to "x64". + # + set(CMAKE_LIBRARY_ARCHITECTURE "x64") endif() # Find the header @@ -64,7 +72,6 @@ find_path(PACKET_INCLUDE_DIR Packet32.h find_library(PACKET_LIBRARY NAMES Packet packet HINTS "${PACKET_DLL_DIR}" ENV PACKET_DLL_DIR - PATH_SUFFIXES Lib${64BIT_SUBDIR} lib${64BIT_SUBDIR} ) # Set PACKET_FOUND to TRUE if PACKET_INCLUDE_DIR and PACKET_LIBRARY are TRUE. diff --git a/cmake/Modules/FindPthreads-w32.cmake b/cmake/Modules/FindPthreads-w32.cmake deleted file mode 100644 index ba2a78c2e404..000000000000 --- a/cmake/Modules/FindPthreads-w32.cmake +++ /dev/null @@ -1,152 +0,0 @@ -# ============================================================================== -# This is a heavily modified version of FindPthreads.cmake for the pcap project. -# It's meant to find Pthreads-w32, an implementation of the -# Threads component of the POSIX 1003.1c 1995 Standard (or later) -# for Microsoft's WIndows. -# -# Apart from this notice, this module "enjoys" the following modifications: -# -# - changed its name to FindPthreads-w32.cmake to not conflict with FindThreads.cmake -# -# - users may be able to use the environment variable PTHREADS_ROOT to point -# cmake to the *root* of their Pthreads-w32 installation. -# Alternatively, PTHREADS_ROOT may also be set from cmake command line or GUI -# (-DPTHREADS_ROOT=/path/to/Pthreads-w32) -# Two other variables that can be defined in a similar fashion are -# PTHREAD_INCLUDE_PATH and PTHREAD_LIBRARY_PATH. -# -# - added some additional status/error messages -# -# - changed formating (uppercase to lowercare + indentation) -# -# - removed some stuff -# -# - when searching for Pthreads-win32 libraries, the directory structure of the -# pre-build binaries folder found in the pthreads-win32 CVS code repository is -# considered (e.i /Pre-built.2/lib/x64 /Pre-built.2/lib/x86) -# -# Send suggestion, patches, gifts and praises to pcap's developers. -# ============================================================================== -# -# Find the Pthreads library -# This module searches for the Pthreads-win32 library (including the -# pthreads-win32 port). -# -# This module defines these variables: -# -# PTHREADS_FOUND - True if the Pthreads library was found -# PTHREADS_LIBRARY - The location of the Pthreads library -# PTHREADS_INCLUDE_DIR - The include directory of the Pthreads library -# PTHREADS_DEFINITIONS - Preprocessor definitions to define (HAVE_PTHREAD_H is a fairly common one) -# -# This module responds to the PTHREADS_EXCEPTION_SCHEME -# variable on Win32 to allow the user to control the -# library linked against. The Pthreads-win32 port -# provides the ability to link against a version of the -# library with exception handling. -# IT IS NOT RECOMMENDED THAT YOU CHANGE PTHREADS_EXCEPTION_SCHEME -# TO ANYTHING OTHER THAN "C" because most POSIX thread implementations -# do not support stack unwinding. -# -# PTHREADS_EXCEPTION_SCHEME -# C = no exceptions (default) -# (NOTE: This is the default scheme on most POSIX thread -# implementations and what you should probably be using) -# CE = C++ Exception Handling -# SE = Structure Exception Handling (MSVC only) -# - -# -# Define a default exception scheme to link against -# and validate user choice. -# -# -if(NOT DEFINED PTHREADS_EXCEPTION_SCHEME) - # Assign default if needed - set(PTHREADS_EXCEPTION_SCHEME "C") -else(NOT DEFINED PTHREADS_EXCEPTION_SCHEME) - # Validate - if(NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "C" AND - NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "CE" AND - NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "SE") - - message(FATAL_ERROR "See documentation for FindPthreads.cmake, only C, CE, and SE modes are allowed") - - endif(NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "C" AND - NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "CE" AND - NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "SE") - - if(NOT MSVC AND PTHREADS_EXCEPTION_SCHEME STREQUAL "SE") - message(FATAL_ERROR "Structured Exception Handling is only allowed for MSVC") - endif(NOT MSVC AND PTHREADS_EXCEPTION_SCHEME STREQUAL "SE") - -endif(NOT DEFINED PTHREADS_EXCEPTION_SCHEME) - -if(PTHREADS_ROOT) - set(PTHREADS_ROOT PATHS ${PTHREADS_ROOT} NO_DEFAULT_PATH) -else() - set(PTHREADS_ROOT $ENV{PTHREADS_ROOT}) -endif(PTHREADS_ROOT) - -# -# Find the header file -# -find_path(PTHREADS_INCLUDE_DIR - NAMES pthread.h - HINTS - $ENV{PTHREAD_INCLUDE_PATH} - ${PTHREADS_ROOT}/include -) - -if(PTHREADS_INCLUDE_DIR) - message(STATUS "Found pthread.h: ${PTHREADS_INCLUDE_DIR}") -# else() -# message(FATAL_ERROR "Could not find pthread.h. See README.Win32 for more information.") -endif(PTHREADS_INCLUDE_DIR) - -# -# Find the library -# -set(names) -if(MSVC) - set(names - pthreadV${PTHREADS_EXCEPTION_SCHEME}2 - libpthread - ) -elseif(MINGW) - set(names - pthreadG${PTHREADS_EXCEPTION_SCHEME}2 - pthread - ) -endif(MSVC) - -if(CMAKE_SIZEOF_VOID_P EQUAL 4) - set(SUBDIR "/x86") -elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(SUBDIR "/x64") -endif() - -find_library(PTHREADS_LIBRARY NAMES ${names} - DOC "The Portable Threads Library" - HINTS - ${CMAKE_SOURCE_DIR}/lib - $ENV{PTHREAD_LIBRARY_PATH} - ${PTHREADS_ROOT} - C:/MinGW/lib/ - PATH_SUFFIXES lib/${SUBDIR} -) - -if(PTHREADS_LIBRARY) -message(STATUS "Found PTHREADS library: ${PTHREADS_LIBRARY} (PTHREADS Exception Scheme: ${PTHREADS_EXCEPTION_SCHEME})") -# else() -# message(FATAL_ERROR "Could not find PTHREADS LIBRARY. See README.Win32 for more information.") -endif(PTHREADS_LIBRARY) - -if(PTHREADS_INCLUDE_DIR AND PTHREADS_LIBRARY) - set(PTHREADS_DEFINITIONS -DHAVE_PTHREAD_H) - set(PTHREADS_INCLUDE_DIRS ${PTHREADS_INCLUDE_DIR}) - set(PTHREADS_LIBRARIES ${PTHREADS_LIBRARY}) - set(PTHREADS_FOUND TRUE) -endif(PTHREADS_INCLUDE_DIR AND PTHREADS_LIBRARY) - -mark_as_advanced(PTHREADS_INCLUDE_DIR PTHREADS_LIBRARY) diff --git a/cmakeconfig.h.in b/cmakeconfig.h.in index 6760cec76834..1639925e35d6 100644 --- a/cmakeconfig.h.in +++ b/cmakeconfig.h.in @@ -15,6 +15,9 @@ /* define if we have the AIX getprotobyname_r() */ #cmakedefine HAVE_AIX_GETPROTOBYNAME_R 1 +/* Define to 1 if you have the `asprintf' function. */ +#cmakedefine HAVE_ASPRINTF 1 + /* define if you have the DAG API */ #cmakedefine HAVE_DAG_API 1 @@ -48,6 +51,9 @@ /* Define to 1 if you have the `getspnam' function. */ #cmakedefine HAVE_GETSPNAM 1 +/* Define to 1 if you have a GNU-style `strerror_r' function. */ +#cmakedefine HAVE_GNU_STRERROR_R 1 + /* on HP-UX 10.20 or later */ #cmakedefine HAVE_HPUX10_20_OR_LATER 1 @@ -138,9 +144,15 @@ /* if there's an os_proto.h for this platform, to use additional prototypes */ #cmakedefine HAVE_OS_PROTO_H 1 -/* Define to 1 if Packet32 API (WinPcap NPF driver) is available */ +/* Define to 1 if Packet32 API (Npcap driver) is available */ #cmakedefine HAVE_PACKET32 1 +/* Define to 1 if NPcap's version.h is available */ +#cmakedefine HAVE_VERSION_H 1 + +/* Define to 1 if you have a POSIX-style `strerror_r' function. */ +#cmakedefine HAVE_POSIX_STRERROR_R 1 + /* define if net/pfvar.h defines PF_NAT through PF_NORDR */ #cmakedefine HAVE_PF_NAT_THROUGH_PF_NORDR 1 @@ -174,9 +186,6 @@ /* Define to 1 if you have the `strerror' function. */ #cmakedefine HAVE_STRERROR 1 -/* Define to 1 if you have the `strerror_r' function. */ -#cmakedefine HAVE_STRERROR_R 1 - /* Define to 1 if you have the `strerror_s' function. */ #cmakedefine HAVE_STRERROR_S 1 @@ -256,9 +265,15 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_UNISTD_H 1 +/* Define to 1 if you have the `vasprintf' function. */ +#cmakedefine HAVE_VASPRINTF 1 + /* Define to 1 if you have the `vsnprintf' function. */ #cmakedefine HAVE_VSNPRINTF 1 +/* Define to 1 if you have the `vsyslog' function. */ +#undef HAVE_VSYSLOG + /* Define to 1 if you have the `PacketIsLoopbackAdapter' function. */ #cmakedefine HAVE_PACKET_IS_LOOPBACK_ADAPTER 1 diff --git a/config.guess b/config.guess index 44290b838cd0..2b79f6d837b9 100755 --- a/config.guess +++ b/config.guess @@ -1,8 +1,8 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2015 Free Software Foundation, Inc. +# Copyright 1992-2018 Free Software Foundation, Inc. -timestamp='2015-02-23' +timestamp='2018-07-06' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -15,7 +15,7 @@ timestamp='2015-02-23' # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, see . +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -27,7 +27,7 @@ timestamp='2015-02-23' # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # # Please send patches to . @@ -39,7 +39,7 @@ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. -Operation modes: +Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit @@ -50,7 +50,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2015 Free Software Foundation, Inc. +Copyright 1992-2018 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." @@ -101,15 +101,15 @@ trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && e trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || - { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || - { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp 2>/dev/null) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; -case $CC_FOR_BUILD,$HOST_CC,$CC in - ,,) echo "int x;" > $dummy.c ; +case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in + ,,) echo "int x;" > "$dummy.c" ; for c in cc gcc c89 c99 ; do - if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + if ($c -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; @@ -132,14 +132,14 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown -case "${UNAME_SYSTEM}" in +case "$UNAME_SYSTEM" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu - eval $set_cc_for_build - cat <<-EOF > $dummy.c + eval "$set_cc_for_build" + cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc @@ -149,13 +149,20 @@ Linux|GNU|GNU/*) LIBC=gnu #endif EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`" + + # If ldd exists, use it to detect musl libc. + if command -v ldd >/dev/null && \ + ldd --version 2>&1 | grep -q ^musl + then + LIBC=musl + fi ;; esac # Note: order is significant - the case branches are not exclusive. -case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in +case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, @@ -169,27 +176,30 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ - /sbin/$sysctl 2>/dev/null || \ - /usr/sbin/$sysctl 2>/dev/null || \ + "/sbin/$sysctl" 2>/dev/null || \ + "/usr/sbin/$sysctl" 2>/dev/null || \ echo unknown)` - case "${UNAME_MACHINE_ARCH}" in + case "$UNAME_MACHINE_ARCH" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) - arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` - endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` - machine=${arch}${endian}-unknown + arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` + machine="${arch}${endian}"-unknown ;; - *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + *) machine="$UNAME_MACHINE_ARCH"-unknown ;; esac # The Operating System including object format, if it has switched - # to ELF recently, or will in the future. - case "${UNAME_MACHINE_ARCH}" in - arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax) - eval $set_cc_for_build + # to ELF recently (or will in the future) and ABI. + case "$UNAME_MACHINE_ARCH" in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval "$set_cc_for_build" if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then @@ -205,10 +215,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in ;; esac # Determine ABI tags. - case "${UNAME_MACHINE_ARCH}" in + case "$UNAME_MACHINE_ARCH" in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' - abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release @@ -216,39 +226,55 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. - case "${UNAME_VERSION}" in + case "$UNAME_VERSION" in Debian*) release='-gnu' ;; *) - release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}${abi}" + echo "$machine-${os}${release}${abi-}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" + exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" + exit ;; + *:MidnightBSD:*:*) + echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" exit ;; *:ekkoBSD:*:*) - echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" exit ;; *:SolidBSD:*:*) - echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" exit ;; macppc:MirBSD:*:*) - echo powerpc-unknown-mirbsd${UNAME_RELEASE} + echo powerpc-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:MirBSD:*:*) - echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" exit ;; + *:Sortix:*:*) + echo "$UNAME_MACHINE"-unknown-sortix + exit ;; + *:Redox:*:*) + echo "$UNAME_MACHINE"-unknown-redox + exit ;; + mips:OSF1:*.*) + echo mips-dec-osf1 + exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) @@ -265,63 +291,54 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "EV4.5 (21064)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "EV5 (21164)") - UNAME_MACHINE="alphaev5" ;; + UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") - UNAME_MACHINE="alphaev56" ;; + UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") - UNAME_MACHINE="alphapca56" ;; + UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") - UNAME_MACHINE="alphapca57" ;; + UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") - UNAME_MACHINE="alphaev6" ;; + UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") - UNAME_MACHINE="alphaev67" ;; + UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") - UNAME_MACHINE="alphaev69" ;; + UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") - UNAME_MACHINE="alphaev7" ;; + UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") - UNAME_MACHINE="alphaev79" ;; + UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`" # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; - Alpha\ *:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # Should we change UNAME_MACHINE based on the output of uname instead - # of the specific Alpha model? - echo alpha-pc-interix - exit ;; - 21064:Windows_NT:50:3) - echo alpha-dec-winnt3.5 - exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-amigaos + echo "$UNAME_MACHINE"-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-morphos + echo "$UNAME_MACHINE"-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition @@ -333,7 +350,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix${UNAME_RELEASE} + echo arm-acorn-riscix"$UNAME_RELEASE" exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos @@ -360,38 +377,38 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) - echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" exit ;; sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) - echo i386-pc-auroraux${UNAME_RELEASE} + echo i386-pc-auroraux"$UNAME_RELEASE" exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) - eval $set_cc_for_build - SUN_ARCH="i386" + eval "$set_cc_for_build" + SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then - SUN_ARCH="x86_64" + SUN_ARCH=x86_64 fi fi - echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in @@ -400,25 +417,25 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`" exit ;; sun3*:SunOS:*:*) - echo m68k-sun-sunos${UNAME_RELEASE} + echo m68k-sun-sunos"$UNAME_RELEASE" exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) - echo m68k-sun-sunos${UNAME_RELEASE} + echo m68k-sun-sunos"$UNAME_RELEASE" ;; sun4) - echo sparc-sun-sunos${UNAME_RELEASE} + echo sparc-sun-sunos"$UNAME_RELEASE" ;; esac exit ;; aushp:SunOS:*:*) - echo sparc-auspex-sunos${UNAME_RELEASE} + echo sparc-auspex-sunos"$UNAME_RELEASE" exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not @@ -429,44 +446,44 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint"$UNAME_RELEASE" exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint"$UNAME_RELEASE" exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint"$UNAME_RELEASE" exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} + echo m68k-milan-mint"$UNAME_RELEASE" exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} + echo m68k-hades-mint"$UNAME_RELEASE" exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} + echo m68k-unknown-mint"$UNAME_RELEASE" exit ;; m68k:machten:*:*) - echo m68k-apple-machten${UNAME_RELEASE} + echo m68k-apple-machten"$UNAME_RELEASE" exit ;; powerpc:machten:*:*) - echo powerpc-apple-machten${UNAME_RELEASE} + echo powerpc-apple-machten"$UNAME_RELEASE" exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) - echo mips-dec-ultrix${UNAME_RELEASE} + echo mips-dec-ultrix"$UNAME_RELEASE" exit ;; VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix${UNAME_RELEASE} + echo vax-dec-ultrix"$UNAME_RELEASE" exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) - echo clipper-intergraph-clix${UNAME_RELEASE} + echo clipper-intergraph-clix"$UNAME_RELEASE" exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { @@ -475,23 +492,23 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) - printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) - printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) - printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF - $CC_FOR_BUILD -o $dummy $dummy.c && - dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && - SYSTEM_NAME=`$dummy $dummyarg` && + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && + dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } - echo mips-mips-riscos${UNAME_RELEASE} + echo mips-mips-riscos"$UNAME_RELEASE" exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax @@ -517,17 +534,17 @@ EOF AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` - if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ] then - if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ - [ ${TARGET_BINARY_INTERFACE}x = x ] + if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \ + [ "$TARGET_BINARY_INTERFACE"x = x ] then - echo m88k-dg-dgux${UNAME_RELEASE} + echo m88k-dg-dgux"$UNAME_RELEASE" else - echo m88k-dg-dguxbcs${UNAME_RELEASE} + echo m88k-dg-dguxbcs"$UNAME_RELEASE" fi else - echo i586-dg-dgux${UNAME_RELEASE} + echo i586-dg-dgux"$UNAME_RELEASE" fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) @@ -544,7 +561,7 @@ EOF echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) - echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`" exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id @@ -556,14 +573,14 @@ EOF if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi - echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" #include main() @@ -574,7 +591,7 @@ EOF exit(0); } EOF - if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then echo "$SYSTEM_NAME" else @@ -588,7 +605,7 @@ EOF exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` - if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc @@ -597,18 +614,18 @@ EOF IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi - echo ${IBM_ARCH}-ibm-aix${IBM_REV} + echo "$IBM_ARCH"-ibm-aix"$IBM_REV" exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; - ibmrt:4.4BSD:*|romp-ibm:BSD:*) + ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and - echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx @@ -623,28 +640,28 @@ EOF echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - case "${UNAME_MACHINE}" in - 9000/31? ) HP_ARCH=m68000 ;; - 9000/[34]?? ) HP_ARCH=m68k ;; + HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` + case "$UNAME_MACHINE" in + 9000/31?) HP_ARCH=m68000 ;; + 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + case "$sc_cpu_version" in + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 - case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; - '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + case "$sc_kernel_bits" in + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi - if [ "${HP_ARCH}" = "" ]; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + if [ "$HP_ARCH" = "" ]; then + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include @@ -677,13 +694,13 @@ EOF exit (0); } EOF - (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac - if [ ${HP_ARCH} = "hppa2.0w" ] + if [ "$HP_ARCH" = hppa2.0w ] then - eval $set_cc_for_build + eval "$set_cc_for_build" # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler @@ -694,23 +711,23 @@ EOF # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 - if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then - HP_ARCH="hppa2.0w" + HP_ARCH=hppa2.0w else - HP_ARCH="hppa64" + HP_ARCH=hppa64 fi fi - echo ${HP_ARCH}-hp-hpux${HPUX_REV} + echo "$HP_ARCH"-hp-hpux"$HPUX_REV" exit ;; ia64:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - echo ia64-hp-hpux${HPUX_REV} + HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux"$HPUX_REV" exit ;; 3050*:HI-UX:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" #include int main () @@ -735,11 +752,11 @@ EOF exit (0); } EOF - $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; - 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) @@ -748,7 +765,7 @@ EOF *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; - hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) @@ -756,9 +773,9 @@ EOF exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then - echo ${UNAME_MACHINE}-unknown-osf1mk + echo "$UNAME_MACHINE"-unknown-osf1mk else - echo ${UNAME_MACHINE}-unknown-osf1 + echo "$UNAME_MACHINE"-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) @@ -783,127 +800,109 @@ EOF echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) - echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) - echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) - echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) - echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) - echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" exit ;; sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi${UNAME_RELEASE} + echo sparc-unknown-bsdi"$UNAME_RELEASE" exit ;; *:BSD/OS:*:*) - echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` - case ${UNAME_PROCESSOR} in + case "$UNAME_PROCESSOR" in amd64) - echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - *) - echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + UNAME_PROCESSOR=x86_64 ;; + i386) + UNAME_PROCESSOR=i586 ;; esac + echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" exit ;; i*:CYGWIN*:*) - echo ${UNAME_MACHINE}-pc-cygwin + echo "$UNAME_MACHINE"-pc-cygwin exit ;; *:MINGW64*:*) - echo ${UNAME_MACHINE}-pc-mingw64 + echo "$UNAME_MACHINE"-pc-mingw64 exit ;; *:MINGW*:*) - echo ${UNAME_MACHINE}-pc-mingw32 + echo "$UNAME_MACHINE"-pc-mingw32 exit ;; *:MSYS*:*) - echo ${UNAME_MACHINE}-pc-msys - exit ;; - i*:windows32*:*) - # uname -m includes "-pc" on this system. - echo ${UNAME_MACHINE}-mingw32 + echo "$UNAME_MACHINE"-pc-msys exit ;; i*:PW*:*) - echo ${UNAME_MACHINE}-pc-pw32 + echo "$UNAME_MACHINE"-pc-pw32 exit ;; *:Interix*:*) - case ${UNAME_MACHINE} in + case "$UNAME_MACHINE" in x86) - echo i586-pc-interix${UNAME_RELEASE} + echo i586-pc-interix"$UNAME_RELEASE" exit ;; authenticamd | genuineintel | EM64T) - echo x86_64-unknown-interix${UNAME_RELEASE} + echo x86_64-unknown-interix"$UNAME_RELEASE" exit ;; IA64) - echo ia64-unknown-interix${UNAME_RELEASE} + echo ia64-unknown-interix"$UNAME_RELEASE" exit ;; esac ;; - [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) - echo i${UNAME_MACHINE}-pc-mks - exit ;; - 8664:Windows_NT:*) - echo x86_64-pc-mks - exit ;; - i*:Windows_NT*:* | Pentium*:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we - # UNAME_MACHINE based on the output of uname instead of i386? - echo i586-pc-interix - exit ;; i*:UWIN*:*) - echo ${UNAME_MACHINE}-pc-uwin + echo "$UNAME_MACHINE"-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; - p*:CYGWIN*:*) - echo powerpcle-unknown-cygwin - exit ;; prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; *:GNU:*:*) # the GNU system - echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`" exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC" exit ;; - i*86:Minix:*:*) - echo ${UNAME_MACHINE}-pc-minix + *:Minix:*:*) + echo "$UNAME_MACHINE"-unknown-minix exit ;; aarch64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in @@ -916,58 +915,64 @@ EOF EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC="gnulibc1" ; fi - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arc:Linux:*:* | arceb:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arm*:Linux:*:*) - eval $set_cc_for_build + eval "$set_cc_for_build" if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then - echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi else - echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf fi fi exit ;; avr32*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; cris:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} + echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; crisv32:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} + echo "$UNAME_MACHINE"-axis-linux-"$LIBC" + exit ;; + e2k:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; frv:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; hexagon:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:Linux:*:*) - echo ${UNAME_MACHINE}-pc-linux-${LIBC} + echo "$UNAME_MACHINE"-pc-linux-"$LIBC" exit ;; ia64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + k1om:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m32r*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m68*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; mips:Linux:*:* | mips64:Linux:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el @@ -981,64 +986,70 @@ EOF #endif #endif EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU'`" + test "x$CPU" != x && { echo "$CPU-unknown-linux-$LIBC"; exit; } ;; + mips64el:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; openrisc*:Linux:*:*) - echo or1k-unknown-linux-${LIBC} + echo or1k-unknown-linux-"$LIBC" exit ;; or32:Linux:*:* | or1k*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; padre:Linux:*:*) - echo sparc-unknown-linux-${LIBC} + echo sparc-unknown-linux-"$LIBC" exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-${LIBC} + echo hppa64-unknown-linux-"$LIBC" exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in - PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; - PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; - *) echo hppa-unknown-linux-${LIBC} ;; + PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; + PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; + *) echo hppa-unknown-linux-"$LIBC" ;; esac exit ;; ppc64:Linux:*:*) - echo powerpc64-unknown-linux-${LIBC} + echo powerpc64-unknown-linux-"$LIBC" exit ;; ppc:Linux:*:*) - echo powerpc-unknown-linux-${LIBC} + echo powerpc-unknown-linux-"$LIBC" exit ;; ppc64le:Linux:*:*) - echo powerpc64le-unknown-linux-${LIBC} + echo powerpc64le-unknown-linux-"$LIBC" exit ;; ppcle:Linux:*:*) - echo powerpcle-unknown-linux-${LIBC} + echo powerpcle-unknown-linux-"$LIBC" + exit ;; + riscv32:Linux:*:* | riscv64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; s390:Linux:*:* | s390x:Linux:*:*) - echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" exit ;; sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sh*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; tile*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; vax:Linux:*:*) - echo ${UNAME_MACHINE}-dec-linux-${LIBC} + echo "$UNAME_MACHINE"-dec-linux-"$LIBC" exit ;; x86_64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-pc-linux-"$LIBC" exit ;; xtensa*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. @@ -1052,34 +1063,34 @@ EOF # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. - echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. - echo ${UNAME_MACHINE}-pc-os2-emx + echo "$UNAME_MACHINE"-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) - echo ${UNAME_MACHINE}-unknown-stop + echo "$UNAME_MACHINE"-unknown-stop exit ;; i*86:atheos:*:*) - echo ${UNAME_MACHINE}-unknown-atheos + echo "$UNAME_MACHINE"-unknown-atheos exit ;; i*86:syllable:*:*) - echo ${UNAME_MACHINE}-pc-syllable + echo "$UNAME_MACHINE"-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) - echo i386-unknown-lynxos${UNAME_RELEASE} + echo i386-unknown-lynxos"$UNAME_RELEASE" exit ;; i*86:*DOS:*:*) - echo ${UNAME_MACHINE}-pc-msdosdjgpp + echo "$UNAME_MACHINE"-pc-msdosdjgpp exit ;; - i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) - UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + i*86:*:4.*:*) + UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" else - echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" fi exit ;; i*86:*:5:[678]*) @@ -1089,12 +1100,12 @@ EOF *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac - echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}{$UNAME_VERSION}" exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 @@ -1104,9 +1115,9 @@ EOF && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 - echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" else - echo ${UNAME_MACHINE}-pc-sysv32 + echo "$UNAME_MACHINE"-pc-sysv32 fi exit ;; pc:*:*:*) @@ -1114,7 +1125,7 @@ EOF # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub - # prints for the "djgpp" host, or else GDB configury will decide that + # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; @@ -1126,9 +1137,9 @@ EOF exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) @@ -1148,9 +1159,9 @@ EOF test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; @@ -1159,28 +1170,28 @@ EOF test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - echo m68k-unknown-lynxos${UNAME_RELEASE} + echo m68k-unknown-lynxos"$UNAME_RELEASE" exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos${UNAME_RELEASE} + echo sparc-unknown-lynxos"$UNAME_RELEASE" exit ;; rs6000:LynxOS:2.*:*) - echo rs6000-unknown-lynxos${UNAME_RELEASE} + echo rs6000-unknown-lynxos"$UNAME_RELEASE" exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) - echo powerpc-unknown-lynxos${UNAME_RELEASE} + echo powerpc-unknown-lynxos"$UNAME_RELEASE" exit ;; SM[BE]S:UNIX_SV:*:*) - echo mips-dde-sysv${UNAME_RELEASE} + echo mips-dde-sysv"$UNAME_RELEASE" exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 @@ -1191,7 +1202,7 @@ EOF *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` - echo ${UNAME_MACHINE}-sni-sysv4 + echo "$UNAME_MACHINE"-sni-sysv4 else echo ns32k-sni-sysv fi @@ -1211,23 +1222,23 @@ EOF exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. - echo ${UNAME_MACHINE}-stratus-vos + echo "$UNAME_MACHINE"-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) - echo m68k-apple-aux${UNAME_RELEASE} + echo m68k-apple-aux"$UNAME_RELEASE" exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} + echo mips-nec-sysv"$UNAME_RELEASE" else - echo mips-unknown-sysv${UNAME_RELEASE} + echo mips-unknown-sysv"$UNAME_RELEASE" fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. @@ -1246,46 +1257,56 @@ EOF echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) - echo sx4-nec-superux${UNAME_RELEASE} + echo sx4-nec-superux"$UNAME_RELEASE" exit ;; SX-5:SUPER-UX:*:*) - echo sx5-nec-superux${UNAME_RELEASE} + echo sx5-nec-superux"$UNAME_RELEASE" exit ;; SX-6:SUPER-UX:*:*) - echo sx6-nec-superux${UNAME_RELEASE} + echo sx6-nec-superux"$UNAME_RELEASE" exit ;; SX-7:SUPER-UX:*:*) - echo sx7-nec-superux${UNAME_RELEASE} + echo sx7-nec-superux"$UNAME_RELEASE" exit ;; SX-8:SUPER-UX:*:*) - echo sx8-nec-superux${UNAME_RELEASE} + echo sx8-nec-superux"$UNAME_RELEASE" exit ;; SX-8R:SUPER-UX:*:*) - echo sx8r-nec-superux${UNAME_RELEASE} + echo sx8r-nec-superux"$UNAME_RELEASE" + exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux"$UNAME_RELEASE" exit ;; Power*:Rhapsody:*:*) - echo powerpc-apple-rhapsody${UNAME_RELEASE} + echo powerpc-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Rhapsody:*:*) - echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - eval $set_cc_for_build + eval "$set_cc_for_build" if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi - if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi + # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc + if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_PPC >/dev/null + then + UNAME_PROCESSOR=powerpc + fi fi elif test "$UNAME_PROCESSOR" = i386 ; then # Avoid executing cc on OS X 10.9, as it ships with a stub @@ -1296,27 +1317,33 @@ EOF # that Apple uses in portable devices. UNAME_PROCESSOR=x86_64 fi - echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` - if test "$UNAME_PROCESSOR" = "x86"; then + if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi - echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; - NEO-?:NONSTOP_KERNEL:*:*) - echo neo-tandem-nsk${UNAME_RELEASE} + NEO-*:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk"$UNAME_RELEASE" exit ;; NSE-*:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk${UNAME_RELEASE} + echo nse-tandem-nsk"$UNAME_RELEASE" exit ;; - NSR-?:NONSTOP_KERNEL:*:*) - echo nsr-tandem-nsk${UNAME_RELEASE} + NSR-*:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSV-*:NONSTOP_KERNEL:*:*) + echo nsv-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSX-*:NONSTOP_KERNEL:*:*) + echo nsx-tandem-nsk"$UNAME_RELEASE" exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux @@ -1325,18 +1352,18 @@ EOF echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) - echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. - if test "$cputype" = "386"; then + if test "$cputype" = 386; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi - echo ${UNAME_MACHINE}-unknown-plan9 + echo "$UNAME_MACHINE"-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 @@ -1357,14 +1384,14 @@ EOF echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) - echo mips-sei-seiux${UNAME_RELEASE} + echo mips-sei-seiux"$UNAME_RELEASE" exit ;; *:DragonFly:*:*) - echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` - case "${UNAME_MACHINE}" in + case "$UNAME_MACHINE" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; @@ -1373,34 +1400,48 @@ EOF echo i386-pc-xenix exit ;; i*86:skyos:*:*) - echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`" exit ;; i*86:rdos:*:*) - echo ${UNAME_MACHINE}-pc-rdos + echo "$UNAME_MACHINE"-pc-rdos exit ;; i*86:AROS:*:*) - echo ${UNAME_MACHINE}-pc-aros + echo "$UNAME_MACHINE"-pc-aros exit ;; x86_64:VMkernel:*:*) - echo ${UNAME_MACHINE}-unknown-esx + echo "$UNAME_MACHINE"-unknown-esx + exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs exit ;; esac +echo "$0: unable to guess system type" >&2 + +case "$UNAME_MACHINE:$UNAME_SYSTEM" in + mips:Linux | mips64:Linux) + # If we got here on MIPS GNU/Linux, output extra information. + cat >&2 <&2 < in order to provide the needed -information to handle your system. +If $0 has already been updated, send the following data and any +information you think might be pertinent to config-patches@gnu.org to +provide the necessary information to handle your system. config.guess timestamp = $timestamp @@ -1419,16 +1460,16 @@ hostinfo = `(hostinfo) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` -UNAME_MACHINE = ${UNAME_MACHINE} -UNAME_RELEASE = ${UNAME_RELEASE} -UNAME_SYSTEM = ${UNAME_SYSTEM} -UNAME_VERSION = ${UNAME_VERSION} +UNAME_MACHINE = "$UNAME_MACHINE" +UNAME_RELEASE = "$UNAME_RELEASE" +UNAME_SYSTEM = "$UNAME_SYSTEM" +UNAME_VERSION = "$UNAME_VERSION" EOF exit 1 # Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" diff --git a/config.h.in b/config.h.in index b1a20a44131c..94db7bbc4177 100644 --- a/config.h.in +++ b/config.h.in @@ -15,6 +15,9 @@ /* define if we have the AIX getprotobyname_r() */ #undef HAVE_AIX_GETPROTOBYNAME_R +/* Define to 1 if you have the `asprintf' function. */ +#undef HAVE_ASPRINTF + /* Define to 1 if you have the header file. */ #undef HAVE_DAGAPI_H @@ -54,6 +57,9 @@ /* Define to 1 if you have the `getspnam' function. */ #undef HAVE_GETSPNAM +/* Define to 1 if you have a GNU-style `strerror_r' function. */ +#undef HAVE_GNU_STRERROR_R + /* on HP-UX 10.20 or later */ #undef HAVE_HPUX10_20_OR_LATER @@ -150,6 +156,9 @@ /* define if net/pfvar.h defines PF_NAT through PF_NORDR */ #undef HAVE_PF_NAT_THROUGH_PF_NORDR +/* Define to 1 if you have a POSIX-style `strerror_r' function. */ +#undef HAVE_POSIX_STRERROR_R + /* define if you have the Septel API */ #undef HAVE_SEPTEL_API @@ -180,9 +189,6 @@ /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR -/* Define to 1 if you have the `strerror_r' function. */ -#undef HAVE_STRERROR_R - /* Define to 1 if you have the `strerror_s' function. */ #undef HAVE_STRERROR_S @@ -262,9 +268,15 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have the `vasprintf' function. */ +#undef HAVE_VASPRINTF + /* Define to 1 if you have the `vsnprintf' function. */ #undef HAVE_VSNPRINTF +/* Define to 1 if you have the `vsyslog' function. */ +#undef HAVE_VSYSLOG + /* IPv6 */ #undef INET6 diff --git a/config.sub b/config.sub index bc855a2a910e..c95acc681d1b 100755 --- a/config.sub +++ b/config.sub @@ -1,8 +1,8 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2015 Free Software Foundation, Inc. +# Copyright 1992-2018 Free Software Foundation, Inc. -timestamp='2015-02-22' +timestamp='2018-07-03' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -15,7 +15,7 @@ timestamp='2015-02-22' # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, see . +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -33,7 +33,7 @@ timestamp='2015-02-22' # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases @@ -53,12 +53,11 @@ timestamp='2015-02-22' me=`echo "$0" | sed -e 's,.*/,,'` usage="\ -Usage: $0 [OPTION] CPU-MFR-OPSYS - $0 [OPTION] ALIAS +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. -Operation modes: +Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit @@ -68,7 +67,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2015 Free Software Foundation, Inc. +Copyright 1992-2018 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." @@ -95,7 +94,7 @@ while test $# -gt 0 ; do *local*) # First pass through any local machine types. - echo $1 + echo "$1" exit ;; * ) @@ -111,134 +110,455 @@ case $# in exit 1;; esac -# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). -# Here we must recognize all the valid KERNEL-OS combinations. -maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` -case $maybe_os in - nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ - linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ - knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ - kopensolaris*-gnu* | \ - storm-chaos* | os2-emx* | rtmk-nova*) - os=-$maybe_os - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` - ;; - android-linux) - os=-linux-android - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown - ;; - *) - basic_machine=`echo $1 | sed 's/-[^-]*$//'` - if [ $basic_machine != $1 ] - then os=`echo $1 | sed 's/.*-/-/'` - else os=; fi - ;; -esac +# Split fields of configuration type +IFS="-" read -r field1 field2 field3 field4 <&2 + exit 1 ;; - -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ - -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ - -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ - -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ - -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ - -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple | -axis | -knuth | -cray | -microblaze*) - os= - basic_machine=$1 + *-*-*-*) + basic_machine=$field1-$field2 + os=$field3-$field4 ;; - -bluegene*) - os=-cnk + *-*-*) + # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two + # parts + maybe_os=$field2-$field3 + case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc \ + | linux-newlib* | linux-musl* | linux-uclibc* | uclinux-uclibc* \ + | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ + | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ + | storm-chaos* | os2-emx* | rtmk-nova*) + basic_machine=$field1 + os=$maybe_os + ;; + android-linux) + basic_machine=$field1-unknown + os=linux-android + ;; + *) + basic_machine=$field1-$field2 + os=$field3 + ;; + esac ;; - -sim | -cisco | -oki | -wec | -winbond) - os= - basic_machine=$1 + *-*) + # Second component is usually, but not always the OS + case $field2 in + # Prevent following clause from handling this valid os + sun*os*) + basic_machine=$field1 + os=$field2 + ;; + # Manufacturers + dec* | mips* | sequent* | encore* | pc532* | sgi* | sony* \ + | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ + | unicom* | ibm* | next | hp | isi* | apollo | altos* \ + | convergent* | ncr* | news | 32* | 3600* | 3100* | hitachi* \ + | c[123]* | convex* | sun | crds | omron* | dg | ultra | tti* \ + | harris | dolphin | highlevel | gould | cbm | ns | masscomp \ + | apple | axis | knuth | cray | microblaze* \ + | sim | cisco | oki | wec | wrs | winbond) + basic_machine=$field1-$field2 + os= + ;; + *) + basic_machine=$field1 + os=$field2 + ;; + esac ;; - -scout) - ;; - -wrs) - os=-vxworks - basic_machine=$1 - ;; - -chorusos*) - os=-chorusos - basic_machine=$1 - ;; - -chorusrdb) - os=-chorusrdb - basic_machine=$1 - ;; - -hiux*) - os=-hiuxwe2 - ;; - -sco6) - os=-sco5v6 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco5) - os=-sco3.2v5 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco4) - os=-sco3.2v4 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2.[4-9]*) - os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2v[4-9]*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco5v6*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco*) - os=-sco3.2v2 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -udk*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -isc) - os=-isc2.2 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -clix*) - basic_machine=clipper-intergraph - ;; - -isc*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -lynx*178) - os=-lynxos178 - ;; - -lynx*5) - os=-lynxos5 - ;; - -lynx*) - os=-lynxos - ;; - -ptx*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` - ;; - -windowsnt*) - os=`echo $os | sed -e 's/windowsnt/winnt/'` - ;; - -psos*) - os=-psos - ;; - -mint | -mint[0-9]*) - basic_machine=m68k-atari - os=-mint + *) + # Convert single-component short-hands not valid as part of + # multi-component configurations. + case $field1 in + 386bsd) + basic_machine=i386-pc + os=bsd + ;; + a29khif) + basic_machine=a29k-amd + os=udi + ;; + adobe68k) + basic_machine=m68010-adobe + os=scout + ;; + am29k) + basic_machine=a29k-none + os=bsd + ;; + amdahl) + basic_machine=580-amdahl + os=sysv + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=bsd + ;; + aros) + basic_machine=i386-pc + os=aros + ;; + aux) + basic_machine=m68k-apple + os=aux + ;; + balance) + basic_machine=ns32k-sequent + os=dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=linux + ;; + cegcc) + basic_machine=arm-unknown + os=cegcc + ;; + cray) + basic_machine=j90-cray + os=unicos + ;; + craynv) + basic_machine=craynv-cray + os=unicosmp + ;; + delta88) + basic_machine=m88k-motorola + os=sysv3 + ;; + dicos) + basic_machine=i686-pc + os=dicos + ;; + djgpp) + basic_machine=i586-pc + os=msdosdjgpp + ;; + ebmon29k) + basic_machine=a29k-amd + os=ebmon + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=ose + ;; + gmicro) + basic_machine=tron-gmicro + os=sysv + ;; + go32) + basic_machine=i386-pc + os=go32 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=hms + ;; + harris) + basic_machine=m88k-harris + os=sysv3 + ;; + hp300bsd) + basic_machine=m68k-hp + os=bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=hpux + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=proelf + ;; + i386mach) + basic_machine=i386-mach + os=mach + ;; + vsta) + basic_machine=i386-unknown + os=vsta + ;; + isi68 | isi) + basic_machine=m68k-isi + os=sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=linux + ;; + magnum | m3230) + basic_machine=mips-mips + os=sysv + ;; + merlin) + basic_machine=ns32k-utek + os=sysv + ;; + mingw64) + basic_machine=x86_64-pc + os=mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=mingw32ce + ;; + monitor) + basic_machine=m68k-rom68k + os=coff + ;; + morphos) + basic_machine=powerpc-unknown + os=morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=moxiebox + ;; + msdos) + basic_machine=i386-pc + os=msdos + ;; + msys) + basic_machine=i686-pc + os=msys + ;; + mvs) + basic_machine=i370-ibm + os=mvs + ;; + nacl) + basic_machine=le32-unknown + os=nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=newsos + ;; + news1000) + basic_machine=m68030-sony + os=newsos + ;; + necv70) + basic_machine=v70-nec + os=sysv + ;; + nh3000) + basic_machine=m68k-harris + os=cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=cxux + ;; + nindy960) + basic_machine=i960-intel + os=nindy + ;; + mon960) + basic_machine=i960-intel + os=mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=nonstopux + ;; + os400) + basic_machine=powerpc-ibm + os=os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=ose + ;; + os68k) + basic_machine=m68k-none + os=os68k + ;; + paragon) + basic_machine=i860-intel + os=osf + ;; + parisc) + basic_machine=hppa-unknown + os=linux + ;; + pw32) + basic_machine=i586-unknown + os=pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=rdos + ;; + rdos32) + basic_machine=i386-pc + os=rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=coff + ;; + sa29200) + basic_machine=a29k-amd + os=udi + ;; + sei) + basic_machine=mips-sei + os=seiux + ;; + sps7) + basic_machine=m68k-bull + os=sysv2 + ;; + stratus) + basic_machine=i860-stratus + os=sysv4 + ;; + sun2os3) + basic_machine=m68000-sun + os=sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=solaris2 + ;; + sv1) + basic_machine=sv1-cray + os=unicos + ;; + symmetry) + basic_machine=i386-sequent + os=dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=unicos + ;; + t90) + basic_machine=t90-cray + os=unicos + ;; + toad1) + basic_machine=pdp10-xkl + os=tops20 + ;; + tpf) + basic_machine=s390x-ibm + os=tpf + ;; + udi29k) + basic_machine=a29k-amd + os=udi + ;; + ultra3) + basic_machine=a29k-nyu + os=sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=none + ;; + vaxv) + basic_machine=vax-dec + os=sysv + ;; + vms) + basic_machine=vax-dec + os=vms + ;; + vxworks960) + basic_machine=i960-wrs + os=vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=vxworks + ;; + xbox) + basic_machine=i686-pc + os=mingw32 + ;; + ymp) + basic_machine=ymp-cray + os=unicos + ;; + *) + basic_machine=$1 + os= + ;; + esac ;; esac @@ -253,17 +573,18 @@ case $basic_machine in | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ - | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv6m | armv[78][arm] \ | avr | avr32 \ + | ba \ | be32 | be64 \ | bfin \ - | c4x | c8051 | clipper \ + | c4x | c8051 | clipper | csky \ | d10v | d30v | dlx | dsp16xx \ - | epiphany \ + | e2k | epiphany \ | fido | fr30 | frv | ft32 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ - | i370 | i860 | i960 | ia64 \ + | i370 | i860 | i960 | ia16 | ia64 \ | ip2k | iq2000 \ | k1om \ | le32 | le64 \ @@ -296,16 +617,18 @@ case $basic_machine in | mt \ | msp430 \ | nds32 | nds32le | nds32be \ + | nfp \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 | or1k | or1knd | or32 \ - | pdp10 | pdp11 | pj | pjl \ + | pdp10 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pru \ | pyramid \ - | riscv32 | riscv64 \ + | riscv | riscv32 | riscv64 \ | rl78 | rx \ | score \ - | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ @@ -314,7 +637,7 @@ case $basic_machine in | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | visium \ - | we32k \ + | wasm32 \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown @@ -333,20 +656,23 @@ case $basic_machine in ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown - os=-none + os=${os:-none} ;; - m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65) + ;; + m9s12z | m68hcs12z | hcs12z | s12z) + basic_machine=s12z-unknown + os=${os:-none} ;; ms1) basic_machine=mt-unknown ;; - strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown - os=-none + os=${os:-none} ;; xscaleeb) basic_machine=armeb-unknown @@ -362,11 +688,6 @@ case $basic_machine in i*86 | x86_64) basic_machine=$basic_machine-pc ;; - # Object if more than one company name word. - *-*-*) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ @@ -376,17 +697,18 @@ case $basic_machine in | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ + | ba-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ - | c8051-* | clipper-* | craynv-* | cydra-* \ + | c8051-* | clipper-* | craynv-* | csky-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ - | elxsi-* \ + | e2k-* | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ - | i*86-* | i860-* | i960-* | ia64-* \ + | i*86-* | i860-* | i960-* | ia16-* | ia64-* \ | ip2k-* | iq2000-* \ | k1om-* \ | le32-* | le64-* \ @@ -420,6 +742,7 @@ case $basic_machine in | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ + | nfp-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ @@ -427,13 +750,15 @@ case $basic_machine in | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pru-* \ | pyramid-* \ + | riscv-* | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ @@ -442,6 +767,7 @@ case $basic_machine in | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | visium-* \ + | wasm32-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ @@ -454,138 +780,77 @@ case $basic_machine in ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. - 386bsd) - basic_machine=i386-unknown - os=-bsd - ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; - a29khif) - basic_machine=a29k-amd - os=-udi - ;; abacus) basic_machine=abacus-unknown ;; - adobe68k) - basic_machine=m68010-adobe - os=-scout - ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; - am29k) - basic_machine=a29k-none - os=-bsd - ;; amd64) basic_machine=x86_64-pc ;; amd64-*) - basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - amdahl) - basic_machine=580-amdahl - os=-sysv + basic_machine=x86_64-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; amiga | amiga-*) basic_machine=m68k-unknown ;; - amigaos | amigados) - basic_machine=m68k-unknown - os=-amigaos - ;; - amigaunix | amix) - basic_machine=m68k-unknown - os=-sysv4 - ;; - apollo68) - basic_machine=m68k-apollo - os=-sysv - ;; - apollo68bsd) - basic_machine=m68k-apollo - os=-bsd - ;; - aros) - basic_machine=i386-pc - os=-aros - ;; - aux) - basic_machine=m68k-apple - os=-aux - ;; - balance) - basic_machine=ns32k-sequent - os=-dynix - ;; - blackfin) - basic_machine=bfin-unknown - os=-linux + asmjs) + basic_machine=asmjs-unknown ;; blackfin-*) - basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux + basic_machine=bfin-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=linux ;; bluegene*) basic_machine=powerpc-ibm - os=-cnk + os=cnk ;; c54x-*) - basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=tic54x-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; c55x-*) - basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=tic55x-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; c6x-*) - basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=tic6x-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray - os=-unicos - ;; - cegcc) - basic_machine=arm-unknown - os=-cegcc + os=${os:-unicos} ;; convex-c1) basic_machine=c1-convex - os=-bsd + os=bsd ;; convex-c2) basic_machine=c2-convex - os=-bsd + os=bsd ;; convex-c32) basic_machine=c32-convex - os=-bsd + os=bsd ;; convex-c34) basic_machine=c34-convex - os=-bsd + os=bsd ;; convex-c38) basic_machine=c38-convex - os=-bsd - ;; - cray | j90) - basic_machine=j90-cray - os=-unicos - ;; - craynv) - basic_machine=craynv-cray - os=-unicosmp + os=bsd ;; cr16 | cr16-*) basic_machine=cr16-unknown - os=-elf + os=${os:-elf} ;; crds | unos) basic_machine=m68k-crds @@ -598,7 +863,7 @@ case $basic_machine in ;; crx) basic_machine=crx-unknown - os=-elf + os=${os:-elf} ;; da30 | da30-*) basic_machine=m68k-da30 @@ -608,50 +873,38 @@ case $basic_machine in ;; decsystem10* | dec10*) basic_machine=pdp10-dec - os=-tops10 + os=tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec - os=-tops20 + os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; - delta88) - basic_machine=m88k-motorola - os=-sysv3 - ;; - dicos) - basic_machine=i686-pc - os=-dicos - ;; - djgpp) - basic_machine=i586-pc - os=-msdosdjgpp - ;; dpx20 | dpx20-*) basic_machine=rs6000-bull - os=-bosx + os=${os:-bosx} ;; - dpx2* | dpx2*-bull) + dpx2*) basic_machine=m68k-bull - os=-sysv3 + os=sysv3 ;; - ebmon29k) - basic_machine=a29k-amd - os=-ebmon + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" ;; - elxsi) - basic_machine=elxsi-elxsi - os=-bsd + e500v[12]-*) + basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=$os"spe" ;; encore | umax | mmax) basic_machine=ns32k-encore ;; - es1800 | OSE68k | ose68k | ose | OSE) - basic_machine=m68k-ericsson - os=-ose + elxsi) + basic_machine=elxsi-elxsi + os=${os:-bsd} ;; fx2800) basic_machine=i860-alliant @@ -659,45 +912,13 @@ case $basic_machine in genix) basic_machine=ns32k-ns ;; - gmicro) - basic_machine=tron-gmicro - os=-sysv - ;; - go32) - basic_machine=i386-pc - os=-go32 - ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - h8300hms) - basic_machine=h8300-hitachi - os=-hms - ;; - h8300xray) - basic_machine=h8300-hitachi - os=-xray - ;; - h8500hms) - basic_machine=h8500-hitachi - os=-hms - ;; - harris) - basic_machine=m88k-harris - os=-sysv3 + os=hiuxwe2 ;; hp300-*) basic_machine=m68k-hp ;; - hp300bsd) - basic_machine=m68k-hp - os=-bsd - ;; - hp300hpux) - basic_machine=m68k-hp - os=-hpux - ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; @@ -727,200 +948,82 @@ case $basic_machine in hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; - hppa-next) - os=-nextstep3 - ;; - hppaosf) - basic_machine=hppa1.1-hp - os=-osf - ;; - hppro) - basic_machine=hppa1.1-hp - os=-proelf - ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv32 + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=sysv32 ;; i*86v4*) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv4 + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=sysv4 ;; i*86v) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=sysv ;; i*86sol2) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-solaris2 + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=solaris2 ;; - i386mach) - basic_machine=i386-mach - os=-mach - ;; - i386-vsta | vsta) - basic_machine=i386-unknown - os=-vsta + j90 | j90-cray) + basic_machine=j90-cray + os=${os:-unicos} ;; iris | iris4d) basic_machine=mips-sgi case $os in - -irix*) + irix*) ;; *) - os=-irix4 + os=irix4 ;; esac ;; - isi68 | isi) - basic_machine=m68k-isi - os=-sysv - ;; leon-*|leon[3-9]-*) - basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` - ;; - m68knommu) - basic_machine=m68k-unknown - os=-linux + basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'` ;; m68knommu-*) - basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - m88k-omron*) - basic_machine=m88k-omron - ;; - magnum | m3230) - basic_machine=mips-mips - os=-sysv - ;; - merlin) - basic_machine=ns32k-utek - os=-sysv + basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=linux ;; microblaze*) basic_machine=microblaze-xilinx ;; - mingw64) - basic_machine=x86_64-pc - os=-mingw64 - ;; - mingw32) - basic_machine=i686-pc - os=-mingw32 - ;; - mingw32ce) - basic_machine=arm-unknown - os=-mingw32ce - ;; miniframe) basic_machine=m68000-convergent ;; - *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari - os=-mint + os=mint ;; mips3*-*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'` ;; mips3*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown - ;; - monitor) - basic_machine=m68k-rom68k - os=-coff - ;; - morphos) - basic_machine=powerpc-unknown - os=-morphos - ;; - moxiebox) - basic_machine=moxie-unknown - os=-moxiebox - ;; - msdos) - basic_machine=i386-pc - os=-msdos + basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`-unknown ;; ms1-*) - basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` - ;; - msys) - basic_machine=i686-pc - os=-msys - ;; - mvs) - basic_machine=i370-ibm - os=-mvs - ;; - nacl) - basic_machine=le32-unknown - os=-nacl - ;; - ncr3000) - basic_machine=i486-ncr - os=-sysv4 - ;; - netbsd386) - basic_machine=i386-unknown - os=-netbsd - ;; - netwinder) - basic_machine=armv4l-rebel - os=-linux - ;; - news | news700 | news800 | news900) - basic_machine=m68k-sony - os=-newsos - ;; - news1000) - basic_machine=m68030-sony - os=-newsos + basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'` ;; news-3600 | risc-news) basic_machine=mips-sony - os=-newsos + os=newsos ;; - necv70) - basic_machine=v70-nec - os=-sysv - ;; - next | m*-next ) + next | m*-next) basic_machine=m68k-next case $os in - -nextstep* ) + nextstep* ) ;; - -ns2*) - os=-nextstep2 + ns2*) + os=nextstep2 ;; *) - os=-nextstep3 + os=nextstep3 ;; esac ;; - nh3000) - basic_machine=m68k-harris - os=-cxux - ;; - nh[45]000) - basic_machine=m88k-harris - os=-cxux - ;; - nindy960) - basic_machine=i960-intel - os=-nindy - ;; - mon960) - basic_machine=i960-intel - os=-mon960 - ;; - nonstopux) - basic_machine=mips-compaq - os=-nonstopux - ;; np1) basic_machine=np1-gould ;; @@ -933,40 +1036,26 @@ case $basic_machine in nsr-tandem) basic_machine=nsr-tandem ;; + nsv-tandem) + basic_machine=nsv-tandem + ;; + nsx-tandem) + basic_machine=nsx-tandem + ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki - os=-proelf + os=proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; - os400) - basic_machine=powerpc-ibm - os=-os400 - ;; - OSE68000 | ose68000) - basic_machine=m68000-ericsson - os=-ose - ;; - os68k) - basic_machine=m68k-none - os=-os68k - ;; pa-hitachi) basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - paragon) - basic_machine=i860-intel - os=-osf - ;; - parisc) - basic_machine=hppa-unknown - os=-linux + os=hiuxwe2 ;; parisc-*) - basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux + basic_machine=hppa-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=linux ;; pbd) basic_machine=sparc-tti @@ -981,7 +1070,7 @@ case $basic_machine in basic_machine=i386-pc ;; pc98-*) - basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=i386-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc @@ -996,16 +1085,16 @@ case $basic_machine in basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) - basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=i586-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentium4-*) - basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=i786-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould @@ -1015,43 +1104,27 @@ case $basic_machine in ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) - basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; - ppcle | powerpclittle | ppc-le | powerpc-little) + ppcle | powerpclittle) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) - basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=powerpcle-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; - ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ppc64-*) basic_machine=powerpc64-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; - ppc64le | powerpc64little | ppc64-le | powerpc64-little) + ppc64le | powerpc64little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) - basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=powerpc64le-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; - pw32) - basic_machine=i586-unknown - os=-pw32 - ;; - rdos | rdos64) - basic_machine=x86_64-pc - os=-rdos - ;; - rdos32) - basic_machine=i386-pc - os=-rdos - ;; - rom68k) - basic_machine=m68k-rom68k - os=-coff - ;; rm[46]00) basic_machine=mips-siemens ;; @@ -1064,10 +1137,6 @@ case $basic_machine in s390x | s390x-*) basic_machine=s390x-ibm ;; - sa29200) - basic_machine=a29k-amd - os=-udi - ;; sb1) basic_machine=mipsisa64sb1-unknown ;; @@ -1076,32 +1145,17 @@ case $basic_machine in ;; sde) basic_machine=mipsisa32-sde - os=-elf - ;; - sei) - basic_machine=mips-sei - os=-seiux + os=${os:-elf} ;; sequent) basic_machine=i386-sequent ;; - sh) - basic_machine=sh-hitachi - os=-hms - ;; sh5el) basic_machine=sh5le-unknown ;; - sh64) - basic_machine=sh64-unknown - ;; - sparclite-wrs | simso-wrs) + simso-wrs) basic_machine=sparclite-wrs - os=-vxworks - ;; - sps7) - basic_machine=m68k-bull - os=-sysv2 + os=vxworks ;; spur) basic_machine=spur-unknown @@ -1109,44 +1163,12 @@ case $basic_machine in st2000) basic_machine=m68k-tandem ;; - stratus) - basic_machine=i860-stratus - os=-sysv4 - ;; strongarm-* | thumb-*) - basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=arm-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; - sun2os3) - basic_machine=m68000-sun - os=-sunos3 - ;; - sun2os4) - basic_machine=m68000-sun - os=-sunos4 - ;; - sun3os3) - basic_machine=m68k-sun - os=-sunos3 - ;; - sun3os4) - basic_machine=m68k-sun - os=-sunos4 - ;; - sun4os3) - basic_machine=sparc-sun - os=-sunos3 - ;; - sun4os4) - basic_machine=sparc-sun - os=-sunos4 - ;; - sun4sol2) - basic_machine=sparc-sun - os=-solaris2 - ;; sun3 | sun3-*) basic_machine=m68k-sun ;; @@ -1156,25 +1178,9 @@ case $basic_machine in sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; - sv1) - basic_machine=sv1-cray - os=-unicos - ;; - symmetry) - basic_machine=i386-sequent - os=-dynix - ;; - t3e) - basic_machine=alphaev5-cray - os=-unicos - ;; - t90) - basic_machine=t90-cray - os=-unicos - ;; tile*) basic_machine=$basic_machine-unknown - os=-linux-gnu + os=linux-gnu ;; tx39) basic_machine=mipstx39-unknown @@ -1182,85 +1188,32 @@ case $basic_machine in tx39el) basic_machine=mipstx39el-unknown ;; - toad1) - basic_machine=pdp10-xkl - os=-tops20 - ;; tower | tower-32) basic_machine=m68k-ncr ;; - tpf) - basic_machine=s390x-ibm - os=-tpf - ;; - udi29k) - basic_machine=a29k-amd - os=-udi - ;; - ultra3) - basic_machine=a29k-nyu - os=-sym1 - ;; - v810 | necv810) - basic_machine=v810-nec - os=-none - ;; - vaxv) - basic_machine=vax-dec - os=-sysv - ;; - vms) - basic_machine=vax-dec - os=-vms - ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; - vxworks960) - basic_machine=i960-wrs - os=-vxworks - ;; - vxworks68) - basic_machine=m68k-wrs - os=-vxworks - ;; - vxworks29k) - basic_machine=a29k-wrs - os=-vxworks - ;; w65*) basic_machine=w65-wdc - os=-none + os=none ;; w89k-*) basic_machine=hppa1.1-winbond - os=-proelf + os=proelf ;; - xbox) - basic_machine=i686-pc - os=-mingw32 + x64) + basic_machine=x86_64-pc ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) - basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` - ;; - ymp) - basic_machine=ymp-cray - os=-unicos - ;; - z8k-*-coff) - basic_machine=z8k-unknown - os=-sim - ;; - z80-*-coff) - basic_machine=z80-unknown - os=-sim + basic_machine=`echo "$basic_machine" | sed 's/^xscale/arm/'` ;; none) basic_machine=none-none - os=-none + os=${os:-none} ;; # Here we handle the default manufacturer of certain CPU types. It is in @@ -1286,10 +1239,6 @@ case $basic_machine in vax) basic_machine=vax-dec ;; - pdp10) - # there are many clones, so DEC is not a safe bet - basic_machine=pdp10-unknown - ;; pdp11) basic_machine=pdp11-dec ;; @@ -1299,9 +1248,6 @@ case $basic_machine in sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; - sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) - basic_machine=sparc-sun - ;; cydra) basic_machine=cydra-cydrome ;; @@ -1321,7 +1267,7 @@ case $basic_machine in # Make sure to match an already-canonicalized machine name. ;; *) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2 exit 1 ;; esac @@ -1329,10 +1275,10 @@ esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) - basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + basic_machine=`echo "$basic_machine" | sed 's/digital.*/dec/'` ;; *-commodore*) - basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + basic_machine=`echo "$basic_machine" | sed 's/commodore.*/cbm/'` ;; *) ;; @@ -1340,197 +1286,246 @@ esac # Decode manufacturer-specific aliases for certain operating systems. -if [ x"$os" != x"" ] +if [ x$os != x ] then case $os in - # First match some system type aliases - # that might get confused with valid system types. - # -solaris* is a basic system type, with this one exception. - -auroraux) - os=-auroraux + # First match some system type aliases that might get confused + # with valid system types. + # solaris* is a basic system type, with this one exception. + auroraux) + os=auroraux ;; - -solaris1 | -solaris1.*) + bluegene*) + os=cnk + ;; + solaris1 | solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; - -solaris) - os=-solaris2 + solaris) + os=solaris2 ;; - -svr4*) - os=-sysv4 + unixware*) + os=sysv4.2uw ;; - -unixware*) - os=-sysv4.2uw - ;; - -gnu/linux*) + gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; - # First accept the basic system types. + # es1800 is here to avoid being matched by es* (a different OS) + es1800*) + os=ose + ;; + # Some version numbers need modification + chorusos*) + os=chorusos + ;; + isc) + os=isc2.2 + ;; + sco6) + os=sco5v6 + ;; + sco5) + os=sco3.2v5 + ;; + sco4) + os=sco3.2v4 + ;; + sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + ;; + sco3.2v[4-9]* | sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + ;; + scout) + # Don't match below + ;; + sco*) + os=sco3.2v2 + ;; + psos*) + os=psos + ;; + # Now accept the basic system types. # The portable systems comes first. - # Each alternative MUST END IN A *, to match a version number. - # -sysv* is not here because it comes later, after sysvr4. - -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ - | -sym* | -kopensolaris* | -plan9* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -bitrig* | -openbsd* | -solidbsd* \ - | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ - | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ - | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ - | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -chorusos* | -chorusrdb* | -cegcc* \ - | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ - | -linux-newlib* | -linux-musl* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ - | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ - | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ - | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ - | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ - | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ - | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) + # Each alternative MUST end in a * to match a version number. + # sysv* is not here because it comes later, after sysvr4. + gnu* | bsd* | mach* | minix* | genix* | ultrix* | irix* \ + | *vms* | esix* | aix* | cnk* | sunos | sunos[34]*\ + | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ + | sym* | kopensolaris* | plan9* \ + | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ + | aos* | aros* | cloudabi* | sortix* \ + | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \ + | clix* | riscos* | uniplus* | iris* | rtu* | xenix* \ + | knetbsd* | mirbsd* | netbsd* \ + | bitrig* | openbsd* | solidbsd* | libertybsd* \ + | ekkobsd* | kfreebsd* | freebsd* | riscix* | lynxos* \ + | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ + | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ + | udi* | eabi* | lites* | ieee* | go32* | aux* | hcos* \ + | chorusrdb* | cegcc* | glidix* \ + | cygwin* | msys* | pe* | moss* | proelf* | rtems* \ + | midipix* | mingw32* | mingw64* | linux-gnu* | linux-android* \ + | linux-newlib* | linux-musl* | linux-uclibc* \ + | uxpv* | beos* | mpeix* | udk* | moxiebox* \ + | interix* | uwin* | mks* | rhapsody* | darwin* \ + | openstep* | oskit* | conix* | pw32* | nonstopux* \ + | storm-chaos* | tops10* | tenex* | tops20* | its* \ + | os2* | vos* | palmos* | uclinux* | nucleus* \ + | morphos* | superux* | rtmk* | windiss* \ + | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \ + | skyos* | haiku* | rdos* | toppers* | drops* | es* \ + | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ + | midnightbsd*) # Remember, each alternative MUST END IN *, to match a version number. ;; - -qnx*) + qnx*) case $basic_machine in x86-* | i*86-*) ;; *) - os=-nto$os + os=nto-$os ;; esac ;; - -nto-qnx*) + hiux*) + os=hiuxwe2 ;; - -nto*) + nto-qnx*) + ;; + nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; - -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ - | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ - | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + sim | xray | os68k* | v88r* \ + | windows* | osx | abug | netware* | os9* \ + | macos* | mpw* | magic* | mmixware* | mon960* | lnews*) ;; - -mac*) - os=`echo $os | sed -e 's|mac|macos|'` + linux-dietlibc) + os=linux-dietlibc ;; - -linux-dietlibc) - os=-linux-dietlibc - ;; - -linux*) + linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; - -sunos5*) - os=`echo $os | sed -e 's|sunos5|solaris2|'` + lynx*178) + os=lynxos178 ;; - -sunos6*) - os=`echo $os | sed -e 's|sunos6|solaris3|'` + lynx*5) + os=lynxos5 ;; - -opened*) - os=-openedition + lynx*) + os=lynxos ;; - -os400*) - os=-os400 + mac*) + os=`echo "$os" | sed -e 's|mac|macos|'` ;; - -wince*) - os=-wince + opened*) + os=openedition ;; - -osfrose*) - os=-osfrose + os400*) + os=os400 ;; - -osf*) - os=-osf + sunos5*) + os=`echo "$os" | sed -e 's|sunos5|solaris2|'` ;; - -utek*) - os=-bsd + sunos6*) + os=`echo "$os" | sed -e 's|sunos6|solaris3|'` ;; - -dynix*) - os=-bsd + wince*) + os=wince ;; - -acis*) - os=-aos + utek*) + os=bsd ;; - -atheos*) - os=-atheos + dynix*) + os=bsd ;; - -syllable*) - os=-syllable + acis*) + os=aos ;; - -386bsd) - os=-bsd + atheos*) + os=atheos ;; - -ctix* | -uts*) - os=-sysv + syllable*) + os=syllable ;; - -nova*) - os=-rtmk-nova + 386bsd) + os=bsd ;; - -ns2 ) - os=-nextstep2 + ctix* | uts*) + os=sysv ;; - -nsk*) - os=-nsk + nova*) + os=rtmk-nova + ;; + ns2) + os=nextstep2 + ;; + nsk*) + os=nsk ;; # Preserve the version number of sinix5. - -sinix5.*) + sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; - -sinix*) - os=-sysv4 + sinix*) + os=sysv4 ;; - -tpf*) - os=-tpf + tpf*) + os=tpf ;; - -triton*) - os=-sysv3 + triton*) + os=sysv3 ;; - -oss*) - os=-sysv3 + oss*) + os=sysv3 ;; - -svr4) - os=-sysv4 + svr4*) + os=sysv4 ;; - -svr3) - os=-sysv3 + svr3) + os=sysv3 ;; - -sysvr4) - os=-sysv4 + sysvr4) + os=sysv4 ;; - # This must come after -sysvr4. - -sysv*) + # This must come after sysvr4. + sysv*) ;; - -ose*) - os=-ose + ose*) + os=ose ;; - -es1800*) - os=-ose + *mint | mint[0-9]* | *MiNT | MiNT[0-9]*) + os=mint ;; - -xenix) - os=-xenix + zvmoe) + os=zvmoe ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - os=-mint + dicos*) + os=dicos ;; - -aros*) - os=-aros + pikeos*) + # Until real need of OS specific support for + # particular features comes up, bare metal + # configurations are quite functional. + case $basic_machine in + arm*) + os=eabi + ;; + *) + os=elf + ;; + esac ;; - -zvmoe) - os=-zvmoe + nacl*) ;; - -dicos*) - os=-dicos + ios) ;; - -nacl*) + none) ;; - -none) + *-eabi) ;; *) - # Get rid of the `-' at the beginning of $os. - os=`echo $os | sed 's/[^-]*-//'` - echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2 exit 1 ;; esac @@ -1548,176 +1543,179 @@ else case $basic_machine in score-*) - os=-elf + os=elf ;; spu-*) - os=-elf + os=elf ;; *-acorn) - os=-riscix1.2 + os=riscix1.2 ;; arm*-rebel) - os=-linux + os=linux ;; arm*-semi) - os=-aout + os=aout ;; c4x-* | tic4x-*) - os=-coff + os=coff ;; c8051-*) - os=-elf + os=elf + ;; + clipper-intergraph) + os=clix ;; hexagon-*) - os=-elf + os=elf ;; tic54x-*) - os=-coff + os=coff ;; tic55x-*) - os=-coff + os=coff ;; tic6x-*) - os=-coff + os=coff ;; # This must come before the *-dec entry. pdp10-*) - os=-tops20 + os=tops20 ;; pdp11-*) - os=-none + os=none ;; *-dec | vax-*) - os=-ultrix4.2 + os=ultrix4.2 ;; m68*-apollo) - os=-domain + os=domain ;; i386-sun) - os=-sunos4.0.2 + os=sunos4.0.2 ;; m68000-sun) - os=-sunos3 + os=sunos3 ;; m68*-cisco) - os=-aout + os=aout ;; mep-*) - os=-elf + os=elf ;; mips*-cisco) - os=-elf + os=elf ;; mips*-*) - os=-elf + os=elf ;; or32-*) - os=-coff + os=coff ;; *-tti) # must be before sparc entry or we get the wrong os. - os=-sysv3 + os=sysv3 ;; sparc-* | *-sun) - os=-sunos4.1.1 + os=sunos4.1.1 + ;; + pru-*) + os=elf ;; *-be) - os=-beos - ;; - *-haiku) - os=-haiku + os=beos ;; *-ibm) - os=-aix + os=aix ;; *-knuth) - os=-mmixware + os=mmixware ;; *-wec) - os=-proelf + os=proelf ;; *-winbond) - os=-proelf + os=proelf ;; *-oki) - os=-proelf + os=proelf ;; *-hp) - os=-hpux + os=hpux ;; *-hitachi) - os=-hiux + os=hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) - os=-sysv + os=sysv ;; *-cbm) - os=-amigaos + os=amigaos ;; *-dg) - os=-dgux + os=dgux ;; *-dolphin) - os=-sysv3 + os=sysv3 ;; m68k-ccur) - os=-rtu + os=rtu ;; m88k-omron*) - os=-luna - ;; - *-next ) - os=-nextstep - ;; - *-sequent) - os=-ptx - ;; - *-crds) - os=-unos - ;; - *-ns) - os=-genix - ;; - i370-*) - os=-mvs + os=luna ;; *-next) - os=-nextstep3 + os=nextstep + ;; + *-sequent) + os=ptx + ;; + *-crds) + os=unos + ;; + *-ns) + os=genix + ;; + i370-*) + os=mvs ;; *-gould) - os=-sysv + os=sysv ;; *-highlevel) - os=-bsd + os=bsd ;; *-encore) - os=-bsd + os=bsd ;; *-sgi) - os=-irix + os=irix ;; *-siemens) - os=-sysv4 + os=sysv4 ;; *-masscomp) - os=-rtu + os=rtu ;; f30[01]-fujitsu | f700-fujitsu) - os=-uxpv + os=uxpv ;; *-rom68k) - os=-coff + os=coff ;; *-*bug) - os=-coff + os=coff ;; *-apple) - os=-macos + os=macos ;; *-atari*) - os=-mint + os=mint + ;; + *-wrs) + os=vxworks ;; *) - os=-none + os=none ;; esac fi @@ -1728,79 +1726,82 @@ vendor=unknown case $basic_machine in *-unknown) case $os in - -riscix*) + riscix*) vendor=acorn ;; - -sunos*) + sunos*) vendor=sun ;; - -cnk*|-aix*) + cnk*|-aix*) vendor=ibm ;; - -beos*) + beos*) vendor=be ;; - -hpux*) + hpux*) vendor=hp ;; - -mpeix*) + mpeix*) vendor=hp ;; - -hiux*) + hiux*) vendor=hitachi ;; - -unos*) + unos*) vendor=crds ;; - -dgux*) + dgux*) vendor=dg ;; - -luna*) + luna*) vendor=omron ;; - -genix*) + genix*) vendor=ns ;; - -mvs* | -opened*) + clix*) + vendor=intergraph + ;; + mvs* | opened*) vendor=ibm ;; - -os400*) + os400*) vendor=ibm ;; - -ptx*) + ptx*) vendor=sequent ;; - -tpf*) + tpf*) vendor=ibm ;; - -vxsim* | -vxworks* | -windiss*) + vxsim* | vxworks* | windiss*) vendor=wrs ;; - -aux*) + aux*) vendor=apple ;; - -hms*) + hms*) vendor=hitachi ;; - -mpw* | -macos*) + mpw* | macos*) vendor=apple ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + *mint | mint[0-9]* | *MiNT | MiNT[0-9]*) vendor=atari ;; - -vos*) + vos*) vendor=stratus ;; esac - basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + basic_machine=`echo "$basic_machine" | sed "s/unknown/$vendor/"` ;; esac -echo $basic_machine$os +echo "$basic_machine-$os" exit # Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" diff --git a/configure b/configure index ef4bc9f2cc06..fa15fc7314eb 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for pcap 1.9.0-PRE-GIT. +# Generated by GNU Autoconf 2.69 for pcap 1.9.1. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -577,8 +577,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='pcap' PACKAGE_TARNAME='pcap' -PACKAGE_VERSION='1.9.0-PRE-GIT' -PACKAGE_STRING='pcap 1.9.0-PRE-GIT' +PACKAGE_VERSION='1.9.1' +PACKAGE_STRING='pcap 1.9.1' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -645,6 +645,7 @@ PTHREAD_LIBS MAN_ADMIN_COMMANDS MAN_MISC_INFO MAN_FILE_FORMATS +MAN_DEVICES DYEXT SSRC ADDLARCHIVEOBJS @@ -660,6 +661,10 @@ V_LEX V_INCLS V_FINDALLDEVS V_DEFS +V_PROG_LDFLAGS_FAT +V_PROG_CCOPT_FAT +V_LIB_LDFLAGS_FAT +V_LIB_CCOPT_FAT V_CCOPT MKDEP DEPENDENCY_CFLAG @@ -716,6 +721,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -814,6 +820,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1066,6 +1073,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1203,7 +1219,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1316,7 +1332,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures pcap 1.9.0-PRE-GIT to adapt to many kinds of systems. +\`configure' configures pcap 1.9.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1356,6 +1372,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -1382,7 +1399,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of pcap 1.9.0-PRE-GIT:";; + short | recursive ) echo "Configuration of pcap 1.9.1:";; esac cat <<\_ACEOF @@ -1520,7 +1537,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -pcap configure 1.9.0-PRE-GIT +pcap configure 1.9.1 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2042,7 +2059,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by pcap $as_me 1.9.0-PRE-GIT, which was +It was created by pcap $as_me 1.9.1, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3576,6 +3593,10 @@ if test "x$ac_cv_prog_cc_c99" != xno; then : fi +if test "$ac_cv_prog_cc_c99" = "no"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: The C compiler does not support C99; there may be compiler errors" >&5 +$as_echo "$as_me: WARNING: The C compiler does not support C99; there may be compiler errors" >&2;} +fi @@ -3623,8 +3644,47 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -fvisibility=hidden " >&5 +$as_echo_n "checking whether -fvisibility=hidden ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # + # Not a problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + # + # A problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi CFLAGS="$save_CFLAGS" - V_CCOPT="$V_CCOPT -fvisibility=hidden" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -fvisibility=hidden" + fi else @@ -3684,8 +3744,47 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -fvisibility=hidden " >&5 +$as_echo_n "checking whether -fvisibility=hidden ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # + # Not a problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + # + # A problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi CFLAGS="$save_CFLAGS" - V_CCOPT="$V_CCOPT -fvisibility=hidden" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -fvisibility=hidden" + fi else @@ -3807,8 +3906,47 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -xldscope=hidden " >&5 +$as_echo_n "checking whether -xldscope=hidden ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # + # Not a problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + # + # A problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi CFLAGS="$save_CFLAGS" - V_CCOPT="$V_CCOPT -xldscope=hidden" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -xldscope=hidden" + fi else @@ -3880,7 +4018,7 @@ $as_echo "#define const /**/" >>confdefs.h aix*) ;; - freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*) + freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*|midipix*) # # Platforms where the linker is the GNU linker # or accepts command-line arguments like @@ -3897,7 +4035,7 @@ $as_echo "#define const /**/" >>confdefs.h sparc64*) case "$host_os" in - freebsd*|openbsd*) + freebsd*|openbsd*|linux*) PIC_OPT=-fPIC ;; esac @@ -4097,7 +4235,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -4143,7 +4281,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -4167,7 +4305,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -4212,7 +4350,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -4236,7 +4374,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -4881,19 +5019,120 @@ $as_echo "$ac_cv_lbl_gcc_fixincludes" >&6; } fi fi -for ac_func in strerror strerror_r strerror_s strlcpy strlcat +for ac_func in strerror do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + ac_fn_c_check_func "$LINENO" "strerror" "ac_cv_func_strerror" +if test "x$ac_cv_func_strerror" = xyes; then : cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +#define HAVE_STRERROR 1 +_ACEOF + +fi +done + +ac_fn_c_check_func "$LINENO" "strerror_r" "ac_cv_func_strerror_r" +if test "x$ac_cv_func_strerror_r" = xyes; then : + + # + # We have strerror_r; if we define _GNU_SOURCE, is it a + # POSIX-compliant strerror_r() or a GNU strerror_r()? + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether strerror_r is GNU-style" >&5 +$as_echo_n "checking whether strerror_r is GNU-style... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #define _GNU_SOURCE +#include + +/* Define it GNU-style; that will cause an error if it's not GNU-style */ +extern char *strerror_r(int, char *, size_t); + +int +main(void) +{ + return 0; +} + + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # GNU-style + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define HAVE_GNU_STRERROR_R /**/" >>confdefs.h + + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +$as_echo "#define HAVE_POSIX_STRERROR_R /**/" >>confdefs.h + + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +else + + # + # We don't have strerror_r; do we have strerror_s? + # + for ac_func in strerror_s +do : + ac_fn_c_check_func "$LINENO" "strerror_s" "ac_cv_func_strerror_s" +if test "x$ac_cv_func_strerror_s" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRERROR_S 1 _ACEOF fi done +fi + + +# +# Thanks, IBM, for not providing vsyslog() in AIX! +# +for ac_func in vsyslog +do : + ac_fn_c_check_func "$LINENO" "vsyslog" "ac_cv_func_vsyslog" +if test "x$ac_cv_func_vsyslog" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_VSYSLOG 1 +_ACEOF + +fi +done + + +# +# Either: +# +# we have snprintf() and vsnprintf(), and have asprintf() and +# vasprintf(); +# +# we have snprintf() and vsnprintf(), but don't have asprintf() +# or vasprintf(); +# +# we have neither snprintf() nor vsnprintf(), and don't have +# asprintf() or vasprintf(), either. +# +# We assume that if we have asprintf() we have vasprintf(), as well +# as snprintf() and vsnprintf(), and that if we have snprintf() we +# have vsnprintf(). +# +# For the first case, we don't need any replacement routines. +# For the second case, we need replacement asprintf()/vasprintf() +# routines. +# For the third case, we need replacement snprintf()/vsnprintf() and +# asprintf()/vasprintf() routines. +# needsnprintf=no for ac_func in vsnprintf snprintf do : @@ -4909,13 +5148,90 @@ else fi done +needasprintf=no +for ac_func in vasprintf asprintf +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +else + needasprintf=yes +fi +done + if test $needsnprintf = yes; then + # + # We assume we have none of them; missing/snprintf.c supplies + # all of them. + # case " $LIBOBJS " in *" snprintf.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS snprintf.$ac_objext" ;; esac +elif test $needasprintf = yes; then + # + # We assume we have snprintf()/vsnprintf() but lack + # asprintf()/vasprintf(); missing/asprintf.c supplies + # the latter (using vsnprintf()). + # + case " $LIBOBJS " in + *" asprintf.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS asprintf.$ac_objext" + ;; +esac + +fi + +needstrlcat=no +for ac_func in strlcat +do : + ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat" +if test "x$ac_cv_func_strlcat" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRLCAT 1 +_ACEOF + +else + needstrlcat=yes +fi +done + +if test $needstrlcat = yes; then + case " $LIBOBJS " in + *" strlcat.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS strlcat.$ac_objext" + ;; +esac + +fi + +needstrlcpy=no +for ac_func in strlcpy +do : + ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" +if test "x$ac_cv_func_strlcpy" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRLCPY 1 +_ACEOF + +else + needstrlcpy=yes +fi +done + +if test $needstrlcpy = yes; then + case " $LIBOBJS " in + *" strlcpy.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS strlcpy.$ac_objext" + ;; +esac + fi needstrtok_r=no @@ -5845,6 +6161,10 @@ done # requires that various BSD-style integer types # be defined; # + # sys/time.h, because AIX 5.2 and 5.3's net/bpf.h + # doesn't include it but does use struct timeval + # in ioctl definitions; + # # sys/ioctl.h and, if we have it, sys/ioccom.h, # because net/bpf.h defines ioctls; # @@ -5867,6 +6187,7 @@ else /* end confdefs.h. */ #include +#include #include #include #ifdef HAVE_SYS_IOCCOM_H @@ -7844,18 +8165,20 @@ fi $as_echo "$tcpdump_cv_capable_yacc" >&6; } if test $tcpdump_cv_capable_yacc = insufficient ; then as_fn_error $? "$YACC is insufficient to compile libpcap. - libpcap requires Bison, Berkeley YACC, or another YACC compatible with them." "$LINENO" 5 + libpcap requires Bison, a newer version of Berkeley YACC with support + for reentrant parsers, or another YACC compatible with them." "$LINENO" 5 fi # # Do various checks for various OSes and versions of those OSes. # # Assume, by default, no support for shared libraries and V7/BSD -# convention for man pages (file formats in section 5, miscellaneous -# info in section 7, administrative commands and daemons in section 8). -# Individual cases can override this. +# convention for man pages (devices in section 4, file formats in +# section 5, miscellaneous info in section 7, administrative commands +# and daemons in section 8). Individual cases can override this. # DYEXT="none" +MAN_DEVICES=4 MAN_FILE_FORMATS=5 MAN_MISC_INFO=7 MAN_ADMIN_COMMANDS=8 @@ -7917,79 +8240,168 @@ fi if test "$enable_universal" != "no"; then case "$host_os" in - darwin0-7.*) + darwin[0-7].*) # # Pre-Tiger. Build only for 32-bit PowerPC; no # need for any special compiler or linker flags. # ;; - darwin8.0123*) + darwin8.[0123]|darwin8.[0123].*) # - # Tiger, prior to Intel support. Build for 32-bit - # PowerPC and 64-bit PowerPC, with 32-bit PowerPC - # first. (I'm guessing that's what Apple does.) - # - V_CCOPT="$V_CCOPT -arch ppc -arch ppc64" - LDFLAGS="$LDFLAGS -arch ppc -arch ppc64" - ;; - - darwin8.456*) - # - # Tiger, subsequent to Intel support but prior to - # x86-64 support. Build for 32-bit PowerPC, 64-bit - # PowerPC, and x86, with 32-bit PowerPC first. + # Tiger, prior to Intel support. Build + # libraries and executables for 32-bit PowerPC + # and 64-bit PowerPC, with 32-bit PowerPC first. # (I'm guessing that's what Apple does.) # - V_CCOPT="$V_CCOPT -arch ppc -arch ppc64 -arch i386" - LDFLAGS="$LDFLAGS -arch ppc -arch ppc64 -arch i386" + # (The double brackets are needed because + # autotools/m4 use brackets as a quoting + # character; the double brackets turn into + # single brackets in the generated configure + # file.) + # + V_LIB_CCOPT_FAT="-arch ppc -arch ppc64" + V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64" + V_PROG_CCOPT_FAT="-arch ppc -arch ppc64" + V_PROG_LDFLAGS_FAT="-arch ppc -arch ppc64" + ;; + + darwin8.[456]|darwin.[456].*) + # + # Tiger, subsequent to Intel support but prior + # to x86-64 support. Build libraries and + # executables for 32-bit PowerPC, 64-bit + # PowerPC, and 32-bit x86, with 32-bit PowerPC + # first. (I'm guessing that's what Apple does.) + # + # (The double brackets are needed because + # autotools/m4 use brackets as a quoting + # character; the double brackets turn into + # single brackets in the generated configure + # file.) + # + V_LIB_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386" + V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386" + V_PROG_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386" + V_PROG_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386" ;; darwin8.*) # # All other Tiger, so subsequent to x86-64 - # support. Build for 32-bit PowerPC, 64-bit - # PowerPC, x86, and x86-64, and with 32-bit PowerPC - # first. (I'm guessing that's what Apple does.) + # support. Build libraries and executables for + # 32-bit PowerPC, 64-bit PowerPC, 32-bit x86, + # and x86-64, with 32-bit PowerPC first. (I'm + # guessing that's what Apple does.) # - V_CCOPT="$V_CCOPT -arch ppc -arch ppc64 -arch i386 -arch x86_64" - LDFLAGS="$LDFLAGS -arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_LIB_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_PROG_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_PROG_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" ;; darwin9.*) # - # Leopard. Build for 32-bit PowerPC, 64-bit - # PowerPC, x86, and x86-64, with 32-bit PowerPC - # first. (That's what Apple does.) + # Leopard. Build libraries for 32-bit PowerPC, + # 64-bit PowerPC, 32-bit x86, and x86-64, with + # 32-bit PowerPC first, and build executables + # for 32-bit x86 and 32-bit PowerPC, with 32-bit + # x86 first. (That's what Apple does.) # - V_CCOPT="$V_CCOPT -arch ppc -arch ppc64 -arch i386 -arch x86_64" - LDFLAGS="$LDFLAGS -arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_LIB_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_PROG_CCOPT_FAT="-arch i386 -arch ppc" + V_PROG_LDFLAGS_FAT="-arch i386 -arch ppc" ;; darwin10.*) # - # Snow Leopard. Build for x86-64, x86, and - # 32-bit PowerPC, with x86-64 first. (That's - # what Apple does, even though Snow Leopard - # doesn't run on PPC, so PPC libpcap runs under - # Rosetta, and Rosetta doesn't support BPF - # ioctls, so PPC programs can't do live - # captures.) + # Snow Leopard. Build libraries for x86-64, + # 32-bit x86, and 32-bit PowerPC, with x86-64 + # first, and build executables for x86-64 and + # 32-bit x86, with x86-64 first. (That's what + # Apple does, even though Snow Leopard doesn't + # run on PPC, so PPC libpcap runs under Rosetta, + # and Rosetta doesn't support BPF ioctls, so PPC + # programs can't do live captures.) # - V_CCOPT="$V_CCOPT -arch x86_64 -arch i386 -arch ppc" - LDFLAGS="$LDFLAGS -arch x86_64 -arch i386 -arch ppc" + V_LIB_CCOPT_FAT="-arch x86_64 -arch i386 -arch ppc" + V_LIB_LDFLAGS_FAT="-arch x86_64 -arch i386 -arch ppc" + V_PROG_CCOPT_FAT="-arch x86_64 -arch i386" + V_PROG_LDFLAGS_FAT="-arch x86_64 -arch i386" ;; darwin*) # - # Post-Snow Leopard. Build for x86-64 and - # x86, with x86-64 first. (That's probably what - # Apple does, given that Rosetta is gone.) + # Post-Snow Leopard. Build libraries for x86-64 + # and 32-bit x86, with x86-64 first, and build + # executables only for x86-64. (That's what + # Apple does.) This requires no special flags + # for programs. # XXX - update if and when Apple drops support - # for 32-bit x86 code. + # for 32-bit x86 code and if and when Apple adds + # ARM-based Macs. (You're on your own for iOS + # etc.) # - V_CCOPT="$V_CCOPT -arch x86_64 -arch i386" - LDFLAGS="$LDFLAGS -arch x86_64 -arch i386" + # XXX - check whether we *can* build for + # i386 and, if not, suggest that the user + # install the /usr/include headers if they + # want to build fat. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether building for 32-bit x86 is supported" >&5 +$as_echo_n "checking whether building for 32-bit x86 is supported... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -arch i386" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + V_LIB_CCOPT_FAT="-arch x86_64 -arch i386" + V_LIB_LDFLAGS_FAT="-arch x86_64 -arch i386" + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + V_LIB_CCOPT_FAT="-arch x86_64" + V_LIB_LDFLAGS_FAT="-arch x86_64" + case "$host_os" in + + darwin18.*) + # + # Mojave; you need to install the + # /usr/include headers to get + # 32-bit x86 builds to work. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Compiling for 32-bit x86 gives an error; try installing the command-line tools and, after that, installing the /usr/include headers from the /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg package" >&5 +$as_echo "$as_me: WARNING: Compiling for 32-bit x86 gives an error; try installing the command-line tools and, after that, installing the /usr/include headers from the /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg package" >&2;} + ;; + + *) + # + # Pre-Mojave; the command-line + # tools should be sufficient to + # enable 32-bit x86 builds. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Compiling for 32-bit x86 gives an error; try installing the command-line tools" >&5 +$as_echo "$as_me: WARNING: Compiling for 32-bit x86 gives an error; try installing the command-line tools" >&2;} + ;; + esac + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$save_CFLAGS" ;; esac fi @@ -8061,7 +8473,7 @@ irix*) MAN_MISC_INFO=5 ;; -linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*) +linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*|midipix*) DYEXT="so" # @@ -8084,6 +8496,7 @@ osf*) # MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 + MAN_DEVICES=7 ;; sinix*) @@ -8149,6 +8562,7 @@ $as_echo "#define HAVE_SOLARIS 1" >>confdefs.h MAN_ADMIN_COMMANDS=1m MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 + MAN_DEVICES=7D esac ;; esac @@ -8404,6 +8818,88 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$save_CFLAGS" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -W option" >&5 +$as_echo_n "checking whether the compiler supports the -W option... " >&6; } + save_CFLAGS="$CFLAGS" + if expr "x-W" : "x-W.*" >/dev/null + then + CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -W" + elif expr "x-W" : "x-f.*" >/dev/null + then + CFLAGS="$CFLAGS -Werror -W" + elif expr "x-W" : "x-m.*" >/dev/null + then + CFLAGS="$CFLAGS -Werror -W" + else + CFLAGS="$CFLAGS -W" + fi + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -W " >&5 +$as_echo_n "checking whether -W ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # + # Not a problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + # + # A problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -W" + fi + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wall option" >&5 $as_echo_n "checking whether the compiler supports the -Wall option... " >&6; } save_CFLAGS="$CFLAGS" @@ -8434,309 +8930,47 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } - CFLAGS="$save_CFLAGS" - V_CCOPT="$V_CCOPT -Wall" - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - CFLAGS="$save_CFLAGS" - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wsign-compare option" >&5 -$as_echo_n "checking whether the compiler supports the -Wsign-compare option... " >&6; } - save_CFLAGS="$CFLAGS" - if expr "x-Wsign-compare" : "x-W.*" >/dev/null - then - CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wsign-compare" - elif expr "x-Wsign-compare" : "x-f.*" >/dev/null - then - CFLAGS="$CFLAGS -Werror -Wsign-compare" - elif expr "x-Wsign-compare" : "x-m.*" >/dev/null - then - CFLAGS="$CFLAGS -Werror -Wsign-compare" - else - CFLAGS="$CFLAGS -Wsign-compare" - fi - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wall " >&5 +$as_echo_n "checking whether -Wall ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -int -main () -{ -return 0 - ; - return 0; -} _ACEOF if ac_fn_c_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - CFLAGS="$save_CFLAGS" - V_CCOPT="$V_CCOPT -Wsign-compare" + # + # Not a problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - CFLAGS="$save_CFLAGS" + # + # A problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-prototypes option" >&5 -$as_echo_n "checking whether the compiler supports the -Wmissing-prototypes option... " >&6; } - save_CFLAGS="$CFLAGS" - if expr "x-Wmissing-prototypes" : "x-W.*" >/dev/null - then - CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wmissing-prototypes" - elif expr "x-Wmissing-prototypes" : "x-f.*" >/dev/null - then - CFLAGS="$CFLAGS -Werror -Wmissing-prototypes" - elif expr "x-Wmissing-prototypes" : "x-m.*" >/dev/null - then - CFLAGS="$CFLAGS -Werror -Wmissing-prototypes" - else - CFLAGS="$CFLAGS -Wmissing-prototypes" - fi - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -return 0 - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + fi CFLAGS="$save_CFLAGS" - V_CCOPT="$V_CCOPT -Wmissing-prototypes" - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - CFLAGS="$save_CFLAGS" - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wstrict-prototypes option" >&5 -$as_echo_n "checking whether the compiler supports the -Wstrict-prototypes option... " >&6; } - save_CFLAGS="$CFLAGS" - if expr "x-Wstrict-prototypes" : "x-W.*" >/dev/null - then - CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wstrict-prototypes" - elif expr "x-Wstrict-prototypes" : "x-f.*" >/dev/null - then - CFLAGS="$CFLAGS -Werror -Wstrict-prototypes" - elif expr "x-Wstrict-prototypes" : "x-m.*" >/dev/null - then - CFLAGS="$CFLAGS -Werror -Wstrict-prototypes" - else - CFLAGS="$CFLAGS -Wstrict-prototypes" - fi - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -return 0 - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - CFLAGS="$save_CFLAGS" - V_CCOPT="$V_CCOPT -Wstrict-prototypes" - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - CFLAGS="$save_CFLAGS" - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wshadow option" >&5 -$as_echo_n "checking whether the compiler supports the -Wshadow option... " >&6; } - save_CFLAGS="$CFLAGS" - if expr "x-Wshadow" : "x-W.*" >/dev/null - then - CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wshadow" - elif expr "x-Wshadow" : "x-f.*" >/dev/null - then - CFLAGS="$CFLAGS -Werror -Wshadow" - elif expr "x-Wshadow" : "x-m.*" >/dev/null - then - CFLAGS="$CFLAGS -Werror -Wshadow" - else - CFLAGS="$CFLAGS -Wshadow" - fi - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -return 0 - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - CFLAGS="$save_CFLAGS" - V_CCOPT="$V_CCOPT -Wshadow" - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - CFLAGS="$save_CFLAGS" - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wdeclaration-after-statement option" >&5 -$as_echo_n "checking whether the compiler supports the -Wdeclaration-after-statement option... " >&6; } - save_CFLAGS="$CFLAGS" - if expr "x-Wdeclaration-after-statement" : "x-W.*" >/dev/null - then - CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wdeclaration-after-statement" - elif expr "x-Wdeclaration-after-statement" : "x-f.*" >/dev/null - then - CFLAGS="$CFLAGS -Werror -Wdeclaration-after-statement" - elif expr "x-Wdeclaration-after-statement" : "x-m.*" >/dev/null - then - CFLAGS="$CFLAGS -Werror -Wdeclaration-after-statement" - else - CFLAGS="$CFLAGS -Wdeclaration-after-statement" - fi - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -return 0 - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - CFLAGS="$save_CFLAGS" - V_CCOPT="$V_CCOPT -Wdeclaration-after-statement" - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - CFLAGS="$save_CFLAGS" - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wused-but-marked-unused option" >&5 -$as_echo_n "checking whether the compiler supports the -Wused-but-marked-unused option... " >&6; } - save_CFLAGS="$CFLAGS" - if expr "x-Wused-but-marked-unused" : "x-W.*" >/dev/null - then - CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wused-but-marked-unused" - elif expr "x-Wused-but-marked-unused" : "x-f.*" >/dev/null - then - CFLAGS="$CFLAGS -Werror -Wused-but-marked-unused" - elif expr "x-Wused-but-marked-unused" : "x-m.*" >/dev/null - then - CFLAGS="$CFLAGS -Werror -Wused-but-marked-unused" - else - CFLAGS="$CFLAGS -Wused-but-marked-unused" - fi - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -return 0 - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - CFLAGS="$save_CFLAGS" - V_CCOPT="$V_CCOPT -Wused-but-marked-unused" - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - CFLAGS="$save_CFLAGS" - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wdocumentation option" >&5 -$as_echo_n "checking whether the compiler supports the -Wdocumentation option... " >&6; } - save_CFLAGS="$CFLAGS" - if expr "x-Wdocumentation" : "x-W.*" >/dev/null - then - CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wdocumentation" - elif expr "x-Wdocumentation" : "x-f.*" >/dev/null - then - CFLAGS="$CFLAGS -Werror -Wdocumentation" - elif expr "x-Wdocumentation" : "x-m.*" >/dev/null - then - CFLAGS="$CFLAGS -Werror -Wdocumentation" - else - CFLAGS="$CFLAGS -Wdocumentation" - fi - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -return 0 - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - CFLAGS="$save_CFLAGS" - V_CCOPT="$V_CCOPT -Wdocumentation" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wall" + fi else @@ -8778,8 +9012,47 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wcomma " >&5 +$as_echo_n "checking whether -Wcomma ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # + # Not a problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + # + # A problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi CFLAGS="$save_CFLAGS" - V_CCOPT="$V_CCOPT -Wcomma" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wcomma" + fi else @@ -8791,20 +9064,20 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-noreturn option" >&5 -$as_echo_n "checking whether the compiler supports the -Wmissing-noreturn option... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wdeclaration-after-statement option" >&5 +$as_echo_n "checking whether the compiler supports the -Wdeclaration-after-statement option... " >&6; } save_CFLAGS="$CFLAGS" - if expr "x-Wmissing-noreturn" : "x-W.*" >/dev/null + if expr "x-Wdeclaration-after-statement" : "x-W.*" >/dev/null then - CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wmissing-noreturn" - elif expr "x-Wmissing-noreturn" : "x-f.*" >/dev/null + CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wdeclaration-after-statement" + elif expr "x-Wdeclaration-after-statement" : "x-f.*" >/dev/null then - CFLAGS="$CFLAGS -Werror -Wmissing-noreturn" - elif expr "x-Wmissing-noreturn" : "x-m.*" >/dev/null + CFLAGS="$CFLAGS -Werror -Wdeclaration-after-statement" + elif expr "x-Wdeclaration-after-statement" : "x-m.*" >/dev/null then - CFLAGS="$CFLAGS -Werror -Wmissing-noreturn" + CFLAGS="$CFLAGS -Werror -Wdeclaration-after-statement" else - CFLAGS="$CFLAGS -Wmissing-noreturn" + CFLAGS="$CFLAGS -Wdeclaration-after-statement" fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -8821,8 +9094,47 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wdeclaration-after-statement " >&5 +$as_echo_n "checking whether -Wdeclaration-after-statement ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # + # Not a problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + # + # A problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi CFLAGS="$save_CFLAGS" - V_CCOPT="$V_CCOPT -Wmissing-noreturn" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wdeclaration-after-statement" + fi else @@ -8833,24 +9145,21 @@ $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - # Warns about safeguards added in case the enums are - # extended - # AC_LBL_CHECK_COMPILER_OPT(V_CCOPT, -Wcovered-switch-default) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-variable-declarations option" >&5 -$as_echo_n "checking whether the compiler supports the -Wmissing-variable-declarations option... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wdocumentation option" >&5 +$as_echo_n "checking whether the compiler supports the -Wdocumentation option... " >&6; } save_CFLAGS="$CFLAGS" - if expr "x-Wmissing-variable-declarations" : "x-W.*" >/dev/null + if expr "x-Wdocumentation" : "x-W.*" >/dev/null then - CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wmissing-variable-declarations" - elif expr "x-Wmissing-variable-declarations" : "x-f.*" >/dev/null + CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wdocumentation" + elif expr "x-Wdocumentation" : "x-f.*" >/dev/null then - CFLAGS="$CFLAGS -Werror -Wmissing-variable-declarations" - elif expr "x-Wmissing-variable-declarations" : "x-m.*" >/dev/null + CFLAGS="$CFLAGS -Werror -Wdocumentation" + elif expr "x-Wdocumentation" : "x-m.*" >/dev/null then - CFLAGS="$CFLAGS -Werror -Wmissing-variable-declarations" + CFLAGS="$CFLAGS -Werror -Wdocumentation" else - CFLAGS="$CFLAGS -Wmissing-variable-declarations" + CFLAGS="$CFLAGS -Wdocumentation" fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -8867,51 +9176,47 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } - CFLAGS="$save_CFLAGS" - V_CCOPT="$V_CCOPT -Wmissing-variable-declarations" - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - CFLAGS="$save_CFLAGS" - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wunused-parameter option" >&5 -$as_echo_n "checking whether the compiler supports the -Wunused-parameter option... " >&6; } - save_CFLAGS="$CFLAGS" - if expr "x-Wunused-parameter" : "x-W.*" >/dev/null - then - CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wunused-parameter" - elif expr "x-Wunused-parameter" : "x-f.*" >/dev/null - then - CFLAGS="$CFLAGS -Werror -Wunused-parameter" - elif expr "x-Wunused-parameter" : "x-m.*" >/dev/null - then - CFLAGS="$CFLAGS -Werror -Wunused-parameter" - else - CFLAGS="$CFLAGS -Wunused-parameter" - fi - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wdocumentation " >&5 +$as_echo_n "checking whether -Wdocumentation ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -int -main () -{ -return 0 - ; - return 0; -} _ACEOF if ac_fn_c_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + # + # Not a problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + # + # A problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi CFLAGS="$save_CFLAGS" - V_CCOPT="$V_CCOPT -Wunused-parameter" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wdocumentation" + fi else @@ -8953,8 +9258,47 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wformat-nonliteral " >&5 +$as_echo_n "checking whether -Wformat-nonliteral ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # + # Not a problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + # + # A problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi CFLAGS="$save_CFLAGS" - V_CCOPT="$V_CCOPT -Wformat-nonliteral" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wformat-nonliteral" + fi else @@ -8966,6 +9310,689 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-noreturn option" >&5 +$as_echo_n "checking whether the compiler supports the -Wmissing-noreturn option... " >&6; } + save_CFLAGS="$CFLAGS" + if expr "x-Wmissing-noreturn" : "x-W.*" >/dev/null + then + CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wmissing-noreturn" + elif expr "x-Wmissing-noreturn" : "x-f.*" >/dev/null + then + CFLAGS="$CFLAGS -Werror -Wmissing-noreturn" + elif expr "x-Wmissing-noreturn" : "x-m.*" >/dev/null + then + CFLAGS="$CFLAGS -Werror -Wmissing-noreturn" + else + CFLAGS="$CFLAGS -Wmissing-noreturn" + fi + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wmissing-noreturn " >&5 +$as_echo_n "checking whether -Wmissing-noreturn ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # + # Not a problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + # + # A problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wmissing-noreturn" + fi + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-prototypes option" >&5 +$as_echo_n "checking whether the compiler supports the -Wmissing-prototypes option... " >&6; } + save_CFLAGS="$CFLAGS" + if expr "x-Wmissing-prototypes" : "x-W.*" >/dev/null + then + CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wmissing-prototypes" + elif expr "x-Wmissing-prototypes" : "x-f.*" >/dev/null + then + CFLAGS="$CFLAGS -Werror -Wmissing-prototypes" + elif expr "x-Wmissing-prototypes" : "x-m.*" >/dev/null + then + CFLAGS="$CFLAGS -Werror -Wmissing-prototypes" + else + CFLAGS="$CFLAGS -Wmissing-prototypes" + fi + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wmissing-prototypes " >&5 +$as_echo_n "checking whether -Wmissing-prototypes ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # + # Not a problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + # + # A problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wmissing-prototypes" + fi + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-variable-declarations option" >&5 +$as_echo_n "checking whether the compiler supports the -Wmissing-variable-declarations option... " >&6; } + save_CFLAGS="$CFLAGS" + if expr "x-Wmissing-variable-declarations" : "x-W.*" >/dev/null + then + CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wmissing-variable-declarations" + elif expr "x-Wmissing-variable-declarations" : "x-f.*" >/dev/null + then + CFLAGS="$CFLAGS -Werror -Wmissing-variable-declarations" + elif expr "x-Wmissing-variable-declarations" : "x-m.*" >/dev/null + then + CFLAGS="$CFLAGS -Werror -Wmissing-variable-declarations" + else + CFLAGS="$CFLAGS -Wmissing-variable-declarations" + fi + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wmissing-variable-declarations " >&5 +$as_echo_n "checking whether -Wmissing-variable-declarations ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # + # Not a problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + # + # A problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wmissing-variable-declarations" + fi + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wshadow option" >&5 +$as_echo_n "checking whether the compiler supports the -Wshadow option... " >&6; } + save_CFLAGS="$CFLAGS" + if expr "x-Wshadow" : "x-W.*" >/dev/null + then + CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wshadow" + elif expr "x-Wshadow" : "x-f.*" >/dev/null + then + CFLAGS="$CFLAGS -Werror -Wshadow" + elif expr "x-Wshadow" : "x-m.*" >/dev/null + then + CFLAGS="$CFLAGS -Werror -Wshadow" + else + CFLAGS="$CFLAGS -Wshadow" + fi + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wshadow " >&5 +$as_echo_n "checking whether -Wshadow ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # + # Not a problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + # + # A problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wshadow" + fi + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wsign-compare option" >&5 +$as_echo_n "checking whether the compiler supports the -Wsign-compare option... " >&6; } + save_CFLAGS="$CFLAGS" + if expr "x-Wsign-compare" : "x-W.*" >/dev/null + then + CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wsign-compare" + elif expr "x-Wsign-compare" : "x-f.*" >/dev/null + then + CFLAGS="$CFLAGS -Werror -Wsign-compare" + elif expr "x-Wsign-compare" : "x-m.*" >/dev/null + then + CFLAGS="$CFLAGS -Werror -Wsign-compare" + else + CFLAGS="$CFLAGS -Wsign-compare" + fi + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wsign-compare " >&5 +$as_echo_n "checking whether -Wsign-compare ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # + # Not a problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + # + # A problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wsign-compare" + fi + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wstrict-prototypes option" >&5 +$as_echo_n "checking whether the compiler supports the -Wstrict-prototypes option... " >&6; } + save_CFLAGS="$CFLAGS" + if expr "x-Wstrict-prototypes" : "x-W.*" >/dev/null + then + CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wstrict-prototypes" + elif expr "x-Wstrict-prototypes" : "x-f.*" >/dev/null + then + CFLAGS="$CFLAGS -Werror -Wstrict-prototypes" + elif expr "x-Wstrict-prototypes" : "x-m.*" >/dev/null + then + CFLAGS="$CFLAGS -Werror -Wstrict-prototypes" + else + CFLAGS="$CFLAGS -Wstrict-prototypes" + fi + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wstrict-prototypes " >&5 +$as_echo_n "checking whether -Wstrict-prototypes ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # + # Not a problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + # + # A problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wstrict-prototypes" + fi + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wunused-parameter option" >&5 +$as_echo_n "checking whether the compiler supports the -Wunused-parameter option... " >&6; } + save_CFLAGS="$CFLAGS" + if expr "x-Wunused-parameter" : "x-W.*" >/dev/null + then + CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wunused-parameter" + elif expr "x-Wunused-parameter" : "x-f.*" >/dev/null + then + CFLAGS="$CFLAGS -Werror -Wunused-parameter" + elif expr "x-Wunused-parameter" : "x-m.*" >/dev/null + then + CFLAGS="$CFLAGS -Werror -Wunused-parameter" + else + CFLAGS="$CFLAGS -Wunused-parameter" + fi + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wunused-parameter " >&5 +$as_echo_n "checking whether -Wunused-parameter ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # + # Not a problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + # + # A problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wunused-parameter" + fi + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wused-but-marked-unused option" >&5 +$as_echo_n "checking whether the compiler supports the -Wused-but-marked-unused option... " >&6; } + save_CFLAGS="$CFLAGS" + if expr "x-Wused-but-marked-unused" : "x-W.*" >/dev/null + then + CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wused-but-marked-unused" + elif expr "x-Wused-but-marked-unused" : "x-f.*" >/dev/null + then + CFLAGS="$CFLAGS -Werror -Wused-but-marked-unused" + elif expr "x-Wused-but-marked-unused" : "x-m.*" >/dev/null + then + CFLAGS="$CFLAGS -Werror -Wused-but-marked-unused" + else + CFLAGS="$CFLAGS -Wused-but-marked-unused" + fi + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wused-but-marked-unused " >&5 +$as_echo_n "checking whether -Wused-but-marked-unused ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # + # Not a problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + # + # A problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wused-but-marked-unused" + fi + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + # Warns about safeguards added in case the enums are + # extended + # AC_LBL_CHECK_COMPILER_OPT(V_CCOPT, -Wcovered-switch-default) + # + # This can cause problems with ntohs(), ntohl(), + # htons(), and htonl() on some platforms, such + # as OpenBSD 6.3 with Clang 5.0.1. I guess the + # problem is that the macro that ultimately does + # the byte-swapping involves a conditional + # expression that tests whether the value being + # swapped is a compile-time constant or not, + # using __builtin_constant_p(), and, depending + # on whether it is, does a compile-time swap or + # a run-time swap; perhaps the compiler always + # considers one of the two results of the + # conditional expressin is never evaluated, + # because the conditional check is done at + # compile time, and thus always says "that + # expression is never executed". + # + # (Perhaps there should be a way of flagging + # an expression that you *want* evaluated at + # compile time, so that the compiler 1) warns + # if it *can't* be evaluated at compile time + # and 2) *doesn't* warn that the true or false + # branch will never be reached.) + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wunreachable-code option" >&5 $as_echo_n "checking whether the compiler supports the -Wunreachable-code option... " >&6; } save_CFLAGS="$CFLAGS" @@ -8996,8 +10023,54 @@ if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "xgenerates warnings from ntohs()" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wunreachable-code generates warnings from ntohs()" >&5 +$as_echo_n "checking whether -Wunreachable-code generates warnings from ntohs()... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +unsigned short +testme(unsigned short a) +{ + return ntohs(a); +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # + # Not a problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + # + # A problem. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi CFLAGS="$save_CFLAGS" - V_CCOPT="$V_CCOPT -Wunreachable-code" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wunreachable-code" + fi else @@ -9309,6 +10382,11 @@ $as_echo "#define LBL_ALIGN 1" >>confdefs.h + + + + + @@ -9843,17 +10921,17 @@ fi if test "${enable_rdma+set}" = set; then : enableval=$enable_rdma; else - enable_rdmasniff=ifavailable + enable_rdma=ifavailable fi if test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want RDMA support. - enable_rdmasniff=no + enable_rdma=no fi -if test "x$enable_rdmasniff" != "xno"; then +if test "x$enable_rdma" != "xno"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ibv_get_device_list in -libverbs" >&5 $as_echo_n "checking for ibv_get_device_list in -libverbs... " >&6; } if ${ac_cv_lib_ibverbs_ibv_get_device_list+:} false; then : @@ -10053,7 +11131,7 @@ ac_config_headers="$ac_config_headers config.h" ac_config_commands="$ac_config_commands default-1" -ac_config_files="$ac_config_files Makefile pcap-filter.manmisc pcap-linktype.manmisc pcap-tstamp.manmisc pcap-savefile.manfile pcap.3pcap pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap pcap_get_tstamp_precision.3pcap pcap_list_datalinks.3pcap pcap_list_tstamp_types.3pcap pcap_open_dead.3pcap pcap_open_offline.3pcap pcap_set_tstamp_precision.3pcap pcap_set_tstamp_type.3pcap rpcapd/Makefile rpcapd/rpcapd.manadmin testprogs/Makefile" +ac_config_files="$ac_config_files Makefile pcap-filter.manmisc pcap-linktype.manmisc pcap-tstamp.manmisc pcap-savefile.manfile pcap.3pcap pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap pcap_get_tstamp_precision.3pcap pcap_list_datalinks.3pcap pcap_list_tstamp_types.3pcap pcap_open_dead.3pcap pcap_open_offline.3pcap pcap_set_immediate_mode.3pcap pcap_set_tstamp_precision.3pcap pcap_set_tstamp_type.3pcap rpcapd/Makefile rpcapd/rpcapd.manadmin rpcapd/rpcapd-config.manfile testprogs/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -10561,7 +11639,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by pcap $as_me 1.9.0-PRE-GIT, which was +This file was extended by pcap $as_me 1.9.1, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -10627,7 +11705,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -pcap config.status 1.9.0-PRE-GIT +pcap config.status 1.9.1 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -10770,10 +11848,12 @@ do "pcap_list_tstamp_types.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_list_tstamp_types.3pcap" ;; "pcap_open_dead.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_open_dead.3pcap" ;; "pcap_open_offline.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_open_offline.3pcap" ;; + "pcap_set_immediate_mode.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_set_immediate_mode.3pcap" ;; "pcap_set_tstamp_precision.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_set_tstamp_precision.3pcap" ;; "pcap_set_tstamp_type.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_set_tstamp_type.3pcap" ;; "rpcapd/Makefile") CONFIG_FILES="$CONFIG_FILES rpcapd/Makefile" ;; "rpcapd/rpcapd.manadmin") CONFIG_FILES="$CONFIG_FILES rpcapd/rpcapd.manadmin" ;; + "rpcapd/rpcapd-config.manfile") CONFIG_FILES="$CONFIG_FILES rpcapd/rpcapd-config.manfile" ;; "testprogs/Makefile") CONFIG_FILES="$CONFIG_FILES testprogs/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; diff --git a/configure.ac b/configure.ac index 2a9c8e95e19e..eba2723954a6 100644 --- a/configure.ac +++ b/configure.ac @@ -28,6 +28,9 @@ AC_LBL_C_INIT_BEFORE_CC(V_CCOPT, V_INCLS) # At minimum, we want C++/C99-style // comments. # AC_PROG_CC_C99 +if test "$ac_cv_prog_cc_c99" = "no"; then + AC_MSG_WARN([The C compiler does not support C99; there may be compiler errors]) +fi AC_LBL_C_INIT(V_CCOPT, V_INCLS) AC_LBL_SHLIBS_INIT AC_LBL_C_INLINE @@ -83,13 +86,109 @@ esac AC_LBL_FIXINCLUDES -AC_CHECK_FUNCS(strerror strerror_r strerror_s strlcpy strlcat) +AC_CHECK_FUNCS(strerror) +AC_CHECK_FUNC(strerror_r, + [ + # + # We have strerror_r; if we define _GNU_SOURCE, is it a + # POSIX-compliant strerror_r() or a GNU strerror_r()? + # + AC_MSG_CHECKING(whether strerror_r is GNU-style) + AC_COMPILE_IFELSE( + [ + AC_LANG_SOURCE( +#define _GNU_SOURCE +#include +/* Define it GNU-style; that will cause an error if it's not GNU-style */ +extern char *strerror_r(int, char *, size_t); + +int +main(void) +{ + return 0; +} +) + ], + [ + # GNU-style + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_GNU_STRERROR_R,, + [Define to 1 if you have a GNU-style `strerror_r' function.]) + ], + [ + AC_MSG_RESULT(no) + AC_DEFINE(HAVE_POSIX_STRERROR_R,, + [Define to 1 if you have a POSIX-style `strerror_r' function.]) + ]) + ], + [ + # + # We don't have strerror_r; do we have strerror_s? + # + AC_CHECK_FUNCS(strerror_s) + ]) + +# +# Thanks, IBM, for not providing vsyslog() in AIX! +# +AC_CHECK_FUNCS(vsyslog) + +# +# Either: +# +# we have snprintf() and vsnprintf(), and have asprintf() and +# vasprintf(); +# +# we have snprintf() and vsnprintf(), but don't have asprintf() +# or vasprintf(); +# +# we have neither snprintf() nor vsnprintf(), and don't have +# asprintf() or vasprintf(), either. +# +# We assume that if we have asprintf() we have vasprintf(), as well +# as snprintf() and vsnprintf(), and that if we have snprintf() we +# have vsnprintf(). +# +# For the first case, we don't need any replacement routines. +# For the second case, we need replacement asprintf()/vasprintf() +# routines. +# For the third case, we need replacement snprintf()/vsnprintf() and +# asprintf()/vasprintf() routines. +# needsnprintf=no AC_CHECK_FUNCS(vsnprintf snprintf,, [needsnprintf=yes]) +needasprintf=no +AC_CHECK_FUNCS(vasprintf asprintf,, + [needasprintf=yes]) if test $needsnprintf = yes; then + # + # We assume we have none of them; missing/snprintf.c supplies + # all of them. + # AC_LIBOBJ([snprintf]) +elif test $needasprintf = yes; then + # + # We assume we have snprintf()/vsnprintf() but lack + # asprintf()/vasprintf(); missing/asprintf.c supplies + # the latter (using vsnprintf()). + # + AC_LIBOBJ([asprintf]) +fi + +needstrlcat=no +AC_CHECK_FUNCS(strlcat,, + [needstrlcat=yes]) +if test $needstrlcat = yes; then + AC_LIBOBJ([strlcat]) +fi + +needstrlcpy=no +AC_CHECK_FUNCS(strlcpy,, + [needstrlcpy=yes]) +if test $needstrlcpy = yes; then + AC_LIBOBJ([strlcpy]) fi needstrtok_r=no @@ -550,6 +649,10 @@ else # requires that various BSD-style integer types # be defined; # + # sys/time.h, because AIX 5.2 and 5.3's net/bpf.h + # doesn't include it but does use struct timeval + # in ioctl definitions; + # # sys/ioctl.h and, if we have it, sys/ioccom.h, # because net/bpf.h defines ioctls; # @@ -568,6 +671,7 @@ else AC_TRY_COMPILE( [ #include +#include #include #include #ifdef HAVE_SYS_IOCCOM_H @@ -1529,18 +1633,20 @@ AC_CACHE_CHECK([for capable yacc/bison], tcpdump_cv_capable_yacc, fi) if test $tcpdump_cv_capable_yacc = insufficient ; then AC_MSG_ERROR([$YACC is insufficient to compile libpcap. - libpcap requires Bison, Berkeley YACC, or another YACC compatible with them.]) + libpcap requires Bison, a newer version of Berkeley YACC with support + for reentrant parsers, or another YACC compatible with them.]) fi # # Do various checks for various OSes and versions of those OSes. # # Assume, by default, no support for shared libraries and V7/BSD -# convention for man pages (file formats in section 5, miscellaneous -# info in section 7, administrative commands and daemons in section 8). -# Individual cases can override this. +# convention for man pages (devices in section 4, file formats in +# section 5, miscellaneous info in section 7, administrative commands +# and daemons in section 8). Individual cases can override this. # DYEXT="none" +MAN_DEVICES=4 MAN_FILE_FORMATS=5 MAN_MISC_INFO=7 MAN_ADMIN_COMMANDS=8 @@ -1596,79 +1702,151 @@ darwin*) if test "$enable_universal" != "no"; then case "$host_os" in - darwin[0-7].*) + darwin[[0-7]].*) # # Pre-Tiger. Build only for 32-bit PowerPC; no # need for any special compiler or linker flags. # ;; - darwin8.[0123]*) + darwin8.[[0123]]|darwin8.[[0123]].*) # - # Tiger, prior to Intel support. Build for 32-bit - # PowerPC and 64-bit PowerPC, with 32-bit PowerPC - # first. (I'm guessing that's what Apple does.) - # - V_CCOPT="$V_CCOPT -arch ppc -arch ppc64" - LDFLAGS="$LDFLAGS -arch ppc -arch ppc64" - ;; - - darwin8.[456]*) - # - # Tiger, subsequent to Intel support but prior to - # x86-64 support. Build for 32-bit PowerPC, 64-bit - # PowerPC, and x86, with 32-bit PowerPC first. + # Tiger, prior to Intel support. Build + # libraries and executables for 32-bit PowerPC + # and 64-bit PowerPC, with 32-bit PowerPC first. # (I'm guessing that's what Apple does.) # - V_CCOPT="$V_CCOPT -arch ppc -arch ppc64 -arch i386" - LDFLAGS="$LDFLAGS -arch ppc -arch ppc64 -arch i386" + # (The double brackets are needed because + # autotools/m4 use brackets as a quoting + # character; the double brackets turn into + # single brackets in the generated configure + # file.) + # + V_LIB_CCOPT_FAT="-arch ppc -arch ppc64" + V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64" + V_PROG_CCOPT_FAT="-arch ppc -arch ppc64" + V_PROG_LDFLAGS_FAT="-arch ppc -arch ppc64" + ;; + + darwin8.[[456]]|darwin.[[456]].*) + # + # Tiger, subsequent to Intel support but prior + # to x86-64 support. Build libraries and + # executables for 32-bit PowerPC, 64-bit + # PowerPC, and 32-bit x86, with 32-bit PowerPC + # first. (I'm guessing that's what Apple does.) + # + # (The double brackets are needed because + # autotools/m4 use brackets as a quoting + # character; the double brackets turn into + # single brackets in the generated configure + # file.) + # + V_LIB_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386" + V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386" + V_PROG_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386" + V_PROG_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386" ;; darwin8.*) # # All other Tiger, so subsequent to x86-64 - # support. Build for 32-bit PowerPC, 64-bit - # PowerPC, x86, and x86-64, and with 32-bit PowerPC - # first. (I'm guessing that's what Apple does.) + # support. Build libraries and executables for + # 32-bit PowerPC, 64-bit PowerPC, 32-bit x86, + # and x86-64, with 32-bit PowerPC first. (I'm + # guessing that's what Apple does.) # - V_CCOPT="$V_CCOPT -arch ppc -arch ppc64 -arch i386 -arch x86_64" - LDFLAGS="$LDFLAGS -arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_LIB_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_PROG_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_PROG_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" ;; darwin9.*) # - # Leopard. Build for 32-bit PowerPC, 64-bit - # PowerPC, x86, and x86-64, with 32-bit PowerPC - # first. (That's what Apple does.) + # Leopard. Build libraries for 32-bit PowerPC, + # 64-bit PowerPC, 32-bit x86, and x86-64, with + # 32-bit PowerPC first, and build executables + # for 32-bit x86 and 32-bit PowerPC, with 32-bit + # x86 first. (That's what Apple does.) # - V_CCOPT="$V_CCOPT -arch ppc -arch ppc64 -arch i386 -arch x86_64" - LDFLAGS="$LDFLAGS -arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_LIB_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_PROG_CCOPT_FAT="-arch i386 -arch ppc" + V_PROG_LDFLAGS_FAT="-arch i386 -arch ppc" ;; darwin10.*) # - # Snow Leopard. Build for x86-64, x86, and - # 32-bit PowerPC, with x86-64 first. (That's - # what Apple does, even though Snow Leopard - # doesn't run on PPC, so PPC libpcap runs under - # Rosetta, and Rosetta doesn't support BPF - # ioctls, so PPC programs can't do live - # captures.) + # Snow Leopard. Build libraries for x86-64, + # 32-bit x86, and 32-bit PowerPC, with x86-64 + # first, and build executables for x86-64 and + # 32-bit x86, with x86-64 first. (That's what + # Apple does, even though Snow Leopard doesn't + # run on PPC, so PPC libpcap runs under Rosetta, + # and Rosetta doesn't support BPF ioctls, so PPC + # programs can't do live captures.) # - V_CCOPT="$V_CCOPT -arch x86_64 -arch i386 -arch ppc" - LDFLAGS="$LDFLAGS -arch x86_64 -arch i386 -arch ppc" + V_LIB_CCOPT_FAT="-arch x86_64 -arch i386 -arch ppc" + V_LIB_LDFLAGS_FAT="-arch x86_64 -arch i386 -arch ppc" + V_PROG_CCOPT_FAT="-arch x86_64 -arch i386" + V_PROG_LDFLAGS_FAT="-arch x86_64 -arch i386" ;; darwin*) # - # Post-Snow Leopard. Build for x86-64 and - # x86, with x86-64 first. (That's probably what - # Apple does, given that Rosetta is gone.) + # Post-Snow Leopard. Build libraries for x86-64 + # and 32-bit x86, with x86-64 first, and build + # executables only for x86-64. (That's what + # Apple does.) This requires no special flags + # for programs. # XXX - update if and when Apple drops support - # for 32-bit x86 code. + # for 32-bit x86 code and if and when Apple adds + # ARM-based Macs. (You're on your own for iOS + # etc.) # - V_CCOPT="$V_CCOPT -arch x86_64 -arch i386" - LDFLAGS="$LDFLAGS -arch x86_64 -arch i386" + # XXX - check whether we *can* build for + # i386 and, if not, suggest that the user + # install the /usr/include headers if they + # want to build fat. + # + AC_MSG_CHECKING(whether building for 32-bit x86 is supported) + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -arch i386" + AC_TRY_COMPILE( + [], + [return 0;], + [ + AC_MSG_RESULT(yes) + V_LIB_CCOPT_FAT="-arch x86_64 -arch i386" + V_LIB_LDFLAGS_FAT="-arch x86_64 -arch i386" + ], + [ + AC_MSG_RESULT(no) + V_LIB_CCOPT_FAT="-arch x86_64" + V_LIB_LDFLAGS_FAT="-arch x86_64" + case "$host_os" in + + darwin18.*) + # + # Mojave; you need to install the + # /usr/include headers to get + # 32-bit x86 builds to work. + # + AC_MSG_WARN([Compiling for 32-bit x86 gives an error; try installing the command-line tools and, after that, installing the /usr/include headers from the /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg package]) + ;; + + *) + # + # Pre-Mojave; the command-line + # tools should be sufficient to + # enable 32-bit x86 builds. + # + AC_MSG_WARN([Compiling for 32-bit x86 gives an error; try installing the command-line tools]) + ;; + esac + ]) + CFLAGS="$save_CFLAGS" ;; esac fi @@ -1742,7 +1920,7 @@ irix*) MAN_MISC_INFO=5 ;; -linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*) +linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*|midipix*) DYEXT="so" # @@ -1765,6 +1943,7 @@ osf*) # MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 + MAN_DEVICES=7 ;; sinix*) @@ -1808,6 +1987,7 @@ solaris*) MAN_ADMIN_COMMANDS=1m MAN_FILE_FORMATS=4 MAN_MISC_INFO=5 + MAN_DEVICES=7D esac ;; esac @@ -1863,6 +2043,10 @@ AC_CHECK_MEMBERS([dl_hp_ppa_info_t.dl_module_id_1],,, AC_LBL_UNALIGNED_ACCESS AC_SUBST(V_CCOPT) +AC_SUBST(V_LIB_CCOPT_FAT) +AC_SUBST(V_LIB_LDFLAGS_FAT) +AC_SUBST(V_PROG_CCOPT_FAT) +AC_SUBST(V_PROG_LDFLAGS_FAT) AC_SUBST(V_DEFS) AC_SUBST(V_FINDALLDEVS) AC_SUBST(V_INCLS) @@ -1878,6 +2062,7 @@ AC_SUBST(ADDLOBJS) AC_SUBST(ADDLARCHIVEOBJS) AC_SUBST(SSRC) AC_SUBST(DYEXT) +AC_SUBST(MAN_DEVICES) AC_SUBST(MAN_FILE_FORMATS) AC_SUBST(MAN_MISC_INFO) AC_SUBST(MAN_ADMIN_COMMANDS) @@ -2212,15 +2397,15 @@ fi AC_ARG_ENABLE([rdma], [AC_HELP_STRING([--enable-rdma],[enable RDMA capture support @<:@default=yes, if support available@:>@])], [], - [enable_rdmasniff=ifavailable]) + [enable_rdma=ifavailable]) if test "xxx_only" = yes; then # User requested something-else-only pcap, so they don't # want RDMA support. - enable_rdmasniff=no + enable_rdma=no fi -if test "x$enable_rdmasniff" != "xno"; then +if test "x$enable_rdma" != "xno"; then AC_CHECK_LIB(ibverbs, ibv_get_device_list, [ AC_CHECK_HEADER(infiniband/verbs.h, [ # @@ -2273,7 +2458,8 @@ AC_OUTPUT(Makefile pcap-filter.manmisc pcap-linktype.manmisc pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap pcap_get_tstamp_precision.3pcap pcap_list_datalinks.3pcap pcap_list_tstamp_types.3pcap pcap_open_dead.3pcap - pcap_open_offline.3pcap pcap_set_tstamp_precision.3pcap - pcap_set_tstamp_type.3pcap rpcapd/Makefile rpcapd/rpcapd.manadmin + pcap_open_offline.3pcap pcap_set_immediate_mode.3pcap + pcap_set_tstamp_precision.3pcap pcap_set_tstamp_type.3pcap + rpcapd/Makefile rpcapd/rpcapd.manadmin rpcapd/rpcapd-config.manfile testprogs/Makefile) exit 0 diff --git a/diag-control.h b/diag-control.h index 127703618633..cfc581b37b57 100644 --- a/diag-control.h +++ b/diag-control.h @@ -120,13 +120,14 @@ * shadowing the global declaration. * * So, if the compiler warns about that, we turn off -Wshadow warnings. + * + * In addition, the generated code may have functions with unreachable + * code, so suppress warnings about those. */ #if defined(_MSC_VER) /* * This is Microsoft Visual Studio; we can use * __pragma(warning(disable:XXXX)) and __pragma(warning(push/pop)). - * - * Suppress unreachable code warnings. */ #define DIAG_OFF_BISON_BYACC \ __pragma(warning(push)) \ @@ -166,6 +167,9 @@ #else /* * Bison. + * + * The generated code may have functions with unreachable code, so + * suppress warnings about those. */ #if defined(_MSC_VER) /* diff --git a/doc/DLT_ALLOCATE_HOWTO.md b/doc/DLT_ALLOCATE_HOWTO.md new file mode 100644 index 000000000000..ff77128e2302 --- /dev/null +++ b/doc/DLT_ALLOCATE_HOWTO.md @@ -0,0 +1,29 @@ +DLT and LINKTYPE allocation +=========================== + +DLT_ types live in pcap/dlt.h. They can be requested by the community on a +First-Come First-Served basis [i.e. https://tools.ietf.org/html/rfc8126#section-4.4 ] +(Although libpcap is not at this time an IETF specification, there have been +some as yet-incomplete efforts to do this). + +The Tcpdump Group prefers to link to an open specification on the new DLT_ +type, but they are available for closed, proprietary projects as well. +In that case, a stable email address suffices so that someone who finds +an unknown DLT_ type can investigate. +We prefer to give out unambiguous numbers, and we try to do it as quickly +as possible, but DLT_USERx is available while you wait. + +Note that DLT_ types are, in theory, private to the capture mechanism and can +in some cases be operating system specific, and so a second set of values, +LINKTYPE_ is allocated for actually writing to pcap files. As much as +possible going forward, the DLT_ and LINKTYPE_ value are identical, however, +this was not always the case. See pcap-common.c. + +The LINKTYPE_ values are not exported, but are in pcap-common.c only. + +DEVELOPER NOTES +--------------- + +When allocating a new DLT_ value, a corresponding value needs to be +added to pcap-common.c. +It is not necessary to copy the comments from dlt.h to pcap-common.c. diff --git a/doc/README.Win32.md b/doc/README.Win32.md new file mode 100644 index 000000000000..8de25c85a95c --- /dev/null +++ b/doc/README.Win32.md @@ -0,0 +1,3 @@ +Win32 used to build with Visual Studio 6, but we now use cmake. + +This file needs to be adopted by a windows expert developer. diff --git a/README.aix b/doc/README.aix similarity index 100% rename from README.aix rename to doc/README.aix diff --git a/README.dag b/doc/README.dag similarity index 97% rename from README.dag rename to doc/README.dag index accae7c38276..7ea25040eb1a 100644 --- a/README.dag +++ b/doc/README.dag @@ -5,7 +5,7 @@ Endace (http://www.endace.com, see below for further contact details). 1) Install and build the DAG software distribution by following the instructions supplied with that package. Current Endace customers can download -the DAG software distibution from https://www.endace.com +the DAG software distribution from https://www.endace.com 2) Configure libcap. To allow the 'configure' script to locate the DAG software distribution use the '--with-dag' option: @@ -88,7 +88,7 @@ as separate interfaces, e.g. dag0:0, dag0:2, dag0:4 etc. dag0:0 is the same as dag0. These are visible via pcap_findalldevs(). libpcap now does NOT set the card's hardware snaplen (slen). This must now be -set using the appropriate DAG coniguration program, e.g. dagthree, dagfour, +set using the appropriate DAG configuration program, e.g. dagthree, dagfour, dagsix, dagconfig. This is because the snaplen is currently shared between all of the streams. In future this may change if per-stream slen is implemented. diff --git a/README.hpux b/doc/README.hpux similarity index 100% rename from README.hpux rename to doc/README.hpux diff --git a/README.linux b/doc/README.linux.md similarity index 98% rename from README.linux rename to doc/README.linux.md index ffcb9288ca13..ddca4fecfa9e 100644 --- a/README.linux +++ b/doc/README.linux.md @@ -97,9 +97,9 @@ reported by pcap_stats on Linux are as follows: 2.2.x ===== ps_recv Number of packets that were accepted by the pcap filter -ps_drop Always 0, this statistic is not gatherd on this platform +ps_drop Always 0, this statistic is not gathered on this platform -2.4.x +2.4.x and later ===== ps_recv Number of packets that were accepted by the pcap filter ps_drop Number of packets that had passed filtering but were not diff --git a/README.macos b/doc/README.macos similarity index 100% rename from README.macos rename to doc/README.macos diff --git a/README.septel b/doc/README.septel similarity index 100% rename from README.septel rename to doc/README.septel diff --git a/README.sita b/doc/README.sita similarity index 100% rename from README.sita rename to doc/README.sita diff --git a/README.tru64 b/doc/README.tru64 similarity index 100% rename from README.tru64 rename to doc/README.tru64 diff --git a/fmtutils.c b/fmtutils.c index f1a8907327de..091e0d35eede 100644 --- a/fmtutils.c +++ b/fmtutils.c @@ -65,11 +65,6 @@ pcap_fmt_errmsg_for_errno(char *errbuf, size_t errbuflen, int errnum, size_t msglen; char *p; size_t errbuflen_remaining; -#if defined(HAVE_STRERROR_S) - errno_t err; -#elif defined(HAVE_STRERROR_R) - int err; -#endif va_start(ap, fmt); pcap_vsnprintf(errbuf, errbuflen, fmt, ap); @@ -96,7 +91,10 @@ pcap_fmt_errmsg_for_errno(char *errbuf, size_t errbuflen, int errnum, * Now append the string for the error code. */ #if defined(HAVE_STRERROR_S) - err = strerror_s(p, errbuflen_remaining, errnum); + /* + * We have a Windows-style strerror_s(). + */ + errno_t err = strerror_s(p, errbuflen_remaining, errnum); if (err != 0) { /* * It doesn't appear to be documented anywhere obvious @@ -104,8 +102,24 @@ pcap_fmt_errmsg_for_errno(char *errbuf, size_t errbuflen, int errnum, */ pcap_snprintf(p, errbuflen_remaining, "Error %d", errnum); } -#elif defined(HAVE_STRERROR_R) - err = strerror_r(errnum, p, errbuflen_remaining); +#elif defined(HAVE_GNU_STRERROR_R) + /* + * We have a GNU-style strerror_r(), which is *not* guaranteed to + * do anything to the buffer handed to it, and which returns a + * pointer to the error string, which may or may not be in + * the buffer. + * + * It is, however, guaranteed to succeed. + */ + char strerror_buf[PCAP_ERRBUF_SIZE]; + char *errstring = strerror_r(errnum, strerror_buf, PCAP_ERRBUF_SIZE); + pcap_snprintf(p, errbuflen_remaining, "%s", errstring); +#elif defined(HAVE_POSIX_STRERROR_R) + /* + * We have a POSIX-style strerror_r(), which is guaranteed to fill + * in the buffer, but is not guaranteed to succeed. + */ + int err = strerror_r(errnum, p, errbuflen_remaining); if (err == EINVAL) { /* * UNIX 03 says this isn't guaranteed to produce a @@ -129,3 +143,72 @@ pcap_fmt_errmsg_for_errno(char *errbuf, size_t errbuflen, int errnum, pcap_snprintf(p, errbuflen_remaining, "%s", pcap_strerror(errnum)); #endif } + +#ifdef _WIN32 +/* + * Generate an error message based on a format, arguments, and a + * Win32 error, with a message for the Win32 error after the formatted output. + */ +void +pcap_fmt_errmsg_for_win32_err(char *errbuf, size_t errbuflen, DWORD errnum, + const char *fmt, ...) +{ + va_list ap; + size_t msglen; + char *p; + size_t errbuflen_remaining; + DWORD retval; + char win32_errbuf[PCAP_ERRBUF_SIZE+1]; + + va_start(ap, fmt); + pcap_vsnprintf(errbuf, errbuflen, fmt, ap); + va_end(ap); + msglen = strlen(errbuf); + + /* + * Do we have enough space to append ": "? + * Including the terminating '\0', that's 3 bytes. + */ + if (msglen + 3 > errbuflen) { + /* No - just give them what we've produced. */ + return; + } + p = errbuf + msglen; + errbuflen_remaining = errbuflen - msglen; + *p++ = ':'; + *p++ = ' '; + *p = '\0'; + msglen += 2; + errbuflen_remaining -= 2; + + /* + * Now append the string for the error code. + * + * XXX - what language ID to use? + * + * For UN*Xes, pcap_strerror() may or may not return localized + * strings. + * + * We currently don't have localized messages for libpcap, but + * we might want to do so. On the other hand, if most of these + * messages are going to be read by libpcap developers and + * perhaps by developers of libpcap-based applications, English + * might be a better choice, so the developer doesn't have to + * get the message translated if it's in a language they don't + * happen to understand. + */ + retval = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_MAX_WIDTH_MASK, + NULL, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + win32_errbuf, PCAP_ERRBUF_SIZE, NULL); + if (retval == 0) { + /* + * Failed. + */ + pcap_snprintf(p, errbuflen_remaining, + "Couldn't get error message for error (%lu)", errnum); + return; + } + + pcap_snprintf(p, errbuflen_remaining, "%s (%lu)", win32_errbuf, errnum); +} +#endif diff --git a/fmtutils.h b/fmtutils.h index 62c78fdba1b2..838948bcd3d6 100644 --- a/fmtutils.h +++ b/fmtutils.h @@ -43,6 +43,11 @@ extern "C" { void pcap_fmt_errmsg_for_errno(char *, size_t, int, PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(4, 5); +#ifdef _WIN32 +void pcap_fmt_errmsg_for_win32_err(char *, size_t, DWORD, + PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(4, 5); +#endif + #ifdef __cplusplus } #endif diff --git a/ftmacros.h b/ftmacros.h index de8da98e38b6..cd3daebdf175 100644 --- a/ftmacros.h +++ b/ftmacros.h @@ -85,20 +85,14 @@ */ #elif defined(__linux__) || defined(linux) || defined(__linux) /* - * We can't turn _GNU_SOURCE on because some versions of GNU Libc - * will give the GNU version of strerror_r(), which returns a - * string pointer and doesn't necessarily fill in the buffer, - * rather than the standard version of strerror_r(), which - * returns 0 or an errno and always fills in the buffer. We - * require both of the latter behaviors. + * Turn on _GNU_SOURCE to get everything GNU libc has to offer, + * including asprintf(). * - * So we try turning everything else on that we can. This includes - * defining _XOPEN_SOURCE as 600, because we want to force crypt() - * to be declared on systems that use GNU libc, such as most Linux - * distributions. + * Unfortunately, one thing it has to offer is a strerror_r() + * that's not POSIX-compliant, but we deal with that in + * pcap_fmt_errmsg_for_errno(). */ - #define _POSIX_C_SOURCE 200809L - #define _XOPEN_SOURCE 600 + #define _GNU_SOURCE /* * We turn on both _DEFAULT_SOURCE and _BSD_SOURCE to try to get diff --git a/gencode.c b/gencode.c index 959a56e6e5e6..e3425cd9eb95 100644 --- a/gencode.c +++ b/gencode.c @@ -50,6 +50,8 @@ #include "pcap-int.h" +#include "extract.h" + #include "ethertype.h" #include "nlpid.h" #include "llc.h" @@ -276,6 +278,13 @@ struct _compiler_state { */ struct addrinfo *ai; + /* + * Another thing that's allocated is the result of pcap_ether_aton(); + * it must be freed with free(). This variable points to any + * address that would need to be freed. + */ + u_char *e; + /* * Various code constructs need to know the layout of the packet. * These values give the necessary offsets from the beginning @@ -417,35 +426,49 @@ struct _compiler_state { int cur_chunk; }; -void PCAP_NORETURN -bpf_syntax_error(compiler_state_t *cstate, const char *msg) +/* + * For use by routines outside this file. + */ +/* VARARGS */ +void +bpf_set_error(compiler_state_t *cstate, const char *fmt, ...) { - bpf_error(cstate, "syntax error in filter expression: %s", msg); - /* NOTREACHED */ + va_list ap; + + va_start(ap, fmt); + (void)pcap_vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE, + fmt, ap); + va_end(ap); } +/* + * For use *ONLY* in routines in this file. + */ +static void PCAP_NORETURN bpf_error(compiler_state_t *, const char *, ...) + PCAP_PRINTFLIKE(2, 3); + /* VARARGS */ -void PCAP_NORETURN +static void PCAP_NORETURN bpf_error(compiler_state_t *cstate, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - if (cstate->bpf_pcap != NULL) - (void)pcap_vsnprintf(pcap_geterr(cstate->bpf_pcap), - PCAP_ERRBUF_SIZE, fmt, ap); + (void)pcap_vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE, + fmt, ap); va_end(ap); longjmp(cstate->top_ctx, 1); - /* NOTREACHED */ + /*NOTREACHED*/ } -static void init_linktype(compiler_state_t *, pcap_t *); +static int init_linktype(compiler_state_t *, pcap_t *); static void init_regs(compiler_state_t *); static int alloc_reg(compiler_state_t *); static void free_reg(compiler_state_t *, int); static void initchunks(compiler_state_t *cstate); +static void *newchunk_nolongjmp(compiler_state_t *cstate, size_t); static void *newchunk(compiler_state_t *cstate, size_t); static void freechunks(compiler_state_t *cstate); static inline struct block *new_block(compiler_state_t *cstate, int); @@ -543,6 +566,9 @@ static struct block *gen_check_802_11_data_frame(compiler_state_t *); static struct block *gen_geneve_ll_check(compiler_state_t *cstate); static struct block *gen_ppi_dlt_check(compiler_state_t *); +static struct block *gen_atmfield_code_internal(compiler_state_t *, int, + bpf_int32, bpf_u_int32, int); +static struct block *gen_atmtype_llc(compiler_state_t *); static struct block *gen_msg_abbrev(compiler_state_t *, int type); static void @@ -558,7 +584,7 @@ initchunks(compiler_state_t *cstate) } static void * -newchunk(compiler_state_t *cstate, size_t n) +newchunk_nolongjmp(compiler_state_t *cstate, size_t n) { struct chunk *cp; int k; @@ -576,21 +602,40 @@ newchunk(compiler_state_t *cstate, size_t n) if (n > cp->n_left) { ++cp; k = ++cstate->cur_chunk; - if (k >= NCHUNKS) - bpf_error(cstate, "out of memory"); + if (k >= NCHUNKS) { + bpf_set_error(cstate, "out of memory"); + return (NULL); + } size = CHUNK0SIZE << k; cp->m = (void *)malloc(size); - if (cp->m == NULL) - bpf_error(cstate, "out of memory"); + if (cp->m == NULL) { + bpf_set_error(cstate, "out of memory"); + return (NULL); + } memset((char *)cp->m, 0, size); cp->n_left = size; - if (n > size) - bpf_error(cstate, "out of memory"); + if (n > size) { + bpf_set_error(cstate, "out of memory"); + return (NULL); + } } cp->n_left -= n; return (void *)((char *)cp->m + cp->n_left); } +static void * +newchunk(compiler_state_t *cstate, size_t n) +{ + void *p; + + p = newchunk_nolongjmp(cstate, n); + if (p == NULL) { + longjmp(cstate->top_ctx, 1); + /*NOTREACHED*/ + } + return (p); +} + static void freechunks(compiler_state_t *cstate) { @@ -603,14 +648,19 @@ freechunks(compiler_state_t *cstate) /* * A strdup whose allocations are freed after code generation is over. + * This is used by the lexical analyzer, so it can't longjmp; it just + * returns NULL on an allocation error, and the callers must check + * for it. */ char * sdup(compiler_state_t *cstate, const char *s) { size_t n = strlen(s) + 1; - char *cp = newchunk(cstate, n); + char *cp = newchunk_nolongjmp(cstate, n); - strlcpy(cp, s, n); + if (cp == NULL) + return (NULL); + pcap_strlcpy(cp, s, n); return (cp); } @@ -662,7 +712,7 @@ pcap_compile(pcap_t *p, struct bpf_program *program, compiler_state_t cstate; const char * volatile xbuf = buf; yyscan_t scanner = NULL; - YY_BUFFER_STATE in_buffer = NULL; + volatile YY_BUFFER_STATE in_buffer = NULL; u_int len; int rc; @@ -697,7 +747,7 @@ pcap_compile(pcap_t *p, struct bpf_program *program, * filter for this pcap_t; we might be running it from userland * on captured packets to do packet classification. We really * need a better way of handling this, but this is all that - * the WinPcap code did. + * the WinPcap remote capture code did. */ if (p->save_current_filter_op != NULL) (p->save_current_filter_op)(p, buf); @@ -708,20 +758,12 @@ pcap_compile(pcap_t *p, struct bpf_program *program, #ifdef INET6 cstate.ai = NULL; #endif + cstate.e = NULL; cstate.ic.root = NULL; cstate.ic.cur_mark = 0; cstate.bpf_pcap = p; init_regs(&cstate); - if (setjmp(cstate.top_ctx)) { -#ifdef INET6 - if (cstate.ai != NULL) - freeaddrinfo(cstate.ai); -#endif - rc = -1; - goto quit; - } - cstate.netmask = mask; cstate.snaplen = pcap_snapshot(p); @@ -743,19 +785,53 @@ pcap_compile(pcap_t *p, struct bpf_program *program, */ pcap_set_extra(&cstate, scanner); - init_linktype(&cstate, p); - (void)pcap_parse(scanner, &cstate); + if (init_linktype(&cstate, p) == -1) { + rc = -1; + goto quit; + } + if (pcap_parse(scanner, &cstate) != 0) { +#ifdef INET6 + if (cstate.ai != NULL) + freeaddrinfo(cstate.ai); +#endif + if (cstate.e != NULL) + free(cstate.e); + rc = -1; + goto quit; + } - if (cstate.ic.root == NULL) + if (cstate.ic.root == NULL) { + /* + * Catch errors reported by gen_retblk(). + */ + if (setjmp(cstate.top_ctx)) { + rc = -1; + goto quit; + } cstate.ic.root = gen_retblk(&cstate, cstate.snaplen); + } if (optimize && !cstate.no_optimize) { - bpf_optimize(&cstate, &cstate.ic); + if (bpf_optimize(&cstate.ic, p->errbuf) == -1) { + /* Failure */ + rc = -1; + goto quit; + } if (cstate.ic.root == NULL || - (cstate.ic.root->s.code == (BPF_RET|BPF_K) && cstate.ic.root->s.k == 0)) - bpf_error(&cstate, "expression rejects all packets"); + (cstate.ic.root->s.code == (BPF_RET|BPF_K) && cstate.ic.root->s.k == 0)) { + (void)pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "expression rejects all packets"); + rc = -1; + goto quit; + } + } + program->bf_insns = icode_to_fcode(&cstate.ic, + cstate.ic.root, &len, p->errbuf); + if (program->bf_insns == NULL) { + /* Failure */ + rc = -1; + goto quit; } - program->bf_insns = icode_to_fcode(&cstate, &cstate.ic, cstate.ic.root, &len); program->bf_len = len; rc = 0; /* We're all okay */ @@ -851,11 +927,18 @@ merge(struct block *b0, struct block *b1) *p = b1; } -void +int finish_parse(compiler_state_t *cstate, struct block *p) { struct block *ppi_dlt_check; + /* + * Catch errors reported by us and routines below us, and return -1 + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (-1); + /* * Insert before the statements of the first (root) block any * statements needed to load the lengths of any variable-length @@ -898,6 +981,7 @@ finish_parse(compiler_state_t *cstate, struct block *p) p->sense = !p->sense; backpatch(p, gen_retblk(cstate, 0)); cstate->ic.root = p->head; + return (0); } void @@ -975,13 +1059,22 @@ gen_bcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, { register struct block *b, *tmp; + /* + * XXX - the actual *instructions* do unsigned comparisons on + * most platforms, and the load instructions don't do sign + * extension, so gen_cmp() should really take an unsigned + * value argument. + * + * As the load instructons also don't do sign-extension, we + * fetch the values from the byte array as unsigned. We don't + * want to use the signed versions of the extract calls. + */ b = NULL; while (size >= 4) { register const u_char *p = &v[size - 4]; - bpf_int32 w = ((bpf_int32)p[0] << 24) | - ((bpf_int32)p[1] << 16) | ((bpf_int32)p[2] << 8) | p[3]; - tmp = gen_cmp(cstate, offrel, offset + size - 4, BPF_W, w); + tmp = gen_cmp(cstate, offrel, offset + size - 4, BPF_W, + (bpf_int32)EXTRACT_32BITS(p)); if (b != NULL) gen_and(b, tmp); b = tmp; @@ -989,9 +1082,9 @@ gen_bcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, } while (size >= 2) { register const u_char *p = &v[size - 2]; - bpf_int32 w = ((bpf_int32)p[0] << 8) | p[1]; - tmp = gen_cmp(cstate, offrel, offset + size - 2, BPF_H, w); + tmp = gen_cmp(cstate, offrel, offset + size - 2, BPF_H, + (bpf_int32)EXTRACT_16BITS(p)); if (b != NULL) gen_and(b, tmp); b = tmp; @@ -1036,7 +1129,7 @@ gen_ncmp(compiler_state_t *cstate, enum e_offrel offrel, bpf_u_int32 offset, return b; } -static void +static int init_linktype(compiler_state_t *cstate, pcap_t *p) { cstate->pcap_fddipad = p->fddipad; @@ -1241,6 +1334,7 @@ init_linktype(compiler_state_t *cstate, pcap_t *p) cstate->off_linkhdr.is_variable = 1; /* Fall through, 802.11 doesn't have a variable link * prefix but is otherwise the same. */ + /* FALLTHROUGH */ case DLT_IEEE802_11: /* @@ -1330,13 +1424,20 @@ init_linktype(compiler_state_t *cstate, pcap_t *p) cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; - case DLT_LINUX_SLL: /* fake header for Linux cooked socket */ + case DLT_LINUX_SLL: /* fake header for Linux cooked socket v1 */ cstate->off_linktype.constant_part = 14; cstate->off_linkpl.constant_part = 16; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; + case DLT_LINUX_SLL2: /* fake header for Linux cooked socket v2 */ + cstate->off_linktype.constant_part = 0; + cstate->off_linkpl.constant_part = 20; + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + case DLT_LTALK: /* * LocalTalk does have a 1-byte type field in the LLAP header, @@ -1612,12 +1713,14 @@ init_linktype(compiler_state_t *cstate, pcap_t *p) cstate->off_nl = OFFSET_NOT_SET; cstate->off_nl_nosnap = OFFSET_NOT_SET; } else { - bpf_error(cstate, "unknown data link type %d", cstate->linktype); + bpf_set_error(cstate, "unknown data link type %d", cstate->linktype); + return (-1); } break; } cstate->off_outermostlinkhdr = cstate->off_prevlinkhdr = cstate->off_linkhdr; + return (0); } /* @@ -1669,6 +1772,19 @@ gen_load_a(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, { struct slist *s, *s2; + /* + * Squelch warnings from compilers that *don't* assume that + * offrel always has a valid enum value and therefore don't + * assume that we'll always go through one of the case arms. + * + * If we have a default case, compilers that *do* assume that + * will then complain about the default case code being + * unreachable. + * + * Damned if you do, damned if you don't. + */ + s = NULL; + switch (offrel) { case OR_PACKET: @@ -1732,10 +1848,6 @@ gen_load_a(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, case OR_TRAN_IPV6: s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl + 40 + offset, size); break; - - default: - abort(); - /* NOTREACHED */ } return s; } @@ -2059,12 +2171,12 @@ gen_ipnet_linktype(compiler_state_t *cstate, int proto) case ETHERTYPE_IP: return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)IPH_AF_INET); - /* NOTREACHED */ + /*NOTREACHED*/ case ETHERTYPE_IPV6: return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)IPH_AF_INET6); - /* NOTREACHED */ + /*NOTREACHED*/ default: break; @@ -3041,7 +3153,7 @@ gen_linktype(compiler_state_t *cstate, int proto) default: bpf_error(cstate, "unsupported protocol over mpls"); - /* NOTREACHED */ + /*NOTREACHED*/ } } @@ -3062,7 +3174,6 @@ gen_linktype(compiler_state_t *cstate, int proto) gen_and(b0, b1); return b1; /*NOTREACHED*/ - break; case DLT_C_HDLC: switch (proto) { @@ -3074,9 +3185,7 @@ gen_linktype(compiler_state_t *cstate, int proto) default: return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); /*NOTREACHED*/ - break; } - break; case DLT_IEEE802_11: case DLT_PRISM_HEADER: @@ -3095,7 +3204,6 @@ gen_linktype(compiler_state_t *cstate, int proto) gen_and(b0, b1); return b1; /*NOTREACHED*/ - break; case DLT_FDDI: /* @@ -3103,7 +3211,6 @@ gen_linktype(compiler_state_t *cstate, int proto) */ return gen_llc_linktype(cstate, proto); /*NOTREACHED*/ - break; case DLT_IEEE802: /* @@ -3111,14 +3218,12 @@ gen_linktype(compiler_state_t *cstate, int proto) */ return gen_llc_linktype(cstate, proto); /*NOTREACHED*/ - break; case DLT_ATM_RFC1483: case DLT_ATM_CLIP: case DLT_IP_OVER_FC: return gen_llc_linktype(cstate, proto); /*NOTREACHED*/ - break; case DLT_SUNATM: /* @@ -3128,17 +3233,15 @@ gen_linktype(compiler_state_t *cstate, int proto) * * Check for LLC encapsulation and then check the protocol. */ - b0 = gen_atmfield_code(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0); + b0 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0); b1 = gen_llc_linktype(cstate, proto); gen_and(b0, b1); return b1; /*NOTREACHED*/ - break; case DLT_LINUX_SLL: return gen_linux_sll_linktype(cstate, proto); /*NOTREACHED*/ - break; case DLT_SLIP: case DLT_SLIP_BSDOS: @@ -3164,7 +3267,6 @@ gen_linktype(compiler_state_t *cstate, int proto) return gen_false(cstate); /* always false */ } /*NOTREACHED*/ - break; case DLT_IPV4: /* @@ -3176,7 +3278,6 @@ gen_linktype(compiler_state_t *cstate, int proto) /* Checking for something other than IPv4; always false */ return gen_false(cstate); /*NOTREACHED*/ - break; case DLT_IPV6: /* @@ -3188,7 +3289,6 @@ gen_linktype(compiler_state_t *cstate, int proto) /* Checking for something other than IPv6; always false */ return gen_false(cstate); /*NOTREACHED*/ - break; case DLT_PPP: case DLT_PPP_PPPD: @@ -3201,7 +3301,6 @@ gen_linktype(compiler_state_t *cstate, int proto) proto = ethertype_to_ppptype(proto); return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); /*NOTREACHED*/ - break; case DLT_PPP_BSDOS: /* @@ -3228,7 +3327,6 @@ gen_linktype(compiler_state_t *cstate, int proto) (bpf_int32)proto); } /*NOTREACHED*/ - break; case DLT_NULL: case DLT_LOOP: @@ -3323,7 +3421,6 @@ gen_linktype(compiler_state_t *cstate, int proto) else return gen_false(cstate); /*NOTREACHED*/ - break; #endif /* HAVE_NET_PFVAR_H */ case DLT_ARCNET: @@ -3366,7 +3463,6 @@ gen_linktype(compiler_state_t *cstate, int proto) (bpf_int32)ARCTYPE_ATALK)); } /*NOTREACHED*/ - break; case DLT_LTALK: switch (proto) { @@ -3376,7 +3472,6 @@ gen_linktype(compiler_state_t *cstate, int proto) return gen_false(cstate); } /*NOTREACHED*/ - break; case DLT_FRELAY: /* @@ -3420,7 +3515,6 @@ gen_linktype(compiler_state_t *cstate, int proto) return gen_false(cstate); } /*NOTREACHED*/ - break; case DLT_MFR: bpf_error(cstate, "Multi-link Frame Relay link-layer type filtering not implemented"); @@ -3511,7 +3605,8 @@ gen_linktype(compiler_state_t *cstate, int proto) case DLT_RAIF1: bpf_error(cstate, "RAIF1 link-layer type filtering not implemented"); - case DLT_IPMB: + case DLT_IPMB_KONTRON: + case DLT_IPMB_LINUX: bpf_error(cstate, "IPMB link-layer type filtering not implemented"); case DLT_AX25_KISS: @@ -3538,20 +3633,16 @@ gen_linktype(compiler_state_t *cstate, int proto) * above.) */ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto); + /*NOTREACHED */ } else { /* * No; report an error. */ - description = pcap_datalink_val_to_description(cstate->linktype); - if (description != NULL) { - bpf_error(cstate, "%s link-layer type filtering not implemented", - description); - } else { - bpf_error(cstate, "DLT %u link-layer type filtering not implemented", - cstate->linktype); - } + description = pcap_datalink_val_to_description_or_dlt(cstate->linktype); + bpf_error(cstate, "%s link-layer type filtering not implemented", + description); + /*NOTREACHED */ } - break; } } @@ -3581,8 +3672,8 @@ gen_snap(compiler_state_t *cstate, bpf_u_int32 orgcode, bpf_u_int32 ptype) /* * Generate code to match frames with an LLC header. */ -struct block * -gen_llc(compiler_state_t *cstate) +static struct block * +gen_llc_internal(compiler_state_t *cstate) { struct block *b0, *b1; @@ -3609,7 +3700,7 @@ gen_llc(compiler_state_t *cstate) /* * We check for LLC traffic. */ - b0 = gen_atmtype_abbrev(cstate, A_LLC); + b0 = gen_atmtype_llc(cstate); return b0; case DLT_IEEE802: /* Token Ring */ @@ -3647,21 +3738,42 @@ gen_llc(compiler_state_t *cstate) return b0; default: - bpf_error(cstate, "'llc' not supported for linktype %d", cstate->linktype); - /* NOTREACHED */ + bpf_error(cstate, "'llc' not supported for %s", + pcap_datalink_val_to_description_or_dlt(cstate->linktype)); + /*NOTREACHED*/ } } +struct block * +gen_llc(compiler_state_t *cstate) +{ + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + return gen_llc_internal(cstate); +} + struct block * gen_llc_i(compiler_state_t *cstate) { struct block *b0, *b1; struct slist *s; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + /* * Check whether this is an LLC frame. */ - b0 = gen_llc(cstate); + b0 = gen_llc_internal(cstate); /* * Load the control byte and test the low-order bit; it must @@ -3681,10 +3793,17 @@ gen_llc_s(compiler_state_t *cstate) { struct block *b0, *b1; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + /* * Check whether this is an LLC frame. */ - b0 = gen_llc(cstate); + b0 = gen_llc_internal(cstate); /* * Now compare the low-order 2 bit of the control byte against @@ -3700,10 +3819,17 @@ gen_llc_u(compiler_state_t *cstate) { struct block *b0, *b1; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + /* * Check whether this is an LLC frame. */ - b0 = gen_llc(cstate); + b0 = gen_llc_internal(cstate); /* * Now compare the low-order 2 bit of the control byte against @@ -3719,10 +3845,17 @@ gen_llc_s_subtype(compiler_state_t *cstate, bpf_u_int32 subtype) { struct block *b0, *b1; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + /* * Check whether this is an LLC frame. */ - b0 = gen_llc(cstate); + b0 = gen_llc_internal(cstate); /* * Now check for an S frame with the appropriate type. @@ -3737,10 +3870,17 @@ gen_llc_u_subtype(compiler_state_t *cstate, bpf_u_int32 subtype) { struct block *b0, *b1; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + /* * Check whether this is an LLC frame. */ - b0 = gen_llc(cstate); + b0 = gen_llc_internal(cstate); /* * Now check for a U frame with the appropriate type. @@ -3860,8 +4000,8 @@ gen_hostop(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, gen_and(b0, b1); return b1; - case Q_OR: case Q_DEFAULT: + case Q_OR: b0 = gen_hostop(cstate, addr, mask, Q_SRC, proto, src_off, dst_off); b1 = gen_hostop(cstate, addr, mask, Q_DST, proto, src_off, dst_off); gen_or(b0, b1); @@ -3869,30 +4009,31 @@ gen_hostop(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, case Q_ADDR1: bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses"); - break; + /*NOTREACHED*/ case Q_ADDR2: bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses"); - break; + /*NOTREACHED*/ case Q_ADDR3: bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses"); - break; + /*NOTREACHED*/ case Q_ADDR4: bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses"); - break; + /*NOTREACHED*/ case Q_RA: bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses"); - break; + /*NOTREACHED*/ case Q_TA: bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses"); - break; + /*NOTREACHED*/ default: abort(); + /*NOTREACHED*/ } b0 = gen_linktype(cstate, proto); b1 = gen_mcmp(cstate, OR_LINKPL, offset, BPF_W, (bpf_int32)addr, mask); @@ -3925,8 +4066,8 @@ gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr, gen_and(b0, b1); return b1; - case Q_OR: case Q_DEFAULT: + case Q_OR: b0 = gen_hostop6(cstate, addr, mask, Q_SRC, proto, src_off, dst_off); b1 = gen_hostop6(cstate, addr, mask, Q_DST, proto, src_off, dst_off); gen_or(b0, b1); @@ -3934,30 +4075,31 @@ gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr, case Q_ADDR1: bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses"); - break; + /*NOTREACHED*/ case Q_ADDR2: bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses"); - break; + /*NOTREACHED*/ case Q_ADDR3: bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses"); - break; + /*NOTREACHED*/ case Q_ADDR4: bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses"); - break; + /*NOTREACHED*/ case Q_RA: bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses"); - break; + /*NOTREACHED*/ case Q_TA: bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses"); - break; + /*NOTREACHED*/ default: abort(); + /*NOTREACHED*/ } /* this order is important */ a = (uint32_t *)addr; @@ -4002,30 +4144,30 @@ gen_ehostop(compiler_state_t *cstate, const u_char *eaddr, int dir) case Q_ADDR1: bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11 with 802.11 headers"); - break; + /*NOTREACHED*/ case Q_ADDR2: bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11 with 802.11 headers"); - break; + /*NOTREACHED*/ case Q_ADDR3: bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11 with 802.11 headers"); - break; + /*NOTREACHED*/ case Q_ADDR4: bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11 with 802.11 headers"); - break; + /*NOTREACHED*/ case Q_RA: bpf_error(cstate, "'ra' is only supported on 802.11 with 802.11 headers"); - break; + /*NOTREACHED*/ case Q_TA: bpf_error(cstate, "'ta' is only supported on 802.11 with 802.11 headers"); - break; + /*NOTREACHED*/ } abort(); - /* NOTREACHED */ + /*NOTREACHED*/ } /* @@ -4058,30 +4200,30 @@ gen_fhostop(compiler_state_t *cstate, const u_char *eaddr, int dir) case Q_ADDR1: bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_ADDR2: bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_ADDR3: bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_ADDR4: bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_RA: bpf_error(cstate, "'ra' is only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_TA: bpf_error(cstate, "'ta' is only supported on 802.11"); - break; + /*NOTREACHED*/ } abort(); - /* NOTREACHED */ + /*NOTREACHED*/ } /* @@ -4114,30 +4256,30 @@ gen_thostop(compiler_state_t *cstate, const u_char *eaddr, int dir) case Q_ADDR1: bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_ADDR2: bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_ADDR3: bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_ADDR4: bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_RA: bpf_error(cstate, "'ra' is only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_TA: bpf_error(cstate, "'ta' is only supported on 802.11"); - break; + /*NOTREACHED*/ } abort(); - /* NOTREACHED */ + /*NOTREACHED*/ } /* @@ -4426,6 +4568,68 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir) gen_and(b1, b0); return b0; + case Q_AND: + b0 = gen_wlanhostop(cstate, eaddr, Q_SRC); + b1 = gen_wlanhostop(cstate, eaddr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_wlanhostop(cstate, eaddr, Q_SRC); + b1 = gen_wlanhostop(cstate, eaddr, Q_DST); + gen_or(b0, b1); + return b1; + + /* + * XXX - add BSSID keyword? + */ + case Q_ADDR1: + return (gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr)); + + case Q_ADDR2: + /* + * Not present in CTS or ACK control frames. + */ + b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, + IEEE80211_FC0_TYPE_MASK); + gen_not(b0); + b1 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS, + IEEE80211_FC0_SUBTYPE_MASK); + gen_not(b1); + b2 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK, + IEEE80211_FC0_SUBTYPE_MASK); + gen_not(b2); + gen_and(b1, b2); + gen_or(b0, b2); + b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); + gen_and(b2, b1); + return b1; + + case Q_ADDR3: + /* + * Not present in control frames. + */ + b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, + IEEE80211_FC0_TYPE_MASK); + gen_not(b0); + b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr); + gen_and(b0, b1); + return b1; + + case Q_ADDR4: + /* + * Present only if the direction mask has both "From DS" + * and "To DS" set. Neither control frames nor management + * frames should have both of those set, so we don't + * check the frame type. + */ + b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, + IEEE80211_FC1_DIR_DSTODS, IEEE80211_FC1_DIR_MASK); + b1 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr); + gen_and(b0, b1); + return b1; + case Q_RA: /* * Not present in management frames; addr1 in other @@ -4496,71 +4700,9 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir) b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); gen_and(b2, b1); return b1; - - /* - * XXX - add BSSID keyword? - */ - case Q_ADDR1: - return (gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr)); - - case Q_ADDR2: - /* - * Not present in CTS or ACK control frames. - */ - b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, - IEEE80211_FC0_TYPE_MASK); - gen_not(b0); - b1 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS, - IEEE80211_FC0_SUBTYPE_MASK); - gen_not(b1); - b2 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK, - IEEE80211_FC0_SUBTYPE_MASK); - gen_not(b2); - gen_and(b1, b2); - gen_or(b0, b2); - b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); - gen_and(b2, b1); - return b1; - - case Q_ADDR3: - /* - * Not present in control frames. - */ - b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, - IEEE80211_FC0_TYPE_MASK); - gen_not(b0); - b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr); - gen_and(b0, b1); - return b1; - - case Q_ADDR4: - /* - * Present only if the direction mask has both "From DS" - * and "To DS" set. Neither control frames nor management - * frames should have both of those set, so we don't - * check the frame type. - */ - b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, - IEEE80211_FC1_DIR_DSTODS, IEEE80211_FC1_DIR_MASK); - b1 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr); - gen_and(b0, b1); - return b1; - - case Q_AND: - b0 = gen_wlanhostop(cstate, eaddr, Q_SRC); - b1 = gen_wlanhostop(cstate, eaddr, Q_DST); - gen_and(b0, b1); - return b1; - - case Q_DEFAULT: - case Q_OR: - b0 = gen_wlanhostop(cstate, eaddr, Q_SRC); - b1 = gen_wlanhostop(cstate, eaddr, Q_DST); - gen_or(b0, b1); - return b1; } abort(); - /* NOTREACHED */ + /*NOTREACHED*/ } /* @@ -4595,30 +4737,30 @@ gen_ipfchostop(compiler_state_t *cstate, const u_char *eaddr, int dir) case Q_ADDR1: bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_ADDR2: bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_ADDR3: bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_ADDR4: bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_RA: bpf_error(cstate, "'ra' is only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_TA: bpf_error(cstate, "'ta' is only supported on 802.11"); - break; + /*NOTREACHED*/ } abort(); - /* NOTREACHED */ + /*NOTREACHED*/ } /* @@ -4665,19 +4807,41 @@ gen_dnhostop(compiler_state_t *cstate, bpf_u_int32 addr, int dir) gen_and(b0, b1); return b1; - case Q_OR: case Q_DEFAULT: + case Q_OR: /* Inefficient because we do our Calvinball dance twice */ b0 = gen_dnhostop(cstate, addr, Q_SRC); b1 = gen_dnhostop(cstate, addr, Q_DST); gen_or(b0, b1); return b1; - case Q_ISO: - bpf_error(cstate, "ISO host filtering not implemented"); + case Q_ADDR1: + bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_ADDR2: + bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_ADDR3: + bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_ADDR4: + bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_RA: + bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_TA: + bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ default: abort(); + /*NOTREACHED*/ } b0 = gen_linktype(cstate, ETHERTYPE_DN); /* Check for pad = 1, long header case */ @@ -4769,6 +4933,9 @@ gen_host(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, } return b0; + case Q_LINK: + bpf_error(cstate, "link-layer modifier applied to %s", typestr); + case Q_IP: return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_IP, 12, 16); @@ -4778,12 +4945,12 @@ gen_host(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, case Q_ARP: return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_ARP, 14, 24); - case Q_TCP: - bpf_error(cstate, "'tcp' modifier applied to %s", typestr); - case Q_SCTP: bpf_error(cstate, "'sctp' modifier applied to %s", typestr); + case Q_TCP: + bpf_error(cstate, "'tcp' modifier applied to %s", typestr); + case Q_UDP: bpf_error(cstate, "'udp' modifier applied to %s", typestr); @@ -4796,36 +4963,24 @@ gen_host(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, case Q_IGRP: bpf_error(cstate, "'igrp' modifier applied to %s", typestr); - case Q_PIM: - bpf_error(cstate, "'pim' modifier applied to %s", typestr); - - case Q_VRRP: - bpf_error(cstate, "'vrrp' modifier applied to %s", typestr); - - case Q_CARP: - bpf_error(cstate, "'carp' modifier applied to %s", typestr); - case Q_ATALK: - bpf_error(cstate, "ATALK host filtering not implemented"); - - case Q_AARP: - bpf_error(cstate, "AARP host filtering not implemented"); + bpf_error(cstate, "AppleTalk host filtering not implemented"); case Q_DECNET: return gen_dnhostop(cstate, addr, dir); - case Q_SCA: - bpf_error(cstate, "SCA host filtering not implemented"); - case Q_LAT: bpf_error(cstate, "LAT host filtering not implemented"); - case Q_MOPDL: - bpf_error(cstate, "MOPDL host filtering not implemented"); + case Q_SCA: + bpf_error(cstate, "SCA host filtering not implemented"); case Q_MOPRC: bpf_error(cstate, "MOPRC host filtering not implemented"); + case Q_MOPDL: + bpf_error(cstate, "MOPDL host filtering not implemented"); + case Q_IPV6: bpf_error(cstate, "'ip6' modifier applied to ip host"); @@ -4838,6 +4993,15 @@ gen_host(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, case Q_ESP: bpf_error(cstate, "'esp' modifier applied to %s", typestr); + case Q_PIM: + bpf_error(cstate, "'pim' modifier applied to %s", typestr); + + case Q_VRRP: + bpf_error(cstate, "'vrrp' modifier applied to %s", typestr); + + case Q_AARP: + bpf_error(cstate, "AARP host filtering not implemented"); + case Q_ISO: bpf_error(cstate, "ISO host filtering not implemented"); @@ -4859,13 +5023,37 @@ gen_host(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, case Q_NETBEUI: bpf_error(cstate, "'netbeui' modifier applied to %s", typestr); + case Q_ISIS_L1: + bpf_error(cstate, "'l1' modifier applied to %s", typestr); + + case Q_ISIS_L2: + bpf_error(cstate, "'l2' modifier applied to %s", typestr); + + case Q_ISIS_IIH: + bpf_error(cstate, "'iih' modifier applied to %s", typestr); + + case Q_ISIS_SNP: + bpf_error(cstate, "'snp' modifier applied to %s", typestr); + + case Q_ISIS_CSNP: + bpf_error(cstate, "'csnp' modifier applied to %s", typestr); + + case Q_ISIS_PSNP: + bpf_error(cstate, "'psnp' modifier applied to %s", typestr); + + case Q_ISIS_LSP: + bpf_error(cstate, "'lsp' modifier applied to %s", typestr); + case Q_RADIO: bpf_error(cstate, "'radio' modifier applied to %s", typestr); + case Q_CARP: + bpf_error(cstate, "'carp' modifier applied to %s", typestr); + default: abort(); } - /* NOTREACHED */ + /*NOTREACHED*/ } #ifdef INET6 @@ -4898,93 +5086,114 @@ gen_host6(compiler_state_t *cstate, struct in6_addr *addr, bpf_error(cstate, "'arp' modifier applied to ip6 %s", typestr); case Q_SCTP: - bpf_error(cstate, "'sctp' modifier applied to %s", typestr); + bpf_error(cstate, "'sctp' modifier applied to ip6 %s", typestr); case Q_TCP: - bpf_error(cstate, "'tcp' modifier applied to %s", typestr); + bpf_error(cstate, "'tcp' modifier applied to ip6 %s", typestr); case Q_UDP: - bpf_error(cstate, "'udp' modifier applied to %s", typestr); + bpf_error(cstate, "'udp' modifier applied to ip6 %s", typestr); case Q_ICMP: - bpf_error(cstate, "'icmp' modifier applied to %s", typestr); + bpf_error(cstate, "'icmp' modifier applied to ip6 %s", typestr); case Q_IGMP: - bpf_error(cstate, "'igmp' modifier applied to %s", typestr); + bpf_error(cstate, "'igmp' modifier applied to ip6 %s", typestr); case Q_IGRP: - bpf_error(cstate, "'igrp' modifier applied to %s", typestr); - - case Q_PIM: - bpf_error(cstate, "'pim' modifier applied to %s", typestr); - - case Q_VRRP: - bpf_error(cstate, "'vrrp' modifier applied to %s", typestr); - - case Q_CARP: - bpf_error(cstate, "'carp' modifier applied to %s", typestr); + bpf_error(cstate, "'igrp' modifier applied to ip6 %s", typestr); case Q_ATALK: - bpf_error(cstate, "ATALK host filtering not implemented"); - - case Q_AARP: - bpf_error(cstate, "AARP host filtering not implemented"); + bpf_error(cstate, "AppleTalk modifier applied to ip6 %s", typestr); case Q_DECNET: bpf_error(cstate, "'decnet' modifier applied to ip6 %s", typestr); - case Q_SCA: - bpf_error(cstate, "SCA host filtering not implemented"); - case Q_LAT: - bpf_error(cstate, "LAT host filtering not implemented"); + bpf_error(cstate, "'lat' modifier applied to ip6 %s", typestr); - case Q_MOPDL: - bpf_error(cstate, "MOPDL host filtering not implemented"); + case Q_SCA: + bpf_error(cstate, "'sca' modifier applied to ip6 %s", typestr); case Q_MOPRC: - bpf_error(cstate, "MOPRC host filtering not implemented"); + bpf_error(cstate, "'moprc' modifier applied to ip6 %s", typestr); + + case Q_MOPDL: + bpf_error(cstate, "'mopdl' modifier applied to ip6 %s", typestr); case Q_IPV6: return gen_hostop6(cstate, addr, mask, dir, ETHERTYPE_IPV6, 8, 24); case Q_ICMPV6: - bpf_error(cstate, "'icmp6' modifier applied to %s", typestr); + bpf_error(cstate, "'icmp6' modifier applied to ip6 %s", typestr); case Q_AH: - bpf_error(cstate, "'ah' modifier applied to %s", typestr); + bpf_error(cstate, "'ah' modifier applied to ip6 %s", typestr); case Q_ESP: - bpf_error(cstate, "'esp' modifier applied to %s", typestr); + bpf_error(cstate, "'esp' modifier applied to ip6 %s", typestr); + + case Q_PIM: + bpf_error(cstate, "'pim' modifier applied to ip6 %s", typestr); + + case Q_VRRP: + bpf_error(cstate, "'vrrp' modifier applied to ip6 %s", typestr); + + case Q_AARP: + bpf_error(cstate, "'aarp' modifier applied to ip6 %s", typestr); case Q_ISO: - bpf_error(cstate, "ISO host filtering not implemented"); + bpf_error(cstate, "'iso' modifier applied to ip6 %s", typestr); case Q_ESIS: - bpf_error(cstate, "'esis' modifier applied to %s", typestr); + bpf_error(cstate, "'esis' modifier applied to ip6 %s", typestr); case Q_ISIS: - bpf_error(cstate, "'isis' modifier applied to %s", typestr); + bpf_error(cstate, "'isis' modifier applied to ip6 %s", typestr); case Q_CLNP: - bpf_error(cstate, "'clnp' modifier applied to %s", typestr); + bpf_error(cstate, "'clnp' modifier applied to ip6 %s", typestr); case Q_STP: - bpf_error(cstate, "'stp' modifier applied to %s", typestr); + bpf_error(cstate, "'stp' modifier applied to ip6 %s", typestr); case Q_IPX: - bpf_error(cstate, "IPX host filtering not implemented"); + bpf_error(cstate, "'ipx' modifier applied to ip6 %s", typestr); case Q_NETBEUI: - bpf_error(cstate, "'netbeui' modifier applied to %s", typestr); + bpf_error(cstate, "'netbeui' modifier applied to ip6 %s", typestr); + + case Q_ISIS_L1: + bpf_error(cstate, "'l1' modifier applied to ip6 %s", typestr); + + case Q_ISIS_L2: + bpf_error(cstate, "'l2' modifier applied to ip6 %s", typestr); + + case Q_ISIS_IIH: + bpf_error(cstate, "'iih' modifier applied to ip6 %s", typestr); + + case Q_ISIS_SNP: + bpf_error(cstate, "'snp' modifier applied to ip6 %s", typestr); + + case Q_ISIS_CSNP: + bpf_error(cstate, "'csnp' modifier applied to ip6 %s", typestr); + + case Q_ISIS_PSNP: + bpf_error(cstate, "'psnp' modifier applied to ip6 %s", typestr); + + case Q_ISIS_LSP: + bpf_error(cstate, "'lsp' modifier applied to ip6 %s", typestr); case Q_RADIO: - bpf_error(cstate, "'radio' modifier applied to %s", typestr); + bpf_error(cstate, "'radio' modifier applied to ip6 %s", typestr); + + case Q_CARP: + bpf_error(cstate, "'carp' modifier applied to ip6 %s", typestr); default: abort(); } - /* NOTREACHED */ + /*NOTREACHED*/ } #endif @@ -5091,12 +5300,12 @@ gen_gateway(compiler_state_t *cstate, const u_char *eaddr, return b1; } bpf_error(cstate, "illegal modifier of 'gateway'"); - /* NOTREACHED */ + /*NOTREACHED*/ } #endif -struct block * -gen_proto_abbrev(compiler_state_t *cstate, int proto) +static struct block * +gen_proto_abbrev_internal(compiler_state_t *cstate, int proto) { struct block *b0; struct block *b1; @@ -5335,6 +5544,19 @@ gen_proto_abbrev(compiler_state_t *cstate, int proto) return b1; } +struct block * +gen_proto_abbrev(compiler_state_t *cstate, int proto) +{ + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + return gen_proto_abbrev_internal(cstate, proto); +} + static struct block * gen_ipfrag(compiler_state_t *cstate) { @@ -5391,21 +5613,46 @@ gen_portop(compiler_state_t *cstate, int port, int proto, int dir) b1 = gen_portatom(cstate, 2, (bpf_int32)port); break; - case Q_OR: - case Q_DEFAULT: - tmp = gen_portatom(cstate, 0, (bpf_int32)port); - b1 = gen_portatom(cstate, 2, (bpf_int32)port); - gen_or(tmp, b1); - break; - case Q_AND: tmp = gen_portatom(cstate, 0, (bpf_int32)port); b1 = gen_portatom(cstate, 2, (bpf_int32)port); gen_and(tmp, b1); break; + case Q_DEFAULT: + case Q_OR: + tmp = gen_portatom(cstate, 0, (bpf_int32)port); + b1 = gen_portatom(cstate, 2, (bpf_int32)port); + gen_or(tmp, b1); + break; + + case Q_ADDR1: + bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for ports"); + /*NOTREACHED*/ + + case Q_ADDR2: + bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for ports"); + /*NOTREACHED*/ + + case Q_ADDR3: + bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for ports"); + /*NOTREACHED*/ + + case Q_ADDR4: + bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for ports"); + /*NOTREACHED*/ + + case Q_RA: + bpf_error(cstate, "'ra' is not a valid qualifier for ports"); + /*NOTREACHED*/ + + case Q_TA: + bpf_error(cstate, "'ta' is not a valid qualifier for ports"); + /*NOTREACHED*/ + default: abort(); + /*NOTREACHED*/ } gen_and(b0, b1); @@ -5476,19 +5723,19 @@ gen_portop6(compiler_state_t *cstate, int port, int proto, int dir) b1 = gen_portatom6(cstate, 2, (bpf_int32)port); break; - case Q_OR: - case Q_DEFAULT: - tmp = gen_portatom6(cstate, 0, (bpf_int32)port); - b1 = gen_portatom6(cstate, 2, (bpf_int32)port); - gen_or(tmp, b1); - break; - case Q_AND: tmp = gen_portatom6(cstate, 0, (bpf_int32)port); b1 = gen_portatom6(cstate, 2, (bpf_int32)port); gen_and(tmp, b1); break; + case Q_DEFAULT: + case Q_OR: + tmp = gen_portatom6(cstate, 0, (bpf_int32)port); + b1 = gen_portatom6(cstate, 2, (bpf_int32)port); + gen_or(tmp, b1); + break; + default: abort(); } @@ -5573,21 +5820,46 @@ gen_portrangeop(compiler_state_t *cstate, int port1, int port2, int proto, b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); break; - case Q_OR: - case Q_DEFAULT: - tmp = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); - b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); - gen_or(tmp, b1); - break; - case Q_AND: tmp = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); gen_and(tmp, b1); break; + case Q_DEFAULT: + case Q_OR: + tmp = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); + b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); + gen_or(tmp, b1); + break; + + case Q_ADDR1: + bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for port ranges"); + /*NOTREACHED*/ + + case Q_ADDR2: + bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for port ranges"); + /*NOTREACHED*/ + + case Q_ADDR3: + bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for port ranges"); + /*NOTREACHED*/ + + case Q_ADDR4: + bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for port ranges"); + /*NOTREACHED*/ + + case Q_RA: + bpf_error(cstate, "'ra' is not a valid qualifier for port ranges"); + /*NOTREACHED*/ + + case Q_TA: + bpf_error(cstate, "'ta' is not a valid qualifier for port ranges"); + /*NOTREACHED*/ + default: abort(); + /*NOTREACHED*/ } gen_and(b0, b1); @@ -5669,19 +5941,19 @@ gen_portrangeop6(compiler_state_t *cstate, int port1, int port2, int proto, b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); break; - case Q_OR: - case Q_DEFAULT: - tmp = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); - b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); - gen_or(tmp, b1); - break; - case Q_AND: tmp = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); gen_and(tmp, b1); break; + case Q_DEFAULT: + case Q_OR: + tmp = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); + b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); + gen_or(tmp, b1); + break; + default: abort(); } @@ -6116,6 +6388,9 @@ gen_proto(compiler_state_t *cstate, int v, int proto, int dir) gen_or(b0, b1); return b1; + case Q_LINK: + return gen_linktype(cstate, v); + case Q_IP: /* * For FDDI, RFC 1188 says that SNAP encapsulation is used, @@ -6141,6 +6416,104 @@ gen_proto(compiler_state_t *cstate, int v, int proto, int dir) gen_and(b0, b1); return b1; + case Q_ARP: + bpf_error(cstate, "arp does not encapsulate another protocol"); + /*NOTREACHED*/ + + case Q_RARP: + bpf_error(cstate, "rarp does not encapsulate another protocol"); + /*NOTREACHED*/ + + case Q_SCTP: + bpf_error(cstate, "'sctp proto' is bogus"); + /*NOTREACHED*/ + + case Q_TCP: + bpf_error(cstate, "'tcp proto' is bogus"); + /*NOTREACHED*/ + + case Q_UDP: + bpf_error(cstate, "'udp proto' is bogus"); + /*NOTREACHED*/ + + case Q_ICMP: + bpf_error(cstate, "'icmp proto' is bogus"); + /*NOTREACHED*/ + + case Q_IGMP: + bpf_error(cstate, "'igmp proto' is bogus"); + /*NOTREACHED*/ + + case Q_IGRP: + bpf_error(cstate, "'igrp proto' is bogus"); + /*NOTREACHED*/ + + case Q_ATALK: + bpf_error(cstate, "AppleTalk encapsulation is not specifiable"); + /*NOTREACHED*/ + + case Q_DECNET: + bpf_error(cstate, "DECNET encapsulation is not specifiable"); + /*NOTREACHED*/ + + case Q_LAT: + bpf_error(cstate, "LAT does not encapsulate another protocol"); + /*NOTREACHED*/ + + case Q_SCA: + bpf_error(cstate, "SCA does not encapsulate another protocol"); + /*NOTREACHED*/ + + case Q_MOPRC: + bpf_error(cstate, "MOPRC does not encapsulate another protocol"); + /*NOTREACHED*/ + + case Q_MOPDL: + bpf_error(cstate, "MOPDL does not encapsulate another protocol"); + /*NOTREACHED*/ + + case Q_IPV6: + b0 = gen_linktype(cstate, ETHERTYPE_IPV6); +#ifndef CHASE_CHAIN + /* + * Also check for a fragment header before the final + * header. + */ + b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, IPPROTO_FRAGMENT); + b1 = gen_cmp(cstate, OR_LINKPL, 40, BPF_B, (bpf_int32)v); + gen_and(b2, b1); + b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, (bpf_int32)v); + gen_or(b2, b1); +#else + b1 = gen_protochain(cstate, v, Q_IPV6); +#endif + gen_and(b0, b1); + return b1; + + case Q_ICMPV6: + bpf_error(cstate, "'icmp6 proto' is bogus"); + /*NOTREACHED*/ + + case Q_AH: + bpf_error(cstate, "'ah proto' is bogus"); + /*NOTREACHED*/ + + case Q_ESP: + bpf_error(cstate, "'ah proto' is bogus"); + /*NOTREACHED*/ + + case Q_PIM: + bpf_error(cstate, "'pim proto' is bogus"); + /*NOTREACHED*/ + + case Q_VRRP: + bpf_error(cstate, "'vrrp proto' is bogus"); + /*NOTREACHED*/ + + case Q_AARP: + bpf_error(cstate, "'aarp proto' is bogus"); + /*NOTREACHED*/ + case Q_ISO: switch (cstate->linktype) { @@ -6165,7 +6538,6 @@ gen_proto(compiler_state_t *cstate, int v, int proto, int dir) */ return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | v); /*NOTREACHED*/ - break; case DLT_C_HDLC: /* @@ -6185,6 +6557,10 @@ gen_proto(compiler_state_t *cstate, int v, int proto, int dir) return b1; } + case Q_ESIS: + bpf_error(cstate, "'esis proto' is bogus"); + /*NOTREACHED*/ + case Q_ISIS: b0 = gen_proto(cstate, ISO10589_ISIS, Q_ISO, Q_DEFAULT); /* @@ -6195,121 +6571,63 @@ gen_proto(compiler_state_t *cstate, int v, int proto, int dir) gen_and(b0, b1); return b1; - case Q_ARP: - bpf_error(cstate, "arp does not encapsulate another protocol"); - /* NOTREACHED */ - - case Q_RARP: - bpf_error(cstate, "rarp does not encapsulate another protocol"); - /* NOTREACHED */ - - case Q_ATALK: - bpf_error(cstate, "atalk encapsulation is not specifiable"); - /* NOTREACHED */ - - case Q_DECNET: - bpf_error(cstate, "decnet encapsulation is not specifiable"); - /* NOTREACHED */ - - case Q_SCA: - bpf_error(cstate, "sca does not encapsulate another protocol"); - /* NOTREACHED */ - - case Q_LAT: - bpf_error(cstate, "lat does not encapsulate another protocol"); - /* NOTREACHED */ - - case Q_MOPRC: - bpf_error(cstate, "moprc does not encapsulate another protocol"); - /* NOTREACHED */ - - case Q_MOPDL: - bpf_error(cstate, "mopdl does not encapsulate another protocol"); - /* NOTREACHED */ - - case Q_LINK: - return gen_linktype(cstate, v); - - case Q_UDP: - bpf_error(cstate, "'udp proto' is bogus"); - /* NOTREACHED */ - - case Q_TCP: - bpf_error(cstate, "'tcp proto' is bogus"); - /* NOTREACHED */ - - case Q_SCTP: - bpf_error(cstate, "'sctp proto' is bogus"); - /* NOTREACHED */ - - case Q_ICMP: - bpf_error(cstate, "'icmp proto' is bogus"); - /* NOTREACHED */ - - case Q_IGMP: - bpf_error(cstate, "'igmp proto' is bogus"); - /* NOTREACHED */ - - case Q_IGRP: - bpf_error(cstate, "'igrp proto' is bogus"); - /* NOTREACHED */ - - case Q_PIM: - bpf_error(cstate, "'pim proto' is bogus"); - /* NOTREACHED */ - - case Q_VRRP: - bpf_error(cstate, "'vrrp proto' is bogus"); - /* NOTREACHED */ - - case Q_CARP: - bpf_error(cstate, "'carp proto' is bogus"); - /* NOTREACHED */ - - case Q_IPV6: - b0 = gen_linktype(cstate, ETHERTYPE_IPV6); -#ifndef CHASE_CHAIN - /* - * Also check for a fragment header before the final - * header. - */ - b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, IPPROTO_FRAGMENT); - b1 = gen_cmp(cstate, OR_LINKPL, 40, BPF_B, (bpf_int32)v); - gen_and(b2, b1); - b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, (bpf_int32)v); - gen_or(b2, b1); -#else - b1 = gen_protochain(cstate, v, Q_IPV6); -#endif - gen_and(b0, b1); - return b1; - - case Q_ICMPV6: - bpf_error(cstate, "'icmp6 proto' is bogus"); - - case Q_AH: - bpf_error(cstate, "'ah proto' is bogus"); - - case Q_ESP: - bpf_error(cstate, "'ah proto' is bogus"); + case Q_CLNP: + bpf_error(cstate, "'clnp proto' is not supported"); + /*NOTREACHED*/ case Q_STP: bpf_error(cstate, "'stp proto' is bogus"); + /*NOTREACHED*/ case Q_IPX: bpf_error(cstate, "'ipx proto' is bogus"); + /*NOTREACHED*/ case Q_NETBEUI: bpf_error(cstate, "'netbeui proto' is bogus"); + /*NOTREACHED*/ + + case Q_ISIS_L1: + bpf_error(cstate, "'l1 proto' is bogus"); + /*NOTREACHED*/ + + case Q_ISIS_L2: + bpf_error(cstate, "'l2 proto' is bogus"); + /*NOTREACHED*/ + + case Q_ISIS_IIH: + bpf_error(cstate, "'iih proto' is bogus"); + /*NOTREACHED*/ + + case Q_ISIS_SNP: + bpf_error(cstate, "'snp proto' is bogus"); + /*NOTREACHED*/ + + case Q_ISIS_CSNP: + bpf_error(cstate, "'csnp proto' is bogus"); + /*NOTREACHED*/ + + case Q_ISIS_PSNP: + bpf_error(cstate, "'psnp proto' is bogus"); + /*NOTREACHED*/ + + case Q_ISIS_LSP: + bpf_error(cstate, "'lsp proto' is bogus"); + /*NOTREACHED*/ case Q_RADIO: bpf_error(cstate, "'radio proto' is bogus"); + /*NOTREACHED*/ + + case Q_CARP: + bpf_error(cstate, "'carp proto' is bogus"); + /*NOTREACHED*/ default: abort(); - /* NOTREACHED */ + /*NOTREACHED*/ } - /* NOTREACHED */ + /*NOTREACHED*/ } struct block * @@ -6331,6 +6649,13 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q) int port, real_proto; int port1, port2; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + switch (q.addr) { case Q_NET: @@ -6609,10 +6934,10 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q) case Q_UNDEF: syntax(cstate); - /* NOTREACHED */ + /*NOTREACHED*/ } abort(); - /* NOTREACHED */ + /*NOTREACHED*/ } struct block * @@ -6622,6 +6947,13 @@ gen_mcode(compiler_state_t *cstate, const char *s1, const char *s2, register int nlen, mlen; bpf_u_int32 n, m; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + nlen = __pcap_atoin(s1, &n); /* Promote short ipaddr */ n <<= 32 - nlen; @@ -6657,19 +6989,28 @@ gen_mcode(compiler_state_t *cstate, const char *s1, const char *s2, default: bpf_error(cstate, "Mask syntax for networks only"); - /* NOTREACHED */ + /*NOTREACHED*/ } - /* NOTREACHED */ + /*NOTREACHED*/ } struct block * gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q) { bpf_u_int32 mask; - int proto = q.proto; - int dir = q.dir; + int proto; + int dir; register int vlen; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + proto = q.proto; + dir = q.dir; if (s == NULL) vlen = 32; else if (q.proto == Q_DECNET) { @@ -6750,7 +7091,7 @@ gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q) case Q_GATEWAY: bpf_error(cstate, "'gateway' requires a name"); - /* NOTREACHED */ + /*NOTREACHED*/ case Q_PROTO: return gen_proto(cstate, (int)v, proto, dir); @@ -6760,13 +7101,13 @@ gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q) case Q_UNDEF: syntax(cstate); - /* NOTREACHED */ + /*NOTREACHED*/ default: abort(); - /* NOTREACHED */ + /*NOTREACHED*/ } - /* NOTREACHED */ + /*NOTREACHED*/ } #ifdef INET6 @@ -6780,6 +7121,13 @@ gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2, struct block *b; uint32_t *a, *m; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + if (s2) bpf_error(cstate, "no mask %s supported", s2); @@ -6823,45 +7171,64 @@ gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2, default: bpf_error(cstate, "invalid qualifier against IPv6 address"); - /* NOTREACHED */ + /*NOTREACHED*/ } } #endif /*INET6*/ struct block * -gen_ecode(compiler_state_t *cstate, const u_char *eaddr, struct qual q) +gen_ecode(compiler_state_t *cstate, const char *s, struct qual q) { struct block *b, *tmp; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) { + cstate->e = pcap_ether_aton(s); + if (cstate->e == NULL) + bpf_error(cstate, "malloc"); switch (cstate->linktype) { case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: tmp = gen_prevlinkhdr_check(cstate); - b = gen_ehostop(cstate, eaddr, (int)q.dir); + b = gen_ehostop(cstate, cstate->e, (int)q.dir); if (tmp != NULL) gen_and(tmp, b); - return b; + break; case DLT_FDDI: - return gen_fhostop(cstate, eaddr, (int)q.dir); + b = gen_fhostop(cstate, cstate->e, (int)q.dir); + break; case DLT_IEEE802: - return gen_thostop(cstate, eaddr, (int)q.dir); + b = gen_thostop(cstate, cstate->e, (int)q.dir); + break; case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: case DLT_PPI: - return gen_wlanhostop(cstate, eaddr, (int)q.dir); - case DLT_IP_OVER_FC: - return gen_ipfchostop(cstate, eaddr, (int)q.dir); - default: - bpf_error(cstate, "ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); + b = gen_wlanhostop(cstate, cstate->e, (int)q.dir); break; + case DLT_IP_OVER_FC: + b = gen_ipfchostop(cstate, cstate->e, (int)q.dir); + break; + default: + free(cstate->e); + cstate->e = NULL; + bpf_error(cstate, "ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); + /*NOTREACHED*/ } + free(cstate->e); + cstate->e = NULL; + return (b); } bpf_error(cstate, "ethernet address used in non-ether expression"); - /* NOTREACHED */ + /*NOTREACHED*/ } void @@ -6903,8 +7270,8 @@ xfer_to_a(compiler_state_t *cstate, struct arth *a) * (1, 2, or 4) at that offset into that register, making it the register * for "index". */ -struct arth * -gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size) +static struct arth * +gen_load_internal(compiler_state_t *cstate, int proto, struct arth *inst, int size) { struct slist *s, *tmp; struct block *b; @@ -7050,7 +7417,7 @@ gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size) * Do the computation only if the packet contains * the protocol in question. */ - b = gen_proto_abbrev(cstate, proto); + b = gen_proto_abbrev_internal(cstate, proto); if (inst->b) gen_and(inst->b, b); inst->b = b; @@ -7108,10 +7475,10 @@ gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size) * if this is an IP datagram and is the first or * only fragment of that datagram. */ - gen_and(gen_proto_abbrev(cstate, proto), b = gen_ipfrag(cstate)); + gen_and(gen_proto_abbrev_internal(cstate, proto), b = gen_ipfrag(cstate)); if (inst->b) gen_and(inst->b, b); - gen_and(gen_proto_abbrev(cstate, Q_IP), b); + gen_and(gen_proto_abbrev_internal(cstate, Q_IP), b); inst->b = b; break; case Q_ICMPV6: @@ -7119,7 +7486,7 @@ gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size) * Do the computation only if the packet contains * the protocol in question. */ - b = gen_proto_abbrev(cstate, Q_IPV6); + b = gen_proto_abbrev_internal(cstate, Q_IPV6); if (inst->b) { gen_and(inst->b, b); } @@ -7176,8 +7543,21 @@ gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size) return inst; } -struct block * -gen_relation(compiler_state_t *cstate, int code, struct arth *a0, +struct arth * +gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size) +{ + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + return gen_load_internal(cstate, proto, inst, size); +} + +static struct block * +gen_relation_internal(compiler_state_t *cstate, int code, struct arth *a0, struct arth *a1, int reversed) { struct slist *s0, *s1, *s2; @@ -7220,13 +7600,36 @@ gen_relation(compiler_state_t *cstate, int code, struct arth *a0, return b; } +struct block * +gen_relation(compiler_state_t *cstate, int code, struct arth *a0, + struct arth *a1, int reversed) +{ + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + return gen_relation_internal(cstate, code, a0, a1, reversed); +} + struct arth * gen_loadlen(compiler_state_t *cstate) { - int regno = alloc_reg(cstate); - struct arth *a = (struct arth *)newchunk(cstate, sizeof(*a)); + int regno; + struct arth *a; struct slist *s; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + regno = alloc_reg(cstate); + a = (struct arth *)newchunk(cstate, sizeof(*a)); s = new_stmt(cstate, BPF_LD|BPF_LEN); s->next = new_stmt(cstate, BPF_ST); s->next->s.k = regno; @@ -7236,8 +7639,8 @@ gen_loadlen(compiler_state_t *cstate) return a; } -struct arth * -gen_loadi(compiler_state_t *cstate, int val) +static struct arth * +gen_loadi_internal(compiler_state_t *cstate, int val) { struct arth *a; struct slist *s; @@ -7258,10 +7661,36 @@ gen_loadi(compiler_state_t *cstate, int val) } struct arth * -gen_neg(compiler_state_t *cstate, struct arth *a) +gen_loadi(compiler_state_t *cstate, int val) { + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + return gen_loadi_internal(cstate, val); +} + +/* + * The a_arg dance is to avoid annoying whining by compilers that + * a might be clobbered by longjmp - yeah, it might, but *WHO CARES*? + * It's not *used* after setjmp returns. + */ +struct arth * +gen_neg(compiler_state_t *cstate, struct arth *a_arg) +{ + struct arth *a = a_arg; struct slist *s; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + s = xfer_to_a(cstate, a); sappend(a->s, s); s = new_stmt(cstate, BPF_ALU|BPF_NEG); @@ -7274,15 +7703,31 @@ gen_neg(compiler_state_t *cstate, struct arth *a) return a; } +/* + * The a0_arg dance is to avoid annoying whining by compilers that + * a0 might be clobbered by longjmp - yeah, it might, but *WHO CARES*? + * It's not *used* after setjmp returns. + */ struct arth * -gen_arth(compiler_state_t *cstate, int code, struct arth *a0, +gen_arth(compiler_state_t *cstate, int code, struct arth *a0_arg, struct arth *a1) { + struct arth *a0 = a0_arg; struct slist *s0, *s1, *s2; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + /* * Disallow division by, or modulus by, zero; we do this here * so that it gets done even if the optimizer is disabled. + * + * Also disallow shifts by a value greater than 31; we do this + * here, for the same reason. */ if (code == BPF_DIV) { if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0) @@ -7290,6 +7735,15 @@ gen_arth(compiler_state_t *cstate, int code, struct arth *a0, } else if (code == BPF_MOD) { if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0) bpf_error(cstate, "modulus by zero"); + } else if (code == BPF_LSH || code == BPF_RSH) { + /* + * XXX - we need to make up our minds as to what integers + * are signed and what integers are unsigned in BPF programs + * and in our IR. + */ + if (a1->s->s.code == (BPF_LD|BPF_IMM) && + (a1->s->s.k < 0 || a1->s->s.k > 31)) + bpf_error(cstate, "shift by more than 31 bits"); } s0 = xfer_to_x(cstate, a1); s1 = xfer_to_a(cstate, a0); @@ -7337,7 +7791,7 @@ alloc_reg(compiler_state_t *cstate) } } bpf_error(cstate, "too many registers needed to evaluate expression"); - /* NOTREACHED */ + /*NOTREACHED*/ } /* @@ -7367,6 +7821,13 @@ gen_len(compiler_state_t *cstate, int jmp, int n) struct block * gen_greater(compiler_state_t *cstate, int n) { + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + return gen_len(cstate, BPF_JGE, n); } @@ -7378,6 +7839,13 @@ gen_less(compiler_state_t *cstate, int n) { struct block *b; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + b = gen_len(cstate, BPF_JGT, n); gen_not(b); @@ -7400,6 +7868,13 @@ gen_byteop(compiler_state_t *cstate, int op, int idx, int val) struct block *b; struct slist *s; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + switch (op) { default: abort(); @@ -7440,6 +7915,13 @@ gen_broadcast(compiler_state_t *cstate, int proto) struct block *b0, *b1, *b2; static const u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + switch (proto) { case Q_DEFAULT: @@ -7471,7 +7953,7 @@ gen_broadcast(compiler_state_t *cstate, int proto) default: bpf_error(cstate, "not a broadcast link"); } - break; + /*NOTREACHED*/ case Q_IP: /* @@ -7491,7 +7973,7 @@ gen_broadcast(compiler_state_t *cstate, int proto) return b2; } bpf_error(cstate, "only link-layer/IP broadcast filters supported"); - /* NOTREACHED */ + /*NOTREACHED*/ } /* @@ -7518,6 +8000,13 @@ gen_multicast(compiler_state_t *cstate, int proto) register struct block *b0, *b1, *b2; register struct slist *s; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + switch (proto) { case Q_DEFAULT: @@ -7686,7 +8175,7 @@ gen_multicast(compiler_state_t *cstate, int proto) return b1; } bpf_error(cstate, "link-layer multicast filters supported only on ethernet/FDDI/token ring/ARCNET/802.11/ATM LANE/Fibre Channel"); - /* NOTREACHED */ + /*NOTREACHED*/ } /* @@ -7703,14 +8192,21 @@ gen_inbound(compiler_state_t *cstate, int dir) { register struct block *b0; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + /* * Only some data link types support inbound/outbound qualifiers. */ switch (cstate->linktype) { case DLT_SLIP: - b0 = gen_relation(cstate, BPF_JEQ, - gen_load(cstate, Q_LINK, gen_loadi(cstate, 0), 1), - gen_loadi(cstate, 0), + b0 = gen_relation_internal(cstate, BPF_JEQ, + gen_load_internal(cstate, Q_LINK, gen_loadi_internal(cstate, 0), 1), + gen_loadi_internal(cstate, 0), dir); break; @@ -7733,6 +8229,15 @@ gen_inbound(compiler_state_t *cstate, int dir) } break; + case DLT_LINUX_SLL2: + /* match outgoing packets */ + b0 = gen_cmp(cstate, OR_LINKHDR, 10, BPF_B, LINUX_SLL_OUTGOING); + if (!dir) { + /* to filter on inbound traffic, invert the match */ + gen_not(b0); + } + break; + #ifdef HAVE_NET_PFVAR_H case DLT_PFLOG: b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, dir), BPF_B, @@ -7809,10 +8314,10 @@ gen_inbound(compiler_state_t *cstate, int dir) */ if (cstate->bpf_pcap->rfile != NULL) { /* We have a FILE *, so this is a savefile */ - bpf_error(cstate, "inbound/outbound not supported on linktype %d when reading savefiles", - cstate->linktype); + bpf_error(cstate, "inbound/outbound not supported on %s when reading savefiles", + pcap_datalink_val_to_description_or_dlt(cstate->linktype)); b0 = NULL; - /* NOTREACHED */ + /*NOTREACHED*/ } /* match outgoing packets */ b0 = gen_cmp(cstate, OR_LINKHDR, SKF_AD_OFF + SKF_AD_PKTTYPE, BPF_H, @@ -7822,9 +8327,9 @@ gen_inbound(compiler_state_t *cstate, int dir) gen_not(b0); } #else /* defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */ - bpf_error(cstate, "inbound/outbound not supported on linktype %d", - cstate->linktype); - /* NOTREACHED */ + bpf_error(cstate, "inbound/outbound not supported on %s", + pcap_datalink_val_to_description_or_dlt(cstate->linktype)); + /*NOTREACHED*/ #endif /* defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */ } return (b0); @@ -7838,18 +8343,26 @@ gen_pf_ifname(compiler_state_t *cstate, const char *ifname) struct block *b0; u_int len, off; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + if (cstate->linktype != DLT_PFLOG) { bpf_error(cstate, "ifname supported only on PF linktype"); - /* NOTREACHED */ + /*NOTREACHED*/ } len = sizeof(((struct pfloghdr *)0)->ifname); off = offsetof(struct pfloghdr, ifname); if (strlen(ifname) >= len) { bpf_error(cstate, "ifname interface names can only be %d characters", len-1); - /* NOTREACHED */ + /*NOTREACHED*/ } - b0 = gen_bcmp(cstate, OR_LINKHDR, off, strlen(ifname), (const u_char *)ifname); + b0 = gen_bcmp(cstate, OR_LINKHDR, off, (u_int)strlen(ifname), + (const u_char *)ifname); return (b0); } @@ -7859,19 +8372,26 @@ gen_pf_ruleset(compiler_state_t *cstate, char *ruleset) { struct block *b0; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + if (cstate->linktype != DLT_PFLOG) { bpf_error(cstate, "ruleset supported only on PF linktype"); - /* NOTREACHED */ + /*NOTREACHED*/ } if (strlen(ruleset) >= sizeof(((struct pfloghdr *)0)->ruleset)) { bpf_error(cstate, "ruleset names can only be %ld characters", (long)(sizeof(((struct pfloghdr *)0)->ruleset) - 1)); - /* NOTREACHED */ + /*NOTREACHED*/ } b0 = gen_bcmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, ruleset), - strlen(ruleset), (const u_char *)ruleset); + (u_int)strlen(ruleset), (const u_char *)ruleset); return (b0); } @@ -7881,9 +8401,16 @@ gen_pf_rnr(compiler_state_t *cstate, int rnr) { struct block *b0; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + if (cstate->linktype != DLT_PFLOG) { bpf_error(cstate, "rnr supported only on PF linktype"); - /* NOTREACHED */ + /*NOTREACHED*/ } b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, rulenr), BPF_W, @@ -7897,9 +8424,16 @@ gen_pf_srnr(compiler_state_t *cstate, int srnr) { struct block *b0; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + if (cstate->linktype != DLT_PFLOG) { bpf_error(cstate, "srnr supported only on PF linktype"); - /* NOTREACHED */ + /*NOTREACHED*/ } b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, subrulenr), BPF_W, @@ -7913,9 +8447,16 @@ gen_pf_reason(compiler_state_t *cstate, int reason) { struct block *b0; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + if (cstate->linktype != DLT_PFLOG) { bpf_error(cstate, "reason supported only on PF linktype"); - /* NOTREACHED */ + /*NOTREACHED*/ } b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, reason), BPF_B, @@ -7929,9 +8470,16 @@ gen_pf_action(compiler_state_t *cstate, int action) { struct block *b0; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + if (cstate->linktype != DLT_PFLOG) { bpf_error(cstate, "action supported only on PF linktype"); - /* NOTREACHED */ + /*NOTREACHED*/ } b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, action), BPF_B, @@ -7942,43 +8490,85 @@ gen_pf_action(compiler_state_t *cstate, int action) struct block * gen_pf_ifname(compiler_state_t *cstate, const char *ifname _U_) { + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + bpf_error(cstate, "libpcap was compiled without pf support"); - /* NOTREACHED */ + /*NOTREACHED*/ } struct block * gen_pf_ruleset(compiler_state_t *cstate, char *ruleset _U_) { + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + bpf_error(cstate, "libpcap was compiled on a machine without pf support"); - /* NOTREACHED */ + /*NOTREACHED*/ } struct block * gen_pf_rnr(compiler_state_t *cstate, int rnr _U_) { + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + bpf_error(cstate, "libpcap was compiled on a machine without pf support"); - /* NOTREACHED */ + /*NOTREACHED*/ } struct block * gen_pf_srnr(compiler_state_t *cstate, int srnr _U_) { + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + bpf_error(cstate, "libpcap was compiled on a machine without pf support"); - /* NOTREACHED */ + /*NOTREACHED*/ } struct block * gen_pf_reason(compiler_state_t *cstate, int reason _U_) { + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + bpf_error(cstate, "libpcap was compiled on a machine without pf support"); - /* NOTREACHED */ + /*NOTREACHED*/ } struct block * gen_pf_action(compiler_state_t *cstate, int action _U_) { + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + bpf_error(cstate, "libpcap was compiled on a machine without pf support"); - /* NOTREACHED */ + /*NOTREACHED*/ } #endif /* HAVE_NET_PFVAR_H */ @@ -7988,6 +8578,13 @@ gen_p80211_type(compiler_state_t *cstate, int type, int mask) { struct block *b0; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + switch (cstate->linktype) { case DLT_IEEE802_11: @@ -8000,7 +8597,7 @@ gen_p80211_type(compiler_state_t *cstate, int type, int mask) default: bpf_error(cstate, "802.11 link-layer types supported only on 802.11"); - /* NOTREACHED */ + /*NOTREACHED*/ } return (b0); @@ -8011,6 +8608,13 @@ gen_p80211_fcdir(compiler_state_t *cstate, int fcdir) { struct block *b0; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + switch (cstate->linktype) { case DLT_IEEE802_11: @@ -8021,7 +8625,7 @@ gen_p80211_fcdir(compiler_state_t *cstate, int fcdir) default: bpf_error(cstate, "frame direction supported only with 802.11 headers"); - /* NOTREACHED */ + /*NOTREACHED*/ } b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, (bpf_int32)fcdir, @@ -8031,24 +8635,37 @@ gen_p80211_fcdir(compiler_state_t *cstate, int fcdir) } struct block * -gen_acode(compiler_state_t *cstate, const u_char *eaddr, struct qual q) +gen_acode(compiler_state_t *cstate, const char *s, struct qual q) { + struct block *b; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + switch (cstate->linktype) { case DLT_ARCNET: case DLT_ARCNET_LINUX: if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && - q.proto == Q_LINK) - return (gen_ahostop(cstate, eaddr, (int)q.dir)); - else { + q.proto == Q_LINK) { + cstate->e = pcap_ether_aton(s); + if (cstate->e == NULL) + bpf_error(cstate, "malloc"); + b = gen_ahostop(cstate, cstate->e, (int)q.dir); + free(cstate->e); + cstate->e = NULL; + return (b); + } else bpf_error(cstate, "ARCnet address used in non-arc expression"); - /* NOTREACHED */ - } - break; + /*NOTREACHED*/ default: bpf_error(cstate, "aid supported only on ARCnet"); - /* NOTREACHED */ + /*NOTREACHED*/ } } @@ -8080,30 +8697,30 @@ gen_ahostop(compiler_state_t *cstate, const u_char *eaddr, int dir) case Q_ADDR1: bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_ADDR2: bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_ADDR3: bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_ADDR4: bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_RA: bpf_error(cstate, "'ra' is only supported on 802.11"); - break; + /*NOTREACHED*/ case Q_TA: bpf_error(cstate, "'ta' is only supported on 802.11"); - break; + /*NOTREACHED*/ } abort(); - /* NOTREACHED */ + /*NOTREACHED*/ } static struct block * @@ -8123,19 +8740,24 @@ gen_vlan_tpid_test(compiler_state_t *cstate) } static struct block * -gen_vlan_vid_test(compiler_state_t *cstate, int vlan_num) +gen_vlan_vid_test(compiler_state_t *cstate, bpf_u_int32 vlan_num) { + if (vlan_num > 0x0fff) { + bpf_error(cstate, "VLAN tag %u greater than maximum %u", + vlan_num, 0x0fff); + } return gen_mcmp(cstate, OR_LINKPL, 0, BPF_H, (bpf_int32)vlan_num, 0x0fff); } static struct block * -gen_vlan_no_bpf_extensions(compiler_state_t *cstate, int vlan_num) +gen_vlan_no_bpf_extensions(compiler_state_t *cstate, bpf_u_int32 vlan_num, + int has_vlan_tag) { struct block *b0, *b1; b0 = gen_vlan_tpid_test(cstate); - if (vlan_num >= 0) { + if (has_vlan_tag) { b1 = gen_vlan_vid_test(cstate, vlan_num); gen_and(b0, b1); b0 = b1; @@ -8218,12 +8840,15 @@ gen_vlan_patch_vid_test(compiler_state_t *cstate, struct block *b_vid) sappend(s, s2); sjeq->s.jt = s2; - /* jump to the test in b_vid (bypass loading VID from packet data) */ + /* Jump to the test in b_vid. We need to jump one instruction before + * the end of the b_vid block so that we only skip loading the TCI + * from packet data and not the 'and' instruction extractging VID. + */ cnt = 0; for (s2 = b_vid->stmts; s2; s2 = s2->next) cnt++; s2 = new_stmt(cstate, JMP(BPF_JA)); - s2->s.k = cnt; + s2->s.k = cnt - 1; sappend(s, s2); /* insert our statements at the beginning of b_vid */ @@ -8240,7 +8865,8 @@ gen_vlan_patch_vid_test(compiler_state_t *cstate, struct block *b_vid) * update variable part of the offsets */ static struct block * -gen_vlan_bpf_extensions(compiler_state_t *cstate, int vlan_num) +gen_vlan_bpf_extensions(compiler_state_t *cstate, bpf_u_int32 vlan_num, + int has_vlan_tag) { struct block *b0, *b_tpid, *b_vid = NULL; struct slist *s; @@ -8265,14 +8891,14 @@ gen_vlan_bpf_extensions(compiler_state_t *cstate, int vlan_num) * function but gen_vlan_bpf_extensions() isn't called in that case. */ b_tpid = gen_vlan_tpid_test(cstate); - if (vlan_num >= 0) + if (has_vlan_tag) b_vid = gen_vlan_vid_test(cstate, vlan_num); gen_vlan_patch_tpid_test(cstate, b_tpid); gen_or(b0, b_tpid); b0 = b_tpid; - if (vlan_num >= 0) { + if (has_vlan_tag) { gen_vlan_patch_vid_test(cstate, b_vid); gen_and(b0, b_vid); b0 = b_vid; @@ -8286,10 +8912,17 @@ gen_vlan_bpf_extensions(compiler_state_t *cstate, int vlan_num) * support IEEE 802.1Q VLAN trunk over ethernet */ struct block * -gen_vlan(compiler_state_t *cstate, int vlan_num) +gen_vlan(compiler_state_t *cstate, bpf_u_int32 vlan_num, int has_vlan_tag) { struct block *b0; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + /* can't check for VLAN-encapsulated packets inside MPLS */ if (cstate->label_stack_depth > 0) bpf_error(cstate, "no VLAN match after MPLS"); @@ -8340,24 +8973,27 @@ gen_vlan(compiler_state_t *cstate, int vlan_num) * Do we need special VLAN handling? */ if (cstate->bpf_pcap->bpf_codegen_flags & BPF_SPECIAL_VLAN_HANDLING) - b0 = gen_vlan_bpf_extensions(cstate, vlan_num); + b0 = gen_vlan_bpf_extensions(cstate, vlan_num, + has_vlan_tag); else - b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num); + b0 = gen_vlan_no_bpf_extensions(cstate, + vlan_num, has_vlan_tag); } else #endif - b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num); + b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num, + has_vlan_tag); break; case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: - b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num); + b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num, has_vlan_tag); break; default: - bpf_error(cstate, "no VLAN support for data link type %d", - cstate->linktype); + bpf_error(cstate, "no VLAN support for %s", + pcap_datalink_val_to_description_or_dlt(cstate->linktype)); /*NOTREACHED*/ } @@ -8368,12 +9004,25 @@ gen_vlan(compiler_state_t *cstate, int vlan_num) /* * support for MPLS + * + * The label_num_arg dance is to avoid annoying whining by compilers that + * label_num might be clobbered by longjmp - yeah, it might, but *WHO CARES*? + * It's not *used* after setjmp returns. */ struct block * -gen_mpls(compiler_state_t *cstate, int label_num) +gen_mpls(compiler_state_t *cstate, bpf_u_int32 label_num_arg, + int has_label_num) { + volatile bpf_u_int32 label_num = label_num_arg; struct block *b0, *b1; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + if (cstate->label_stack_depth > 0) { /* just match the bottom-of-stack bit clear */ b0 = gen_mcmp(cstate, OR_PREVMPLSHDR, 2, BPF_B, 0, 0x01); @@ -8400,15 +9049,18 @@ gen_mpls(compiler_state_t *cstate, int label_num) * leave it for now */ default: - bpf_error(cstate, "no MPLS support for data link type %d", - cstate->linktype); + bpf_error(cstate, "no MPLS support for %s", + pcap_datalink_val_to_description_or_dlt(cstate->linktype)); /*NOTREACHED*/ - break; } } /* If a specific MPLS label is requested, check it */ - if (label_num >= 0) { + if (has_label_num) { + if (label_num > 0xFFFFF) { + bpf_error(cstate, "MPLS label %u greater than maximum %u", + label_num, 0xFFFFF); + } label_num = label_num << 12; /* label is shifted 12 bits on the wire */ b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, (bpf_int32)label_num, 0xfffff000); /* only compare the first 20 bits */ @@ -8442,22 +9094,40 @@ gen_mpls(compiler_state_t *cstate, int label_num) struct block * gen_pppoed(compiler_state_t *cstate) { + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + /* check for PPPoE discovery */ return gen_linktype(cstate, (bpf_int32)ETHERTYPE_PPPOED); } struct block * -gen_pppoes(compiler_state_t *cstate, int sess_num) +gen_pppoes(compiler_state_t *cstate, bpf_u_int32 sess_num, int has_sess_num) { struct block *b0, *b1; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + /* * Test against the PPPoE session link-layer type. */ b0 = gen_linktype(cstate, (bpf_int32)ETHERTYPE_PPPOES); /* If a specific session is requested, check PPPoE session id */ - if (sess_num >= 0) { + if (has_sess_num) { + if (sess_num > 0x0000ffff) { + bpf_error(cstate, "PPPoE session number %u greater than maximum %u", + sess_num, 0x0000ffff); + } b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, (bpf_int32)sess_num, 0x0000ffff); gen_and(b0, b1); @@ -8469,29 +9139,8 @@ gen_pppoes(compiler_state_t *cstate, int sess_num) * the PPP packet, and note that this is PPPoE rather than * raw PPP. * - * XXX - this is a bit of a kludge. If we were to split the - * compiler into a parser that parses an expression and - * generates an expression tree, and a code generator that - * takes an expression tree (which could come from our - * parser or from some other parser) and generates BPF code, - * we could perhaps make the offsets parameters of routines - * and, in the handler for an "AND" node, pass to subnodes - * other than the PPPoE node the adjusted offsets. - * - * This would mean that "pppoes" would, instead of changing the - * behavior of *all* tests after it, change only the behavior - * of tests ANDed with it. That would change the documented - * semantics of "pppoes", which might break some expressions. - * However, it would mean that "(pppoes and ip) or ip" would check - * both for VLAN-encapsulated IP and IP-over-Ethernet, rather than - * checking only for VLAN-encapsulated IP, so that could still - * be considered worth doing; it wouldn't break expressions - * that are of the form "pppoes and ..." which I suspect are the - * most common expressions involving "pppoes". "pppoes or ..." - * doesn't necessarily do what the user would really want, now, - * as all the "or ..." tests would be done assuming PPPoE, even - * though the "or" could be viewed as meaning "or, if this isn't - * a PPPoE packet...". + * XXX - this is a bit of a kludge. See the comments in + * gen_vlan(). * * The "network-layer" protocol is PPPoE, which has a 6-byte * PPPoE header, followed by a PPP packet. @@ -8521,7 +9170,7 @@ gen_pppoes(compiler_state_t *cstate, int sess_num) static struct block * gen_geneve_check(compiler_state_t *cstate, struct block *(*gen_portfn)(compiler_state_t *, int, int, int), - enum e_offrel offrel, int vni) + enum e_offrel offrel, bpf_u_int32 vni, int has_vni) { struct block *b0, *b1; @@ -8534,7 +9183,11 @@ gen_geneve_check(compiler_state_t *cstate, gen_and(b0, b1); b0 = b1; - if (vni >= 0) { + if (has_vni) { + if (vni > 0xffffff) { + bpf_error(cstate, "Geneve VNI %u greater than maximum %u", + vni, 0xffffff); + } vni <<= 8; /* VNI is in the upper 3 bytes */ b1 = gen_mcmp(cstate, offrel, 12, BPF_W, (bpf_int32)vni, 0xffffff00); @@ -8551,12 +9204,12 @@ gen_geneve_check(compiler_state_t *cstate, * needed) into register A to be used later to compute * the inner packet offsets. */ static struct block * -gen_geneve4(compiler_state_t *cstate, int vni) +gen_geneve4(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni) { struct block *b0, *b1; struct slist *s, *s1; - b0 = gen_geneve_check(cstate, gen_port, OR_TRAN_IPV4, vni); + b0 = gen_geneve_check(cstate, gen_port, OR_TRAN_IPV4, vni, has_vni); /* Load the IP header length into A. */ s = gen_loadx_iphdrlen(cstate); @@ -8577,12 +9230,12 @@ gen_geneve4(compiler_state_t *cstate, int vni) } static struct block * -gen_geneve6(compiler_state_t *cstate, int vni) +gen_geneve6(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni) { struct block *b0, *b1; struct slist *s, *s1; - b0 = gen_geneve_check(cstate, gen_port6, OR_TRAN_IPV6, vni); + b0 = gen_geneve_check(cstate, gen_port6, OR_TRAN_IPV6, vni, has_vni); /* Load the IP header length. We need to account for a * variable length link prefix if there is one. */ @@ -8755,13 +9408,20 @@ gen_geneve_offsets(compiler_state_t *cstate) /* Check to see if this is a Geneve packet. */ struct block * -gen_geneve(compiler_state_t *cstate, int vni) +gen_geneve(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni) { struct block *b0, *b1; struct slist *s; - b0 = gen_geneve4(cstate, vni); - b1 = gen_geneve6(cstate, vni); + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + b0 = gen_geneve4(cstate, vni, has_vni); + b1 = gen_geneve6(cstate, vni, has_vni); gen_or(b0, b1); b0 = b1; @@ -8811,9 +9471,9 @@ gen_geneve_ll_check(compiler_state_t *cstate) return b0; } -struct block * -gen_atmfield_code(compiler_state_t *cstate, int atmfield, bpf_int32 jvalue, - bpf_u_int32 jtype, int reverse) +static struct block * +gen_atmfield_code_internal(compiler_state_t *cstate, int atmfield, + bpf_int32 jvalue, bpf_u_int32 jtype, int reverse) { struct block *b0; @@ -8866,28 +9526,80 @@ gen_atmfield_code(compiler_state_t *cstate, int atmfield, bpf_int32 jvalue, return b0; } +static struct block * +gen_atmtype_metac(compiler_state_t *cstate) +{ + struct block *b0, *b1; + + b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_VCI, 1, BPF_JEQ, 0); + gen_and(b0, b1); + return b1; +} + +static struct block * +gen_atmtype_sc(compiler_state_t *cstate) +{ + struct block *b0, *b1; + + b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_VCI, 5, BPF_JEQ, 0); + gen_and(b0, b1); + return b1; +} + +static struct block * +gen_atmtype_llc(compiler_state_t *cstate) +{ + struct block *b0; + + b0 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0); + cstate->linktype = cstate->prevlinktype; + return b0; +} + +struct block * +gen_atmfield_code(compiler_state_t *cstate, int atmfield, + bpf_int32 jvalue, bpf_u_int32 jtype, int reverse) +{ + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + return gen_atmfield_code_internal(cstate, atmfield, jvalue, jtype, + reverse); +} + struct block * gen_atmtype_abbrev(compiler_state_t *cstate, int type) { struct block *b0, *b1; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + switch (type) { case A_METAC: /* Get all packets in Meta signalling Circuit */ if (!cstate->is_atm) bpf_error(cstate, "'metac' supported only on raw ATM"); - b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); - b1 = gen_atmfield_code(cstate, A_VCI, 1, BPF_JEQ, 0); - gen_and(b0, b1); + b1 = gen_atmtype_metac(cstate); break; case A_BCC: /* Get all packets in Broadcast Circuit*/ if (!cstate->is_atm) bpf_error(cstate, "'bcc' supported only on raw ATM"); - b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); - b1 = gen_atmfield_code(cstate, A_VCI, 2, BPF_JEQ, 0); + b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_VCI, 2, BPF_JEQ, 0); gen_and(b0, b1); break; @@ -8895,8 +9607,8 @@ gen_atmtype_abbrev(compiler_state_t *cstate, int type) /* Get all cells in Segment OAM F4 circuit*/ if (!cstate->is_atm) bpf_error(cstate, "'oam4sc' supported only on raw ATM"); - b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); - b1 = gen_atmfield_code(cstate, A_VCI, 3, BPF_JEQ, 0); + b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_VCI, 3, BPF_JEQ, 0); gen_and(b0, b1); break; @@ -8904,8 +9616,8 @@ gen_atmtype_abbrev(compiler_state_t *cstate, int type) /* Get all cells in End-to-End OAM F4 Circuit*/ if (!cstate->is_atm) bpf_error(cstate, "'oam4ec' supported only on raw ATM"); - b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); - b1 = gen_atmfield_code(cstate, A_VCI, 4, BPF_JEQ, 0); + b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_VCI, 4, BPF_JEQ, 0); gen_and(b0, b1); break; @@ -8913,17 +9625,15 @@ gen_atmtype_abbrev(compiler_state_t *cstate, int type) /* Get all packets in connection Signalling Circuit */ if (!cstate->is_atm) bpf_error(cstate, "'sc' supported only on raw ATM"); - b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); - b1 = gen_atmfield_code(cstate, A_VCI, 5, BPF_JEQ, 0); - gen_and(b0, b1); + b1 = gen_atmtype_sc(cstate); break; case A_ILMIC: /* Get all packets in ILMI Circuit */ if (!cstate->is_atm) bpf_error(cstate, "'ilmic' supported only on raw ATM"); - b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); - b1 = gen_atmfield_code(cstate, A_VCI, 16, BPF_JEQ, 0); + b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_VCI, 16, BPF_JEQ, 0); gen_and(b0, b1); break; @@ -8931,7 +9641,7 @@ gen_atmtype_abbrev(compiler_state_t *cstate, int type) /* Get all LANE packets */ if (!cstate->is_atm) bpf_error(cstate, "'lane' supported only on raw ATM"); - b1 = gen_atmfield_code(cstate, A_PROTOTYPE, PT_LANE, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LANE, BPF_JEQ, 0); /* * Arrange that all subsequent tests assume LANE @@ -8954,8 +9664,7 @@ gen_atmtype_abbrev(compiler_state_t *cstate, int type) /* Get all LLC-encapsulated packets */ if (!cstate->is_atm) bpf_error(cstate, "'llc' supported only on raw ATM"); - b1 = gen_atmfield_code(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0); - cstate->linktype = cstate->prevlinktype; + b1 = gen_atmtype_llc(cstate); break; default: @@ -8976,6 +9685,13 @@ gen_mtp2type_abbrev(compiler_state_t *cstate, int type) { struct block *b0, *b1; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + switch (type) { case M_FISU: @@ -9038,17 +9754,34 @@ gen_mtp2type_abbrev(compiler_state_t *cstate, int type) return b0; } +/* + * The jvalue_arg dance is to avoid annoying whining by compilers that + * jvalue might be clobbered by longjmp - yeah, it might, but *WHO CARES*? + * It's not *used* after setjmp returns. + */ struct block * -gen_mtp3field_code(compiler_state_t *cstate, int mtp3field, bpf_u_int32 jvalue, - bpf_u_int32 jtype, int reverse) +gen_mtp3field_code(compiler_state_t *cstate, int mtp3field, + bpf_u_int32 jvalue_arg, bpf_u_int32 jtype, int reverse) { + volatile bpf_u_int32 jvalue = jvalue_arg; struct block *b0; bpf_u_int32 val1 , val2 , val3; - u_int newoff_sio = cstate->off_sio; - u_int newoff_opc = cstate->off_opc; - u_int newoff_dpc = cstate->off_dpc; - u_int newoff_sls = cstate->off_sls; + u_int newoff_sio; + u_int newoff_opc; + u_int newoff_dpc; + u_int newoff_sls; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + newoff_sio = cstate->off_sio; + newoff_opc = cstate->off_opc; + newoff_dpc = cstate->off_dpc; + newoff_sls = cstate->off_sls; switch (mtp3field) { case MH_SIO: @@ -9067,7 +9800,9 @@ gen_mtp3field_code(compiler_state_t *cstate, int mtp3field, bpf_u_int32 jvalue, break; case MH_OPC: - newoff_opc+=3; + newoff_opc += 3; + + /* FALLTHROUGH */ case M_OPC: if (cstate->off_opc == OFFSET_NOT_SET) bpf_error(cstate, "'opc' supported only on SS7"); @@ -9111,7 +9846,9 @@ gen_mtp3field_code(compiler_state_t *cstate, int mtp3field, bpf_u_int32 jvalue, break; case MH_SLS: - newoff_sls+=3; + newoff_sls += 3; + /* FALLTHROUGH */ + case M_SLS: if (cstate->off_sls == OFFSET_NOT_SET) bpf_error(cstate, "'sls' supported only on SS7"); @@ -9144,27 +9881,27 @@ gen_msg_abbrev(compiler_state_t *cstate, int type) switch (type) { case A_SETUP: - b1 = gen_atmfield_code(cstate, A_MSGTYPE, SETUP, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, SETUP, BPF_JEQ, 0); break; case A_CALLPROCEED: - b1 = gen_atmfield_code(cstate, A_MSGTYPE, CALL_PROCEED, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, CALL_PROCEED, BPF_JEQ, 0); break; case A_CONNECT: - b1 = gen_atmfield_code(cstate, A_MSGTYPE, CONNECT, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, CONNECT, BPF_JEQ, 0); break; case A_CONNECTACK: - b1 = gen_atmfield_code(cstate, A_MSGTYPE, CONNECT_ACK, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, CONNECT_ACK, BPF_JEQ, 0); break; case A_RELEASE: - b1 = gen_atmfield_code(cstate, A_MSGTYPE, RELEASE, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, RELEASE, BPF_JEQ, 0); break; case A_RELEASE_DONE: - b1 = gen_atmfield_code(cstate, A_MSGTYPE, RELEASE_DONE, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, RELEASE_DONE, BPF_JEQ, 0); break; default: @@ -9178,22 +9915,34 @@ gen_atmmulti_abbrev(compiler_state_t *cstate, int type) { struct block *b0, *b1; + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + switch (type) { case A_OAM: if (!cstate->is_atm) bpf_error(cstate, "'oam' supported only on raw ATM"); - b1 = gen_atmmulti_abbrev(cstate, A_OAMF4); + /* OAM F4 type */ + b0 = gen_atmfield_code_internal(cstate, A_VCI, 3, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_VCI, 4, BPF_JEQ, 0); + gen_or(b0, b1); + b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); + gen_and(b0, b1); break; case A_OAMF4: if (!cstate->is_atm) bpf_error(cstate, "'oamf4' supported only on raw ATM"); /* OAM F4 type */ - b0 = gen_atmfield_code(cstate, A_VCI, 3, BPF_JEQ, 0); - b1 = gen_atmfield_code(cstate, A_VCI, 4, BPF_JEQ, 0); + b0 = gen_atmfield_code_internal(cstate, A_VCI, 3, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_VCI, 4, BPF_JEQ, 0); gen_or(b0, b1); - b0 = gen_atmfield_code(cstate, A_VPI, 0, BPF_JEQ, 0); + b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); gen_and(b0, b1); break; @@ -9215,7 +9964,7 @@ gen_atmmulti_abbrev(compiler_state_t *cstate, int type) gen_or(b0, b1); b0 = gen_msg_abbrev(cstate, A_RELEASE_DONE); gen_or(b0, b1); - b0 = gen_atmtype_abbrev(cstate, A_SC); + b0 = gen_atmtype_sc(cstate); gen_and(b0, b1); break; @@ -9231,7 +9980,7 @@ gen_atmmulti_abbrev(compiler_state_t *cstate, int type) gen_or(b0, b1); b0 = gen_msg_abbrev(cstate, A_RELEASE_DONE); gen_or(b0, b1); - b0 = gen_atmtype_abbrev(cstate, A_METAC); + b0 = gen_atmtype_metac(cstate); gen_and(b0, b1); break; diff --git a/gencode.h b/gencode.h index 88def5a8ad28..cc21e04384a6 100644 --- a/gencode.h +++ b/gencode.h @@ -113,16 +113,14 @@ #define Q_ISIS_L2 32 /* PDU types */ #define Q_ISIS_IIH 33 -#define Q_ISIS_LAN_IIH 34 -#define Q_ISIS_PTP_IIH 35 -#define Q_ISIS_SNP 36 -#define Q_ISIS_CSNP 37 -#define Q_ISIS_PSNP 38 -#define Q_ISIS_LSP 39 +#define Q_ISIS_SNP 34 +#define Q_ISIS_CSNP 35 +#define Q_ISIS_PSNP 36 +#define Q_ISIS_LSP 37 -#define Q_RADIO 40 +#define Q_RADIO 38 -#define Q_CARP 41 +#define Q_CARP 39 /* Directional qualifiers. */ @@ -299,8 +297,8 @@ void gen_or(struct block *, struct block *); void gen_not(struct block *); struct block *gen_scode(compiler_state_t *, const char *, struct qual); -struct block *gen_ecode(compiler_state_t *, const u_char *, struct qual); -struct block *gen_acode(compiler_state_t *, const u_char *, struct qual); +struct block *gen_ecode(compiler_state_t *, const char *, struct qual); +struct block *gen_acode(compiler_state_t *, const char *, struct qual); struct block *gen_mcode(compiler_state_t *, const char *, const char *, unsigned int, struct qual); #ifdef INET6 @@ -326,13 +324,13 @@ struct block *gen_llc_u(compiler_state_t *); struct block *gen_llc_s_subtype(compiler_state_t *, bpf_u_int32); struct block *gen_llc_u_subtype(compiler_state_t *, bpf_u_int32); -struct block *gen_vlan(compiler_state_t *, int); -struct block *gen_mpls(compiler_state_t *, int); +struct block *gen_vlan(compiler_state_t *, bpf_u_int32, int); +struct block *gen_mpls(compiler_state_t *, bpf_u_int32, int); struct block *gen_pppoed(compiler_state_t *); -struct block *gen_pppoes(compiler_state_t *, int); +struct block *gen_pppoes(compiler_state_t *, bpf_u_int32, int); -struct block *gen_geneve(compiler_state_t *, int); +struct block *gen_geneve(compiler_state_t *, bpf_u_int32, int); struct block *gen_atmfield_code(compiler_state_t *, int, bpf_int32, bpf_u_int32, int); @@ -343,29 +341,11 @@ struct block *gen_mtp2type_abbrev(compiler_state_t *, int type); struct block *gen_mtp3field_code(compiler_state_t *, int, bpf_u_int32, bpf_u_int32, int); -#ifndef HAVE_NET_PFVAR_H -PCAP_NORETURN -#endif struct block *gen_pf_ifname(compiler_state_t *, const char *); -#ifndef HAVE_NET_PFVAR_H -PCAP_NORETURN -#endif struct block *gen_pf_rnr(compiler_state_t *, int); -#ifndef HAVE_NET_PFVAR_H -PCAP_NORETURN -#endif struct block *gen_pf_srnr(compiler_state_t *, int); -#ifndef HAVE_NET_PFVAR_H -PCAP_NORETURN -#endif struct block *gen_pf_ruleset(compiler_state_t *, char *); -#ifndef HAVE_NET_PFVAR_H -PCAP_NORETURN -#endif struct block *gen_pf_reason(compiler_state_t *, int); -#ifndef HAVE_NET_PFVAR_H -PCAP_NORETURN -#endif struct block *gen_pf_action(compiler_state_t *, int); struct block *gen_p80211_type(compiler_state_t *, int, int); @@ -386,16 +366,15 @@ struct icode { int cur_mark; }; -void bpf_optimize(compiler_state_t *, struct icode *ic); -void PCAP_NORETURN bpf_syntax_error(compiler_state_t *, const char *); -void PCAP_NORETURN bpf_error(compiler_state_t *, const char *, ...) +int bpf_optimize(struct icode *, char *); +void bpf_set_error(compiler_state_t *, const char *, ...) PCAP_PRINTFLIKE(2, 3); -void finish_parse(compiler_state_t *, struct block *); +int finish_parse(compiler_state_t *, struct block *); char *sdup(compiler_state_t *, const char *); -struct bpf_insn *icode_to_fcode(compiler_state_t *, struct icode *, - struct block *, u_int *); +struct bpf_insn *icode_to_fcode(struct icode *, struct block *, u_int *, + char *); void sappend(struct slist *, struct slist *); /* diff --git a/grammar.y b/grammar.y index be80e2bfcfde..32cb19c11bb7 100644 --- a/grammar.y +++ b/grammar.y @@ -216,13 +216,12 @@ str2tok(const char *str, const struct tok *toks) return (-1); } -static struct qual qerr = { Q_UNDEF, Q_UNDEF, Q_UNDEF, Q_UNDEF }; +static const struct qual qerr = { Q_UNDEF, Q_UNDEF, Q_UNDEF, Q_UNDEF }; -static PCAP_NORETURN_DEF void +static void yyerror(void *yyscanner _U_, compiler_state_t *cstate, const char *msg) { - bpf_syntax_error(cstate, msg); - /* NOTREACHED */ + bpf_set_error(cstate, "can't parse filter expression: %s", msg); } #ifdef HAVE_NET_PFVAR_H @@ -236,8 +235,8 @@ pfreason_to_num(compiler_state_t *cstate, const char *reason) if (pcap_strcasecmp(reason, reasons[i]) == 0) return (i); } - bpf_error(cstate, "unknown PF reason"); - /*NOTREACHED*/ + bpf_set_error(cstate, "unknown PF reason"); + return (-1); } static int @@ -260,33 +259,38 @@ pfaction_to_num(compiler_state_t *cstate, const char *action) return (PF_NORDR); #endif else { - bpf_error(cstate, "unknown PF action"); - /*NOTREACHED*/ + bpf_set_error(cstate, "unknown PF action"); + return (-1); } } #else /* !HAVE_NET_PFVAR_H */ -static PCAP_NORETURN_DEF int +static int pfreason_to_num(compiler_state_t *cstate, const char *reason _U_) { - bpf_error(cstate, "libpcap was compiled on a machine without pf support"); - /*NOTREACHED*/ + bpf_set_error(cstate, "libpcap was compiled on a machine without pf support"); + return (-1); } -static PCAP_NORETURN_DEF int +static int pfaction_to_num(compiler_state_t *cstate, const char *action _U_) { - bpf_error(cstate, "libpcap was compiled on a machine without pf support"); - /*NOTREACHED*/ + bpf_set_error(cstate, "libpcap was compiled on a machine without pf support"); + return (-1); } #endif /* HAVE_NET_PFVAR_H */ +/* + * For calls that might return an "an error occurred" value. + */ +#define CHECK_INT_VAL(val) if (val == -1) YYABORT +#define CHECK_PTR_VAL(val) if (val == NULL) YYABORT + DIAG_OFF_BISON_BYACC %} %union { int i; bpf_u_int32 h; - u_char *e; char *s; struct stmt *stmt; struct arth *a; @@ -340,11 +344,9 @@ DIAG_OFF_BISON_BYACC %token RADIO %token FISU LSSU MSU HFISU HLSSU HMSU %token SIO OPC DPC SLS HSIO HOPC HDPC HSLS +%token LEX_ERROR - -%type ID -%type EID -%type AID +%type ID EID AID %type HID HID6 %type NUM action reason type subtype type_subtype dir @@ -359,7 +361,7 @@ DIAG_OFF_BISON_BYACC %% prog: null expr { - finish_parse(cstate, $2.b); + CHECK_INT_VAL(finish_parse(cstate, $2.b)); } | null ; @@ -376,64 +378,58 @@ and: AND { $$ = $0; } or: OR { $$ = $0; } ; id: nid - | pnum { $$.b = gen_ncode(cstate, NULL, (bpf_u_int32)$1, - $$.q = $0.q); } + | pnum { CHECK_PTR_VAL(($$.b = gen_ncode(cstate, NULL, (bpf_u_int32)$1, + $$.q = $0.q))); } | paren pid ')' { $$ = $2; } ; -nid: ID { $$.b = gen_scode(cstate, $1, $$.q = $0.q); } - | HID '/' NUM { $$.b = gen_mcode(cstate, $1, NULL, $3, - $$.q = $0.q); } - | HID NETMASK HID { $$.b = gen_mcode(cstate, $1, $3, 0, - $$.q = $0.q); } +nid: ID { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_scode(cstate, $1, $$.q = $0.q))); } + | HID '/' NUM { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_mcode(cstate, $1, NULL, $3, + $$.q = $0.q))); } + | HID NETMASK HID { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_mcode(cstate, $1, $3, 0, + $$.q = $0.q))); } | HID { + CHECK_PTR_VAL($1); /* Decide how to parse HID based on proto */ $$.q = $0.q; - if ($$.q.addr == Q_PORT) - bpf_error(cstate, "'port' modifier applied to ip host"); - else if ($$.q.addr == Q_PORTRANGE) - bpf_error(cstate, "'portrange' modifier applied to ip host"); - else if ($$.q.addr == Q_PROTO) - bpf_error(cstate, "'proto' modifier applied to ip host"); - else if ($$.q.addr == Q_PROTOCHAIN) - bpf_error(cstate, "'protochain' modifier applied to ip host"); - $$.b = gen_ncode(cstate, $1, 0, $$.q); + if ($$.q.addr == Q_PORT) { + bpf_set_error(cstate, "'port' modifier applied to ip host"); + YYABORT; + } else if ($$.q.addr == Q_PORTRANGE) { + bpf_set_error(cstate, "'portrange' modifier applied to ip host"); + YYABORT; + } else if ($$.q.addr == Q_PROTO) { + bpf_set_error(cstate, "'proto' modifier applied to ip host"); + YYABORT; + } else if ($$.q.addr == Q_PROTOCHAIN) { + bpf_set_error(cstate, "'protochain' modifier applied to ip host"); + YYABORT; + } + CHECK_PTR_VAL(($$.b = gen_ncode(cstate, $1, 0, $$.q))); } | HID6 '/' NUM { + CHECK_PTR_VAL($1); #ifdef INET6 - $$.b = gen_mcode6(cstate, $1, NULL, $3, - $$.q = $0.q); + CHECK_PTR_VAL(($$.b = gen_mcode6(cstate, $1, NULL, $3, + $$.q = $0.q))); #else - bpf_error(cstate, "'ip6addr/prefixlen' not supported " + bpf_set_error(cstate, "'ip6addr/prefixlen' not supported " "in this configuration"); + YYABORT; #endif /*INET6*/ } | HID6 { + CHECK_PTR_VAL($1); #ifdef INET6 - $$.b = gen_mcode6(cstate, $1, 0, 128, - $$.q = $0.q); + CHECK_PTR_VAL(($$.b = gen_mcode6(cstate, $1, 0, 128, + $$.q = $0.q))); #else - bpf_error(cstate, "'ip6addr' not supported " + bpf_set_error(cstate, "'ip6addr' not supported " "in this configuration"); + YYABORT; #endif /*INET6*/ } - | EID { - $$.b = gen_ecode(cstate, $1, $$.q = $0.q); - /* - * $1 was allocated by "pcap_ether_aton()", - * so we must free it now that we're done - * with it. - */ - free($1); - } - | AID { - $$.b = gen_acode(cstate, $1, $$.q = $0.q); - /* - * $1 was allocated by "pcap_ether_aton()", - * so we must free it now that we're done - * with it. - */ - free($1); - } + | EID { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_ecode(cstate, $1, $$.q = $0.q))); } + | AID { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_acode(cstate, $1, $$.q = $0.q))); } | not id { gen_not($2.b); $$ = $2; } ; not: '!' { $$ = $0; } @@ -444,8 +440,8 @@ pid: nid | qid and id { gen_and($1.b, $3.b); $$ = $3; } | qid or id { gen_or($1.b, $3.b); $$ = $3; } ; -qid: pnum { $$.b = gen_ncode(cstate, NULL, (bpf_u_int32)$1, - $$.q = $0.q); } +qid: pnum { CHECK_PTR_VAL(($$.b = gen_ncode(cstate, NULL, (bpf_u_int32)$1, + $$.q = $0.q))); } | pid ; term: rterm @@ -455,21 +451,28 @@ head: pqual dqual aqual { QSET($$.q, $1, $2, $3); } | pqual dqual { QSET($$.q, $1, $2, Q_DEFAULT); } | pqual aqual { QSET($$.q, $1, Q_DEFAULT, $2); } | pqual PROTO { QSET($$.q, $1, Q_DEFAULT, Q_PROTO); } - | pqual PROTOCHAIN { QSET($$.q, $1, Q_DEFAULT, Q_PROTOCHAIN); } + | pqual PROTOCHAIN { +#ifdef NO_PROTOCHAIN + bpf_set_error(cstate, "protochain not supported"); + YYABORT; +#else + QSET($$.q, $1, Q_DEFAULT, Q_PROTOCHAIN); +#endif + } | pqual ndaqual { QSET($$.q, $1, Q_DEFAULT, $2); } ; rterm: head id { $$ = $2; } | paren expr ')' { $$.b = $2.b; $$.q = $1.q; } - | pname { $$.b = gen_proto_abbrev(cstate, $1); $$.q = qerr; } - | arth relop arth { $$.b = gen_relation(cstate, $2, $1, $3, 0); + | pname { CHECK_PTR_VAL(($$.b = gen_proto_abbrev(cstate, $1))); $$.q = qerr; } + | arth relop arth { CHECK_PTR_VAL(($$.b = gen_relation(cstate, $2, $1, $3, 0))); $$.q = qerr; } - | arth irelop arth { $$.b = gen_relation(cstate, $2, $1, $3, 1); + | arth irelop arth { CHECK_PTR_VAL(($$.b = gen_relation(cstate, $2, $1, $3, 1))); $$.q = qerr; } | other { $$.b = $1; $$.q = qerr; } - | atmtype { $$.b = gen_atmtype_abbrev(cstate, $1); $$.q = qerr; } - | atmmultitype { $$.b = gen_atmmulti_abbrev(cstate, $1); $$.q = qerr; } + | atmtype { CHECK_PTR_VAL(($$.b = gen_atmtype_abbrev(cstate, $1))); $$.q = qerr; } + | atmmultitype { CHECK_PTR_VAL(($$.b = gen_atmmulti_abbrev(cstate, $1))); $$.q = qerr; } | atmfield atmvalue { $$.b = $2.b; $$.q = qerr; } - | mtp2type { $$.b = gen_mtp2type_abbrev(cstate, $1); $$.q = qerr; } + | mtp2type { CHECK_PTR_VAL(($$.b = gen_mtp2type_abbrev(cstate, $1))); $$.q = qerr; } | mtp3field mtp3value { $$.b = $2.b; $$.q = qerr; } ; /* protocol level qualifiers */ @@ -539,65 +542,69 @@ pname: LINK { $$ = Q_LINK; } | NETBEUI { $$ = Q_NETBEUI; } | RADIO { $$ = Q_RADIO; } ; -other: pqual TK_BROADCAST { $$ = gen_broadcast(cstate, $1); } - | pqual TK_MULTICAST { $$ = gen_multicast(cstate, $1); } - | LESS NUM { $$ = gen_less(cstate, $2); } - | GREATER NUM { $$ = gen_greater(cstate, $2); } - | CBYTE NUM byteop NUM { $$ = gen_byteop(cstate, $3, $2, $4); } - | INBOUND { $$ = gen_inbound(cstate, 0); } - | OUTBOUND { $$ = gen_inbound(cstate, 1); } - | VLAN pnum { $$ = gen_vlan(cstate, $2); } - | VLAN { $$ = gen_vlan(cstate, -1); } - | MPLS pnum { $$ = gen_mpls(cstate, $2); } - | MPLS { $$ = gen_mpls(cstate, -1); } - | PPPOED { $$ = gen_pppoed(cstate); } - | PPPOES pnum { $$ = gen_pppoes(cstate, $2); } - | PPPOES { $$ = gen_pppoes(cstate, -1); } - | GENEVE pnum { $$ = gen_geneve(cstate, $2); } - | GENEVE { $$ = gen_geneve(cstate, -1); } +other: pqual TK_BROADCAST { CHECK_PTR_VAL(($$ = gen_broadcast(cstate, $1))); } + | pqual TK_MULTICAST { CHECK_PTR_VAL(($$ = gen_multicast(cstate, $1))); } + | LESS NUM { CHECK_PTR_VAL(($$ = gen_less(cstate, $2))); } + | GREATER NUM { CHECK_PTR_VAL(($$ = gen_greater(cstate, $2))); } + | CBYTE NUM byteop NUM { CHECK_PTR_VAL(($$ = gen_byteop(cstate, $3, $2, $4))); } + | INBOUND { CHECK_PTR_VAL(($$ = gen_inbound(cstate, 0))); } + | OUTBOUND { CHECK_PTR_VAL(($$ = gen_inbound(cstate, 1))); } + | VLAN pnum { CHECK_PTR_VAL(($$ = gen_vlan(cstate, (bpf_u_int32)$2, 1))); } + | VLAN { CHECK_PTR_VAL(($$ = gen_vlan(cstate, 0, 0))); } + | MPLS pnum { CHECK_PTR_VAL(($$ = gen_mpls(cstate, (bpf_u_int32)$2, 1))); } + | MPLS { CHECK_PTR_VAL(($$ = gen_mpls(cstate, 0, 0))); } + | PPPOED { CHECK_PTR_VAL(($$ = gen_pppoed(cstate))); } + | PPPOES pnum { CHECK_PTR_VAL(($$ = gen_pppoes(cstate, (bpf_u_int32)$2, 1))); } + | PPPOES { CHECK_PTR_VAL(($$ = gen_pppoes(cstate, 0, 0))); } + | GENEVE pnum { CHECK_PTR_VAL(($$ = gen_geneve(cstate, (bpf_u_int32)$2, 1))); } + | GENEVE { CHECK_PTR_VAL(($$ = gen_geneve(cstate, 0, 0))); } | pfvar { $$ = $1; } | pqual p80211 { $$ = $2; } | pllc { $$ = $1; } ; -pfvar: PF_IFNAME ID { $$ = gen_pf_ifname(cstate, $2); } - | PF_RSET ID { $$ = gen_pf_ruleset(cstate, $2); } - | PF_RNR NUM { $$ = gen_pf_rnr(cstate, $2); } - | PF_SRNR NUM { $$ = gen_pf_srnr(cstate, $2); } - | PF_REASON reason { $$ = gen_pf_reason(cstate, $2); } - | PF_ACTION action { $$ = gen_pf_action(cstate, $2); } +pfvar: PF_IFNAME ID { CHECK_PTR_VAL($2); CHECK_PTR_VAL(($$ = gen_pf_ifname(cstate, $2))); } + | PF_RSET ID { CHECK_PTR_VAL($2); CHECK_PTR_VAL(($$ = gen_pf_ruleset(cstate, $2))); } + | PF_RNR NUM { CHECK_PTR_VAL(($$ = gen_pf_rnr(cstate, $2))); } + | PF_SRNR NUM { CHECK_PTR_VAL(($$ = gen_pf_srnr(cstate, $2))); } + | PF_REASON reason { CHECK_PTR_VAL(($$ = gen_pf_reason(cstate, $2))); } + | PF_ACTION action { CHECK_PTR_VAL(($$ = gen_pf_action(cstate, $2))); } ; p80211: TYPE type SUBTYPE subtype - { $$ = gen_p80211_type(cstate, $2 | $4, + { CHECK_PTR_VAL(($$ = gen_p80211_type(cstate, $2 | $4, IEEE80211_FC0_TYPE_MASK | - IEEE80211_FC0_SUBTYPE_MASK); + IEEE80211_FC0_SUBTYPE_MASK))); } - | TYPE type { $$ = gen_p80211_type(cstate, $2, - IEEE80211_FC0_TYPE_MASK); + | TYPE type { CHECK_PTR_VAL(($$ = gen_p80211_type(cstate, $2, + IEEE80211_FC0_TYPE_MASK))); } - | SUBTYPE type_subtype { $$ = gen_p80211_type(cstate, $2, + | SUBTYPE type_subtype { CHECK_PTR_VAL(($$ = gen_p80211_type(cstate, $2, IEEE80211_FC0_TYPE_MASK | - IEEE80211_FC0_SUBTYPE_MASK); + IEEE80211_FC0_SUBTYPE_MASK))); } - | DIR dir { $$ = gen_p80211_fcdir(cstate, $2); } + | DIR dir { CHECK_PTR_VAL(($$ = gen_p80211_fcdir(cstate, $2))); } ; type: NUM - | ID { $$ = str2tok($1, ieee80211_types); - if ($$ == -1) - bpf_error(cstate, "unknown 802.11 type name"); + | ID { CHECK_PTR_VAL($1); + $$ = str2tok($1, ieee80211_types); + if ($$ == -1) { + bpf_set_error(cstate, "unknown 802.11 type name"); + YYABORT; + } } ; subtype: NUM | ID { const struct tok *types = NULL; int i; + CHECK_PTR_VAL($1); for (i = 0;; i++) { if (ieee80211_type_subtypes[i].tok == NULL) { /* Ran out of types */ - bpf_error(cstate, "unknown 802.11 type"); - break; + bpf_set_error(cstate, "unknown 802.11 type"); + YYABORT; } if ($-1 == ieee80211_type_subtypes[i].type) { types = ieee80211_type_subtypes[i].tok; @@ -606,17 +613,20 @@ subtype: NUM } $$ = str2tok($1, types); - if ($$ == -1) - bpf_error(cstate, "unknown 802.11 subtype name"); + if ($$ == -1) { + bpf_set_error(cstate, "unknown 802.11 subtype name"); + YYABORT; + } } ; type_subtype: ID { int i; + CHECK_PTR_VAL($1); for (i = 0;; i++) { if (ieee80211_type_subtypes[i].tok == NULL) { /* Ran out of types */ - bpf_error(cstate, "unknown 802.11 type name"); - break; + bpf_set_error(cstate, "unknown 802.11 type name"); + YYABORT; } $$ = str2tok($1, ieee80211_type_subtypes[i].tok); if ($$ != -1) { @@ -627,33 +637,37 @@ type_subtype: ID { int i; } ; -pllc: LLC { $$ = gen_llc(cstate); } - | LLC ID { if (pcap_strcasecmp($2, "i") == 0) - $$ = gen_llc_i(cstate); - else if (pcap_strcasecmp($2, "s") == 0) - $$ = gen_llc_s(cstate); - else if (pcap_strcasecmp($2, "u") == 0) - $$ = gen_llc_u(cstate); - else { +pllc: LLC { CHECK_PTR_VAL(($$ = gen_llc(cstate))); } + | LLC ID { CHECK_PTR_VAL($2); + if (pcap_strcasecmp($2, "i") == 0) { + CHECK_PTR_VAL(($$ = gen_llc_i(cstate))); + } else if (pcap_strcasecmp($2, "s") == 0) { + CHECK_PTR_VAL(($$ = gen_llc_s(cstate))); + } else if (pcap_strcasecmp($2, "u") == 0) { + CHECK_PTR_VAL(($$ = gen_llc_u(cstate))); + } else { int subtype; subtype = str2tok($2, llc_s_subtypes); - if (subtype != -1) - $$ = gen_llc_s_subtype(cstate, subtype); - else { + if (subtype != -1) { + CHECK_PTR_VAL(($$ = gen_llc_s_subtype(cstate, subtype))); + } else { subtype = str2tok($2, llc_u_subtypes); - if (subtype == -1) - bpf_error(cstate, "unknown LLC type name \"%s\"", $2); - $$ = gen_llc_u_subtype(cstate, subtype); + if (subtype == -1) { + bpf_set_error(cstate, "unknown LLC type name \"%s\"", $2); + YYABORT; + } + CHECK_PTR_VAL(($$ = gen_llc_u_subtype(cstate, subtype))); } } } /* sigh, "rnr" is already a keyword for PF */ - | LLC PF_RNR { $$ = gen_llc_s_subtype(cstate, LLC_RNR); } + | LLC PF_RNR { CHECK_PTR_VAL(($$ = gen_llc_s_subtype(cstate, LLC_RNR))); } ; dir: NUM - | ID { if (pcap_strcasecmp($1, "nods") == 0) + | ID { CHECK_PTR_VAL($1); + if (pcap_strcasecmp($1, "nods") == 0) $$ = IEEE80211_FC1_DIR_NODS; else if (pcap_strcasecmp($1, "tods") == 0) $$ = IEEE80211_FC1_DIR_TODS; @@ -661,16 +675,18 @@ dir: NUM $$ = IEEE80211_FC1_DIR_FROMDS; else if (pcap_strcasecmp($1, "dstods") == 0) $$ = IEEE80211_FC1_DIR_DSTODS; - else - bpf_error(cstate, "unknown 802.11 direction"); + else { + bpf_set_error(cstate, "unknown 802.11 direction"); + YYABORT; + } } ; reason: NUM { $$ = $1; } - | ID { $$ = pfreason_to_num(cstate, $1); } + | ID { CHECK_PTR_VAL($1); CHECK_INT_VAL(($$ = pfreason_to_num(cstate, $1))); } ; -action: ID { $$ = pfaction_to_num(cstate, $1); } +action: ID { CHECK_PTR_VAL($1); CHECK_INT_VAL(($$ = pfaction_to_num(cstate, $1))); } ; relop: '>' { $$ = BPF_JGT; } @@ -681,24 +697,24 @@ irelop: LEQ { $$ = BPF_JGT; } | '<' { $$ = BPF_JGE; } | NEQ { $$ = BPF_JEQ; } ; -arth: pnum { $$ = gen_loadi(cstate, $1); } +arth: pnum { CHECK_PTR_VAL(($$ = gen_loadi(cstate, $1))); } | narth ; -narth: pname '[' arth ']' { $$ = gen_load(cstate, $1, $3, 1); } - | pname '[' arth ':' NUM ']' { $$ = gen_load(cstate, $1, $3, $5); } - | arth '+' arth { $$ = gen_arth(cstate, BPF_ADD, $1, $3); } - | arth '-' arth { $$ = gen_arth(cstate, BPF_SUB, $1, $3); } - | arth '*' arth { $$ = gen_arth(cstate, BPF_MUL, $1, $3); } - | arth '/' arth { $$ = gen_arth(cstate, BPF_DIV, $1, $3); } - | arth '%' arth { $$ = gen_arth(cstate, BPF_MOD, $1, $3); } - | arth '&' arth { $$ = gen_arth(cstate, BPF_AND, $1, $3); } - | arth '|' arth { $$ = gen_arth(cstate, BPF_OR, $1, $3); } - | arth '^' arth { $$ = gen_arth(cstate, BPF_XOR, $1, $3); } - | arth LSH arth { $$ = gen_arth(cstate, BPF_LSH, $1, $3); } - | arth RSH arth { $$ = gen_arth(cstate, BPF_RSH, $1, $3); } - | '-' arth %prec UMINUS { $$ = gen_neg(cstate, $2); } +narth: pname '[' arth ']' { CHECK_PTR_VAL(($$ = gen_load(cstate, $1, $3, 1))); } + | pname '[' arth ':' NUM ']' { CHECK_PTR_VAL(($$ = gen_load(cstate, $1, $3, $5))); } + | arth '+' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_ADD, $1, $3))); } + | arth '-' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_SUB, $1, $3))); } + | arth '*' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_MUL, $1, $3))); } + | arth '/' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_DIV, $1, $3))); } + | arth '%' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_MOD, $1, $3))); } + | arth '&' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_AND, $1, $3))); } + | arth '|' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_OR, $1, $3))); } + | arth '^' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_XOR, $1, $3))); } + | arth LSH arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_LSH, $1, $3))); } + | arth RSH arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_RSH, $1, $3))); } + | '-' arth %prec UMINUS { CHECK_PTR_VAL(($$ = gen_neg(cstate, $2))); } | paren narth ')' { $$ = $2; } - | LEN { $$ = gen_loadlen(cstate); } + | LEN { CHECK_PTR_VAL(($$ = gen_loadlen(cstate))); } ; byteop: '&' { $$ = '&'; } | '|' { $$ = '|'; } @@ -727,15 +743,15 @@ atmfield: VPI { $$.atmfieldtype = A_VPI; } | VCI { $$.atmfieldtype = A_VCI; } ; atmvalue: atmfieldvalue - | relop NUM { $$.b = gen_atmfield_code(cstate, $0.atmfieldtype, (bpf_int32)$2, (bpf_u_int32)$1, 0); } - | irelop NUM { $$.b = gen_atmfield_code(cstate, $0.atmfieldtype, (bpf_int32)$2, (bpf_u_int32)$1, 1); } + | relop NUM { CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $0.atmfieldtype, (bpf_int32)$2, (bpf_u_int32)$1, 0))); } + | irelop NUM { CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $0.atmfieldtype, (bpf_int32)$2, (bpf_u_int32)$1, 1))); } | paren atmlistvalue ')' { $$.b = $2.b; $$.q = qerr; } ; atmfieldvalue: NUM { $$.atmfieldtype = $0.atmfieldtype; if ($$.atmfieldtype == A_VPI || $$.atmfieldtype == A_VCI) - $$.b = gen_atmfield_code(cstate, $$.atmfieldtype, (bpf_int32) $1, BPF_JEQ, 0); + CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $$.atmfieldtype, (bpf_int32) $1, BPF_JEQ, 0))); } ; atmlistvalue: atmfieldvalue @@ -760,8 +776,8 @@ mtp3field: SIO { $$.mtp3fieldtype = M_SIO; } | HSLS { $$.mtp3fieldtype = MH_SLS; } ; mtp3value: mtp3fieldvalue - | relop NUM { $$.b = gen_mtp3field_code(cstate, $0.mtp3fieldtype, (u_int)$2, (u_int)$1, 0); } - | irelop NUM { $$.b = gen_mtp3field_code(cstate, $0.mtp3fieldtype, (u_int)$2, (u_int)$1, 1); } + | relop NUM { CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $0.mtp3fieldtype, (u_int)$2, (u_int)$1, 0))); } + | irelop NUM { CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $0.mtp3fieldtype, (u_int)$2, (u_int)$1, 1))); } | paren mtp3listvalue ')' { $$.b = $2.b; $$.q = qerr; } ; mtp3fieldvalue: NUM { @@ -774,7 +790,7 @@ mtp3fieldvalue: NUM { $$.mtp3fieldtype == MH_OPC || $$.mtp3fieldtype == MH_DPC || $$.mtp3fieldtype == MH_SLS) - $$.b = gen_mtp3field_code(cstate, $$.mtp3fieldtype, (u_int) $1, BPF_JEQ, 0); + CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $$.mtp3fieldtype, (u_int) $1, BPF_JEQ, 0))); } ; mtp3listvalue: mtp3fieldvalue diff --git a/missing/asprintf.c b/missing/asprintf.c new file mode 100644 index 000000000000..3aa55ed9d65d --- /dev/null +++ b/missing/asprintf.c @@ -0,0 +1,101 @@ +#include +#include +#include + +#include "portability.h" + +/* + * vasprintf() and asprintf() for platforms with a C99-compliant + * snprintf() - so that, if you format into a 1-byte buffer, it + * will return how many characters it would have produced had + * it been given an infinite-sized buffer. + */ +int +pcap_vasprintf(char **strp, const char *format, va_list args) +{ + char buf; + int len; + size_t str_size; + char *str; + int ret; + + /* + * XXX - the C99 standard says, in section 7.19.6.5 "Thes + * nprintf function": + * + * The snprintf function is equivalent to fprintf, except that + * the output is written into an array (specified by argument s) + * rather than to a stream. If n is zero, nothing is written, + * and s may be a null pointer. Otherwise, output characters + * beyond the n-1st are discarded rather than being written + * to the array, and a null character is written at the end + * of the characters actually written into the array. + * + * ... + * + * The snprintf function returns the number of characters that + * would have been written had n been sufficiently large, not + * counting the terminating null character, or a negative value + * if an encoding error occurred. Thus, the null-terminated + * output has been completely written if and only if the returned + * value is nonnegative and less than n. + * + * That doesn't make it entirely clear whether, if a null buffer + * pointer and a zero count are passed, it will return the number + * of characters that would have been written had a buffer been + * passed. + * + * And, even if C99 *does*, in fact, say it has to work, it + * doesn't work in Solaris 8, for example - it returns -1 for + * NULL/0, but returns the correct character count for a 1-byte + * buffer. + * + * So we pass a one-character pointer in order to find out how + * many characters this format and those arguments will need + * without actually generating any more of those characters + * than we need. + * + * (The fact that it might happen to work with GNU libc or with + * various BSD libcs is completely uninteresting, as those tend + * to have asprintf() already and thus don't even *need* this + * code; this is for use in those UN*Xes that *don't* have + * asprintf().) + */ + len = vsnprintf(&buf, sizeof buf, format, args); + if (len == -1) { + *strp = NULL; + return (-1); + } + str_size = len + 1; + str = malloc(str_size); + if (str == NULL) { + *strp = NULL; + return (-1); + } + ret = vsnprintf(str, str_size, format, args); + if (ret == -1) { + free(str); + *strp = NULL; + return (-1); + } + *strp = str; + /* + * vsnprintf() shouldn't truncate the string, as we have + * allocated a buffer large enough to hold the string, so its + * return value should be the number of characters written. + */ + return (ret); +} + +int +pcap_asprintf(char **strp, const char *format, ...) +{ + va_list args; + int ret; + + va_start(args, format); + ret = pcap_vasprintf(strp, format, args); + va_end(args); + return (ret); +} + diff --git a/missing/snprintf.c b/missing/snprintf.c index 99f0bdfc2a93..672aeb86a6d6 100644 --- a/missing/snprintf.c +++ b/missing/snprintf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995-1999 Kungliga Tekniska Högskolan + * Copyright (c) 1995-1999 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -31,6 +31,10 @@ * SUCH DAMAGE. */ +/* + * We use this for platforms that don't have snprintf() at all. + */ + #ifdef HAVE_CONFIG_H #include #endif @@ -42,7 +46,7 @@ #include #include -#include +#include "portability.h" enum format_flags { minus_flag = 1, @@ -525,6 +529,7 @@ pcap_asnprintf (char **ret, size_t max_sz, const char *format, ...) va_start(args, format); val = pcap_vasnprintf (ret, max_sz, format, args); + va_end(args); #ifdef PARANOIA { @@ -534,14 +539,15 @@ pcap_asnprintf (char **ret, size_t max_sz, const char *format, ...) if (tmp == NULL) abort (); + va_start(args, format); ret2 = pcap_vsprintf (tmp, format, args); + va_end(args); if (val != ret2 || strcmp(*ret, tmp)) abort (); free (tmp); } #endif - va_end(args); return val; } #endif diff --git a/missing/strlcat.c b/missing/strlcat.c new file mode 100644 index 000000000000..bb78a3d08259 --- /dev/null +++ b/missing/strlcat.c @@ -0,0 +1,61 @@ +/* $OpenBSD: pcap_strlcat.c,v 1.15 2015/03/02 21:41:08 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "portability.h" + +/* + * Appends src to string dst of size dsize (unlike strncat, dsize is the + * full size of dst, not space left). At most dsize-1 characters + * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). + * Returns strlen(src) + MIN(dsize, strlen(initial dst)). + * If retval >= dsize, truncation occurred. + */ +size_t +pcap_strlcat(char * restrict dst, const char * restrict src, size_t dsize) +{ + const char *odst = dst; + const char *osrc = src; + size_t n = dsize; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end. */ + while (n-- != 0 && *dst != '\0') + dst++; + dlen = dst - odst; + n = dsize - dlen; + + if (n-- == 0) + return(dlen + strlen(src)); + while (*src != '\0') { + if (n != 0) { + *dst++ = *src; + n--; + } + src++; + } + *dst = '\0'; + + return(dlen + (src - osrc)); /* count does not include NUL */ +} diff --git a/missing/strlcpy.c b/missing/strlcpy.c new file mode 100644 index 000000000000..c552e0d59685 --- /dev/null +++ b/missing/strlcpy.c @@ -0,0 +1,56 @@ +/* $OpenBSD: pcap_strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "portability.h" + +/* + * Copy string src to buffer dst of size dsize. At most dsize-1 + * chars will be copied. Always NUL terminates (unless dsize == 0). + * Returns strlen(src); if retval >= dsize, truncation occurred. + */ +size_t +pcap_strlcpy(char * restrict dst, const char * restrict src, size_t dsize) +{ + const char *osrc = src; + size_t nleft = dsize; + + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) + *dst = '\0'; /* NUL-terminate dst */ + while (*src++) + ; + } + + return(src - osrc - 1); /* count does not include NUL */ +} diff --git a/missing/win_asprintf.c b/missing/win_asprintf.c new file mode 100644 index 000000000000..cce6296065fc --- /dev/null +++ b/missing/win_asprintf.c @@ -0,0 +1,51 @@ +#include +#include +#include + +#include "portability.h" + +int +pcap_vasprintf(char **strp, const char *format, va_list args) +{ + int len; + size_t str_size; + char *str; + int ret; + + len = _vscprintf(format, args); + if (len == -1) { + *strp = NULL; + return (-1); + } + str_size = len + 1; + str = malloc(str_size); + if (str == NULL) { + *strp = NULL; + return (-1); + } + ret = pcap_vsnprintf(str, str_size, format, args); + if (ret == -1) { + free(str); + *strp = NULL; + return (-1); + } + *strp = str; + /* + * pcap_vsnprintf() shouldn't truncate the string, as we have + * allocated a buffer large enough to hold the string, so its + * return value should be the number of characters printed. + */ + return (ret); +} + +int +pcap_asprintf(char **strp, const char *format, ...) +{ + va_list args; + int ret; + + va_start(args, format); + ret = pcap_vasprintf(strp, format, args); + va_end(args); + return (ret); +} diff --git a/missing/win_snprintf.c b/missing/win_snprintf.c index 65a8ea1a5cd9..f42240352920 100644 --- a/missing/win_snprintf.c +++ b/missing/win_snprintf.c @@ -1,6 +1,8 @@ #include #include +#include "portability.h" + int pcap_vsnprintf(char *str, size_t str_size, const char *format, va_list args) { @@ -13,6 +15,16 @@ pcap_vsnprintf(char *str, size_t str_size, const char *format, va_list args) * that str is null-terminated, but C99's vsnprintf() * and snprintf() do, and we want to offer C99 behavior, * so forcibly null-terminate the string. + * + * We don't, however, offer C99 behavior for the return + * value; _vsnprintf_s() returns -1, not the number of + * characters that would have been put into the buffer + * had it been large enough, if the string is truncated. + * The only way to get that value is to use _vscprintf(); + * getting that count isn't worth the re-formatting. + * + * XXX - does _vsnprintf_s() return -1 on a formatting + * error? */ str[str_size - 1] = '\0'; return (ret); diff --git a/msdos/readme.dos b/msdos/readme.dos index 990a2e8a63d1..b95483fc9b4a 100644 --- a/msdos/readme.dos +++ b/msdos/readme.dos @@ -127,7 +127,7 @@ Follow these steps in building libpcap: But linking the library with `tcpdump' is the ultimate test. DOS/djgpp should now hopefully be a supported target. Get the sources at: - http://www.tcpdump.org/ + https://www.tcpdump.org/ or https://github.com/the-tcpdump-group/tcpdump/ diff --git a/nametoaddr.c b/nametoaddr.c index 087d14be750d..7c48bd3a3513 100644 --- a/nametoaddr.c +++ b/nametoaddr.c @@ -231,7 +231,22 @@ pcap_nametonetaddr(const char *name) int h_errnoval; int err; - err = getnetbyname_r(name, &result_buf, buf, sizeof buf, &np, + /* + * Apparently, the man page at + * + * http://man7.org/linux/man-pages/man3/getnetbyname_r.3.html + * + * lies when it says + * + * If the function call successfully obtains a network record, + * then *result is set pointing to result_buf; otherwise, *result + * is set to NULL. + * + * and, in fact, at least in some versions of GNU libc, it does + * *not* always get set if getnetbyname_r() succeeds. + */ + np = NULL; + err = getnetbyname_r(name, &result_buf, buf, sizeof buf, &np, &h_errnoval); if (err != 0) { /* @@ -306,7 +321,8 @@ pcap_nametoport(const char *name, int *port, int *proto) hints.ai_protocol = IPPROTO_TCP; error = getaddrinfo(NULL, name, &hints, &res); if (error != 0) { - if (error != EAI_NONAME) { + if (error != EAI_NONAME && + error != EAI_SERVICE) { /* * This is a real error, not just "there's * no such service name". @@ -349,7 +365,8 @@ pcap_nametoport(const char *name, int *port, int *proto) hints.ai_protocol = IPPROTO_UDP; error = getaddrinfo(NULL, name, &hints, &res); if (error != 0) { - if (error != EAI_NONAME) { + if (error != EAI_NONAME && + error != EAI_SERVICE) { /* * This is a real error, not just "there's * no such service name". diff --git a/optimize.c b/optimize.c index 86dcbeef5fe8..448452d2831b 100644 --- a/optimize.c +++ b/optimize.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -226,6 +227,16 @@ struct vmapinfo { }; typedef struct { + /* + * Place to longjmp to on an error. + */ + jmp_buf top_ctx; + + /* + * The buffer into which to put error message. + */ + char *errbuf; + /* * A flag to indicate that further optimization is needed. * Iterative passes are continued until a given pass yields no @@ -252,19 +263,19 @@ typedef struct { * True if a is in uset {p} */ #define SET_MEMBER(p, a) \ -((p)[(unsigned)(a) / BITS_PER_WORD] & (1 << ((unsigned)(a) % BITS_PER_WORD))) +((p)[(unsigned)(a) / BITS_PER_WORD] & ((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD))) /* * Add 'a' to uset p. */ #define SET_INSERT(p, a) \ -(p)[(unsigned)(a) / BITS_PER_WORD] |= (1 << ((unsigned)(a) % BITS_PER_WORD)) +(p)[(unsigned)(a) / BITS_PER_WORD] |= ((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD)) /* * Delete 'a' from uset p. */ #define SET_DELETE(p, a) \ -(p)[(unsigned)(a) / BITS_PER_WORD] &= ~(1 << ((unsigned)(a) % BITS_PER_WORD)) +(p)[(unsigned)(a) / BITS_PER_WORD] &= ~((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD)) /* * a := a intersect b @@ -311,6 +322,16 @@ typedef struct { } opt_state_t; typedef struct { + /* + * Place to longjmp to on an error. + */ + jmp_buf top_ctx; + + /* + * The buffer into which to put error message. + */ + char *errbuf; + /* * Some pointers used to convert the basic block form of the code, * into the array form that BPF requires. 'fstart' will point to @@ -321,14 +342,16 @@ typedef struct { struct bpf_insn *ftail; } conv_state_t; -static void opt_init(compiler_state_t *, opt_state_t *, struct icode *); +static void opt_init(opt_state_t *, struct icode *); static void opt_cleanup(opt_state_t *); +static void PCAP_NORETURN opt_error(opt_state_t *, const char *, ...) + PCAP_PRINTFLIKE(2, 3); static void intern_blocks(opt_state_t *, struct icode *); static void find_inedges(opt_state_t *, struct block *); #ifdef BDEBUG -static void opt_dump(compiler_state_t *, struct icode *); +static void opt_dump(opt_state_t *, struct icode *); #endif #ifndef MAX @@ -661,7 +684,7 @@ F(opt_state_t *opt_state, int code, int v0, int v1) int val; struct valnode *p; - hash = (u_int)code ^ (v0 << 4) ^ (v1 << 8); + hash = (u_int)code ^ ((u_int)v0 << 4) ^ ((u_int)v1 << 8); hash %= MODULUS; for (p = opt_state->hashtbl[hash]; p; p = p->next) @@ -699,8 +722,7 @@ vstore(struct stmt *s, int *valp, int newval, int alter) * (Unary operators are handled elsewhere.) */ static void -fold_op(compiler_state_t *cstate, opt_state_t *opt_state, - struct stmt *s, int v0, int v1) +fold_op(opt_state_t *opt_state, struct stmt *s, int v0, int v1) { bpf_u_int32 a, b; @@ -722,13 +744,13 @@ fold_op(compiler_state_t *cstate, opt_state_t *opt_state, case BPF_DIV: if (b == 0) - bpf_error(cstate, "division by zero"); + opt_error(opt_state, "division by zero"); a /= b; break; case BPF_MOD: if (b == 0) - bpf_error(cstate, "modulus by zero"); + opt_error(opt_state, "modulus by zero"); a %= b; break; @@ -745,11 +767,39 @@ fold_op(compiler_state_t *cstate, opt_state_t *opt_state, break; case BPF_LSH: - a <<= b; + /* + * A left shift of more than the width of the type + * is undefined in C; we'll just treat it as shifting + * all the bits out. + * + * XXX - the BPF interpreter doesn't check for this, + * so its behavior is dependent on the behavior of + * the processor on which it's running. There are + * processors on which it shifts all the bits out + * and processors on which it does no shift. + */ + if (b < 32) + a <<= b; + else + a = 0; break; case BPF_RSH: - a >>= b; + /* + * A right shift of more than the width of the type + * is undefined in C; we'll just treat it as shifting + * all the bits out. + * + * XXX - the BPF interpreter doesn't check for this, + * so its behavior is dependent on the behavior of + * the processor on which it's running. There are + * processors on which it shifts all the bits out + * and processors on which it does no shift. + */ + if (b < 32) + a >>= b; + else + a = 0; break; default: @@ -1041,8 +1091,7 @@ opt_peep(opt_state_t *opt_state, struct block *b) * evaluation and code transformations weren't folded together. */ static void -opt_stmt(compiler_state_t *cstate, opt_state_t *opt_state, - struct stmt *s, int val[], int alter) +opt_stmt(opt_state_t *opt_state, struct stmt *s, int val[], int alter) { int op; int v; @@ -1094,7 +1143,23 @@ opt_stmt(compiler_state_t *cstate, opt_state_t *opt_state, case BPF_ALU|BPF_NEG: if (alter && opt_state->vmap[val[A_ATOM]].is_const) { s->code = BPF_LD|BPF_IMM; - s->k = -opt_state->vmap[val[A_ATOM]].const_val; + /* + * Do this negation as unsigned arithmetic; that's + * what modern BPF engines do, and it guarantees + * that all possible values can be negated. (Yeah, + * negating 0x80000000, the minimum signed 32-bit + * two's-complement value, results in 0x80000000, + * so it's still negative, but we *should* be doing + * all unsigned arithmetic here, to match what + * modern BPF engines do.) + * + * Express it as 0U - (unsigned value) so that we + * don't get compiler warnings about negating an + * unsigned value and don't get UBSan warnings + * about the result of negating 0x80000000 being + * undefined. + */ + s->k = 0U - (bpf_u_int32)(opt_state->vmap[val[A_ATOM]].const_val); val[A_ATOM] = K(s->k); } else @@ -1114,9 +1179,17 @@ opt_stmt(compiler_state_t *cstate, opt_state_t *opt_state, op = BPF_OP(s->code); if (alter) { if (s->k == 0) { - /* don't optimize away "sub #0" + /* + * Optimize operations where the constant + * is zero. + * + * Don't optimize away "sub #0" * as it may be needed later to - * fixup the generated math code */ + * fixup the generated math code. + * + * Fail if we're dividing by zero or taking + * a modulus by zero. + */ if (op == BPF_ADD || op == BPF_LSH || op == BPF_RSH || op == BPF_OR || op == BPF_XOR) { @@ -1128,9 +1201,15 @@ opt_stmt(compiler_state_t *cstate, opt_state_t *opt_state, val[A_ATOM] = K(s->k); break; } + if (op == BPF_DIV) + opt_error(opt_state, + "division by zero"); + if (op == BPF_MOD) + opt_error(opt_state, + "modulus by zero"); } if (opt_state->vmap[val[A_ATOM]].is_const) { - fold_op(cstate, opt_state, s, val[A_ATOM], K(s->k)); + fold_op(opt_state, s, val[A_ATOM], K(s->k)); val[A_ATOM] = K(s->k); break; } @@ -1151,12 +1230,22 @@ opt_stmt(compiler_state_t *cstate, opt_state_t *opt_state, op = BPF_OP(s->code); if (alter && opt_state->vmap[val[X_ATOM]].is_const) { if (opt_state->vmap[val[A_ATOM]].is_const) { - fold_op(cstate, opt_state, s, val[A_ATOM], val[X_ATOM]); + fold_op(opt_state, s, val[A_ATOM], val[X_ATOM]); val[A_ATOM] = K(s->k); } else { s->code = BPF_ALU|BPF_K|op; s->k = opt_state->vmap[val[X_ATOM]].const_val; + /* + * XXX - we need to make up our minds + * as to what integers are signed and + * what integers are unsigned in BPF + * programs and in our IR. + */ + if ((op == BPF_LSH || op == BPF_RSH) && + (s->k < 0 || s->k > 31)) + opt_error(opt_state, + "shift by more than 31 bits"); opt_state->done = 0; val[A_ATOM] = F(opt_state, s->code, val[A_ATOM], K(s->k)); @@ -1275,8 +1364,7 @@ opt_deadstores(opt_state_t *opt_state, register struct block *b) } static void -opt_blk(compiler_state_t *cstate, opt_state_t *opt_state, - struct block *b, int do_stmts) +opt_blk(opt_state_t *opt_state, struct block *b, int do_stmts) { struct slist *s; struct edge *p; @@ -1326,7 +1414,7 @@ opt_blk(compiler_state_t *cstate, opt_state_t *opt_state, aval = b->val[A_ATOM]; xval = b->val[X_ATOM]; for (s = b->stmts; s; s = s->next) - opt_stmt(cstate, opt_state, &s->s, b->val, do_stmts); + opt_stmt(opt_state, &s->s, b->val, do_stmts); /* * This is a special case: if we don't use anything from this @@ -1480,7 +1568,7 @@ opt_j(opt_state_t *opt_state, struct edge *ep) while (x != 0) { k = lowest_set_bit(x); - x &=~ (1 << k); + x &=~ ((bpf_u_int32)1 << k); k += i * BITS_PER_WORD; target = fold_edge(ep->succ, opt_state->edges[k]); @@ -1687,8 +1775,7 @@ and_pullup(opt_state_t *opt_state, struct block *b) } static void -opt_blks(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic, - int do_stmts) +opt_blks(opt_state_t *opt_state, struct icode *ic, int do_stmts) { int i, maxlevel; struct block *p; @@ -1699,7 +1786,7 @@ opt_blks(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic, find_inedges(opt_state, ic->root); for (i = maxlevel; i >= 0; --i) for (p = opt_state->levels[i]; p; p = p->link) - opt_blk(cstate, opt_state, p, do_stmts); + opt_blk(opt_state, p, do_stmts); if (do_stmts) /* @@ -1777,14 +1864,13 @@ opt_root(struct block **b) } static void -opt_loop(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic, - int do_stmts) +opt_loop(opt_state_t *opt_state, struct icode *ic, int do_stmts) { #ifdef BDEBUG if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) { printf("opt_loop(root, %d) begin\n", do_stmts); - opt_dump(cstate, ic); + opt_dump(opt_state, ic); } #endif do { @@ -1794,11 +1880,11 @@ opt_loop(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic, find_closure(opt_state, ic->root); find_ud(opt_state, ic->root); find_edom(opt_state, ic->root); - opt_blks(cstate, opt_state, ic, do_stmts); + opt_blks(opt_state, ic, do_stmts); #ifdef BDEBUG if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) { printf("opt_loop(root, %d) bottom, done=%d\n", do_stmts, opt_state->done); - opt_dump(cstate, ic); + opt_dump(opt_state, ic); } #endif } while (!opt_state->done); @@ -1806,30 +1892,38 @@ opt_loop(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic, /* * Optimize the filter code in its dag representation. + * Return 0 on success, -1 on error. */ -void -bpf_optimize(compiler_state_t *cstate, struct icode *ic) +int +bpf_optimize(struct icode *ic, char *errbuf) { opt_state_t opt_state; - opt_init(cstate, &opt_state, ic); - opt_loop(cstate, &opt_state, ic, 0); - opt_loop(cstate, &opt_state, ic, 1); + memset(&opt_state, 0, sizeof(opt_state)); + opt_state.errbuf = errbuf; + if (setjmp(opt_state.top_ctx)) { + opt_cleanup(&opt_state); + return -1; + } + opt_init(&opt_state, ic); + opt_loop(&opt_state, ic, 0); + opt_loop(&opt_state, ic, 1); intern_blocks(&opt_state, ic); #ifdef BDEBUG if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) { printf("after intern_blocks()\n"); - opt_dump(cstate, ic); + opt_dump(&opt_state, ic); } #endif opt_root(&ic->root); #ifdef BDEBUG if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) { printf("after opt_root()\n"); - opt_dump(cstate, ic); + opt_dump(&opt_state, ic); } #endif opt_cleanup(&opt_state); + return 0; } static void @@ -1943,6 +2037,24 @@ opt_cleanup(opt_state_t *opt_state) free((void *)opt_state->blocks); } +/* + * For optimizer errors. + */ +static void PCAP_NORETURN +opt_error(opt_state_t *opt_state, const char *fmt, ...) +{ + va_list ap; + + if (opt_state->errbuf != NULL) { + va_start(ap, fmt); + (void)pcap_vsnprintf(opt_state->errbuf, + PCAP_ERRBUF_SIZE, fmt, ap); + va_end(ap); + } + longjmp(opt_state->top_ctx, 1); + /* NOTREACHED */ +} + /* * Return the number of stmts in 's'. */ @@ -2027,7 +2139,7 @@ count_stmts(struct icode *ic, struct block *p) * from the total number of blocks and/or statements. */ static void -opt_init(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic) +opt_init(opt_state_t *opt_state, struct icode *ic) { bpf_u_int32 *p; int i, n, max_stmts; @@ -2040,22 +2152,24 @@ opt_init(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic) n = count_blocks(ic, ic->root); opt_state->blocks = (struct block **)calloc(n, sizeof(*opt_state->blocks)); if (opt_state->blocks == NULL) - bpf_error(cstate, "malloc"); + opt_error(opt_state, "malloc"); unMarkAll(ic); opt_state->n_blocks = 0; number_blks_r(opt_state, ic, ic->root); opt_state->n_edges = 2 * opt_state->n_blocks; opt_state->edges = (struct edge **)calloc(opt_state->n_edges, sizeof(*opt_state->edges)); - if (opt_state->edges == NULL) - bpf_error(cstate, "malloc"); + if (opt_state->edges == NULL) { + opt_error(opt_state, "malloc"); + } /* * The number of levels is bounded by the number of nodes. */ opt_state->levels = (struct block **)calloc(opt_state->n_blocks, sizeof(*opt_state->levels)); - if (opt_state->levels == NULL) - bpf_error(cstate, "malloc"); + if (opt_state->levels == NULL) { + opt_error(opt_state, "malloc"); + } opt_state->edgewords = opt_state->n_edges / (8 * sizeof(bpf_u_int32)) + 1; opt_state->nodewords = opt_state->n_blocks / (8 * sizeof(bpf_u_int32)) + 1; @@ -2063,8 +2177,9 @@ opt_init(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic) /* XXX */ opt_state->space = (bpf_u_int32 *)malloc(2 * opt_state->n_blocks * opt_state->nodewords * sizeof(*opt_state->space) + opt_state->n_edges * opt_state->edgewords * sizeof(*opt_state->space)); - if (opt_state->space == NULL) - bpf_error(cstate, "malloc"); + if (opt_state->space == NULL) { + opt_error(opt_state, "malloc"); + } p = opt_state->space; opt_state->all_dom_sets = p; for (i = 0; i < n; ++i) { @@ -2101,9 +2216,13 @@ opt_init(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic) */ opt_state->maxval = 3 * max_stmts; opt_state->vmap = (struct vmapinfo *)calloc(opt_state->maxval, sizeof(*opt_state->vmap)); + if (opt_state->vmap == NULL) { + opt_error(opt_state, "malloc"); + } opt_state->vnode_base = (struct valnode *)calloc(opt_state->maxval, sizeof(*opt_state->vnode_base)); - if (opt_state->vmap == NULL || opt_state->vnode_base == NULL) - bpf_error(cstate, "malloc"); + if (opt_state->vnode_base == NULL) { + opt_error(opt_state, "malloc"); + } } /* @@ -2115,6 +2234,9 @@ opt_init(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic) int bids[NBIDS]; #endif +static void PCAP_NORETURN conv_error(conv_state_t *, const char *, ...) + PCAP_PRINTFLIKE(2, 3); + /* * Returns true if successful. Returns false if a branch has * an offset that is too large. If so, we have marked that @@ -2122,8 +2244,7 @@ int bids[NBIDS]; * properly. */ static int -convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state, - struct icode *ic, struct block *p) +convert_code_r(conv_state_t *conv_state, struct icode *ic, struct block *p) { struct bpf_insn *dst; struct slist *src; @@ -2136,9 +2257,9 @@ convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state, return (1); Mark(ic, p); - if (convert_code_r(cstate, conv_state, ic, JF(p)) == 0) + if (convert_code_r(conv_state, ic, JF(p)) == 0) return (0); - if (convert_code_r(cstate, conv_state, ic, JT(p)) == 0) + if (convert_code_r(conv_state, ic, JT(p)) == 0) return (0); slen = slength(p->stmts); @@ -2151,7 +2272,7 @@ convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state, if (slen) { offset = (struct slist **)calloc(slen, sizeof(struct slist *)); if (!offset) { - bpf_error(cstate, "not enough core"); + conv_error(conv_state, "not enough core"); /*NOTREACHED*/ } } @@ -2175,7 +2296,8 @@ convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state, if (BPF_CLASS(src->s.code) != BPF_JMP || src->s.code == (BPF_JMP|BPF_JA)) { #if 0 if (src->s.jt || src->s.jf) { - bpf_error(cstate, "illegal jmp destination"); + free(offset); + conv_error(conv_state, "illegal jmp destination"); /*NOTREACHED*/ } #endif @@ -2195,7 +2317,8 @@ convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state, #endif if (!src->s.jt || !src->s.jf) { - bpf_error(cstate, ljerr, "no jmp destination", off); + free(offset); + conv_error(conv_state, ljerr, "no jmp destination", off); /*NOTREACHED*/ } @@ -2203,12 +2326,14 @@ convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state, for (i = 0; i < slen; i++) { if (offset[i] == src->s.jt) { if (jt) { - bpf_error(cstate, ljerr, "multiple matches", off); + free(offset); + conv_error(conv_state, ljerr, "multiple matches", off); /*NOTREACHED*/ } if (i - off - 1 >= 256) { - bpf_error(cstate, ljerr, "out-of-range jump", off); + free(offset); + conv_error(conv_state, ljerr, "out-of-range jump", off); /*NOTREACHED*/ } dst->jt = (u_char)(i - off - 1); @@ -2216,11 +2341,13 @@ convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state, } if (offset[i] == src->s.jf) { if (jf) { - bpf_error(cstate, ljerr, "multiple matches", off); + free(offset); + conv_error(conv_state, ljerr, "multiple matches", off); /*NOTREACHED*/ } if (i - off - 1 >= 256) { - bpf_error(cstate, ljerr, "out-of-range jump", off); + free(offset); + conv_error(conv_state, ljerr, "out-of-range jump", off); /*NOTREACHED*/ } dst->jf = (u_char)(i - off - 1); @@ -2228,7 +2355,8 @@ convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state, } } if (!jt || !jf) { - bpf_error(cstate, ljerr, "no destination found", off); + free(offset); + conv_error(conv_state, ljerr, "no destination found", off); /*NOTREACHED*/ } } @@ -2257,7 +2385,7 @@ convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state, } /* branch if T to following jump */ if (extrajmps >= 256) { - bpf_error(cstate, "too many extra jumps"); + conv_error(conv_state, "too many extra jumps"); /*NOTREACHED*/ } dst->jt = (u_char)extrajmps; @@ -2278,7 +2406,7 @@ convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state, /* branch if F to following jump */ /* if two jumps are inserted, F goes to second one */ if (extrajmps >= 256) { - bpf_error(cstate, "too many extra jumps"); + conv_error(conv_state, "too many extra jumps"); /*NOTREACHED*/ } dst->jf = (u_char)extrajmps; @@ -2312,13 +2440,20 @@ convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state, * done with the filter program. See the pcap man page. */ struct bpf_insn * -icode_to_fcode(compiler_state_t *cstate, struct icode *ic, - struct block *root, u_int *lenp) +icode_to_fcode(struct icode *ic, struct block *root, u_int *lenp, + char *errbuf) { u_int n; struct bpf_insn *fp; conv_state_t conv_state; + conv_state.fstart = NULL; + conv_state.errbuf = errbuf; + if (setjmp(conv_state.top_ctx) != 0) { + free(conv_state.fstart); + return NULL; + } + /* * Loop doing convert_code_r() until no branches remain * with too-large offsets. @@ -2328,14 +2463,18 @@ icode_to_fcode(compiler_state_t *cstate, struct icode *ic, n = *lenp = count_stmts(ic, root); fp = (struct bpf_insn *)malloc(sizeof(*fp) * n); - if (fp == NULL) - bpf_error(cstate, "malloc"); + if (fp == NULL) { + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc"); + free(fp); + return NULL; + } memset((char *)fp, 0, sizeof(*fp) * n); conv_state.fstart = fp; conv_state.ftail = fp + n; unMarkAll(ic); - if (convert_code_r(cstate, &conv_state, ic, root)) + if (convert_code_r(&conv_state, ic, root)) break; free(fp); } @@ -2343,6 +2482,22 @@ icode_to_fcode(compiler_state_t *cstate, struct icode *ic, return fp; } +/* + * For iconv_to_fconv() errors. + */ +static void PCAP_NORETURN +conv_error(conv_state_t *conv_state, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + (void)pcap_vsnprintf(conv_state->errbuf, + PCAP_ERRBUF_SIZE, fmt, ap); + va_end(ap); + longjmp(conv_state->top_ctx, 1); + /* NOTREACHED */ +} + /* * Make a copy of a BPF program and put it in the "fcode" member of * a "pcap_t". @@ -2452,14 +2607,16 @@ dot_dump_edge(struct icode *ic, struct block *block, FILE *out) * After install graphviz on http://www.graphviz.org/, save it as bpf.dot * and run `dot -Tpng -O bpf.dot' to draw the graph. */ -static void -dot_dump(compiler_state_t *cstate, struct icode *ic) +static int +dot_dump(struct icode *ic, char *errbuf) { struct bpf_program f; FILE *out = stdout; memset(bids, 0, sizeof bids); - f.bf_insns = icode_to_fcode(cstate, ic, ic->root, &f.bf_len); + f.bf_insns = icode_to_fcode(ic, ic->root, &f.bf_len, errbuf); + if (f.bf_insns == NULL) + return -1; fprintf(out, "digraph BPF {\n"); unMarkAll(ic); @@ -2469,30 +2626,39 @@ dot_dump(compiler_state_t *cstate, struct icode *ic) fprintf(out, "}\n"); free((char *)f.bf_insns); + return 0; } -static void -plain_dump(compiler_state_t *cstate, struct icode *ic) +static int +plain_dump(struct icode *ic, char *errbuf) { struct bpf_program f; memset(bids, 0, sizeof bids); - f.bf_insns = icode_to_fcode(cstate, ic, ic->root, &f.bf_len); + f.bf_insns = icode_to_fcode(ic, ic->root, &f.bf_len, errbuf); + if (f.bf_insns == NULL) + return -1; bpf_dump(&f, 1); putchar('\n'); free((char *)f.bf_insns); + return 0; } static void -opt_dump(compiler_state_t *cstate, struct icode *ic) +opt_dump(opt_state_t *opt_state, struct icode *ic) { + int status; + char errbuf[PCAP_ERRBUF_SIZE]; + /* * If the CFG, in DOT format, is requested, output it rather than * the code that would be generated from that graph. */ if (pcap_print_dot_graph) - dot_dump(cstate, ic); + status = dot_dump(ic, errbuf); else - plain_dump(cstate, ic); + status = plain_dump(ic, errbuf); + if (status == -1) + opt_error(opt_state, "opt_dump: icode_to_fcode failed: %s", errbuf); } #endif diff --git a/pcap-bpf.c b/pcap-bpf.c index 6ce383b0f605..4f1a0afbe69e 100644 --- a/pcap-bpf.c +++ b/pcap-bpf.c @@ -206,7 +206,7 @@ static int monitor_mode(pcap_t *, int); # endif # if defined(__APPLE__) -static void remove_en(pcap_t *); +static void remove_non_802_11(pcap_t *); static void remove_802_11(pcap_t *); # endif @@ -737,10 +737,10 @@ get_dlt_list(int fd, int v, struct bpf_dltlist *bdlp, char *ebuf) } #endif +#if defined(__APPLE__) static int pcap_can_set_rfmon_bpf(pcap_t *p) { -#if defined(__APPLE__) struct utsname osinfo; struct ifreq ifr; int fd; @@ -799,8 +799,8 @@ pcap_can_set_rfmon_bpf(pcap_t *p) errno, "socket"); return (PCAP_ERROR); } - strlcpy(ifr.ifr_name, "wlt", sizeof(ifr.ifr_name)); - strlcat(ifr.ifr_name, p->opt.device + 2, sizeof(ifr.ifr_name)); + pcap_strlcpy(ifr.ifr_name, "wlt", sizeof(ifr.ifr_name)); + pcap_strlcat(ifr.ifr_name, p->opt.device + 2, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { /* * No such device? @@ -880,7 +880,11 @@ pcap_can_set_rfmon_bpf(pcap_t *p) close(fd); #endif /* BIOCGDLTLIST */ return (0); +} #elif defined(HAVE_BSD_IEEE80211) +static int +pcap_can_set_rfmon_bpf(pcap_t *p) +{ int ret; ret = monitor_mode(p, 0); @@ -889,10 +893,14 @@ pcap_can_set_rfmon_bpf(pcap_t *p) if (ret == 0) return (1); /* success */ return (ret); -#else - return (0); -#endif } +#else +static int +pcap_can_set_rfmon_bpf(pcap_t *p _U_) +{ + return (0); +} +#endif static int pcap_stats_bpf(pcap_t *p, struct pcap_stat *ps) @@ -1012,18 +1020,21 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) case EWOULDBLOCK: return (0); - case ENXIO: + case ENXIO: /* FreeBSD, DragonFly BSD, and Darwin */ + case EIO: /* OpenBSD */ + /* NetBSD appears not to return an error in this case */ /* * The device on which we're capturing * went away. * * XXX - we should really return - * PCAP_ERROR_IFACE_NOT_UP, but - * pcap_dispatch() etc. aren't - * defined to retur that. + * an appropriate error for that, + * but pcap_dispatch() etc. aren't + * documented as having error returns + * other than PCAP_ERROR or PCAP_ERROR_BREAK. */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "The interface went down"); + "The interface disappeared"); return (PCAP_ERROR); #if defined(sun) && !defined(BSD) && !defined(__svr4__) && !defined(__SVR4) @@ -1358,8 +1369,8 @@ bpf_load(char *errbuf) /* Check if the driver is loaded */ memset(&cfg_ld, 0x0, sizeof(cfg_ld)); + pcap_snprintf(buf, sizeof(buf), "%s/%s", DRIVER_PATH, BPF_NAME); cfg_ld.path = buf; - pcap_snprintf(cfg_ld.path, sizeof(cfg_ld.path), "%s/%s", DRIVER_PATH, BPF_NAME); if ((sysconfig(SYS_QUERYLOAD, (void *)&cfg_ld, sizeof(cfg_ld)) == -1) || (cfg_ld.kmid == 0)) { /* Driver isn't loaded, load it now */ @@ -1469,7 +1480,7 @@ pcap_cleanup_bpf(pcap_t *p) s = socket(AF_LOCAL, SOCK_DGRAM, 0); if (s >= 0) { - strlcpy(ifr.ifr_name, pb->device, + pcap_strlcpy(ifr.ifr_name, pb->device, sizeof(ifr.ifr_name)); ioctl(s, SIOCIFDESTROY, &ifr); close(s); @@ -1532,9 +1543,9 @@ check_setif_failure(pcap_t *p, int error) */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd != -1) { - strlcpy(ifr.ifr_name, "en", + pcap_strlcpy(ifr.ifr_name, "en", sizeof(ifr.ifr_name)); - strlcat(ifr.ifr_name, p->opt.device + 3, + pcap_strlcat(ifr.ifr_name, p->opt.device + 3, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { /* @@ -1721,7 +1732,7 @@ pcap_activate_bpf(pcap_t *p) goto bad; } znamelen = zonesep - p->opt.device; - (void) strlcpy(path_zname, p->opt.device, znamelen + 1); + (void) pcap_strlcpy(path_zname, p->opt.device, znamelen + 1); ifr.lifr_zoneid = getzoneidbyname(path_zname); if (ifr.lifr_zoneid == -1) { pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, @@ -1786,7 +1797,7 @@ pcap_activate_bpf(pcap_t *p) */ sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd != -1) { - strlcpy(ifrname, + pcap_strlcpy(ifrname, p->opt.device, ifnamsiz); if (ioctl(sockfd, SIOCGIFFLAGS, (char *)&ifr) < 0) { @@ -1888,7 +1899,7 @@ pcap_activate_bpf(pcap_t *p) /* * Create the interface. */ - strlcpy(ifr.ifr_name, p->opt.device, sizeof(ifr.ifr_name)); + pcap_strlcpy(ifr.ifr_name, p->opt.device, sizeof(ifr.ifr_name)); if (ioctl(s, SIOCIFCREATE2, &ifr) < 0) { if (errno == EINVAL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, @@ -2187,7 +2198,7 @@ pcap_activate_bpf(pcap_t *p) * of link-layer types, as selecting * it will keep monitor mode off. */ - remove_en(p); + remove_non_802_11(p); /* * If the new mode we want isn't @@ -2748,12 +2759,21 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf) strncpy(req.ifm_name, name, sizeof(req.ifm_name)); if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) { if (errno == EOPNOTSUPP || errno == EINVAL || errno == ENOTTY || - errno == ENODEV) { + errno == ENODEV || errno == EPERM) { /* * Not supported, so we can't provide any * additional information. Assume that * this means that "connected" vs. * "disconnected" doesn't apply. + * + * The ioctl routine for Apple's pktap devices, + * annoyingly, checks for "are you root?" before + * checking whether the ioctl is valid, so it + * returns EPERM, rather than ENOTSUP, for the + * invalid SIOCGIFMEDIA, unless you're root. + * So, just as we do for some ethtool ioctls + * on Linux, which makes the same mistake, we + * also treat EPERM as meaning "not supported". */ *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; close(sock); @@ -2890,7 +2910,7 @@ monitor_mode(pcap_t *p, int set) default: pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, - errno, "SIOCGIFMEDIA 1"); + errno, "SIOCGIFMEDIA"); close(sock); return (PCAP_ERROR); } @@ -3032,8 +3052,12 @@ find_802_11(struct bpf_dltlist *bdlp) new_dlt = bdlp->bfl_list[i]; break; +#ifdef DLT_PRISM_HEADER case DLT_PRISM_HEADER: +#endif +#ifdef DLT_AIRONET_HEADER case DLT_AIRONET_HEADER: +#endif case DLT_IEEE802_11_RADIO_AVS: /* * 802.11 with radio, but not radiotap. @@ -3068,24 +3092,25 @@ find_802_11(struct bpf_dltlist *bdlp) #if defined(__APPLE__) && defined(BIOCGDLTLIST) /* - * Remove DLT_EN10MB from the list of DLT_ values, as we're in monitor mode, - * and DLT_EN10MB isn't supported in monitor mode. + * Remove non-802.11 header types from the list of DLT_ values, as we're in + * monitor mode, and those header types aren't supported in monitor mode. */ static void -remove_en(pcap_t *p) +remove_non_802_11(pcap_t *p) { int i, j; /* - * Scan the list of DLT_ values and discard DLT_EN10MB. + * Scan the list of DLT_ values and discard non-802.11 ones. */ j = 0; for (i = 0; i < p->dlt_count; i++) { switch (p->dlt_list[i]) { case DLT_EN10MB: + case DLT_RAW: /* - * Don't offer this one. + * Not 802.11. Don't offer this one. */ continue; @@ -3127,10 +3152,17 @@ remove_802_11(pcap_t *p) switch (p->dlt_list[i]) { case DLT_IEEE802_11: +#ifdef DLT_PRISM_HEADER case DLT_PRISM_HEADER: +#endif +#ifdef DLT_AIRONET_HEADER case DLT_AIRONET_HEADER: +#endif case DLT_IEEE802_11_RADIO: case DLT_IEEE802_11_RADIO_AVS: +#ifdef DLT_PPI + case DLT_PPI: +#endif /* * 802.11. Don't offer this one. */ @@ -3222,10 +3254,10 @@ pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp) * Set direction flag: Which packets do we accept on a forwarding * single device? IN, OUT or both? */ +#if defined(BIOCSDIRECTION) static int pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d) { -#if defined(BIOCSDIRECTION) u_int direction; direction = (d == PCAP_D_IN) ? BPF_D_IN : @@ -3238,7 +3270,11 @@ pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d) return (-1); } return (0); +} #elif defined(BIOCSSEESENT) +static int +pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d) +{ u_int seesent; /* @@ -3258,25 +3294,35 @@ pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d) return (-1); } return (0); +} #else +static int +pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d _U_) +{ (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf), "This system doesn't support BIOCSSEESENT, so the direction can't be set"); return (-1); -#endif } +#endif +#ifdef BIOCSDLT static int pcap_set_datalink_bpf(pcap_t *p, int dlt) { -#ifdef BIOCSDLT if (ioctl(p->fd, BIOCSDLT, &dlt) == -1) { pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), errno, "Cannot set DLT %d", dlt); return (-1); } -#endif return (0); } +#else +static int +pcap_set_datalink_bpf(pcap_t *p _U_, int dlt _U_) +{ + return (0); +} +#endif /* * Platform-specific information. diff --git a/pcap-bt-linux.c b/pcap-bt-linux.c index 07ed1c73de5a..9c8712e9531a 100644 --- a/pcap-bt-linux.c +++ b/pcap-bt-linux.c @@ -74,13 +74,14 @@ bt_findalldevs(pcap_if_list_t *devlistp, char *err_str) { struct hci_dev_list_req *dev_list; struct hci_dev_req *dev_req; - int i, sock; + int sock; + unsigned i; int ret = 0; sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); if (sock < 0) { - /* if bluetooth is not supported this this is not fatal*/ + /* if bluetooth is not supported this is not fatal*/ if (errno == EAFNOSUPPORT) return 0; pcap_fmt_errmsg_for_errno(err_str, PCAP_ERRBUF_SIZE, @@ -109,10 +110,10 @@ bt_findalldevs(pcap_if_list_t *devlistp, char *err_str) dev_req = dev_list->dev_req; for (i = 0; i < dev_list->dev_num; i++, dev_req++) { - char dev_name[20], dev_descr[30]; + char dev_name[20], dev_descr[40]; - pcap_snprintf(dev_name, 20, BT_IFACE"%d", dev_req->dev_id); - pcap_snprintf(dev_descr, 30, "Bluetooth adapter number %d", i); + pcap_snprintf(dev_name, sizeof(dev_name), BT_IFACE"%u", dev_req->dev_id); + pcap_snprintf(dev_descr, sizeof(dev_descr), "Bluetooth adapter number %u", i); /* * Bluetooth is a wireless technology. @@ -379,8 +380,8 @@ bt_read_linux(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char static int bt_inject_linux(pcap_t *handle, const void *buf _U_, size_t size _U_) { - pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on " - "bluetooth devices"); + pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Packet injection is not supported on Bluetooth devices"); return (-1); } diff --git a/pcap-bt-monitor-linux.c b/pcap-bt-monitor-linux.c index c222c100edb2..a693949d4618 100644 --- a/pcap-bt-monitor-linux.c +++ b/pcap-bt-monitor-linux.c @@ -149,7 +149,8 @@ bt_monitor_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_ch static int bt_monitor_inject(pcap_t *handle, const void *buf _U_, size_t size _U_) { - pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported yet"); + pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Packet injection is not supported yet on Bluetooth monitor devices"); return -1; } diff --git a/pcap-common.c b/pcap-common.c index 7f2b81a3a337..2a745f0bf969 100644 --- a/pcap-common.c +++ b/pcap-common.c @@ -514,11 +514,20 @@ #define LINKTYPE_RAIF1 198 /* - * IPMB packet for IPMI, beginning with the I2C slave address, followed - * by the netFn and LUN, etc.. Requested by Chanthy Toeung - * . + * IPMB packet for IPMI, beginning with a 2-byte header, followed by + * the I2C slave address, followed by the netFn and LUN, etc.. + * Requested by Chanthy Toeung . + * + * XXX - its DLT_ value used to be called DLT_IPMB, back when we got the + * impression from the email thread requesting it that the packet + * had no extra 2-byte header. We've renamed it; if anybody used + * DLT_IPMB and assumed no 2-byte header, this will cause the compile + * to fail, at which point we'll have to figure out what to do about + * the two header types using the same DLT_/LINKTYPE_ value. If that + * doesn't happen, we'll assume nobody used it and that the redefinition + * is safe. */ -#define LINKTYPE_IPMB 199 +#define LINKTYPE_IPMB_KONTRON 199 /* * Juniper-private data link type, as per request from @@ -549,15 +558,35 @@ */ #define LINKTYPE_LAPD 203 + /* - * Variants of various link-layer headers, with a one-byte direction - * pseudo-header prepended - zero means "received by this host", - * non-zero (any non-zero value) means "sent by this host" - as per - * Will Barker . + * PPP, with a one-byte direction pseudo-header prepended - zero means + * "received by this host", non-zero (any non-zero value) means "sent by + * this host" - as per Will Barker . + */ +#define LINKTYPE_PPP_WITH_DIR 204 /* Don't confuse with LINKTYPE_PPP_PPPD */ + +/* + * Cisco HDLC, with a one-byte direction pseudo-header prepended - zero + * means "received by this host", non-zero (any non-zero value) means + * "sent by this host" - as per Will Barker . */ -#define LINKTYPE_PPP_WITH_DIR 204 /* PPP */ #define LINKTYPE_C_HDLC_WITH_DIR 205 /* Cisco HDLC */ + +/* + * Frame Relay, with a one-byte direction pseudo-header prepended - zero + * means "received by this host" (DCE -> DTE), non-zero (any non-zero + * value) means "sent by this host" (DTE -> DCE) - as per Will Barker + * . + */ #define LINKTYPE_FRELAY_WITH_DIR 206 /* Frame Relay */ + +/* + * LAPB, with a one-byte direction pseudo-header prepended - zero means + * "received by this host" (DCE -> DTE), non-zero (any non-zero value) + * means "sent by this host" (DTE -> DCE)- as per Will Barker + * . + */ #define LINKTYPE_LAPB_WITH_DIR 207 /* LAPB */ /* @@ -1081,7 +1110,21 @@ */ #define LINKTYPE_DISPLAYPORT_AUX 275 -#define LINKTYPE_MATCHING_MAX 275 /* highest value in the "matching" range */ +/* + * Linux cooked sockets v2. + */ +#define LINKTYPE_LINUX_SLL2 276 + +#define LINKTYPE_MATCHING_MAX 276 /* highest value in the "matching" range */ + +/* + * The DLT_ and LINKTYPE_ values in the "matching" range should be the + * same, so DLT_MATCHING_MAX and LINKTYPE_MATCHING_MAX should be the + * same. + */ +#if LINKTYPE_MATCHING_MAX != DLT_MATCHING_MAX +#error The LINKTYPE_ matching range does not match the DLT_ matching range +#endif static struct linktype_map { int dlt; @@ -1231,18 +1274,30 @@ linktype_to_dlt(int linktype) /* * Return the maximum snapshot length for a given DLT_ value. * - * For most link-layer types, we use MAXIMUM_SNAPLEN, but for DLT_DBUS, - * the maximum is 134217728, as per + * For most link-layer types, we use MAXIMUM_SNAPLEN. + * + * For DLT_DBUS, the maximum is 128MiB, as per * * https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages + * + * For DLT_USBPCAP, the maximum is 1MiB, as per + * + * https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=15985 */ u_int max_snaplen_for_dlt(int dlt) { - if (dlt == DLT_DBUS) - return 134217728; - else + switch (dlt) { + + case DLT_DBUS: + return 128*1024*1024; + + case DLT_USBPCAP: + return 1024*1024; + + default: return MAXIMUM_SNAPLEN; + } } /* diff --git a/pcap-common.h b/pcap-common.h index 88c057cb4987..8795a8297a64 100644 --- a/pcap-common.h +++ b/pcap-common.h @@ -35,9 +35,13 @@ * machine (if the file was written in little-end order). */ #define SWAPLONG(y) \ -((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff)) + (((((u_int)(y))&0xff)<<24) | \ + ((((u_int)(y))&0xff00)<<8) | \ + ((((u_int)(y))&0xff0000)>>8) | \ + ((((u_int)(y))>>24)&0xff)) #define SWAPSHORT(y) \ - ( (((y)&0xff)<<8) | ((u_short)((y)&0xff00)>>8) ) + ((u_short)(((((u_int)(y))&0xff)<<8) | \ + ((((u_int)(y))&0xff00)>>8))) extern int dlt_to_linktype(int dlt); diff --git a/pcap-dag.c b/pcap-dag.c index 5d5b6c10318b..e076676c45bc 100644 --- a/pcap-dag.c +++ b/pcap-dag.c @@ -1,18 +1,10 @@ /* - * pcap-dag.c: Packet capture interface for Emulex EndaceDAG cards. - * - * The functionality of this code attempts to mimic that of pcap-linux as much - * as possible. This code is compiled in several different ways depending on - * whether DAG_ONLY and HAVE_DAG_API are defined. If HAVE_DAG_API is not - * defined it should not get compiled in, otherwise if DAG_ONLY is defined then - * the 'dag_' function calls are renamed to 'pcap_' equivalents. If DAG_ONLY - * is not defined then nothing is altered - the dag_ functions will be - * called as required from their pcap-linux/bpf equivalents. + * pcap-dag.c: Packet capture interface for Endace DAG cards. * * Authors: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com) * Modifications: Jesper Peterson * Koryn Grant - * Stephen Donnelly + * Stephen Donnelly */ #ifdef HAVE_CONFIG_H @@ -258,12 +250,18 @@ dag_platform_cleanup(pcap_t *p) if(pd->dag_ref != NULL) { dag_config_dispose(pd->dag_ref); + /* + * Note: we don't need to call close(p->fd) or + * dag_close(p->fd), as dag_config_dispose(pd->dag_ref) + * does this. + * + * Set p->fd to -1 to make sure that's not done. + */ p->fd = -1; pd->dag_ref = NULL; } delete_pcap_dag(p); pcap_cleanup_live_common(p); - /* Note: don't need to call close(p->fd) or dag_close(p->fd) as dag_config_dispose(pd->dag_ref) does this. */ } static void @@ -722,7 +720,7 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) static int dag_inject(pcap_t *p, const void *buf _U_, size_t size _U_) { - strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards", + pcap_strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards", PCAP_ERRBUF_SIZE); return (-1); } @@ -746,18 +744,20 @@ static int dag_activate(pcap_t* p) daginf_t* daginf; char * newDev = NULL; char * device = p->opt.device; + int ret; dag_size_t mindata; struct timeval maxwait; struct timeval poll; if (device == NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL"); - return -1; + return PCAP_ERROR; } /* Initialize some components of the pcap structure. */ newDev = (char *)malloc(strlen(device) + 16); if (newDev == NULL) { + ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't allocate string for device name"); goto fail; @@ -765,6 +765,13 @@ static int dag_activate(pcap_t* p) /* Parse input name to get dag device and stream number if provided */ if (dag_parse_name(device, newDev, strlen(device) + 16, &pd->dag_stream) < 0) { + /* + * XXX - it'd be nice if this indicated what was wrong + * with the name. Does this reliably set errno? + * Should this return PCAP_ERROR_NO_SUCH_DEVICE in some + * cases? + */ + ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "dag_parse_name"); goto fail; @@ -772,25 +779,40 @@ static int dag_activate(pcap_t* p) device = newDev; if (pd->dag_stream%2) { + ret = PCAP_ERROR; pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: tx (even numbered) streams not supported for capture"); goto fail; } /* setup device parameters */ if((pd->dag_ref = dag_config_init((char *)device)) == NULL) { + /* + * XXX - does this reliably set errno? + */ + if (errno == ENOENT) + ret = PCAP_ERROR_NO_SUCH_DEVICE; + else if (errno == EPERM || errno == EACCES) + ret = PCAP_ERROR_PERM_DENIED; + else + ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "dag_config_init %s", device); goto fail; } if((p->fd = dag_config_get_card_fd(pd->dag_ref)) < 0) { + /* + * XXX - does this reliably set errno? + */ + ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "dag_config_get_card_fd %s", device); - goto fail; + goto failclose; } /* Open requested stream. Can fail if already locked or on error */ if (dag_attach_stream64(p->fd, pd->dag_stream, 0, 0) < 0) { + ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "dag_attach_stream"); goto failclose; @@ -809,6 +831,7 @@ static int dag_activate(pcap_t* p) */ if (dag_get_stream_poll64(p->fd, pd->dag_stream, &mindata, &maxwait, &poll) < 0) { + ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "dag_get_stream_poll"); goto faildetach; @@ -853,6 +876,7 @@ static int dag_activate(pcap_t* p) if (dag_set_stream_poll64(p->fd, pd->dag_stream, mindata, &maxwait, &poll) < 0) { + ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "dag_set_stream_poll"); goto faildetach; @@ -875,6 +899,7 @@ static int dag_activate(pcap_t* p) #endif if(dag_start_stream(p->fd, pd->dag_stream) < 0) { + ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "dag_start_stream %s", device); goto faildetach; @@ -910,6 +935,7 @@ static int dag_activate(pcap_t* p) if ((n = atoi(s)) == 0 || n == 16 || n == 32) { pd->dag_fcs_bits = n; } else { + ret = PCAP_ERROR; pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "pcap_activate %s: bad ERF_FCS_BITS value (%d) in environment", device, n); goto failstop; @@ -932,12 +958,15 @@ static int dag_activate(pcap_t* p) pd->dag_timeout = p->opt.timeout; p->linktype = -1; - if (dag_get_datalink(p) < 0) + if (dag_get_datalink(p) < 0) { + ret = PCAP_ERROR; goto failstop; + } p->bufsize = 0; if (new_pcap_dag(p) < 0) { + ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "new_pcap_dag %s", device); goto failstop; @@ -977,6 +1006,14 @@ static int dag_activate(pcap_t* p) failclose: dag_config_dispose(pd->dag_ref); + /* + * Note: we don't need to call close(p->fd) or dag_close(p->fd), + * as dag_config_dispose(pd->dag_ref) does this. + * + * Set p->fd to -1 to make sure that's not done. + */ + p->fd = -1; + pd->dag_ref = NULL; delete_pcap_dag(p); fail: @@ -985,7 +1022,7 @@ static int dag_activate(pcap_t* p) free((char *)newDev); } - return PCAP_ERROR; + return ret; } pcap_t *dag_create(const char *device, char *ebuf, int *is_ours) @@ -1137,7 +1174,7 @@ dag_findalldevs(pcap_if_list_t *devlistp, char *errbuf) } rxstreams = dag_rx_get_stream_count(dagfd); for(stream=0;streamlinktype" and reject the send request if * it's anything other than DLT_EN10MB. */ - strlcpy(p->errbuf, "send: Not supported on this version of this OS", + pcap_strlcpy(p->errbuf, "send: Not supported on this version of this OS", PCAP_ERRBUF_SIZE); ret = -1; #endif /* raw mode */ @@ -363,9 +363,9 @@ open_dlpi_device(const char *name, u_int *ppa, char *errbuf) */ cp = strrchr(name, '/'); if (cp == NULL) - strlcpy(dname, name, sizeof(dname)); + pcap_strlcpy(dname, name, sizeof(dname)); else - strlcpy(dname, cp + 1, sizeof(dname)); + pcap_strlcpy(dname, cp + 1, sizeof(dname)); /* * Split the device name into a device type name and a unit number; @@ -415,7 +415,7 @@ open_dlpi_device(const char *name, u_int *ppa, char *errbuf) * device name. */ if (*name == '/') - strlcpy(dname, name, sizeof(dname)); + pcap_strlcpy(dname, name, sizeof(dname)); else pcap_snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX, name); @@ -432,7 +432,7 @@ open_dlpi_device(const char *name, u_int *ppa, char *errbuf) * Make a copy of the device pathname, and then remove the unit * number from the device pathname. */ - strlcpy(dname2, dname, sizeof(dname)); + pcap_strlcpy(dname2, dname, sizeof(dname)); *cp = '\0'; /* Try device without unit number */ @@ -968,7 +968,7 @@ dl_dohpuxbind(int fd, char *ebuf) *ebuf = '\0'; hpsap++; if (hpsap > 100) { - strlcpy(ebuf, + pcap_strlcpy(ebuf, "All SAPs from 22 through 100 are in use", PCAP_ERRBUF_SIZE); return (-1); @@ -1547,7 +1547,7 @@ get_release(char *buf, size_t bufsize, bpf_u_int32 *majorp, *minorp = 0; *microp = 0; if (sysinfo(SI_RELEASE, buf, bufsize) < 0) { - strlcpy(buf, "?", bufsize); + pcap_strlcpy(buf, "?", bufsize); return; } cp = buf; diff --git a/pcap-dos.c b/pcap-dos.c index b1b9ecd72b16..c159b552a95e 100644 --- a/pcap-dos.c +++ b/pcap-dos.c @@ -413,14 +413,14 @@ int pcap_stats_ex (pcap_t *p, struct pcap_stat_ex *se) if (!dev || !dev->get_stats) { - strlcpy (p->errbuf, "detailed device statistics not available", + pcap_strlcpy (p->errbuf, "detailed device statistics not available", PCAP_ERRBUF_SIZE); return (-1); } if (!strnicmp(dev->name,"pkt",3)) { - strlcpy (p->errbuf, "pktdrvr doesn't have detailed statistics", + pcap_strlcpy (p->errbuf, "pktdrvr doesn't have detailed statistics", PCAP_ERRBUF_SIZE); return (-1); } diff --git a/pcap-filter.manmisc.in b/pcap-filter.manmisc.in index 7e4438d778a8..777e7350cf51 100644 --- a/pcap-filter.manmisc.in +++ b/pcap-filter.manmisc.in @@ -18,7 +18,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP-FILTER @MAN_MISC_INFO@ "3 August 2015" +.TH PCAP-FILTER @MAN_MISC_INFO@ "5 November 2017" .SH NAME pcap-filter \- packet filter syntax .br @@ -29,11 +29,11 @@ pcap-filter \- packet filter syntax is used to compile a string into a filter program. The resulting filter program can then be applied to some stream of packets to determine which packets will be supplied to -.BR pcap_loop() , -.BR pcap_dispatch() , -.BR pcap_next() , +.BR pcap_loop(3PCAP) , +.BR pcap_dispatch(3PCAP) , +.BR pcap_next(3PCAP) , or -.BR pcap_next_ex() . +.BR pcap_next_ex(3PCAP) . .LP The \fIfilter expression\fP consists of one or more .IR primitives . @@ -86,12 +86,6 @@ The and .B addr4 qualifiers are only valid for IEEE 802.11 Wireless LAN link layers. -For some link layers, such as SLIP and the ``cooked'' Linux capture mode -used for the ``any'' device and for some other device types, the -.B inbound -and -.B outbound -qualifiers can be used to specify a desired direction. .IP \fIproto\fP .I proto qualifiers restrict the match to a particular protocol. @@ -466,8 +460,6 @@ Token Ring packets (no check is done for LLC frames); FDDI packets (no check is done for LLC frames); .IP LLC-encapsulated ATM packets, for SunATM on Solaris. -.IP - .IP "\fBllc\fP \Fitype\fR" True if the packet has an 802.2 LLC header and has the specified .IR type . @@ -514,6 +506,16 @@ Exchange Identification (XID) U PDUs \fBfrmr\fR Frame Reject (FRMR) U PDUs .RE +.IP \fBinbound\fP +Packet was received by the host performing the capture rather than being +sent by that host. This is only supported for certain link-layer types, +such as SLIP and the ``cooked'' Linux capture mode +used for the ``any'' device and for some other device types. +.IP \fBoutbound\fP +Packet was sent by the host performing the capture rather than being +received by that host. This is only supported for certain link-layer types, +such as SLIP and the ``cooked'' Linux capture mode +used for the ``any'' device and for some other device types. .IP "\fBifname \fIinterface\fR" True if the packet was logged as coming from the specified interface (applies only to packets logged by OpenBSD's or FreeBSD's @@ -567,7 +569,7 @@ are: and .B block and, with later versions of -.BR pf (4)), +.BR pf (4), .BR nat , .BR rdr , .B binat diff --git a/pcap-int.h b/pcap-int.h index 5888df7241b6..5295f8fb46cd 100644 --- a/pcap-int.h +++ b/pcap-int.h @@ -86,7 +86,12 @@ extern "C" { * 2) small enough not to cause attempts to allocate huge amounts of * memory; some applications might use the snapshot length in a * savefile header to control the size of the buffer they allocate, - * so a size of, say, 2^31-1 might not work well. + * so a size of, say, 2^31-1 might not work well. (libpcap uses it + * as a hint, but doesn't start out allocating a buffer bigger than + * 2 KiB, and grows the buffer as necessary, but not beyond the + * per-linktype maximum snapshot length. Other code might naively + * use it; we want to avoid writing a too-large snapshot length, + * in order not to cause that code problems.) * * We don't enforce this in pcap_set_snaplen(), but we use it internally. */ @@ -472,13 +477,38 @@ int add_addr_to_if(pcap_if_list_t *, const char *, bpf_u_int32, * "pcap_open_offline_common()" allocates and fills in a pcap_t, for use * by pcap_open_offline routines. * + * "pcap_adjust_snapshot()" adjusts the snapshot to be non-zero and + * fit within an int. + * * "sf_cleanup()" closes the file handle associated with a pcap_t, if * appropriate, and frees all data common to all modules for handling * savefile types. */ pcap_t *pcap_open_offline_common(char *ebuf, size_t size); +bpf_u_int32 pcap_adjust_snapshot(bpf_u_int32 linktype, bpf_u_int32 snaplen); void sf_cleanup(pcap_t *p); +/* + * Internal interfaces for doing user-mode filtering of packets and + * validating filter programs. + */ +/* + * Auxiliary data, for use when interpreting a filter intended for the + * Linux kernel when the kernel rejects the filter (requiring us to + * run it in userland). It contains VLAN tag information. + */ +struct bpf_aux_data { + u_short vlan_tag_present; + u_short vlan_tag; +}; + +/* + * Filtering routine that takes the auxiliary data as an additional + * argument. + */ +u_int bpf_filter_with_aux_data(const struct bpf_insn *, + const u_char *, u_int, u_int, const struct bpf_aux_data *); + /* * Internal interfaces for both "pcap_create()" and routines that * open savefiles. @@ -488,10 +518,6 @@ void sf_cleanup(pcap_t *p); */ void pcap_oneshot(u_char *, const struct pcap_pkthdr *, const u_char *); -#ifdef _WIN32 -void pcap_win32_err_to_str(DWORD, char *); -#endif - int install_bpf_program(pcap_t *, struct bpf_program *); int pcap_strcasecmp(const char *, const char *); diff --git a/pcap-libdlpi.c b/pcap-libdlpi.c index a0d16693f6c2..a38da8b6d0ee 100644 --- a/pcap-libdlpi.c +++ b/pcap-libdlpi.c @@ -80,7 +80,7 @@ list_interfaces(const char *linkname, void *arg) lwp->lw_err = ENOMEM; return (B_TRUE); } - (void) strlcpy(entry->linkname, linkname, DLPI_LINKNAME_MAX); + (void) pcap_strlcpy(entry->linkname, linkname, DLPI_LINKNAME_MAX); if (lwp->lw_list == NULL) { lwp->lw_list = entry; diff --git a/pcap-linktype.manmisc.in b/pcap-linktype.manmisc.in index 7634a96290f7..777e9dc73d7d 100644 --- a/pcap-linktype.manmisc.in +++ b/pcap-linktype.manmisc.in @@ -43,6 +43,6 @@ The names for those values begin with .BR LINKTYPE_ . .PP The link-layer header types supported by libpcap are described at -http://www.tcpdump.org/linktypes.html. +https://www.tcpdump.org/linktypes.html. .SH SEE ALSO -pcap_datalink(3PCAP) +pcap(3PCAP) diff --git a/pcap-linux.c b/pcap-linux.c index a35a379c4622..70334b3c860b 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -339,9 +339,6 @@ struct pcap_linux { static int get_if_flags(const char *, bpf_u_int32 *, char *); static int is_wifi(int, const char *); static void map_arphrd_to_dlt(pcap_t *, int, int, const char *, int); -#ifdef HAVE_PF_PACKET_SOCKETS -static short int map_packet_type_to_sll_type(short int); -#endif static int pcap_activate_linux(pcap_t *); static int activate_old(pcap_t *); static int activate_new(pcap_t *); @@ -486,7 +483,7 @@ static int iface_bind_old(int fd, const char *device, char *ebuf); #ifdef SO_ATTACH_FILTER static int fix_program(pcap_t *handle, struct sock_fprog *fcode, int is_mapped); -static int fix_offset(struct bpf_insn *p); +static int fix_offset(pcap_t *handle, struct bpf_insn *p); static int set_kernel_filter(pcap_t *handle, struct sock_fprog *fcode); static int reset_kernel_filter(pcap_t *handle); @@ -977,7 +974,7 @@ enter_rfmon_mode_mac80211(pcap_t *handle, int sock_fd, const char *device) * Now configure the monitor interface up. */ memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, handlep->mondevice, sizeof(ifr.ifr_name)); + pcap_strlcpy(ifr.ifr_name, handlep->mondevice, sizeof(ifr.ifr_name)); if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "%s: Can't get flags for %s", device, @@ -1038,7 +1035,7 @@ is_bonding_device(int fd, const char *device) ifbond ifb; memset(&ifr, 0, sizeof ifr); - strlcpy(ifr.ifr_name, device, sizeof ifr.ifr_name); + pcap_strlcpy(ifr.ifr_name, device, sizeof ifr.ifr_name); memset(&ifb, 0, sizeof ifb); ifr.ifr_data = (caddr_t)&ifb; if (ioctl(fd, BOND_INFO_QUERY_IOCTL, &ifr) == 0) @@ -1127,7 +1124,7 @@ pcap_can_set_rfmon_linux(pcap_t *handle) /* * Attempt to get the current mode. */ - strlcpy(ireq.ifr_ifrn.ifrn_name, handle->opt.device, + pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, handle->opt.device, sizeof ireq.ifr_ifrn.ifrn_name); if (ioctl(sock_fd, SIOCGIWMODE, &ireq) != -1) { /* @@ -1160,16 +1157,16 @@ static long int linux_if_drops(const char * if_name) { char buffer[512]; - char * bufptr; - FILE * file; - int field_to_convert = 3, if_name_sz = strlen(if_name); + FILE *file; + char *bufptr, *nameptr, *colonptr; + int field_to_convert = 3; long int dropped_pkts = 0; file = fopen("/proc/net/dev", "r"); if (!file) return 0; - while (!dropped_pkts && fgets( buffer, sizeof(buffer), file )) + while (fgets(buffer, sizeof(buffer), file) != NULL) { /* search for 'bytes' -- if its in there, then that means we need to grab the fourth field. otherwise @@ -1180,26 +1177,71 @@ linux_if_drops(const char * if_name) continue; } - /* find iface and make sure it actually matches -- space before the name and : after it */ - if ((bufptr = strstr(buffer, if_name)) && - (bufptr == buffer || *(bufptr-1) == ' ') && - *(bufptr + if_name_sz) == ':') + /* + * See whether this line corresponds to this device. + * The line should have zero or more leading blanks, + * followed by a device name, followed by a colon, + * followed by the statistics. + */ + bufptr = buffer; + /* Skip leading blanks */ + while (*bufptr == ' ') + bufptr++; + nameptr = bufptr; + /* Look for the colon */ + colonptr = strchr(nameptr, ':'); + if (colonptr == NULL) { - bufptr = bufptr + if_name_sz + 1; + /* + * Not found; this could, for example, be the + * header line. + */ + continue; + } + /* Null-terminate the interface name. */ + *colonptr = '\0'; + if (strcmp(if_name, nameptr) == 0) + { + /* + * OK, this line has the statistics for the interface. + * Skip past the interface name. + */ + bufptr = colonptr + 1; /* grab the nth field from it */ - while( --field_to_convert && *bufptr != '\0') + while (--field_to_convert && *bufptr != '\0') { - while (*bufptr != '\0' && *(bufptr++) == ' '); - while (*bufptr != '\0' && *(bufptr++) != ' '); + /* + * This isn't the field we want. + * First, skip any leading blanks before + * the field. + */ + while (*bufptr == ' ') + bufptr++; + + /* + * Now skip the non-blank characters of + * the field. + */ + while (*bufptr != '\0' && *bufptr != ' ') + bufptr++; } - /* get rid of any final spaces */ - while (*bufptr != '\0' && *bufptr == ' ') bufptr++; - - if (*bufptr != '\0') - dropped_pkts = strtol(bufptr, NULL, 10); + if (field_to_convert == 0) + { + /* + * We've found the field we want. + * Skip any leading blanks before it. + */ + while (*bufptr == ' ') + bufptr++; + /* + * Now extract the value, if we have one. + */ + if (*bufptr != '\0') + dropped_pkts = strtol(bufptr, NULL, 10); + } break; } } @@ -1250,7 +1292,7 @@ static void pcap_cleanup_linux( pcap_t *handle ) * in 2.0[.x] kernels. */ memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, handlep->device, + pcap_strlcpy(ifr.ifr_name, handlep->device, sizeof(ifr.ifr_name)); if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) { fprintf(stderr, @@ -1314,7 +1356,7 @@ static void pcap_cleanup_linux( pcap_t *handle ) */ oldflags = 0; memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, handlep->device, + pcap_strlcpy(ifr.ifr_name, handlep->device, sizeof(ifr.ifr_name)); if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) != -1) { if (ifr.ifr_flags & IFF_UP) { @@ -1328,7 +1370,7 @@ static void pcap_cleanup_linux( pcap_t *handle ) /* * Now restore the mode. */ - strlcpy(ireq.ifr_ifrn.ifrn_name, handlep->device, + pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, handlep->device, sizeof ireq.ifr_ifrn.ifrn_name); ireq.u.mode = handlep->oldmode; if (ioctl(handle->fd, SIOCSIWMODE, &ireq) == -1) { @@ -1538,7 +1580,8 @@ pcap_activate_linux(pcap_t *handle) if (handlep->device == NULL) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "strdup"); - return PCAP_ERROR; + status = PCAP_ERROR; + goto fail; } /* copy timeout value */ @@ -1602,11 +1645,10 @@ pcap_activate_linux(pcap_t *handle) /* * We failed to set up to use it, or the kernel * supports it, but we failed to enable it. - * ret has been set to the error status to + * status has been set to the error status to * return and, if it's PCAP_ERROR, handle->errbuf * contains the error message. */ - status = ret; goto fail; } } @@ -1750,7 +1792,6 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) int offset; #ifdef HAVE_PF_PACKET_SOCKETS struct sockaddr_ll from; - struct sll_header *hdrp; #else struct sockaddr from; #endif @@ -1774,9 +1815,12 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) * If this is a cooked device, leave extra room for a * fake packet header. */ - if (handlep->cooked) - offset = SLL_HDR_LEN; - else + if (handlep->cooked) { + if (handle->linktype == DLT_LINUX_SLL2) + offset = SLL2_HDR_LEN; + else + offset = SLL_HDR_LEN; + } else offset = 0; #else /* @@ -1906,17 +1950,37 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) * Add the length of the fake header to the length * of packet data we read. */ - packet_len += SLL_HDR_LEN; + if (handle->linktype == DLT_LINUX_SLL2) { + struct sll2_header *hdrp; - hdrp = (struct sll_header *)bp; - hdrp->sll_pkttype = map_packet_type_to_sll_type(from.sll_pkttype); - hdrp->sll_hatype = htons(from.sll_hatype); - hdrp->sll_halen = htons(from.sll_halen); - memcpy(hdrp->sll_addr, from.sll_addr, - (from.sll_halen > SLL_ADDRLEN) ? - SLL_ADDRLEN : - from.sll_halen); - hdrp->sll_protocol = from.sll_protocol; + packet_len += SLL2_HDR_LEN; + + hdrp = (struct sll2_header *)bp; + hdrp->sll2_protocol = from.sll_protocol; + hdrp->sll2_reserved_mbz = 0; + hdrp->sll2_if_index = htonl(from.sll_ifindex); + hdrp->sll2_hatype = htons(from.sll_hatype); + hdrp->sll2_pkttype = from.sll_pkttype; + hdrp->sll2_halen = from.sll_halen; + memcpy(hdrp->sll2_addr, from.sll_addr, + (from.sll_halen > SLL_ADDRLEN) ? + SLL_ADDRLEN : + from.sll_halen); + } else { + struct sll_header *hdrp; + + packet_len += SLL_HDR_LEN; + + hdrp = (struct sll_header *)bp; + hdrp->sll_pkttype = htons(from.sll_pkttype); + hdrp->sll_hatype = htons(from.sll_hatype); + hdrp->sll_halen = htons(from.sll_halen); + memcpy(hdrp->sll_addr, from.sll_addr, + (from.sll_halen > SLL_ADDRLEN) ? + SLL_ADDRLEN : + from.sll_halen); + hdrp->sll_protocol = from.sll_protocol; + } } /* @@ -2121,7 +2185,7 @@ pcap_inject_linux(pcap_t *handle, const void *buf, size_t size) /* * We don't support sending on the "any" device. */ - strlcpy(handle->errbuf, + pcap_strlcpy(handle->errbuf, "Sending packets isn't supported on the \"any\" device", PCAP_ERRBUF_SIZE); return (-1); @@ -2129,13 +2193,13 @@ pcap_inject_linux(pcap_t *handle, const void *buf, size_t size) if (handlep->cooked) { /* - * We don't support sending on the "any" device. + * We don't support sending on cooked-mode sockets. * * XXX - how do you send on a bound cooked-mode * socket? * Is a "sendto()" required there? */ - strlcpy(handle->errbuf, + pcap_strlcpy(handle->errbuf, "Sending packets isn't supported in cooked mode", PCAP_ERRBUF_SIZE); return (-1); @@ -2349,7 +2413,7 @@ add_linux_if(pcap_if_list_t *devlistp, const char *ifname, int fd, char *errbuf) /* * Get the flags for this interface. */ - strlcpy(ifrflags.ifr_name, name, sizeof(ifrflags.ifr_name)); + pcap_strlcpy(ifrflags.ifr_name, name, sizeof(ifrflags.ifr_name)); if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifrflags) < 0) { if (errno == ENXIO || errno == ENODEV) return (0); /* device doesn't actually exist - ignore it */ @@ -2708,7 +2772,7 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf) #ifdef ETHTOOL_GLINK memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + pcap_strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); info.cmd = ETHTOOL_GLINK; ifr.ifr_data = (caddr_t)&info; if (ioctl(sock, SIOCETHTOOL, &ifr) == -1) { @@ -2836,7 +2900,7 @@ pcap_setfilter_linux_common(pcap_t *handle, struct bpf_program *filter, if (!handle) return -1; if (!filter) { - strlcpy(handle->errbuf, "setfilter: No filter specified", + pcap_strlcpy(handle->errbuf, "setfilter: No filter specified", PCAP_ERRBUF_SIZE); return -1; } @@ -3025,41 +3089,6 @@ pcap_setdirection_linux(pcap_t *handle, pcap_direction_t d) return -1; } -#ifdef HAVE_PF_PACKET_SOCKETS -/* - * Map the PACKET_ value to a LINUX_SLL_ value; we - * want the same numerical value to be used in - * the link-layer header even if the numerical values - * for the PACKET_ #defines change, so that programs - * that look at the packet type field will always be - * able to handle DLT_LINUX_SLL captures. - */ -static short int -map_packet_type_to_sll_type(short int sll_pkttype) -{ - switch (sll_pkttype) { - - case PACKET_HOST: - return htons(LINUX_SLL_HOST); - - case PACKET_BROADCAST: - return htons(LINUX_SLL_BROADCAST); - - case PACKET_MULTICAST: - return htons(LINUX_SLL_MULTICAST); - - case PACKET_OTHERHOST: - return htons(LINUX_SLL_OTHERHOST); - - case PACKET_OUTGOING: - return htons(LINUX_SLL_OUTGOING); - - default: - return -1; - } -} -#endif - static int is_wifi(int sock_fd #ifndef IW_MODE_MONITOR @@ -3558,6 +3587,45 @@ static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype, /* ===== Functions to interface to the newer kernels ================== */ +#ifdef PACKET_RESERVE +static void +set_dlt_list_cooked(pcap_t *handle, int sock_fd) +{ + socklen_t len; + unsigned int tp_reserve; + + /* + * If we can't do PACKET_RESERVE, we can't reserve extra space + * for a DLL_LINUX_SLL2 header, so we can't support DLT_LINUX_SLL2. + */ + len = sizeof(tp_reserve); + if (getsockopt(sock_fd, SOL_PACKET, PACKET_RESERVE, &tp_reserve, + &len) == 0) { + /* + * Yes, we can do DLL_LINUX_SLL2. + */ + handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + /* + * If that fails, just leave the list empty. + */ + if (handle->dlt_list != NULL) { + handle->dlt_list[0] = DLT_LINUX_SLL; + handle->dlt_list[1] = DLT_LINUX_SLL2; + handle->dlt_count = 2; + } + } +} +#else +/* + * The build environment doesn't define PACKET_RESERVE, so we can't reserve + * extra space for a DLL_LINUX_SLL2 header, so we can't support DLT_LINUX_SLL2. + */ +static void +set_dlt_list_cooked(pcap_t *handle _U_, int sock_fd _U_) +{ +} +#endif + /* * Try to open a packet socket using the new kernel PF_PACKET interface. * Returns 1 on success, 0 on an error that means the new interface isn't @@ -3573,7 +3641,7 @@ activate_new(pcap_t *handle) const char *device = handle->opt.device; int is_any_device = (strcmp(device, "any") == 0); int protocol = pcap_protocol(handle); - int sock_fd = -1, arptype; + int sock_fd = -1, arptype, ret; #ifdef HAVE_PACKET_AUXDATA int val; #endif @@ -3602,21 +3670,21 @@ activate_new(pcap_t *handle) */ return 0; } - - pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, - errno, "socket"); if (errno == EPERM || errno == EACCES) { /* * You don't have permission to open the * socket. */ - return PCAP_ERROR_PERM_DENIED; + ret = PCAP_ERROR_PERM_DENIED; } else { /* * Other error. */ - return PCAP_ERROR; + ret = PCAP_ERROR; } + pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "socket"); + return ret; } /* It seems the kernel supports the new interface. */ @@ -3711,20 +3779,21 @@ activate_new(pcap_t *handle) } sock_fd = socket(PF_PACKET, SOCK_DGRAM, protocol); if (sock_fd == -1) { - pcap_fmt_errmsg_for_errno(handle->errbuf, - PCAP_ERRBUF_SIZE, errno, "socket"); if (errno == EPERM || errno == EACCES) { /* * You don't have permission to * open the socket. */ - return PCAP_ERROR_PERM_DENIED; + ret = PCAP_ERROR_PERM_DENIED; } else { /* * Other error. */ - return PCAP_ERROR; + ret = PCAP_ERROR; } + pcap_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, "socket"); + return ret; } handlep->cooked = 1; @@ -3737,6 +3806,7 @@ activate_new(pcap_t *handle) free(handle->dlt_list); handle->dlt_list = NULL; handle->dlt_count = 0; + set_dlt_list_cooked(handle, sock_fd); } if (handle->linktype == -1) { @@ -3797,6 +3867,9 @@ activate_new(pcap_t *handle) */ handlep->cooked = 1; handle->linktype = DLT_LINUX_SLL; + handle->dlt_list = NULL; + handle->dlt_count = 0; + set_dlt_list_cooked(handle, sock_fd); /* * We're not bound to a device. @@ -3837,7 +3910,7 @@ activate_new(pcap_t *handle) if (setsockopt(sock_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, - PCAP_ERRBUF_SIZE, errno, "setsockopt"); + PCAP_ERRBUF_SIZE, errno, "setsockopt (PACKET_ADD_MEMBERSHIP)"); close(sock_fd); return PCAP_ERROR; } @@ -3850,7 +3923,7 @@ activate_new(pcap_t *handle) if (setsockopt(sock_fd, SOL_PACKET, PACKET_AUXDATA, &val, sizeof(val)) == -1 && errno != ENOPROTOOPT) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, - errno, "setsockopt"); + errno, "setsockopt (PACKET_AUXDATA)"); close(sock_fd); return PCAP_ERROR; } @@ -3870,10 +3943,14 @@ activate_new(pcap_t *handle) * large enough to hold a "cooked mode" header plus * 1 byte of packet data (so we don't pass a byte * count of 0 to "recvfrom()"). + * XXX - we don't know whether this will be DLT_LINUX_SLL + * or DLT_LINUX_SLL2, so make sure it's big enough for + * a DLT_LINUX_SLL2 "cooked mode" header; a snapshot length + * that small is silly anyway. */ if (handlep->cooked) { - if (handle->snapshot < SLL_HDR_LEN + 1) - handle->snapshot = SLL_HDR_LEN + 1; + if (handle->snapshot < SLL2_HDR_LEN + 1) + handle->snapshot = SLL2_HDR_LEN + 1; } handle->bufsize = handle->snapshot; @@ -3940,7 +4017,7 @@ activate_new(pcap_t *handle) return 1; #else /* HAVE_PF_PACKET_SOCKETS */ - strlcpy(ebuf, + pcap_strlcpy(ebuf, "New packet capturing interface not supported by build " "environment", PCAP_ERRBUF_SIZE); return 0; @@ -4070,10 +4147,20 @@ init_tpacket(pcap_t *handle, int version, const char *version_str) /* * Probe whether kernel supports the specified TPACKET version; * this also gets the length of the header for that version. + * + * This socket option was introduced in 2.6.27, which was + * also the first release with TPACKET_V2 support. */ if (getsockopt(handle->fd, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) { - if (errno == ENOPROTOOPT || errno == EINVAL) + if (errno == ENOPROTOOPT || errno == EINVAL) { + /* + * ENOPROTOOPT means the kernel is too old to + * support PACKET_HDRLEN at all, which means + * it either doesn't support TPACKET at all + * or supports only TPACKET_V1. + */ return 1; /* no */ + } /* Failed to even find out; this is a fatal error. */ pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, @@ -4092,7 +4179,10 @@ init_tpacket(pcap_t *handle, int version, const char *version_str) } handlep->tp_version = version; - /* Reserve space for VLAN tag reconstruction */ + /* + * Reserve space for VLAN tag reconstruction. + * This option was also introduced in 2.6.27. + */ val = VLAN_TAG_LEN; if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE, &val, sizeof(val)) < 0) { @@ -4203,7 +4293,10 @@ prepare_tpacket_socket(pcap_t *handle) #endif /* HAVE_TPACKET2 */ /* - * OK, we're using TPACKET_V1, as that's all the kernel supports. + * OK, we're using TPACKET_V1, as either that's all the kernel + * supports or it doesn't support TPACKET at all. In the latter + * case, create_ring() will fail, and we'll fall back on non- + * memory-mapped capture. */ handlep->tp_version = TPACKET_V1; handlep->tp_hdrlen = sizeof(struct tpacket_hdr); @@ -4359,7 +4452,7 @@ create_ring(pcap_t *handle, int *status) if (getsockopt(handle->fd, SOL_SOCKET, SO_TYPE, &sk_type, &len) < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, - PCAP_ERRBUF_SIZE, errno, "getsockopt"); + PCAP_ERRBUF_SIZE, errno, "getsockopt (SO_TYPE)"); *status = PCAP_ERROR; return -1; } @@ -4374,14 +4467,50 @@ create_ring(pcap_t *handle, int *status) * as best we can. */ pcap_fmt_errmsg_for_errno(handle->errbuf, - PCAP_ERRBUF_SIZE, errno, "getsockopt"); + PCAP_ERRBUF_SIZE, errno, + "getsockopt (PACKET_RESERVE)"); + *status = PCAP_ERROR; + return -1; + } + /* + * Older kernel, so we can't use PACKET_RESERVE; + * this means we can't reserver extra space + * for a DLT_LINUX_SLL2 header. + */ + tp_reserve = 0; + } else { + /* + * We can reserve extra space for a DLT_LINUX_SLL2 + * header. Do so. + * + * XXX - we assume that the kernel is still adding + * 16 bytes of extra space; that happens to + * correspond to SLL_HDR_LEN (whether intentionally + * or not - the kernel code has a raw "16" in + * the expression), so we subtract SLL_HDR_LEN + * from SLL2_HDR_LEN to get the additional space + * needed. + * + * XXX - should we use TPACKET_ALIGN(SLL2_HDR_LEN - SLL_HDR_LEN)? + */ + tp_reserve += SLL2_HDR_LEN - SLL_HDR_LEN; + len = sizeof(tp_reserve); + if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE, + &tp_reserve, len) < 0) { + pcap_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "setsockopt (PACKET_RESERVE)"); *status = PCAP_ERROR; return -1; } - tp_reserve = 0; /* older kernel, reserve not supported */ } #else - tp_reserve = 0; /* older kernel, reserve not supported */ + /* + * Build environment for an older kernel, so we can't + * use PACKET_RESERVE; this means we can't reserve + * extra space for a DLT_LINUX_SLL2 header. + */ + tp_reserve = 0; #endif maclen = (sk_type == SOCK_DGRAM) ? 0 : MAX_LINKHEADER_SIZE; /* XXX: in the kernel maclen is calculated from @@ -4425,6 +4554,49 @@ create_ring(pcap_t *handle, int *status) #ifdef HAVE_TPACKET3 case TPACKET_V3: + /* + * If we have TPACKET_V3, we have PACKET_RESERVE. + */ + len = sizeof(tp_reserve); + if (getsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE, + &tp_reserve, &len) < 0) { + /* + * Even ENOPROTOOPT is an error - we wouldn't + * be here if the kernel didn't support + * TPACKET_V3, which means it supports + * PACKET_RESERVE. + */ + pcap_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "getsockopt (PACKET_RESERVE)"); + *status = PCAP_ERROR; + return -1; + } + /* + * We can reserve extra space for a DLT_LINUX_SLL2 + * header. Do so. + * + * XXX - we assume that the kernel is still adding + * 16 bytes of extra space; that happens to + * correspond to SLL_HDR_LEN (whether intentionally + * or not - the kernel code has a raw "16" in + * the expression), so we subtract SLL_HDR_LEN + * from SLL2_HDR_LEN to get the additional space + * needed. + * + * XXX - should we use TPACKET_ALIGN(SLL2_HDR_LEN - SLL_HDR_LEN)? + */ + tp_reserve += SLL2_HDR_LEN - SLL_HDR_LEN; + len = sizeof(tp_reserve); + if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE, + &tp_reserve, len) < 0) { + pcap_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "setsockopt (PACKET_RESERVE)"); + *status = PCAP_ERROR; + return -1; + } + /* The "frames" for this are actually buffers that * contain multiple variable-sized frames. * @@ -4496,7 +4668,7 @@ create_ring(pcap_t *handle, int *status) hwconfig.rx_filter = HWTSTAMP_FILTER_ALL; memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, handle->opt.device, sizeof(ifr.ifr_name)); + pcap_strlcpy(ifr.ifr_name, handle->opt.device, sizeof(ifr.ifr_name)); ifr.ifr_data = (void *)&hwconfig; if (ioctl(handle->fd, SIOCSHWTSTAMP, &ifr) < 0) { @@ -4580,7 +4752,26 @@ create_ring(pcap_t *handle, int *status) #ifdef HAVE_TPACKET3 /* timeout value to retire block - use the configured buffering timeout, or default if <0. */ - req.tp_retire_blk_tov = (handlep->timeout>=0)?handlep->timeout:0; + if (handlep->timeout > 0) { + /* Use the user specified timeout as the block timeout */ + req.tp_retire_blk_tov = handlep->timeout; + } else if (handlep->timeout == 0) { + /* + * In pcap, this means "infinite timeout"; TPACKET_V3 + * doesn't support that, so just set it to UINT_MAX + * milliseconds. In the TPACKET_V3 loop, if the + * timeout is 0, and we haven't yet seen any packets, + * and we block and still don't have any packets, we + * keep blocking until we do. + */ + req.tp_retire_blk_tov = UINT_MAX; + } else { + /* + * XXX - this is not valid; use 0, meaning "have the + * kernel pick a default", for now. + */ + req.tp_retire_blk_tov = 0; + } /* private data not used */ req.tp_sizeof_priv = 0; /* Rx ring - feature request bits - none (rxhash will not be filled) */ @@ -4908,13 +5099,27 @@ static int pcap_handle_packet_mmap( struct sockaddr_ll *sll; struct pcap_pkthdr pcaphdr; unsigned int snaplen = tp_snaplen; + struct utsname utsname; /* perform sanity check on internal offset. */ if (tp_mac + tp_snaplen > handle->bufsize) { - pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, - "corrupted frame on kernel ring mac " - "offset %u + caplen %u > frame len %d", - tp_mac, tp_snaplen, handle->bufsize); + /* + * Report some system information as a debugging aid. + */ + if (uname(&utsname) != -1) { + pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "corrupted frame on kernel ring mac " + "offset %u + caplen %u > frame len %d " + "(kernel %.32s version %s, machine %.16s)", + tp_mac, tp_snaplen, handle->bufsize, + utsname.release, utsname.version, + utsname.machine); + } else { + pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "corrupted frame on kernel ring mac " + "offset %u + caplen %u > frame len %d", + tp_mac, tp_snaplen, handle->bufsize); + } return -1; } @@ -4932,44 +5137,85 @@ static int pcap_handle_packet_mmap( /* if required build in place the sll header*/ sll = (void *)frame + TPACKET_ALIGN(handlep->tp_hdrlen); if (handlep->cooked) { - struct sll_header *hdrp; + if (handle->linktype == DLT_LINUX_SLL2) { + struct sll2_header *hdrp; - /* - * The kernel should have left us with enough - * space for an sll header; back up the packet - * data pointer into that space, as that'll be - * the beginning of the packet we pass to the - * callback. - */ - bp -= SLL_HDR_LEN; + /* + * The kernel should have left us with enough + * space for an sll header; back up the packet + * data pointer into that space, as that'll be + * the beginning of the packet we pass to the + * callback. + */ + bp -= SLL2_HDR_LEN; - /* - * Let's make sure that's past the end of - * the tpacket header, i.e. >= - * ((u_char *)thdr + TPACKET_HDRLEN), so we - * don't step on the header when we construct - * the sll header. - */ - if (bp < (u_char *)frame + - TPACKET_ALIGN(handlep->tp_hdrlen) + - sizeof(struct sockaddr_ll)) { - pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, - "cooked-mode frame doesn't have room for sll header"); - return -1; + /* + * Let's make sure that's past the end of + * the tpacket header, i.e. >= + * ((u_char *)thdr + TPACKET_HDRLEN), so we + * don't step on the header when we construct + * the sll header. + */ + if (bp < (u_char *)frame + + TPACKET_ALIGN(handlep->tp_hdrlen) + + sizeof(struct sockaddr_ll)) { + pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "cooked-mode frame doesn't have room for sll header"); + return -1; + } + + /* + * OK, that worked; construct the sll header. + */ + hdrp = (struct sll2_header *)bp; + hdrp->sll2_protocol = sll->sll_protocol; + hdrp->sll2_reserved_mbz = 0; + hdrp->sll2_if_index = htonl(sll->sll_ifindex); + hdrp->sll2_hatype = htons(sll->sll_hatype); + hdrp->sll2_pkttype = sll->sll_pkttype; + hdrp->sll2_halen = sll->sll_halen; + memcpy(hdrp->sll2_addr, sll->sll_addr, SLL_ADDRLEN); + + snaplen += sizeof(struct sll2_header); + } else { + struct sll_header *hdrp; + + /* + * The kernel should have left us with enough + * space for an sll header; back up the packet + * data pointer into that space, as that'll be + * the beginning of the packet we pass to the + * callback. + */ + bp -= SLL_HDR_LEN; + + /* + * Let's make sure that's past the end of + * the tpacket header, i.e. >= + * ((u_char *)thdr + TPACKET_HDRLEN), so we + * don't step on the header when we construct + * the sll header. + */ + if (bp < (u_char *)frame + + TPACKET_ALIGN(handlep->tp_hdrlen) + + sizeof(struct sockaddr_ll)) { + pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "cooked-mode frame doesn't have room for sll header"); + return -1; + } + + /* + * OK, that worked; construct the sll header. + */ + hdrp = (struct sll_header *)bp; + hdrp->sll_pkttype = htons(sll->sll_pkttype); + hdrp->sll_hatype = htons(sll->sll_hatype); + hdrp->sll_halen = htons(sll->sll_halen); + memcpy(hdrp->sll_addr, sll->sll_addr, SLL_ADDRLEN); + hdrp->sll_protocol = sll->sll_protocol; + + snaplen += sizeof(struct sll_header); } - - /* - * OK, that worked; construct the sll header. - */ - hdrp = (struct sll_header *)bp; - hdrp->sll_pkttype = map_packet_type_to_sll_type( - sll->sll_pkttype); - hdrp->sll_hatype = htons(sll->sll_hatype); - hdrp->sll_halen = htons(sll->sll_halen); - memcpy(hdrp->sll_addr, sll->sll_addr, SLL_ADDRLEN); - hdrp->sll_protocol = sll->sll_protocol; - - snaplen += sizeof(struct sll_header); } if (handlep->filter_in_userland && handle->fcode.bf_insns) { @@ -4998,8 +5244,13 @@ static int pcap_handle_packet_mmap( /* if required build in place the sll header*/ if (handlep->cooked) { /* update packet len */ - pcaphdr.caplen += SLL_HDR_LEN; - pcaphdr.len += SLL_HDR_LEN; + if (handle->linktype == DLT_LINUX_SLL2) { + pcaphdr.caplen += SLL2_HDR_LEN; + pcaphdr.len += SLL2_HDR_LEN; + } else { + pcaphdr.caplen += SLL_HDR_LEN; + pcaphdr.len += SLL_HDR_LEN; + } } #if defined(HAVE_TPACKET2) || defined(HAVE_TPACKET3) @@ -5521,7 +5772,7 @@ iface_get_id(int fd, const char *device, char *ebuf) struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, @@ -5570,7 +5821,7 @@ iface_bind(int fd, int ifindex, char *ebuf, int protocol) if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, - errno, "getsockopt"); + errno, "getsockopt (SO_ERROR)"); return 0; } @@ -5602,19 +5853,22 @@ static int has_wext(int sock_fd, const char *device, char *ebuf) { struct iwreq ireq; + int ret; if (is_bonding_device(sock_fd, device)) return 0; /* bonding device, so don't even try */ - strlcpy(ireq.ifr_ifrn.ifrn_name, device, + pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); if (ioctl(sock_fd, SIOCGIWNAME, &ireq) >= 0) return 1; /* yes */ + if (errno == ENODEV) + ret = PCAP_ERROR_NO_SUCH_DEVICE; + else + ret = 0; pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "%s: SIOCGIWNAME", device); - if (errno == ENODEV) - return PCAP_ERROR_NO_SUCH_DEVICE; - return 0; + return ret; } /* @@ -5743,7 +5997,7 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device) * return EOPNOTSUPP. */ memset(&ireq, 0, sizeof ireq); - strlcpy(ireq.ifr_ifrn.ifrn_name, device, + pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); ireq.u.data.pointer = (void *)args; ireq.u.data.length = 0; @@ -5943,7 +6197,7 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device) /* * Get the old mode. */ - strlcpy(ireq.ifr_ifrn.ifrn_name, device, + pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); if (ioctl(sock_fd, SIOCGIWMODE, &ireq) == -1) { /* @@ -5999,7 +6253,7 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device) * If it fails, just fall back on SIOCSIWMODE. */ memset(&ireq, 0, sizeof ireq); - strlcpy(ireq.ifr_ifrn.ifrn_name, device, + pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); ireq.u.data.length = 1; /* 1 argument */ args[0] = 3; /* request Prism header */ @@ -6031,7 +6285,7 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device) * might get EBUSY. */ memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "%s: Can't get flags", device); @@ -6052,7 +6306,7 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device) /* * Then turn monitor mode on. */ - strlcpy(ireq.ifr_ifrn.ifrn_name, device, + pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); ireq.u.mode = IW_MODE_MONITOR; if (ioctl(sock_fd, SIOCSIWMODE, &ireq) == -1) { @@ -6092,7 +6346,7 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device) * Try to select the radiotap header. */ memset(&ireq, 0, sizeof ireq); - strlcpy(ireq.ifr_ifrn.ifrn_name, device, + pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); args[0] = 3; /* request radiotap header */ memcpy(ireq.u.name, args, sizeof (int)); @@ -6103,7 +6357,7 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device) * That failed. Try to select the AVS header. */ memset(&ireq, 0, sizeof ireq); - strlcpy(ireq.ifr_ifrn.ifrn_name, device, + pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); args[0] = 2; /* request AVS header */ memcpy(ireq.u.name, args, sizeof (int)); @@ -6114,7 +6368,7 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device) * That failed. Try to select the Prism header. */ memset(&ireq, 0, sizeof ireq); - strlcpy(ireq.ifr_ifrn.ifrn_name, device, + pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); args[0] = 1; /* request Prism header */ memcpy(ireq.u.name, args, sizeof (int)); @@ -6132,7 +6386,7 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device) * Select the Prism header. */ memset(&ireq, 0, sizeof ireq); - strlcpy(ireq.ifr_ifrn.ifrn_name, device, + pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); args[0] = 3; /* request Prism header */ memcpy(ireq.u.name, args, sizeof (int)); @@ -6144,7 +6398,7 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device) * Get the current channel. */ memset(&ireq, 0, sizeof ireq); - strlcpy(ireq.ifr_ifrn.ifrn_name, device, + pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); if (ioctl(sock_fd, SIOCGIWFREQ, &ireq) == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, @@ -6158,7 +6412,7 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device) * current value. */ memset(&ireq, 0, sizeof ireq); - strlcpy(ireq.ifr_ifrn.ifrn_name, device, + pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); args[0] = 1; /* request Prism header */ args[1] = channel; /* set channel */ @@ -6172,7 +6426,7 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device) * Prism header. */ memset(&ireq, 0, sizeof ireq); - strlcpy(ireq.ifr_ifrn.ifrn_name, device, + pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); args[0] = 0; /* disallow transmitting */ memcpy(ireq.u.name, args, sizeof (int)); @@ -6184,7 +6438,7 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device) * Force the Prism header. */ memset(&ireq, 0, sizeof ireq); - strlcpy(ireq.ifr_ifrn.ifrn_name, device, + pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); args[0] = 1; /* request Prism header */ memcpy(ireq.u.name, args, sizeof (int)); @@ -6196,7 +6450,7 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device) * Force the Prism header. */ memset(&ireq, 0, sizeof ireq); - strlcpy(ireq.ifr_ifrn.ifrn_name, device, + pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); ireq.u.data.length = 1; /* 1 argument */ ireq.u.data.pointer = "1"; @@ -6209,7 +6463,7 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device) * Force the Prism header. */ memset(&ireq, 0, sizeof ireq); - strlcpy(ireq.ifr_ifrn.ifrn_name, device, + pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device, sizeof ireq.ifr_ifrn.ifrn_name); args[0] = 1; /* request Prism header */ memcpy(ireq.u.name, args, sizeof (int)); @@ -6357,7 +6611,7 @@ iface_ethtool_get_ts_info(const char *device, pcap_t *handle, char *ebuf) } memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); memset(&info, 0, sizeof(info)); info.cmd = ETHTOOL_GET_TS_INFO; ifr.ifr_data = (caddr_t)&info; @@ -6471,21 +6725,35 @@ iface_ethtool_get_ts_info(const char *device, pcap_t *handle, char *ebuf _U_) * if SIOCETHTOOL isn't defined, or we don't have any #defines for any * of the types of offloading, there's nothing we can do to check, so * we just say "no, we don't". + * + * We treat EOPNOTSUPP, EINVAL and, if eperm_ok is true, EPERM as + * indications that the operation isn't supported. We do EPERM + * weirdly because the SIOCETHTOOL code in later kernels 1) doesn't + * support ETHTOOL_GUFO, 2) also doesn't include it in the list + * of ethtool operations that don't require CAP_NET_ADMIN privileges, + * and 3) does the "is this permitted" check before doing the "is + * this even supported" check, so it fails with "this is not permitted" + * rather than "this is not even supported". To work around this + * annoyance, we only treat EPERM as an error for the first feature, + * and assume that they all do the same permission checks, so if the + * first one is allowed all the others are allowed if supported. */ #if defined(SIOCETHTOOL) && (defined(ETHTOOL_GTSO) || defined(ETHTOOL_GUFO) || defined(ETHTOOL_GGSO) || defined(ETHTOOL_GFLAGS) || defined(ETHTOOL_GGRO)) static int -iface_ethtool_flag_ioctl(pcap_t *handle, int cmd, const char *cmdname) +iface_ethtool_flag_ioctl(pcap_t *handle, int cmd, const char *cmdname, + int eperm_ok) { struct ifreq ifr; struct ethtool_value eval; memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, handle->opt.device, sizeof(ifr.ifr_name)); + pcap_strlcpy(ifr.ifr_name, handle->opt.device, sizeof(ifr.ifr_name)); eval.cmd = cmd; eval.data = 0; ifr.ifr_data = (caddr_t)&eval; if (ioctl(handle->fd, SIOCETHTOOL, &ifr) == -1) { - if (errno == EOPNOTSUPP || errno == EINVAL) { + if (errno == EOPNOTSUPP || errno == EINVAL || + (errno == EPERM && eperm_ok)) { /* * OK, let's just return 0, which, in our * case, either means "no, what we're asking @@ -6502,34 +6770,41 @@ iface_ethtool_flag_ioctl(pcap_t *handle, int cmd, const char *cmdname) return eval.data; } +/* + * XXX - it's annoying that we have to check for offloading at all, but, + * given that we have to, it's still annoying that we have to check for + * particular types of offloading, especially that shiny new types of + * offloading may be added - and, worse, may not be checkable with + * a particular ETHTOOL_ operation; ETHTOOL_GFEATURES would, in + * theory, give those to you, but the actual flags being used are + * opaque (defined in a non-uapi header), and there doesn't seem to + * be any obvious way to ask the kernel what all the offloading flags + * are - at best, you can ask for a set of strings(!) to get *names* + * for various flags. (That whole mechanism appears to have been + * designed for the sole purpose of letting ethtool report flags + * by name and set flags by name, with the names having no semantics + * ethtool understands.) + */ static int iface_get_offload(pcap_t *handle) { int ret; #ifdef ETHTOOL_GTSO - ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GTSO, "ETHTOOL_GTSO"); + ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GTSO, "ETHTOOL_GTSO", 0); if (ret == -1) return -1; if (ret) return 1; /* TCP segmentation offloading on */ #endif -#ifdef ETHTOOL_GUFO - ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GUFO, "ETHTOOL_GUFO"); - if (ret == -1) - return -1; - if (ret) - return 1; /* UDP fragmentation offloading on */ -#endif - #ifdef ETHTOOL_GGSO /* * XXX - will this cause large unsegmented packets to be * handed to PF_PACKET sockets on transmission? If not, * this need not be checked. */ - ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GGSO, "ETHTOOL_GGSO"); + ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GGSO, "ETHTOOL_GGSO", 0); if (ret == -1) return -1; if (ret) @@ -6537,7 +6812,7 @@ iface_get_offload(pcap_t *handle) #endif #ifdef ETHTOOL_GFLAGS - ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GFLAGS, "ETHTOOL_GFLAGS"); + ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GFLAGS, "ETHTOOL_GFLAGS", 0); if (ret == -1) return -1; if (ret & ETH_FLAG_LRO) @@ -6550,13 +6825,27 @@ iface_get_offload(pcap_t *handle) * handed to PF_PACKET sockets on receipt? If not, * this need not be checked. */ - ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GGRO, "ETHTOOL_GGRO"); + ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GGRO, "ETHTOOL_GGRO", 0); if (ret == -1) return -1; if (ret) return 1; /* generic (large) receive offloading on */ #endif +#ifdef ETHTOOL_GUFO + /* + * Do this one last, as support for it was removed in later + * kernels, and it fails with EPERM on those kernels rather + * than with EOPNOTSUPP (see explanation in comment for + * iface_ethtool_flag_ioctl()). + */ + ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GUFO, "ETHTOOL_GUFO", 1); + if (ret == -1) + return -1; + if (ret) + return 1; /* UDP fragmentation offloading on */ +#endif + return 0; } #else /* SIOCETHTOOL */ @@ -6592,8 +6881,17 @@ activate_old(pcap_t *handle) struct utsname utsname; int mtu; - /* Open the socket */ + /* + * PF_INET/SOCK_PACKET sockets must be bound to a device, so we + * can't support the "any" device. + */ + if (strcmp(device, "any") == 0) { + pcap_strlcpy(handle->errbuf, "pcap_activate: The \"any\" device isn't supported on 2.0[.x]-kernel systems", + PCAP_ERRBUF_SIZE); + return PCAP_ERROR; + } + /* Open the socket */ handle->fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL)); if (handle->fd == -1) { err = errno; @@ -6620,12 +6918,6 @@ activate_old(pcap_t *handle) handlep->cooked = 0; /* Bind to the given device */ - - if (strcmp(device, "any") == 0) { - strlcpy(handle->errbuf, "pcap_activate: The \"any\" device isn't supported on 2.0[.x]-kernel systems", - PCAP_ERRBUF_SIZE); - return PCAP_ERROR; - } if (iface_bind_old(handle->fd, device, handle->errbuf) == -1) return PCAP_ERROR; @@ -6651,7 +6943,7 @@ activate_old(pcap_t *handle) if (handle->opt.promisc) { memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "SIOCGIFFLAGS"); @@ -6757,6 +7049,17 @@ activate_old(pcap_t *handle) * * We can safely pass "recvfrom()" a byte count * based on the snapshot length. + * + * XXX - this "should not happen", as 2.2[.x] + * kernels all have PF_PACKET sockets, and there's + * no configuration option to disable them without + * disabling SOCK_PACKET sockets, because + * SOCK_PACKET sockets are implemented in the same + * source file, net/packet/af_packet.c. There *is* + * an option to disable SOCK_PACKET sockets so that + * you only have PF_PACKET sockets, and the kernel + * will log warning messages for code that uses + * "obsolete (PF_INET,SOCK_PACKET)". */ handle->bufsize = (u_int)handle->snapshot; } @@ -6788,7 +7091,7 @@ iface_bind_old(int fd, const char *device, char *ebuf) socklen_t errlen = sizeof(err); memset(&saddr, 0, sizeof(saddr)); - strlcpy(saddr.sa_data, device, sizeof(saddr.sa_data)); + pcap_strlcpy(saddr.sa_data, device, sizeof(saddr.sa_data)); if (bind(fd, &saddr, sizeof(saddr)) == -1) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "bind"); @@ -6799,7 +7102,7 @@ iface_bind_old(int fd, const char *device, char *ebuf) if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, - errno, "getsockopt"); + errno, "getsockopt (SO_ERROR)"); return -1; } @@ -6827,7 +7130,7 @@ iface_get_mtu(int fd, const char *device, char *ebuf) return BIGGER_THAN_ALL_MTUS; memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFMTU, &ifr) == -1) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, @@ -6845,20 +7148,22 @@ static int iface_get_arptype(int fd, const char *device, char *ebuf) { struct ifreq ifr; + int ret; memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) { - pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, - errno, "SIOCGIFHWADDR"); if (errno == ENODEV) { /* * No such device. */ - return PCAP_ERROR_NO_SUCH_DEVICE; - } - return PCAP_ERROR; + ret = PCAP_ERROR_NO_SUCH_DEVICE; + } else + ret = PCAP_ERROR; + pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "SIOCGIFHWADDR"); + return ret; } return ifr.ifr_hwaddr.sa_family; @@ -6950,7 +7255,7 @@ fix_program(pcap_t *handle, struct sock_fprog *fcode, int is_mmapped) * Yes, so we need to fix this * instruction. */ - if (fix_offset(p) < 0) { + if (fix_offset(handle, p) < 0) { /* * We failed to do so. * Return 0, so our caller @@ -6968,38 +7273,80 @@ fix_program(pcap_t *handle, struct sock_fprog *fcode, int is_mmapped) } static int -fix_offset(struct bpf_insn *p) +fix_offset(pcap_t *handle, struct bpf_insn *p) { /* - * What's the offset? + * Existing references to auxiliary data shouldn't be adjusted. + * + * Note that SKF_AD_OFF is negative, but p->k is unsigned, so + * we use >= and cast SKF_AD_OFF to unsigned. */ - if (p->k >= SLL_HDR_LEN) { + if (p->k >= (bpf_u_int32)SKF_AD_OFF) + return 0; + if (handle->linktype == DLT_LINUX_SLL2) { /* - * It's within the link-layer payload; that starts at an - * offset of 0, as far as the kernel packet filter is - * concerned, so subtract the length of the link-layer - * header. + * What's the offset? */ - p->k -= SLL_HDR_LEN; - } else if (p->k == 0) { + if (p->k >= SLL2_HDR_LEN) { + /* + * It's within the link-layer payload; that starts + * at an offset of 0, as far as the kernel packet + * filter is concerned, so subtract the length of + * the link-layer header. + */ + p->k -= SLL2_HDR_LEN; + } else if (p->k == 0) { + /* + * It's the protocol field; map it to the + * special magic kernel offset for that field. + */ + p->k = SKF_AD_OFF + SKF_AD_PROTOCOL; + } else if (p->k == 10) { + /* + * It's the packet type field; map it to the + * special magic kernel offset for that field. + */ + p->k = SKF_AD_OFF + SKF_AD_PKTTYPE; + } else if ((bpf_int32)(p->k) > 0) { + /* + * It's within the header, but it's not one of + * those fields; we can't do that in the kernel, + * so punt to userland. + */ + return -1; + } + } else { /* - * It's the packet type field; map it to the special magic - * kernel offset for that field. + * What's the offset? */ - p->k = SKF_AD_OFF + SKF_AD_PKTTYPE; - } else if (p->k == 14) { - /* - * It's the protocol field; map it to the special magic - * kernel offset for that field. - */ - p->k = SKF_AD_OFF + SKF_AD_PROTOCOL; - } else if ((bpf_int32)(p->k) > 0) { - /* - * It's within the header, but it's not one of those - * fields; we can't do that in the kernel, so punt - * to userland. - */ - return -1; + if (p->k >= SLL_HDR_LEN) { + /* + * It's within the link-layer payload; that starts + * at an offset of 0, as far as the kernel packet + * filter is concerned, so subtract the length of + * the link-layer header. + */ + p->k -= SLL_HDR_LEN; + } else if (p->k == 0) { + /* + * It's the packet type field; map it to the + * special magic kernel offset for that field. + */ + p->k = SKF_AD_OFF + SKF_AD_PKTTYPE; + } else if (p->k == 14) { + /* + * It's the protocol field; map it to the + * special magic kernel offset for that field. + */ + p->k = SKF_AD_OFF + SKF_AD_PROTOCOL; + } else if ((bpf_int32)(p->k) > 0) { + /* + * It's within the header, but it's not one of + * those fields; we can't do that in the kernel, + * so punt to userland. + */ + return -1; + } } return 0; } @@ -7159,7 +7506,7 @@ reset_kernel_filter(pcap_t *handle) #endif int -pcap_set_protocol(pcap_t *p, int protocol) +pcap_set_protocol_linux(pcap_t *p, int protocol) { if (pcap_check_activated(p)) return (PCAP_ERROR_ACTIVATED); diff --git a/pcap-netfilter-linux.c b/pcap-netfilter-linux.c index d5c5dcdc4850..91bad371b53d 100644 --- a/pcap-netfilter-linux.c +++ b/pcap-netfilter-linux.c @@ -301,7 +301,8 @@ netfilter_stats_linux(pcap_t *handle, struct pcap_stat *stats) static int netfilter_inject_linux(pcap_t *handle, const void *buf _U_, size_t size _U_) { - pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on netfilter devices"); + pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Packet injection is not supported on netfilter devices"); return (-1); } @@ -315,6 +316,7 @@ static int netfilter_send_config_msg(const pcap_t *handle, uint16_t msg_type, int ack, u_int8_t family, u_int16_t res_id, const struct my_nfattr *mynfa) { char buf[1024] __attribute__ ((aligned)); + memset(buf, 0, sizeof(buf)); struct nlmsghdr *nlh = (struct nlmsghdr *) buf; struct nfgenmsg *nfg = (struct nfgenmsg *) (buf + sizeof(struct nlmsghdr)); diff --git a/pcap-netmap.c b/pcap-netmap.c index f1505633fcaa..b2301a7fd8de 100644 --- a/pcap-netmap.c +++ b/pcap-netmap.c @@ -67,7 +67,7 @@ pcap_netmap_stats(pcap_t *p, struct pcap_stat *ps) { struct pcap_netmap *pn = p->priv; - ps->ps_recv = pn->rx_pkts; + ps->ps_recv = (u_int)pn->rx_pkts; ps->ps_drop = 0; ps->ps_ifdrop = 0; return 0; diff --git a/pcap-new.c b/pcap-new.c index 6fa52e6ece69..e61cf6ab2e9b 100644 --- a/pcap-new.c +++ b/pcap-new.c @@ -35,6 +35,8 @@ #include #endif +#include "ftmacros.h" + /* * sockutils.h may include on Windows, and pcap-int.h will * include portability.h, and portability.h, on Windows, expects that @@ -54,11 +56,14 @@ /* String identifier to be used in the pcap_findalldevs_ex() */ #define PCAP_TEXT_SOURCE_FILE "File" +#define PCAP_TEXT_SOURCE_FILE_LEN (sizeof PCAP_TEXT_SOURCE_FILE - 1) /* String identifier to be used in the pcap_findalldevs_ex() */ #define PCAP_TEXT_SOURCE_ADAPTER "Network adapter" +#define PCAP_TEXT_SOURCE_ADAPTER_LEN (sizeof "Network adapter" - 1) /* String identifier to be used in the pcap_findalldevs_ex() */ #define PCAP_TEXT_SOURCE_ON_LOCAL_HOST "on local host" +#define PCAP_TEXT_SOURCE_ON_LOCAL_HOST_LEN (sizeof PCAP_TEXT_SOURCE_ON_LOCAL_HOST + 1) /**************************************************** * * @@ -66,10 +71,12 @@ * * ****************************************************/ -int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf) +int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf) { int type; char name[PCAP_BUF_SIZE], path[PCAP_BUF_SIZE], filename[PCAP_BUF_SIZE]; + size_t pathlen; + size_t stringlen; pcap_t *fp; char tmpstring[PCAP_BUF_SIZE + 1]; /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */ pcap_if_t *lastdev; /* Last device in the pcap_if_t list */ @@ -113,7 +120,7 @@ int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **all if (*alldevs == NULL) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "No interfaces found! Make sure libpcap/WinPcap is properly installed" + "No interfaces found! Make sure libpcap/Npcap is properly installed" " on the local machine."); return -1; } @@ -123,6 +130,8 @@ int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **all dev = *alldevs; while (dev) { + char *localdesc, *desc; + /* Create the new device identifier */ if (pcap_createsrcstr(tmpstring, PCAP_SRC_IFLOCAL, NULL, NULL, dev->name, errbuf) == -1) return -1; @@ -141,20 +150,16 @@ int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **all return -1; } - /* Create the new device description */ + /* + * Create the description. + */ if ((dev->description == NULL) || (dev->description[0] == 0)) - pcap_snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_ADAPTER, - dev->name, PCAP_TEXT_SOURCE_ON_LOCAL_HOST); + localdesc = dev->name; else - pcap_snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_ADAPTER, - dev->description, PCAP_TEXT_SOURCE_ON_LOCAL_HOST); - - /* Delete the old pointer */ - free(dev->description); - - /* Make a copy of the description */ - dev->description = strdup(tmpstring); - if (dev->description == NULL) + localdesc = dev->description; + if (pcap_asprintf(&desc, "%s '%s' %s", + PCAP_TEXT_SOURCE_ADAPTER, localdesc, + PCAP_TEXT_SOURCE_ON_LOCAL_HOST) == -1) { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, @@ -163,6 +168,10 @@ int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **all return -1; } + /* Now overwrite the description */ + free(dev->description); + dev->description = desc; + dev = dev->next; } @@ -170,7 +179,6 @@ int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **all case PCAP_SRC_FILE: { - size_t stringlen; #ifdef _WIN32 WIN32_FIND_DATA filedata; HANDLE filehandle; @@ -202,6 +210,7 @@ int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **all /* Save the path for future reference */ pcap_snprintf(path, sizeof(path), "%s", name); + pathlen = strlen(path); #ifdef _WIN32 /* To perform directory listing, Win32 must have an 'asterisk' as ending char */ @@ -236,10 +245,14 @@ int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **all /* Add all files we find to the list. */ do { - #ifdef _WIN32 + /* Skip the file if the pathname won't fit in the buffer */ + if (pathlen + strlen(filedata.cFileName) >= sizeof(filename)) + continue; pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName); #else + if (pathlen + strlen(filedata->d_name) >= sizeof(filename)) + continue; pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata->d_name); #endif @@ -287,9 +300,7 @@ int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **all return -1; } - stringlen = strlen(tmpstring); - - dev->name = (char *)malloc(stringlen + 1); + dev->name = strdup(tmpstring); if (dev->name == NULL) { pcap_fmt_errmsg_for_errno(errbuf, @@ -299,19 +310,12 @@ int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **all return -1; } - strlcpy(dev->name, tmpstring, stringlen); - - dev->name[stringlen] = 0; - - /* Create the description */ - pcap_snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_FILE, - filename, PCAP_TEXT_SOURCE_ON_LOCAL_HOST); - - stringlen = strlen(tmpstring); - - dev->description = (char *)malloc(stringlen + 1); - - if (dev->description == NULL) + /* + * Create the description. + */ + if (pcap_asprintf(&dev->description, + "%s '%s' %s", PCAP_TEXT_SOURCE_FILE, + filename, PCAP_TEXT_SOURCE_ON_LOCAL_HOST) == -1) { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, @@ -320,9 +324,6 @@ int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **all return -1; } - /* Copy the new device description into the correct memory location */ - strlcpy(dev->description, tmpstring, stringlen + 1); - pcap_close(fp); } } @@ -345,7 +346,7 @@ int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **all return pcap_findalldevs_ex_remote(source, auth, alldevs, errbuf); default: - strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE); + pcap_strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE); return -1; } } @@ -357,6 +358,16 @@ pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, pcap_t *fp; int status; + /* + * A null device name is equivalent to the "any" device - + * which might not be supported on this platform, but + * this means that you'll get a "not supported" error + * rather than, say, a crash when we try to dereference + * the null pointer. + */ + if (source == NULL) + source = "any"; + if (strlen(source) > PCAP_BUF_SIZE) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly."); @@ -389,7 +400,7 @@ pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, return pcap_open_rpcap(source, snaplen, flags, read_timeout, auth, errbuf); default: - strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE); + pcap_strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE); return NULL; } diff --git a/pcap-npf.c b/pcap-npf.c index 472b042104e5..da4641f379c8 100644 --- a/pcap-npf.c +++ b/pcap-npf.c @@ -70,7 +70,7 @@ static int pcap_setnonblock_npf(pcap_t *, int); #define SWAPS(_X) ((_X & 0xff) << 8) | (_X >> 8) /* - * Private data for capturing on WinPcap devices. + * Private data for capturing on WinPcap/Npcap devices. */ struct pcap_win { ADAPTER *adapter; /* the packet32 ADAPTER for the device */ @@ -134,7 +134,7 @@ PacketGetMonitorMode(PCHAR AdapterName _U_) * or NDIS_STATUS_NOT_RECOGNIZED if the OID request isn't * supported by the OS or the driver, but that doesn't seem * to make it to the caller of PacketRequest() in a - * reiable fashion. + * reliable fashion. */ #define NDIS_STATUS_INVALID_OID 0xc0010017 #define NDIS_STATUS_NOT_SUPPORTED 0xc00000bb /* STATUS_NOT_SUPPORTED */ @@ -166,11 +166,8 @@ oid_get_request(ADAPTER *adapter, bpf_u_int32 oid, void *data, size_t *lenp, oid_data_arg->Oid = oid; oid_data_arg->Length = (ULONG)(*lenp); /* XXX - check for ridiculously large value? */ if (!PacketRequest(adapter, FALSE, oid_data_arg)) { - char errmsgbuf[PCAP_ERRBUF_SIZE+1]; - - pcap_win32_err_to_str(GetLastError(), errmsgbuf); - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "Error calling PacketRequest: %s", errmsgbuf); + pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "Error calling PacketRequest"); free(oid_data_arg); return (-1); } @@ -193,7 +190,6 @@ pcap_stats_npf(pcap_t *p, struct pcap_stat *ps) { struct pcap_win *pw = p->priv; struct bpf_stat bstats; - char errbuf[PCAP_ERRBUF_SIZE+1]; /* * Try to get statistics. @@ -209,9 +205,8 @@ pcap_stats_npf(pcap_t *p, struct pcap_stat *ps) * to us. */ if (!PacketGetStats(pw->adapter, &bstats)) { - pcap_win32_err_to_str(GetLastError(), errbuf); - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "PacketGetStats error: %s", errbuf); + pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "PacketGetStats error"); return (-1); } ps->ps_recv = bstats.bs_recv; @@ -256,7 +251,6 @@ pcap_stats_ex_npf(pcap_t *p, int *pcap_stat_size) { struct pcap_win *pw = p->priv; struct bpf_stat bstats; - char errbuf[PCAP_ERRBUF_SIZE+1]; *pcap_stat_size = sizeof (p->stat); @@ -268,9 +262,8 @@ pcap_stats_ex_npf(pcap_t *p, int *pcap_stat_size) * same layout, but let's not cheat.) */ if (!PacketGetStatsEx(pw->adapter, &bstats)) { - pcap_win32_err_to_str(GetLastError(), errbuf); - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "PacketGetStatsEx error: %s", errbuf); + pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "PacketGetStatsEx error"); return (NULL); } p->stat.ps_recv = bstats.bs_recv; @@ -347,7 +340,6 @@ pcap_oid_set_request_npf(pcap_t *p, bpf_u_int32 oid, const void *data, { struct pcap_win *pw = p->priv; PACKET_OID_DATA *oid_data_arg; - char errbuf[PCAP_ERRBUF_SIZE+1]; /* * Allocate a PACKET_OID_DATA structure to hand to PacketRequest(). @@ -367,9 +359,8 @@ pcap_oid_set_request_npf(pcap_t *p, bpf_u_int32 oid, const void *data, oid_data_arg->Length = (ULONG)(*lenp); /* XXX - check for ridiculously large value? */ memcpy(oid_data_arg->Data, data, *lenp); if (!PacketRequest(pw->adapter, TRUE, oid_data_arg)) { - pcap_win32_err_to_str(GetLastError(), errbuf); - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "Error calling PacketRequest: %s", errbuf); + pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "Error calling PacketRequest"); free(oid_data_arg); return (PCAP_ERROR); } @@ -391,7 +382,6 @@ pcap_sendqueue_transmit_npf(pcap_t *p, pcap_send_queue *queue, int sync) { struct pcap_win *pw = p->priv; u_int res; - char errbuf[PCAP_ERRBUF_SIZE+1]; if (pw->adapter==NULL) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, @@ -405,9 +395,8 @@ pcap_sendqueue_transmit_npf(pcap_t *p, pcap_send_queue *queue, int sync) (BOOLEAN)sync); if(res != queue->len){ - pcap_win32_err_to_str(GetLastError(), errbuf); - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "Error opening adapter: %s", errbuf); + pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "Error opening adapter"); } return (res); @@ -534,7 +523,34 @@ pcap_read_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) */ PacketInitPacket(&Packet, (BYTE *)p->buffer, p->bufsize); if (!PacketReceivePacket(pw->adapter, &Packet, TRUE)) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed"); + /* + * Did the device go away? + * If so, the error we get is ERROR_GEN_FAILURE. + */ + DWORD errcode = GetLastError(); + + if (errcode == ERROR_GEN_FAILURE) { + /* + * The device on which we're capturing + * went away, or it became unusable + * by NPF due to a suspend/resume. + * + * XXX - hopefully no other error + * conditions are indicated by this. + * + * XXX - we really should return an + * appropriate error for that, but + * pcap_dispatch() etc. aren't + * documented as having error returns + * other than PCAP_ERROR or PCAP_ERROR_BREAK. + */ + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The interface disappeared"); + } else { + pcap_fmt_errmsg_for_win32_err(p->errbuf, + PCAP_ERRBUF_SIZE, errcode, + "PacketReceivePacket error"); + } return (PCAP_ERROR); } @@ -873,7 +889,7 @@ pcap_activate_npf(pcap_t *p) struct pcap_win *pw = p->priv; NetType type; int res; - char errbuf[PCAP_ERRBUF_SIZE+1]; + int status = 0; if (p->opt.rfmon) { /* @@ -912,23 +928,35 @@ pcap_activate_npf(pcap_t *p) if (pw->adapter == NULL) { - /* Adapter detected but we are not able to open it. Return failure. */ - pcap_win32_err_to_str(GetLastError(), errbuf); - if (pw->rfmon_selfstart) - { - PacketSetMonitorMode(p->opt.device, 0); + DWORD errcode = GetLastError(); + + /* + * What error did we get when trying to open the adapter? + */ + if (errcode == ERROR_BAD_UNIT) { + /* + * There's no such device. + */ + return (PCAP_ERROR_NO_SUCH_DEVICE); + } else { + /* + * Unknown - report details. + */ + pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + errcode, "Error opening adapter"); + if (pw->rfmon_selfstart) + { + PacketSetMonitorMode(p->opt.device, 0); + } + return (PCAP_ERROR); } - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "Error opening adapter: %s", errbuf); - return (PCAP_ERROR); } /*get network type*/ if(PacketGetNetType (pw->adapter,&type) == FALSE) { - pcap_win32_err_to_str(GetLastError(), errbuf); - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "Cannot determine the network type: %s", errbuf); + pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "Cannot determine the network type"); goto bad; } @@ -1006,8 +1034,29 @@ pcap_activate_npf(pcap_t *p) p->linktype = DLT_PPI; break; +#ifdef NdisMediumWirelessWan + case NdisMediumWirelessWan: + p->linktype = DLT_RAW; + break; +#endif + default: - p->linktype = DLT_EN10MB; /*an unknown adapter is assumed to be ethernet*/ + /* + * An unknown medium type is assumed to supply Ethernet + * headers; if not, the user will have to report it, + * so that the medium type and link-layer header type + * can be determined. If we were to fail here, we + * might get the link-layer type in the error, but + * the user wouldn't get a capture, so we wouldn't + * be able to determine the link-layer type; we report + * a warning with the link-layer type, so at least + * some programs will report the warning. + */ + p->linktype = DLT_EN10MB; + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Unknown NdisMedium value %d, defaulting to DLT_EN10MB", + type.LinkType); + status = PCAP_WARNING; break; } @@ -1085,10 +1134,9 @@ pcap_activate_npf(pcap_t *p) /* tell the driver to copy the buffer as soon as data arrives */ if(PacketSetMinToCopy(pw->adapter,0)==FALSE) { - pcap_win32_err_to_str(GetLastError(), errbuf); - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "Error calling PacketSetMinToCopy: %s", - errbuf); + pcap_fmt_errmsg_for_win32_err(p->errbuf, + PCAP_ERRBUF_SIZE, GetLastError(), + "Error calling PacketSetMinToCopy"); goto bad; } } @@ -1097,10 +1145,9 @@ pcap_activate_npf(pcap_t *p) /* tell the driver to copy the buffer only if it contains at least 16K */ if(PacketSetMinToCopy(pw->adapter,16000)==FALSE) { - pcap_win32_err_to_str(GetLastError(), errbuf); - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "Error calling PacketSetMinToCopy: %s", - errbuf); + pcap_fmt_errmsg_for_win32_err(p->errbuf, + PCAP_ERRBUF_SIZE, GetLastError(), + "Error calling PacketSetMinToCopy"); goto bad; } } @@ -1221,7 +1268,7 @@ pcap_activate_npf(pcap_t *p) */ p->handle = pw->adapter->hFile; - return (0); + return (status); bad: pcap_cleanup_npf(p); return (PCAP_ERROR); @@ -1316,7 +1363,7 @@ pcap_setfilter_win32_dag(pcap_t *p, struct bpf_program *fp) { if(!fp) { - strlcpy(p->errbuf, "setfilter: No filter specified", sizeof(p->errbuf)); + pcap_strlcpy(p->errbuf, "setfilter: No filter specified", sizeof(p->errbuf)); return (-1); } @@ -1345,7 +1392,6 @@ pcap_setnonblock_npf(pcap_t *p, int nonblock) { struct pcap_win *pw = p->priv; int newtimeout; - char win_errbuf[PCAP_ERRBUF_SIZE+1]; if (nonblock) { /* @@ -1365,9 +1411,8 @@ pcap_setnonblock_npf(pcap_t *p, int nonblock) newtimeout = p->opt.timeout; } if (!PacketSetReadTimeout(pw->adapter, newtimeout)) { - pcap_win32_err_to_str(GetLastError(), win_errbuf); - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "PacketSetReadTimeout: %s", win_errbuf); + pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "PacketSetReadTimeout"); return (-1); } pw->nonblock = (newtimeout == -1); @@ -1684,7 +1729,6 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) char *AdaptersName; ULONG NameLength; char *name; - char our_errbuf[PCAP_ERRBUF_SIZE+1]; /* * Find out how big a buffer we need. @@ -1710,9 +1754,8 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) if (last_error != ERROR_INSUFFICIENT_BUFFER) { - pcap_win32_err_to_str(last_error, our_errbuf); - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "PacketGetAdapterNames: %s", our_errbuf); + pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, + last_error, "PacketGetAdapterNames"); return (-1); } } @@ -1727,9 +1770,8 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) } if (!PacketGetAdapterNames(AdaptersName, &NameLength)) { - pcap_win32_err_to_str(GetLastError(), our_errbuf); - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "PacketGetAdapterNames: %s", - our_errbuf); + pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "PacketGetAdapterNames"); free(AdaptersName); return (-1); } @@ -1818,7 +1860,6 @@ pcap_lookupdev(char *errbuf) { DWORD dwVersion; DWORD dwWindowsMajorVersion; - char our_errbuf[PCAP_ERRBUF_SIZE+1]; #pragma warning (push) #pragma warning (disable: 4996) /* disable MSVC's GetVersion() deprecated warning here */ @@ -1860,9 +1901,8 @@ pcap_lookupdev(char *errbuf) if ( !PacketGetAdapterNames((PTSTR)TAdaptersName,&NameLength) ) { - pcap_win32_err_to_str(GetLastError(), our_errbuf); - (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "PacketGetAdapterNames: %s", our_errbuf); + pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "PacketGetAdapterNames"); free(TAdaptersName); return NULL; } @@ -2000,59 +2040,48 @@ static const char *pcap_lib_version_string; * tree. Include version.h from that source tree to get the WinPcap/Npcap * version. * - * XXX - it'd be nice if we could somehow generate the WinPcap version number - * when building WinPcap. (It'd be nice to do so for the packet.dll version - * number as well.) + * XXX - it'd be nice if we could somehow generate the WinPcap/Npcap version + * number when building as part of WinPcap/Npcap. (It'd be nice to do so + * for the packet.dll version number as well.) */ #include "../../version.h" static const char pcap_version_string[] = WINPCAP_PRODUCT_NAME " version " WINPCAP_VER_STRING ", based on " PCAP_VERSION_STRING; -static const char pcap_version_string_packet_dll_fmt[] = - WINPCAP_PRODUCT_NAME " version " WINPCAP_VER_STRING " (packet.dll version %s), based on " PCAP_VERSION_STRING; const char * pcap_lib_version(void) { - char *packet_version_string; - size_t full_pcap_version_string_len; - char *full_pcap_version_string; - if (pcap_lib_version_string == NULL) { /* * Generate the version string. */ - packet_version_string = PacketGetVersion(); + char *packet_version_string = PacketGetVersion(); + if (strcmp(WINPCAP_VER_STRING, packet_version_string) == 0) { /* - * WinPcap version string and packet.dll version - * string are the same; just report the WinPcap + * WinPcap/Npcap version string and packet.dll version + * string are the same; just report the WinPcap/Npcap * version. */ pcap_lib_version_string = pcap_version_string; } else { /* - * WinPcap version string and packet.dll version + * WinPcap/Npcap version string and packet.dll version * string are different; that shouldn't be the * case (the two libraries should come from the - * same version of WinPcap), so we report both + * same version of WinPcap/Npcap), so we report both * versions. - * - * The -2 is for the %s in the format string, - * which will be replaced by packet_version_string. */ - full_pcap_version_string_len = - (sizeof pcap_version_string_packet_dll_fmt - 2) + - strlen(packet_version_string); - full_pcap_version_string = malloc(full_pcap_version_string_len); - if (full_pcap_version_string == NULL) - return (NULL); - pcap_snprintf(full_pcap_version_string, - full_pcap_version_string_len, - pcap_version_string_packet_dll_fmt, - packet_version_string); + char *full_pcap_version_string; + + if (pcap_asprintf(&full_pcap_version_string, + WINPCAP_PRODUCT_NAME " version " WINPCAP_VER_STRING " (packet.dll version %s), based on " PCAP_VERSION_STRING, + packet_version_string) != -1) { + /* Success */ + pcap_lib_version_string = full_pcap_version_string; + } } - pcap_lib_version_string = full_pcap_version_string; } return (pcap_lib_version_string); } @@ -2063,35 +2092,22 @@ pcap_lib_version(void) * libpcap being built for Windows, not as part of a WinPcap/Npcap source * tree. */ -static const char pcap_version_string_packet_dll_fmt[] = - PCAP_VERSION_STRING " (packet.dll version %s)"; const char * pcap_lib_version(void) { - char *packet_version_string; - size_t full_pcap_version_string_len; - char *full_pcap_version_string; - if (pcap_lib_version_string == NULL) { /* * Generate the version string. Report the packet.dll * version. - * - * The -2 is for the %s in the format string, which will - * be replaced by packet_version_string. */ - packet_version_string = PacketGetVersion(); - full_pcap_version_string_len = - (sizeof pcap_version_string_packet_dll_fmt - 2) + - strlen(packet_version_string); - full_pcap_version_string = malloc(full_pcap_version_string_len); - if (full_pcap_version_string == NULL) - return (NULL); - pcap_snprintf(full_pcap_version_string, - full_pcap_version_string_len, - pcap_version_string_packet_dll_fmt, - packet_version_string); - pcap_lib_version_string = full_pcap_version_string; + char *full_pcap_version_string; + + if (pcap_asprintf(&full_pcap_version_string, + PCAP_VERSION_STRING " (packet.dll version %s)", + PacketGetVersion()) != -1) { + /* Success */ + pcap_lib_version_string = full_pcap_version_string; + } } return (pcap_lib_version_string); } diff --git a/pcap-null.c b/pcap-null.c index 92a5e2d8649b..2ae27bf8226e 100644 --- a/pcap-null.c +++ b/pcap-null.c @@ -32,12 +32,12 @@ static char nosup[] = "live packet capture not supported on this system"; pcap_t * pcap_create_interface(const char *device _U_, char *ebuf) { - (void)strlcpy(ebuf, nosup, PCAP_ERRBUF_SIZE); + (void)pcap_strlcpy(ebuf, nosup, PCAP_ERRBUF_SIZE); return (NULL); } int -pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) +pcap_platform_finddevs(pcap_if_list_t *devlistp _U_, char *errbuf _U_) { /* * There are no interfaces on which we can capture. @@ -50,7 +50,7 @@ int pcap_lookupnet(const char *device _U_, bpf_u_int32 *netp _U_, bpf_u_int32 *maskp _U_, char *errbuf) { - (void)strlcpy(errbuf, nosup, PCAP_ERRBUF_SIZE); + (void)pcap_strlcpy(errbuf, nosup, PCAP_ERRBUF_SIZE); return (-1); } #endif diff --git a/pcap-rpcap.c b/pcap-rpcap.c index 42f381c86273..705f06f2ad87 100644 --- a/pcap-rpcap.c +++ b/pcap-rpcap.c @@ -155,7 +155,6 @@ static void pcap_save_current_filter_rpcap(pcap_t *fp, const char *filter); static int pcap_setfilter_rpcap(pcap_t *fp, struct bpf_program *prog); static int pcap_setsampling_remote(pcap_t *fp); static int pcap_startcapture_remote(pcap_t *fp); -static int rpcap_sendauth(SOCKET sock, uint8 *ver, struct pcap_rmtauth *auth, char *errbuf); static int rpcap_recv_msg_header(SOCKET sock, struct rpcap_header *header, char *errbuf); static int rpcap_check_msg_ver(SOCKET sock, uint8 expected_ver, struct rpcap_header *header, char *errbuf); static int rpcap_check_msg_type(SOCKET sock, uint8 request_type, struct rpcap_header *header, uint16 *errcode, char *errbuf); @@ -409,7 +408,7 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch return 0; } #endif - sock_geterror("select(): ", p->errbuf, PCAP_ERRBUF_SIZE); + sock_geterror("select()", p->errbuf, PCAP_ERRBUF_SIZE); return -1; } @@ -763,6 +762,8 @@ static void pcap_cleanup_rpcap(pcap_t *fp) pr->currentfilter = NULL; } + pcap_cleanup_live_common(fp); + /* To avoid inconsistencies in the number of sock_init() */ sock_cleanup(); } @@ -908,7 +909,7 @@ static struct pcap_stat *rpcap_stats_rpcap(pcap_t *p, struct pcap_stat *ps, int /* Discard the rest of the message. */ if (rpcap_discard(pr->rmt_sockctrl, plen, p->errbuf) == -1) - goto error; + goto error_nodiscard; return ps; @@ -920,6 +921,7 @@ static struct pcap_stat *rpcap_stats_rpcap(pcap_t *p, struct pcap_stat *ps, int */ (void)rpcap_discard(pr->rmt_sockctrl, plen, NULL); +error_nodiscard: return NULL; } @@ -1068,7 +1070,7 @@ static int pcap_startcapture_remote(pcap_t *fp) saddrlen = sizeof(struct sockaddr_storage); if (getpeername(pr->rmt_sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1) { - sock_geterror("getsockname(): ", fp->errbuf, PCAP_ERRBUF_SIZE); + sock_geterror("getsockname()", fp->errbuf, PCAP_ERRBUF_SIZE); goto error_nodiscard; } ai_family = ((struct sockaddr_storage *) &saddr)->ss_family; @@ -1077,7 +1079,7 @@ static int pcap_startcapture_remote(pcap_t *fp) if (getnameinfo((struct sockaddr *) &saddr, saddrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST)) { - sock_geterror("getnameinfo(): ", fp->errbuf, PCAP_ERRBUF_SIZE); + sock_geterror("getnameinfo()", fp->errbuf, PCAP_ERRBUF_SIZE); goto error_nodiscard; } @@ -1115,7 +1117,7 @@ static int pcap_startcapture_remote(pcap_t *fp) saddrlen = sizeof(struct sockaddr_storage); if (getsockname(sockdata, (struct sockaddr *) &saddr, &saddrlen) == -1) { - sock_geterror("getsockname(): ", fp->errbuf, PCAP_ERRBUF_SIZE); + sock_geterror("getsockname()", fp->errbuf, PCAP_ERRBUF_SIZE); goto error_nodiscard; } @@ -1123,7 +1125,7 @@ static int pcap_startcapture_remote(pcap_t *fp) if (getnameinfo((struct sockaddr *) &saddr, saddrlen, NULL, 0, portdata, sizeof(portdata), NI_NUMERICSERV)) { - sock_geterror("getnameinfo(): ", fp->errbuf, PCAP_ERRBUF_SIZE); + sock_geterror("getnameinfo()", fp->errbuf, PCAP_ERRBUF_SIZE); goto error_nodiscard; } } @@ -1233,7 +1235,7 @@ static int pcap_startcapture_remote(pcap_t *fp) if (socktemp == INVALID_SOCKET) { - sock_geterror("accept(): ", fp->errbuf, PCAP_ERRBUF_SIZE); + sock_geterror("accept()", fp->errbuf, PCAP_ERRBUF_SIZE); goto error; } @@ -1259,8 +1261,8 @@ static int pcap_startcapture_remote(pcap_t *fp) res = getsockopt(sockdata, SOL_SOCKET, SO_RCVBUF, (char *)&sockbufsize, &itemp); if (res == -1) { - sock_geterror("pcap_startcapture_remote()", fp->errbuf, PCAP_ERRBUF_SIZE); - SOCK_DEBUG_MESSAGE(fp->errbuf); + sock_geterror("pcap_startcapture_remote(): getsockopt() failed", fp->errbuf, PCAP_ERRBUF_SIZE); + goto error; } /* @@ -1334,7 +1336,7 @@ static int pcap_startcapture_remote(pcap_t *fp) /* Discard the rest of the message. */ if (rpcap_discard(pr->rmt_sockctrl, plen, fp->errbuf) == -1) - goto error; + goto error_nodiscard; /* * In case the user does not want to capture RPCAP packets, let's update the filter @@ -1611,21 +1613,19 @@ static int pcap_createfilter_norpcappkt(pcap_t *fp, struct bpf_program *prog) char peeraddress[128]; char peerctrlport[128]; char *newfilter; - const int newstringsize = 1024; - size_t currentfiltersize; /* Get the name/port of our peer */ saddrlen = sizeof(struct sockaddr_storage); if (getpeername(pr->rmt_sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1) { - sock_geterror("getpeername(): ", fp->errbuf, PCAP_ERRBUF_SIZE); + sock_geterror("getpeername()", fp->errbuf, PCAP_ERRBUF_SIZE); return -1; } if (getnameinfo((struct sockaddr *) &saddr, saddrlen, peeraddress, sizeof(peeraddress), peerctrlport, sizeof(peerctrlport), NI_NUMERICHOST | NI_NUMERICSERV)) { - sock_geterror("getnameinfo(): ", fp->errbuf, PCAP_ERRBUF_SIZE); + sock_geterror("getnameinfo()", fp->errbuf, PCAP_ERRBUF_SIZE); return -1; } @@ -1633,7 +1633,7 @@ static int pcap_createfilter_norpcappkt(pcap_t *fp, struct bpf_program *prog) /* Get the name/port of the current host */ if (getsockname(pr->rmt_sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1) { - sock_geterror("getsockname(): ", fp->errbuf, PCAP_ERRBUF_SIZE); + sock_geterror("getsockname()", fp->errbuf, PCAP_ERRBUF_SIZE); return -1; } @@ -1641,43 +1641,60 @@ static int pcap_createfilter_norpcappkt(pcap_t *fp, struct bpf_program *prog) if (getnameinfo((struct sockaddr *) &saddr, saddrlen, myaddress, sizeof(myaddress), myctrlport, sizeof(myctrlport), NI_NUMERICHOST | NI_NUMERICSERV)) { - sock_geterror("getnameinfo(): ", fp->errbuf, PCAP_ERRBUF_SIZE); + sock_geterror("getnameinfo()", fp->errbuf, PCAP_ERRBUF_SIZE); return -1; } /* Let's now check the data port */ if (getsockname(pr->rmt_sockdata, (struct sockaddr *) &saddr, &saddrlen) == -1) { - sock_geterror("getsockname(): ", fp->errbuf, PCAP_ERRBUF_SIZE); + sock_geterror("getsockname()", fp->errbuf, PCAP_ERRBUF_SIZE); return -1; } /* Get the local port the system picked up */ if (getnameinfo((struct sockaddr *) &saddr, saddrlen, NULL, 0, mydataport, sizeof(mydataport), NI_NUMERICSERV)) { - sock_geterror("getnameinfo(): ", fp->errbuf, PCAP_ERRBUF_SIZE); + sock_geterror("getnameinfo()", fp->errbuf, PCAP_ERRBUF_SIZE); return -1; } - currentfiltersize = pr->currentfilter ? strlen(pr->currentfilter) : 0; - - newfilter = (char *)malloc(currentfiltersize + newstringsize + 1); - - if (currentfiltersize) + if (pr->currentfilter && pr->currentfilter[0] != '\0') { - pcap_snprintf(newfilter, currentfiltersize + newstringsize, - "(%s) and not (host %s and host %s and port %s and port %s) and not (host %s and host %s and port %s)", - pr->currentfilter, myaddress, peeraddress, myctrlport, peerctrlport, myaddress, peeraddress, mydataport); + /* + * We have a current filter; add items to it to + * filter out this rpcap session. + */ + if (pcap_asprintf(&newfilter, + "(%s) and not (host %s and host %s and port %s and port %s) and not (host %s and host %s and port %s)", + pr->currentfilter, myaddress, peeraddress, + myctrlport, peerctrlport, myaddress, peeraddress, + mydataport) == -1) + { + /* Failed. */ + pcap_snprintf(fp->errbuf, PCAP_ERRBUF_SIZE, + "Can't allocate memory for new filter"); + return -1; + } } else { - pcap_snprintf(newfilter, currentfiltersize + newstringsize, - "not (host %s and host %s and port %s and port %s) and not (host %s and host %s and port %s)", - myaddress, peeraddress, myctrlport, peerctrlport, myaddress, peeraddress, mydataport); + /* + * We have no current filter; construct a filter to + * filter out this rpcap session. + */ + if (pcap_asprintf(&newfilter, + "not (host %s and host %s and port %s and port %s) and not (host %s and host %s and port %s)", + myaddress, peeraddress, myctrlport, peerctrlport, + myaddress, peeraddress, mydataport) == -1) + { + /* Failed. */ + pcap_snprintf(fp->errbuf, PCAP_ERRBUF_SIZE, + "Can't allocate memory for new filter"); + return -1; + } } - newfilter[currentfiltersize + newstringsize] = 0; - /* * This is only an hack to prevent the save_current_filter * routine, which will be called when we call pcap_compile(), @@ -1784,16 +1801,25 @@ static int pcap_setsampling_remote(pcap_t *fp) /* * This function performs authentication and protocol version - * negotiation. It first tries to authenticate with the maximum - * version we support and, if that fails with an "I don't support - * that version" error from the server, and the version number in - * the reply from the server is one we support, tries again with - * that version. + * negotiation. It is required in order to open the connection + * with the other end party. + * + * It sends authentication parameters on the control socket and + * reads the reply. If the reply is a success indication, it + * checks whether the reply includes minimum and maximum supported + * versions from the server; if not, it assumes both are 0, as + * that means it's an older server that doesn't return supported + * version numbers in authentication replies, so it only supports + * version 0. It then tries to determine the maximum version + * supported both by us and by the server. If it can find such a + * version, it sets us up to use that version; otherwise, it fails, + * indicating that there is no version supported by us and by the + * server. * * \param sock: the socket we are currently using. * - * \param ver: pointer to variable holding protocol version number to send - * and to set to the protocol version number in the reply. + * \param ver: pointer to variable to which to set the protocol version + * number we selected. * * \param auth: authentication parameters that have to be sent. * @@ -1806,96 +1832,17 @@ static int pcap_setsampling_remote(pcap_t *fp) * an error message string is returned in the 'errbuf' variable. */ static int rpcap_doauth(SOCKET sockctrl, uint8 *ver, struct pcap_rmtauth *auth, char *errbuf) -{ - int status; - - /* - * Send authentication to the remote machine. - * - * First try with the maximum version number we support. - */ - *ver = RPCAP_MAX_VERSION; - status = rpcap_sendauth(sockctrl, ver, auth, errbuf); - if (status == 0) - { - // - // Success. - // - return 0; - } - if (status == -1) - { - /* Unrecoverable error. */ - return -1; - } - - /* - * The server doesn't support the version we used in the initial - * message, and it sent us back a reply either with the maximum - * version they do support, or with the version we sent, and we - * support that version. *ver has been set to that version; try - * authenticating again with that version. - */ - status = rpcap_sendauth(sockctrl, ver, auth, errbuf); - if (status == 0) - { - // - // Success. - // - return 0; - } - if (status == -1) - { - /* Unrecoverable error. */ - return -1; - } - if (status == -2) - { - /* - * The server doesn't support that version, which - * means there is no version we both support, so - * this is a fatal error. - */ - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The server doesn't support any protocol version that we support"); - return -1; - } - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "rpcap_sendauth() returned %d", status); - return -1; -} - -/* - * This function sends the authentication message. - * - * It sends the authentication parameters on the control socket. - * It is required in order to open the connection with the other end party. - * - * \param sock: the socket we are currently using. - * - * \param ver: pointer to variable holding protocol version number to send - * and to set to the protocol version number in the reply. - * - * \param auth: authentication parameters that have to be sent. - * - * \param errbuf: a pointer to a user-allocated buffer (of size - * PCAP_ERRBUF_SIZE) that will contain the error message (in case there - * is one). It could be a network problem or the fact that the authorization - * failed. - * - * \return '0' if everything is fine, '-2' if the server didn't reply with - * the protocol version we requested but replied with a version we do - * support, or '-1' for other errors. For errors, an error message string - * is returned in the 'errbuf' variable. - */ -static int rpcap_sendauth(SOCKET sock, uint8 *ver, struct pcap_rmtauth *auth, char *errbuf) { char sendbuf[RPCAP_NETBUF_SIZE]; /* temporary buffer in which data that has to be sent is buffered */ int sendbufidx = 0; /* index which keeps the number of bytes currently buffered */ uint16 length; /* length of the payload of this message */ - uint16 errcode; struct rpcap_auth *rpauth; uint16 auth_type; struct rpcap_header header; size_t str_length; + uint32 plen; + struct rpcap_authreply authreply; /* authentication reply message */ + uint8 ourvers; if (auth) { @@ -1942,12 +1889,11 @@ static int rpcap_sendauth(SOCKET sock, uint8 *ver, struct pcap_rmtauth *auth, ch length = sizeof(struct rpcap_auth); } - if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE)) return -1; - rpcap_createhdr((struct rpcap_header *) sendbuf, *ver, + rpcap_createhdr((struct rpcap_header *) sendbuf, 0, RPCAP_MSG_AUTH_REQ, 0, length); rpauth = (struct rpcap_auth *) &sendbuf[sendbufidx]; @@ -1984,62 +1930,104 @@ static int rpcap_sendauth(SOCKET sock, uint8 *ver, struct pcap_rmtauth *auth, ch rpauth->slen2 = htons(rpauth->slen2); } - if (sock_send(sock, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) < 0) + if (sock_send(sockctrl, sendbuf, sendbufidx, errbuf, + PCAP_ERRBUF_SIZE) < 0) return -1; - /* Receive the reply */ - if (rpcap_recv_msg_header(sock, &header, errbuf) == -1) + /* Receive and process the reply message header */ + if (rpcap_process_msg_header(sockctrl, 0, RPCAP_MSG_AUTH_REQ, + &header, errbuf) == -1) return -1; - if (rpcap_check_msg_type(sock, RPCAP_MSG_AUTH_REQ, &header, - &errcode, errbuf) == -1) + /* + * OK, it's an authentication reply, so we're logged in. + * + * Did it send any additional information? + */ + plen = header.plen; + if (plen != 0) { - /* Error message - or something else, which is a protocol error. */ - if (header.type == RPCAP_MSG_ERROR && - errcode == PCAP_ERR_WRONGVER) + /* Yes - is it big enough to be version information? */ + if (plen < sizeof(struct rpcap_authreply)) { - /* - * The server didn't support the version we sent, - * and replied with the maximum version it supports - * if our version was too big or with the version - * we sent if out version was too small. - * - * Do we also support it? - */ - if (!RPCAP_VERSION_IS_SUPPORTED(header.ver)) - { - /* - * No, so there's no version we both support. - * This is an unrecoverable error. - */ - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The server doesn't support any protocol version that we support"); - return -1; - } - - /* - * OK, use that version, and tell our caller to - * try again. - */ - *ver = header.ver; - return -2; + /* No - discard it and fail. */ + (void)rpcap_discard(sockctrl, plen, NULL); + return -1; } + /* Read the reply body */ + if (rpcap_recv(sockctrl, (char *)&authreply, + sizeof(struct rpcap_authreply), &plen, errbuf) == -1) + { + (void)rpcap_discard(sockctrl, plen, NULL); + return -1; + } + + /* Discard the rest of the message, if there is any. */ + if (rpcap_discard(sockctrl, plen, errbuf) == -1) + return -1; + /* - * Other error - unrecoverable. + * Check the minimum and maximum versions for sanity; + * the minimum must be <= the maximum. */ - return -1; + if (authreply.minvers > authreply.maxvers) + { + /* + * Bogus - give up on this server. + */ + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "The server's minimum supported protocol version is greater than its maximum supported protocol version"); + return -1; + } + } + else + { + /* No - it supports only version 0. */ + authreply.minvers = 0; + authreply.maxvers = 0; } /* - * OK, it's an authentication reply, so they're OK with the - * protocol version we sent. - * - * Discard the rest of it. + * OK, let's start with the maximum version the server supports. */ - if (rpcap_discard(sock, header.plen, errbuf) == -1) - return -1; + ourvers = authreply.maxvers; +#if RPCAP_MIN_VERSION != 0 + /* + * If that's less than the minimum version we support, we + * can't communicate. + */ + if (ourvers < RPCAP_MIN_VERSION) + goto novers; +#endif + + /* + * If that's greater than the maximum version we support, + * choose the maximum version we support. + */ + if (ourvers > RPCAP_MAX_VERSION) + { + ourvers = RPCAP_MAX_VERSION; + + /* + * If that's less than the minimum version they + * support, we can't communicate. + */ + if (ourvers < authreply.minvers) + goto novers; + } + + *ver = ourvers; return 0; + +novers: + /* + * There is no version we both support; that is a fatal error. + */ + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "The server doesn't support any protocol version that we support"); + return -1; } /* We don't currently support non-blocking mode. */ @@ -2059,6 +2047,103 @@ pcap_setnonblock_rpcap(pcap_t *p, int nonblock _U_) return (-1); } +static int +rpcap_setup_session(const char *source, struct pcap_rmtauth *auth, + int *activep, SOCKET *sockctrlp, uint8 *protocol_versionp, + char *host, char *port, char *iface, char *errbuf) +{ + int type; + struct activehosts *activeconn; /* active connection, if there is one */ + int error; /* 1 if rpcap_remoteact_getsock got an error */ + + /* + * Determine the type of the source (NULL, file, local, remote). + * You must have a valid source string even if we're in active mode, + * because otherwise the call to the following function will fail. + */ + if (pcap_parsesrcstr(source, &type, host, port, iface, errbuf) == -1) + return -1; + + /* + * It must be remote. + */ + if (type != PCAP_SRC_IFREMOTE) + { + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Non-remote interface passed to remote capture routine"); + return -1; + } + + /* Warning: this call can be the first one called by the user. */ + /* For this reason, we have to initialize the WinSock support. */ + if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1) + return -1; + + /* Check for active mode */ + activeconn = rpcap_remoteact_getsock(host, &error, errbuf); + if (activeconn != NULL) + { + *activep = 1; + *sockctrlp = activeconn->sockctrl; + *protocol_versionp = activeconn->protocol_version; + } + else + { + *activep = 0; + struct addrinfo hints; /* temp variable needed to resolve hostnames into to socket representation */ + struct addrinfo *addrinfo; /* temp variable needed to resolve hostnames into to socket representation */ + + if (error) + { + /* + * Call failed. + */ + return -1; + } + + /* + * We're not in active mode; let's try to open a new + * control connection. + */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if (port[0] == 0) + { + /* the user chose not to specify the port */ + if (sock_initaddress(host, RPCAP_DEFAULT_NETPORT, + &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) + return -1; + } + else + { + if (sock_initaddress(host, port, &hints, &addrinfo, + errbuf, PCAP_ERRBUF_SIZE) == -1) + return -1; + } + + if ((*sockctrlp = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, + errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) + { + freeaddrinfo(addrinfo); + return -1; + } + + /* addrinfo is no longer used */ + freeaddrinfo(addrinfo); + addrinfo = NULL; + + if (rpcap_doauth(*sockctrlp, protocol_versionp, auth, + errbuf) == -1) + { + sock_close(*sockctrlp, NULL, 0); + return -1; + } + } + return 0; +} + /* * This function opens a remote adapter by opening an RPCAP connection and * so on. @@ -2104,15 +2189,12 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim char *source_str; struct pcap_rpcap *pr; /* structure used when doing a remote live capture */ char host[PCAP_BUF_SIZE], ctrlport[PCAP_BUF_SIZE], iface[PCAP_BUF_SIZE]; - struct activehosts *activeconn; /* active connection, if there is one */ - int error; /* '1' if rpcap_remoteact_getsock returned an error */ SOCKET sockctrl; uint8 protocol_version; /* negotiated protocol version */ int active; uint32 plen; char sendbuf[RPCAP_NETBUF_SIZE]; /* temporary buffer in which data to be sent is buffered */ int sendbufidx = 0; /* index which keeps the number of bytes currently buffered */ - int retval; /* store the return value of the functions */ /* RPCAP-related variables */ struct rpcap_header header; /* header of the RPCAP packet */ @@ -2151,100 +2233,16 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim pr->rmt_flags = flags; /* - * determine the type of the source (NULL, file, local, remote) - * You must have a valid source string even if we're in active mode, because otherwise - * the call to the following function will fail. + * Attempt to set up the session with the server. */ - if (pcap_parsesrcstr(fp->opt.device, &retval, host, ctrlport, iface, errbuf) == -1) + if (rpcap_setup_session(fp->opt.device, auth, &active, &sockctrl, + &protocol_version, host, ctrlport, iface, errbuf) == -1) { + /* Session setup failed. */ pcap_close(fp); return NULL; } - if (retval != PCAP_SRC_IFREMOTE) - { - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "This function is able to open only remote interfaces"); - pcap_close(fp); - return NULL; - } - - /* - * Warning: this call can be the first one called by the user. - * For this reason, we have to initialize the WinSock support. - */ - if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1) - { - pcap_close(fp); - return NULL; - } - - /* Check for active mode */ - activeconn = rpcap_remoteact_getsock(host, &error, errbuf); - if (activeconn != NULL) - { - sockctrl = activeconn->sockctrl; - protocol_version = activeconn->protocol_version; - active = 1; - } - else - { - struct addrinfo hints; /* temp, needed to open a socket connection */ - struct addrinfo *addrinfo; /* temp, needed to open a socket connection */ - - if (error) - { - /* - * Call failed. - */ - pcap_close(fp); - return NULL; - } - - /* - * We're not in active mode; let's try to open a new - * control connection. - */ - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - - if (ctrlport[0] == 0) - { - /* the user chose not to specify the port */ - if (sock_initaddress(host, RPCAP_DEFAULT_NETPORT, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) - { - pcap_close(fp); - return NULL; - } - } - else - { - if (sock_initaddress(host, ctrlport, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) - { - pcap_close(fp); - return NULL; - } - } - - if ((sockctrl = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) - { - freeaddrinfo(addrinfo); - pcap_close(fp); - return NULL; - } - - /* addrinfo is no longer used */ - freeaddrinfo(addrinfo); - - if (rpcap_doauth(sockctrl, &protocol_version, auth, errbuf) == -1) - { - sock_close(sockctrl, NULL, 0); - pcap_close(fp); - return NULL; - } - active = 0; - } - /* * Now it's time to start playing with the RPCAP protocol * RPCAP open command: create the request message @@ -2276,7 +2274,7 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim goto error; /* Discard the rest of the message, if there is any. */ - if (rpcap_discard(pr->rmt_sockctrl, plen, errbuf) == -1) + if (rpcap_discard(sockctrl, plen, errbuf) == -1) goto error_nodiscard; /* Set proper fields into the pcap_t struct */ @@ -2314,7 +2312,7 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim * We already reported an error; if this gets an error, just * drive on. */ - (void)rpcap_discard(pr->rmt_sockctrl, plen, NULL); + (void)rpcap_discard(sockctrl, plen, NULL); error_nodiscard: if (!active) @@ -2326,8 +2324,10 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim /* String identifier to be used in the pcap_findalldevs_ex() */ #define PCAP_TEXT_SOURCE_ADAPTER "Network adapter" +#define PCAP_TEXT_SOURCE_ADAPTER_LEN (sizeof PCAP_TEXT_SOURCE_ADAPTER - 1) /* String identifier to be used in the pcap_findalldevs_ex() */ #define PCAP_TEXT_SOURCE_ON_REMOTE_HOST "on remote node" +#define PCAP_TEXT_SOURCE_ON_REMOTE_HOST_LEN (sizeof PCAP_TEXT_SOURCE_ON_REMOTE_HOST - 1) static void freeaddr(struct pcap_addr *addr) @@ -2340,10 +2340,8 @@ freeaddr(struct pcap_addr *addr) } int -pcap_findalldevs_ex_remote(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf) +pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf) { - struct activehosts *activeconn; /* active connection, if there is one */ - int error; /* '1' if rpcap_remoteact_getsock returned an error */ uint8 protocol_version; /* protocol version */ SOCKET sockctrl; /* socket descriptor of the control connection */ uint32 plen; @@ -2351,7 +2349,6 @@ pcap_findalldevs_ex_remote(char *source, struct pcap_rmtauth *auth, pcap_if_t ** int i, j; /* temp variables */ int nif; /* Number of interfaces listed */ int active; /* 'true' if we the other end-party is in active mode */ - int type; char host[PCAP_BUF_SIZE], port[PCAP_BUF_SIZE]; char tmpstring[PCAP_BUF_SIZE + 1]; /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */ pcap_if_t *lastdev; /* Last device in the pcap_if_t list */ @@ -2361,72 +2358,14 @@ pcap_findalldevs_ex_remote(char *source, struct pcap_rmtauth *auth, pcap_if_t ** (*alldevs) = NULL; lastdev = NULL; - /* Retrieve the needed data for getting adapter list */ - if (pcap_parsesrcstr(source, &type, host, port, NULL, errbuf) == -1) - return -1; - - /* Warning: this call can be the first one called by the user. */ - /* For this reason, we have to initialize the WinSock support. */ - if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1) - return -1; - - /* Check for active mode */ - activeconn = rpcap_remoteact_getsock(host, &error, errbuf); - if (activeconn != NULL) + /* + * Attempt to set up the session with the server. + */ + if (rpcap_setup_session(source, auth, &active, &sockctrl, + &protocol_version, host, port, NULL, errbuf) == -1) { - sockctrl = activeconn->sockctrl; - protocol_version = activeconn->protocol_version; - active = 1; - } - else - { - struct addrinfo hints; /* temp variable needed to resolve hostnames into to socket representation */ - struct addrinfo *addrinfo; /* temp variable needed to resolve hostnames into to socket representation */ - - if (error) - { - /* - * Call failed. - */ - return -1; - } - - /* - * We're not in active mode; let's try to open a new - * control connection. - */ - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - - if (port[0] == 0) - { - /* the user chose not to specify the port */ - if (sock_initaddress(host, RPCAP_DEFAULT_NETPORT, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) - return -1; - } - else - { - if (sock_initaddress(host, port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) - return -1; - } - - if ((sockctrl = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) - { - freeaddrinfo(addrinfo); - return -1; - } - - /* addrinfo is no longer used */ - freeaddrinfo(addrinfo); - addrinfo = NULL; - - if (rpcap_doauth(sockctrl, &protocol_version, auth, errbuf) == -1) - { - sock_close(sockctrl, NULL, 0); - return -1; - } - active = 0; + /* Session setup failed. */ + return -1; } /* RPCAP findalldevs command */ @@ -2452,7 +2391,6 @@ pcap_findalldevs_ex_remote(char *source, struct pcap_rmtauth *auth, pcap_if_t ** { struct rpcap_findalldevs_if findalldevs_if; char tmpstring2[PCAP_BUF_SIZE + 1]; /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */ - size_t stringlen; struct pcap_addr *addr, *prevaddr; tmpstring2[PCAP_BUF_SIZE] = 0; @@ -2514,21 +2452,17 @@ pcap_findalldevs_ex_remote(char *source, struct pcap_rmtauth *auth, pcap_if_t ** tmpstring[findalldevs_if.namelen] = 0; /* Create the new device identifier */ - if (pcap_createsrcstr(tmpstring2, PCAP_SRC_IFREMOTE, host, port, tmpstring, errbuf) == -1) - return -1; + if (pcap_createsrcstr(tmpstring2, PCAP_SRC_IFREMOTE, + host, port, tmpstring, errbuf) == -1) + goto error; - stringlen = strlen(tmpstring2); - - dev->name = (char *)malloc(stringlen + 1); + dev->name = strdup(tmpstring2); if (dev->name == NULL) { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "malloc() failed"); goto error; } - - /* Copy the new device name into the correct memory location */ - strlcpy(dev->name, tmpstring2, stringlen + 1); } if (findalldevs_if.desclen) @@ -2546,22 +2480,14 @@ pcap_findalldevs_ex_remote(char *source, struct pcap_rmtauth *auth, pcap_if_t ** tmpstring[findalldevs_if.desclen] = 0; - pcap_snprintf(tmpstring2, sizeof(tmpstring2) - 1, "%s '%s' %s %s", PCAP_TEXT_SOURCE_ADAPTER, - tmpstring, PCAP_TEXT_SOURCE_ON_REMOTE_HOST, host); - - stringlen = strlen(tmpstring2); - - dev->description = (char *)malloc(stringlen + 1); - - if (dev->description == NULL) + if (pcap_asprintf(&dev->description, + "%s '%s' %s %s", PCAP_TEXT_SOURCE_ADAPTER, + tmpstring, PCAP_TEXT_SOURCE_ON_REMOTE_HOST, host) == -1) { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "malloc() failed"); goto error; } - - /* Copy the new device description into the correct memory location */ - strlcpy(dev->description, tmpstring2, stringlen + 1); } dev->flags = ntohl(findalldevs_if.flags); @@ -2648,7 +2574,7 @@ pcap_findalldevs_ex_remote(char *source, struct pcap_rmtauth *auth, pcap_if_t ** /* Discard the rest of the message. */ if (rpcap_discard(sockctrl, plen, errbuf) == 1) - return -1; + goto error_nodiscard; /* Control connection has to be closed only in case the remote machine is in passive mode */ if (!active) @@ -2730,7 +2656,6 @@ SOCKET pcap_remoteact_accept(const char *address, const char *port, const char * { if (sock_initaddress(address, RPCAP_DEFAULT_NETPORT_ACTIVE, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) { - SOCK_DEBUG_MESSAGE(errbuf); return (SOCKET)-2; } } @@ -2738,7 +2663,6 @@ SOCKET pcap_remoteact_accept(const char *address, const char *port, const char * { if (sock_initaddress(address, port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) { - SOCK_DEBUG_MESSAGE(errbuf); return (SOCKET)-2; } } @@ -2746,7 +2670,6 @@ SOCKET pcap_remoteact_accept(const char *address, const char *port, const char * if ((sockmain = sock_open(addrinfo, SOCKOPEN_SERVER, 1, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) { - SOCK_DEBUG_MESSAGE(errbuf); freeaddrinfo(addrinfo); return (SOCKET)-2; } @@ -2764,14 +2687,14 @@ SOCKET pcap_remoteact_accept(const char *address, const char *port, const char * if (sockctrl == INVALID_SOCKET) { - sock_geterror("accept(): ", errbuf, PCAP_ERRBUF_SIZE); + sock_geterror("accept()", errbuf, PCAP_ERRBUF_SIZE); return (SOCKET)-2; } /* Get the numeric for of the name of the connecting host */ if (getnameinfo((struct sockaddr *) &from, fromlen, connectinghost, RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST)) { - sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE); + sock_geterror("getnameinfo()", errbuf, PCAP_ERRBUF_SIZE); rpcap_senderror(sockctrl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL); sock_close(sockctrl, NULL, 0); return (SOCKET)-1; @@ -2970,7 +2893,7 @@ int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf) /* if (getnameinfo( (struct sockaddr *) &temp->host, sizeof (struct sockaddr_storage), hoststr, */ /* RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST) ) */ { - /* sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE); */ + /* sock_geterror("getnameinfo()", errbuf, PCAP_ERRBUF_SIZE); */ return -1; } @@ -2983,7 +2906,7 @@ int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf) return -1; } - strlcat(hostlist, hoststr, PCAP_ERRBUF_SIZE); + pcap_strlcat(hostlist, hoststr, PCAP_ERRBUF_SIZE); hostlist[len - 1] = sep; hostlist[len] = 0; @@ -3110,7 +3033,7 @@ static int rpcap_check_msg_type(SOCKET sock, uint8 request_type, struct rpcap_he } return -1; } - + return 0; } diff --git a/pcap-rpcap.h b/pcap-rpcap.h index be31c40d1831..6ad6d98d6a6d 100644 --- a/pcap-rpcap.h +++ b/pcap-rpcap.h @@ -43,7 +43,7 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, /* * Internal interfaces for "pcap_findalldevs_ex()". */ -int pcap_findalldevs_ex_remote(char *source, struct pcap_rmtauth *auth, - pcap_if_t **alldevs, char *errbuf); +int pcap_findalldevs_ex_remote(const char *source, + struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf); #endif diff --git a/pcap-savefile.manfile.in b/pcap-savefile.manfile.in index 451dd90b7e2f..748d7afcfc55 100644 --- a/pcap-savefile.manfile.in +++ b/pcap-savefile.manfile.in @@ -130,4 +130,4 @@ the packet not been truncated by the snapshot length. The two lengths will be equal if the number of bytes of packet data are less than or equal to the snapshot length. .SH SEE ALSO -pcap(3PCAP), pcap-linktype(@MAN_MISC_INFO@) +pcap(3PCAP) diff --git a/pcap-septel.c b/pcap-septel.c index 0471153fdc7a..24cb47bb3962 100644 --- a/pcap-septel.c +++ b/pcap-septel.c @@ -1,15 +1,6 @@ /* * pcap-septel.c: Packet capture interface for Intel/Septel card. * - * The functionality of this code attempts to mimic that of pcap-linux as much - * as possible. This code is compiled in several different ways depending on - * whether SEPTEL_ONLY and HAVE_SEPTEL_API are defined. If HAVE_SEPTEL_API is - * not defined it should not get compiled in, otherwise if SEPTEL_ONLY is - * defined then the 'septel_' function calls are renamed to 'pcap_' - * equivalents. If SEPTEL_ONLY is not defined then nothing is altered - the - * septel_ functions will be called as required from their - * pcap-linux/equivalents. - * * Authors: Gilbert HOYEK (gil_hoyek@hotmail.com), Elias M. KHOURY * (+961 3 485243) */ @@ -182,7 +173,7 @@ static int septel_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) static int septel_inject(pcap_t *handle, const void *buf _U_, size_t size _U_) { - strlcpy(handle->errbuf, "Sending packets isn't supported on Septel cards", + pcap_strlcpy(handle->errbuf, "Sending packets isn't supported on Septel cards", PCAP_ERRBUF_SIZE); return (-1); } diff --git a/pcap-sita.c b/pcap-sita.c index 7c42791aab8b..b9dda9c55b48 100644 --- a/pcap-sita.c +++ b/pcap-sita.c @@ -884,7 +884,7 @@ static void acn_start_monitor(int fd, int snaplen, int timeout, int promiscuous, } static int pcap_inject_acn(pcap_t *p, const void *buf _U_, size_t size _U_) { - strlcpy(p->errbuf, "Sending packets isn't supported on ACN adapters", + pcap_strlcpy(p->errbuf, "Sending packets isn't supported on ACN adapters", PCAP_ERRBUF_SIZE); return (-1); } diff --git a/pcap-sita.html b/pcap-sita.html index 97408d850a86..4a8fe1a27e8a 100644 --- a/pcap-sita.html +++ b/pcap-sita.html @@ -411,7 +411,7 @@ A { text-decoration:none } Interface ID 1 - A NULL to indicate an an empty 'interface ID'. + A NULL to indicate an empty 'interface ID'. diff --git a/pcap-snf.c b/pcap-snf.c index 4eae0b399316..50d92cd9e217 100644 --- a/pcap-snf.c +++ b/pcap-snf.c @@ -182,8 +182,8 @@ snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) hdr.caplen = caplen; hdr.len = req.length; callback(user, &hdr, req.pkt_addr); + n++; } - n++; /* After one successful packet is received, we won't block * again for that timeout. */ @@ -237,7 +237,7 @@ snf_inject(pcap_t *p, const void *buf _U_, size_t size _U_) return (-1); } #else - strlcpy(p->errbuf, "Sending packets isn't supported with this snf version", + pcap_strlcpy(p->errbuf, "Sending packets isn't supported with this snf version", PCAP_ERRBUF_SIZE); return (-1); #endif diff --git a/pcap-tc.c b/pcap-tc.c index 38c702450462..65fb0e2b4aa7 100644 --- a/pcap-tc.c +++ b/pcap-tc.c @@ -123,7 +123,7 @@ static int TcSetDatalink(pcap_t *p, int dlt); static int TcGetNonBlock(pcap_t *p); static int TcSetNonBlock(pcap_t *p, int nonblock); static void TcCleanup(pcap_t *p); -static int TcInject(pcap_t *p, const void *buf, size_t size); +static int TcInject(pcap_t *p, const void *buf, int size); static int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user); static int TcStats(pcap_t *p, struct pcap_stat *ps); static int TcSetFilter(pcap_t *p, struct bpf_program *fp); @@ -440,7 +440,7 @@ TcFindAllDevs(pcap_if_list_t *devlist, char *errbuf) PTC_PORT pPorts = NULL; TC_STATUS status; int result = 0; - pcap_if_t *dev, *cursor; + pcap_if_t *dev; ULONG i; do @@ -472,22 +472,7 @@ TcFindAllDevs(pcap_if_list_t *devlist, char *errbuf) dev = TcCreatePcapIfFromPort(pPorts[i]); if (dev != NULL) - { - /* - * append it at the end - */ - if (devlistp->beginning == NULL) - { - devlistp->beginning = dev; - } - else - { - for (cursor = devlistp->beginning; - cursor->next != NULL; - cursor = cursor->next); - cursor->next = dev; - } - } + add_dev(devlist, dev->name, dev->flags, dev->description, errbuf); } if (numPorts > 0) @@ -846,7 +831,7 @@ static void TcCleanup(pcap_t *p) } /* Send a packet to the network */ -static int TcInject(pcap_t *p, const void *buf, size_t size) +static int TcInject(pcap_t *p, const void *buf, int size) { struct pcap_tc *pt = p->priv; TC_STATUS status; diff --git a/pcap-tstamp.manmisc.in b/pcap-tstamp.manmisc.in index 38c56518334e..6437e80e64e7 100644 --- a/pcap-tstamp.manmisc.in +++ b/pcap-tstamp.manmisc.in @@ -93,9 +93,9 @@ call and before a call to specify the type of time stamp to be used on the device. The time stamp types are listed here; the first value is the #define to use in code, the second value is the value returned by -.B pcap_tstamp_type_val_to_name() +.B pcap_tstamp_type_val_to_name(3PCAP) and accepted by -.BR pcap_tstamp_type_name_to_val() . +.BR pcap_tstamp_type_name_to_val(3PCAP) . .RS 5 .TP 5 .BR PCAP_TSTAMP_HOST " - " host @@ -149,9 +149,9 @@ call will fail, and the time stamps supplied after the call will have microsecond resolution. .LP When opening a savefile, the -.BR pcap_open_offline_with_tstamp_precision (3PCAP) +.BR \%pcap_open_offline_with_tstamp_precision (3PCAP) and -.BR pcap_fopen_offline_with_tstamp_precision (3PCAP) +.BR \%pcap_fopen_offline_with_tstamp_precision (3PCAP) routines can be used to specify the resolution of time stamps to be read from the file; if the time stamps in the file have a lower resolution, the fraction-of-a-second portion of the time stamps will be scaled to @@ -165,13 +165,4 @@ the time stamp supplied by the hardware or operating system and, when reading a savefile, this does not indicate the actual precision of time stamps in the file. .SH SEE ALSO -.na -pcap_set_tstamp_type(3PCAP), -pcap_list_tstamp_types(3PCAP), -pcap_tstamp_type_val_to_name(3PCAP), -pcap_tstamp_type_name_to_val(3PCAP), -pcap_set_tstamp_precision(3PCAP), -pcap_open_offline_with_tstamp_precision(3PCAP), -\%pcap_fopen_offline_with_tstamp_precision(3PCAP), -\%pcap_get_tstamp_precision(3PCAP) -.ad +pcap(3PCAP) diff --git a/pcap-usb-linux.c b/pcap-usb-linux.c index 6f8adf65eab5..b306dca9b951 100644 --- a/pcap-usb-linux.c +++ b/pcap-usb-linux.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -241,7 +242,7 @@ usb_dev_add(pcap_if_list_t *devlistp, int n, char *err_str) */ if (add_dev(devlistp, dev_name, PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, - "All USB buses", err_str) == NULL) + "Raw USB traffic, all USB buses", err_str) == NULL) return -1; } else { /* @@ -250,7 +251,7 @@ usb_dev_add(pcap_if_list_t *devlistp, int n, char *err_str) * PCAP_IF_CONNECTION_STATUS_CONNECTED or * PCAP_IF_CONNECTION_STATUS_DISCONNECTED? */ - pcap_snprintf(dev_descr, 30, "USB bus number %d", n); + pcap_snprintf(dev_descr, 30, "Raw USB traffic, bus number %d", n); if (add_dev(devlistp, dev_name, 0, dev_descr, err_str) == NULL) return -1; } @@ -278,7 +279,7 @@ usb_findalldevs(pcap_if_list_t *devlistp, char *err_str) * Split LINUX_USB_MON_DEV into a directory that we'll * scan and a file name prefix that we'll check for. */ - strlcpy(usb_mon_dir, LINUX_USB_MON_DEV, sizeof usb_mon_dir); + pcap_strlcpy(usb_mon_dir, LINUX_USB_MON_DEV, sizeof usb_mon_dir); usb_mon_prefix = strrchr(usb_mon_dir, '/'); if (usb_mon_prefix == NULL) { /* @@ -380,18 +381,102 @@ usb_findalldevs(pcap_if_list_t *devlistp, char *err_str) } } +/* + * Matches what's in mon_bin.c in the Linux kernel. + */ +#define MIN_RING_SIZE (8*1024) +#define MAX_RING_SIZE (1200*1024) + +static int +usb_set_ring_size(pcap_t* handle, int header_size) +{ + /* + * A packet from binary usbmon has: + * + * 1) a fixed-length header, of size header_size; + * 2) descriptors, for isochronous transfers; + * 3) the payload. + * + * The kernel buffer has a size, defaulting to 300KB, with a + * minimum of 8KB and a maximum of 1200KB. The size is set with + * the MON_IOCT_RING_SIZE ioctl; the size passed in is rounded up + * to a page size. + * + * No more than {buffer size}/5 bytes worth of payload is saved. + * Therefore, if we subtract the fixed-length size from the + * snapshot length, we have the biggest payload we want (we + * don't worry about the descriptors - if we have descriptors, + * we'll just discard the last bit of the payload to get it + * to fit). We multiply that result by 5 and set the buffer + * size to that value. + */ + int ring_size; + + if (handle->snapshot < header_size) + handle->snapshot = header_size; + /* The maximum snapshot size is small enough that this won't overflow */ + ring_size = (handle->snapshot - header_size) * 5; + + /* + * Will this get an error? + * (There's no wqy to query the minimum or maximum, so we just + * copy the value from the kernel source. We don't round it + * up to a multiple of the page size.) + */ + if (ring_size > MAX_RING_SIZE) { + /* + * Yes. Lower the ring size to the maximum, and set the + * snapshot length to the value that would give us a + * maximum-size ring. + */ + ring_size = MAX_RING_SIZE; + handle->snapshot = header_size + (MAX_RING_SIZE/5); + } else if (ring_size < MIN_RING_SIZE) { + /* + * Yes. Raise the ring size to the minimum, but leave + * the snapshot length unchanged, so we show the + * callback no more data than specified by the + * snapshot length. + */ + ring_size = MIN_RING_SIZE; + } + + if (ioctl(handle->fd, MON_IOCT_RING_SIZE, ring_size) == -1) { + pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't set ring size from fd %d", handle->fd); + return -1; + } + return ring_size; +} + static int usb_mmap(pcap_t* handle) { struct pcap_usb_linux *handlep = handle->priv; - int len = ioctl(handle->fd, MON_IOCQ_RING_SIZE); - if (len < 0) + int len; + + /* + * Attempt to set the ring size as appropriate for the snapshot + * length, reducing the snapshot length if that'd make the ring + * bigger than the kernel supports. + */ + len = usb_set_ring_size(handle, (int)sizeof(pcap_usb_header_mmapped)); + if (len == -1) { + /* Failed. Fall back on non-memory-mapped access. */ return 0; + } handlep->mmapbuflen = len; handlep->mmapbuf = mmap(0, handlep->mmapbuflen, PROT_READ, MAP_SHARED, handle->fd, 0); - return handlep->mmapbuf != MAP_FAILED; + if (handlep->mmapbuf == MAP_FAILED) { + /* + * Failed. We don't treat that as a fatal error, we + * just try to fall back on non-memory-mapped access. + */ + return 0; + } + return 1; } #ifdef HAVE_LINUX_USBDEVICE_FS_H @@ -514,6 +599,7 @@ usb_activate(pcap_t* handle) { struct pcap_usb_linux *handlep = handle->priv; char full_path[USB_LINE_LEN]; + int ret; /* * Turn a negative snapshot value (invalid), a snapshot value of @@ -604,6 +690,7 @@ usb_activate(pcap_t* handle) /* try to use fast mmap access */ if (usb_mmap(handle)) { + /* We succeeded. */ handle->linktype = DLT_USB_LINUX_MMAPPED; handle->stats_op = usb_stats_linux_bin; handle->read_op = usb_read_linux_mmap; @@ -620,7 +707,19 @@ usb_activate(pcap_t* handle) return 0; } - /* can't mmap, use plain binary interface access */ + /* + * We failed; try plain binary interface access. + * + * Attempt to set the ring size as appropriate for + * the snapshot length, reducing the snapshot length + * if that'd make the ring bigger than the kernel + * supports. + */ + if (usb_set_ring_size(handle, (int)sizeof(pcap_usb_header)) == -1) { + /* Failed. */ + close(handle->fd); + return PCAP_ERROR; + } handle->stats_op = usb_stats_linux_bin; handle->read_op = usb_read_linux_bin; #ifdef HAVE_LINUX_USBDEVICE_FS_H @@ -646,38 +745,38 @@ usb_activate(pcap_t* handle) handle->fd = open(full_path, O_RDONLY, 0); } if (handle->fd < 0) { - /* - * Is the problem that we didn't have - * sufficient permission to open it? - */ - if (errno == EACCES) { + if (errno == ENOENT) + { /* - * Yes - return that error. + * The problem is that the file + * doesn't exist. Report that as + * "no such device". (That could + * mean "no such USB bus" or + * "monitoring not supported".) */ - return PCAP_ERROR_PERM_DENIED; + ret = PCAP_ERROR_NO_SUCH_DEVICE; } - - /* - * No - was the problem something other - * than "it doesn't exist"? - */ - if (errno != ENOENT) { + else if (errno == EACCES) + { /* - * Yes - return *that* error. + * The problem is that we don't + * have sufficient permission to + * open the file. Report that. */ - pcap_fmt_errmsg_for_errno(handle->errbuf, - PCAP_ERRBUF_SIZE, errno, - "Can't open USB bus file %s", - full_path); - return PCAP_ERROR; + ret = PCAP_ERROR_PERM_DENIED; } - - /* - * No. Report that as "no such device". - * (That could mean "no such USB bus" - * or "monitoring not supported".) - */ - return PCAP_ERROR_NO_SUCH_DEVICE; + else + { + /* + * Some other error. + */ + ret = PCAP_ERROR; + } + pcap_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "Can't open USB bus file %s", + full_path); + return ret; } } @@ -923,8 +1022,8 @@ usb_read_linux(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_cha static int usb_inject_linux(pcap_t *handle, const void *buf _U_, size_t size _U_) { - pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on " - "USB devices"); + pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Packet injection is not supported on USB devices"); return (-1); } @@ -973,6 +1072,10 @@ usb_stats_linux(pcap_t *handle, struct pcap_stat *stats) } string[ret] = 0; + stats->ps_recv = handlep->packets_read; + stats->ps_drop = 0; /* unless we find text_lost */ + stats->ps_ifdrop = 0; + /* extract info on dropped urbs */ for (consumed=0; consumed < ret; ) { /* from the sscanf man page: @@ -989,18 +1092,16 @@ usb_stats_linux(pcap_t *handle, struct pcap_stat *stats) break; consumed += cnt; ptr += cnt; - if (strcmp(token, "nreaders") == 0) - ret = sscanf(ptr, "%d", &stats->ps_drop); + if (strcmp(token, "text_lost") == 0) + ntok = sscanf(ptr, "%d%n", &stats->ps_drop, &cnt); else - ret = sscanf(ptr, "%d", &dummy); - if (ntok != 1) + ntok = sscanf(ptr, "%d%n", &dummy, &cnt); + if ((ntok != 1) || (cnt < 0)) break; consumed += cnt; ptr += cnt; } - stats->ps_recv = handlep->packets_read; - stats->ps_ifdrop = 0; return 0; } @@ -1069,13 +1170,44 @@ usb_read_linux_bin(pcap_t *handle, int max_packets _U_, pcap_handler callback, u return -1; } - /* we can get less that than really captured from kernel, depending on - * snaplen, so adjust header accordingly */ + /* + * info.hdr->data_len is the number of bytes of isochronous + * descriptors (if any) plus the number of bytes of data + * provided. There are no isochronous descriptors here, + * because we're using the old 48-byte header. + * + * If info.hdr->data_flag is non-zero, there's no URB data; + * info.hdr->urb_len is the size of the buffer into which + * data is to be placed; it does not represent the amount + * of data transferred. If info.hdr->data_flag is zero, + * there is URB data, and info.hdr->urb_len is the number + * of bytes transmitted or received; it doesn't include + * isochronous descriptors. + * + * The kernel may give us more data than the snaplen; if it did, + * reduce the data length so that the total number of bytes we + * tell our client we have is not greater than the snaplen. + */ if (info.hdr->data_len < clen) clen = info.hdr->data_len; info.hdr->data_len = clen; - pkth.caplen = clen + sizeof(pcap_usb_header); - pkth.len = info.hdr->data_len + sizeof(pcap_usb_header); + pkth.caplen = sizeof(pcap_usb_header) + clen; + if (info.hdr->data_flag) { + /* + * No data; just base the on-the-wire length on + * info.hdr->data_len (so that it's >= the captured + * length). + */ + pkth.len = sizeof(pcap_usb_header) + info.hdr->data_len; + } else { + /* + * We got data; base the on-the-wire length on + * info.hdr->urb_len, so that it includes data + * discarded by the USB monitor device due to + * its buffer being too small. + */ + pkth.len = sizeof(pcap_usb_header) + info.hdr->urb_len; + } pkth.ts.tv_sec = info.hdr->ts_sec; pkth.ts.tv_usec = info.hdr->ts_usec; @@ -1102,12 +1234,12 @@ usb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_ch struct mon_bin_mfetch fetch; int32_t vec[VEC_SIZE]; struct pcap_pkthdr pkth; - pcap_usb_header* hdr; + pcap_usb_header_mmapped* hdr; int nflush = 0; int packets = 0; u_int clen, max_clen; - max_clen = handle->snapshot - sizeof(pcap_usb_header); + max_clen = handle->snapshot - sizeof(pcap_usb_header_mmapped); for (;;) { int i, ret; @@ -1145,19 +1277,52 @@ usb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_ch nflush = fetch.nfetch; for (i=0; immapbuf[vec[i]]; + hdr = (pcap_usb_header_mmapped*) &handlep->mmapbuf[vec[i]]; if (hdr->event_type == '@') continue; - /* we can get less that than really captured from kernel, depending on - * snaplen, so adjust header accordingly */ + /* + * hdr->data_len is the number of bytes of + * isochronous descriptors (if any) plus the + * number of bytes of data provided. + * + * If hdr->data_flag is non-zero, there's no + * URB data; hdr->urb_len is the size of the + * buffer into which data is to be placed; it does + * not represent the amount of data transferred. + * If hdr->data_flag is zero, there is URB data, + * and hdr->urb_len is the number of bytes + * transmitted or received; it doesn't include + * isochronous descriptors. + * + * The kernel may give us more data than the + * snaplen; if it did, reduce the data length + * so that the total number of bytes we + * tell our client we have is not greater than + * the snaplen. + */ clen = max_clen; if (hdr->data_len < clen) clen = hdr->data_len; - - /* get packet info from header*/ - pkth.caplen = clen + sizeof(pcap_usb_header_mmapped); - pkth.len = hdr->data_len + sizeof(pcap_usb_header_mmapped); + pkth.caplen = sizeof(pcap_usb_header_mmapped) + clen; + if (hdr->data_flag) { + /* + * No data; just base the on-the-wire length + * on hdr->data_len (so that it's >= the + * captured length). + */ + pkth.len = sizeof(pcap_usb_header_mmapped) + + hdr->data_len; + } else { + /* + * We got data; base the on-the-wire length + * on hdr->urb_len, so that it includes + * data discarded by the USB monitor device + * due to its buffer being too small. + */ + pkth.len = sizeof(pcap_usb_header_mmapped) + + (hdr->ndesc * sizeof (usb_isodesc)) + hdr->urb_len; + } pkth.ts.tv_sec = hdr->ts_sec; pkth.ts.tv_usec = hdr->ts_usec; diff --git a/pcap.3pcap.in b/pcap.3pcap.in index cf15941210bc..80101403b2b6 100644 --- a/pcap.3pcap.in +++ b/pcap.3pcap.in @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP 3PCAP "20 January 2017" +.TH PCAP 3PCAP "25 July 2018" .SH NAME pcap \- Packet Capture library .SH SYNOPSIS @@ -181,7 +181,7 @@ negative value is unpredictable. the packet buffer timeout cannot be used to cause calls that read packets to return within a limited period of time, because, on some platforms, the packet buffer timeout isn't supported, and, on other -platforms, the timer doesn't start until at least one packet arrives. +platforms, the timer doesn't start until at least one packet arrives. This means that the packet buffer timeout should .B NOT be used, for example, in an interactive application to allow the packet @@ -191,6 +191,10 @@ expires even if no packets have arrived. .IP The packet buffer timeout is set with .BR pcap_set_timeout (). +.IP "immediate mode" +In immediate mode, packets are always delivered as soon as they arrive, +with no buffering. Immediate mode is set with +.BR pcap_set_immediate_mode (). .IP "buffer size" Packets that arrive for a capture are stored in a buffer, so that they do not have to be read by the application as soon as they arrive. On @@ -304,7 +308,7 @@ link-layer header whose contents can differ for different network interfaces. To determine the format of the packets supplied by the handle, call .BR pcap_datalink (); -.I http://www.tcpdump.org/linktypes.html +.I https://www.tcpdump.org/linktypes.html lists the values it returns and describes the packet formats that correspond to those values. .PP @@ -396,7 +400,7 @@ set promiscuous mode for a not-yet-activated .B pcap_t for live capture .TP -.BR pcap_set_protocol (3PCAP) +.BR pcap_set_protocol_linux (3PCAP) set capture protocol for a not-yet-activated .B pcap_t for live capture (Linux only) @@ -416,6 +420,11 @@ set packet buffer timeout for a not-yet-activated .B pcap_t for live capture .TP +.BR pcap_set_immediate_mode (3PCAP) +set immediate mode for a not-yet-activated +.B pcap_t +for live capture +.TP .BR pcap_set_buffer_size (3PCAP) set buffer size for a not-yet-activated .B pcap_t @@ -632,9 +641,28 @@ or other routines a platform offers to wait for any of a set of descriptors to be ready to read. To obtain, for a handle, a descriptor that can be used in those routines, call .BR pcap_get_selectable_fd (). +If the routine indicates that data is +available to read on the descriptor, an attempt should be made to read +from the device. +.PP Not all handles have such a descriptor available; .BR pcap_get_selectable_fd () -will return \-1 if no such descriptor exists. In addition, for various +will return +.B PCAP_ERROR +if no such descriptor is available. If no such +descriptor is available, this may be because the device must be polled +periodically for packets; in that case, +.BR pcap_get_required_select_timeout () +will return a pointer to a +.B struct timeval +whose value can be used as a timeout in those routines. When the +routine returns, an attmept should be made to read packets from the +device. If +.BR pcap_get_required_select_timeout () +returns NULL, no such timeout is available, and those routines cannot be +used with the device. +.PP +In addition, for various reasons, one or more of those routines will not work properly with the descriptor; the documentation for .BR pcap_get_selectable_fd () @@ -693,6 +721,15 @@ that can be used in calls such as .BR select (2) and .BR poll (2) +.TP +.BR pcap_get_required_select_timeout (3PCAP) +if no descriptor usable with +.BR select (2) +and +.BR poll (2) +is available for the +.BR pcap_t , +attempt to get a timeout usable with those routines .RE .SS Filters In order to cause only certain packets to be returned when reading @@ -890,7 +927,7 @@ To get a string giving version information about libpcap, call .BR pcap_lib_version (3PCAP) get library version string .RE -.SH BACKWARDS COMPATIBILITY +.SH BACKWARD COMPATIBILITY .PP In versions of libpcap prior to 1.0, the .B pcap.h @@ -934,7 +971,7 @@ Lawrence Berkeley National Laboratory, University of California, Berkeley, CA. The current version is available from "The Tcpdump Group"'s Web site at .LP .RS -.I http://www.tcpdump.org/ +.I https://www.tcpdump.org/ .RE .SH BUGS To report a security issue please send an e-mail to security@tcpdump.org. diff --git a/pcap.c b/pcap.c index 3337bcb3196a..5c8b51a25074 100644 --- a/pcap.c +++ b/pcap.c @@ -139,7 +139,7 @@ BOOL WINAPI DllMain( /* * Start WinSock. - * Exported in case some applications using WinPcap called it, + * Exported in case some applications using WinPcap/Npcap called it, * even though it wasn't exported. */ int @@ -186,76 +186,165 @@ pcap_wsockinit(void) PCAP_API char pcap_version[]; PCAP_API_DEF char pcap_version[] = PACKAGE_VERSION; -static int -pcap_not_initialized(pcap_t *pcap) +static void +pcap_set_not_initialized_message(pcap_t *pcap) { if (pcap->activated) { /* A module probably forgot to set the function pointer */ (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), "This operation isn't properly handled by that device"); - return (PCAP_ERROR); + return; } /* in case the caller doesn't check for PCAP_ERROR_NOT_ACTIVATED */ (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), "This handle hasn't been activated yet"); +} + +static int +pcap_read_not_initialized(pcap_t *pcap, int cnt _U_, pcap_handler callback _U_, + u_char *user _U_) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_inject_not_initialized(pcap_t *pcap, const void * buf _U_, size_t size _U_) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_setfilter_not_initialized(pcap_t *pcap, struct bpf_program *fp _U_) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_setdirection_not_initialized(pcap_t *pcap, pcap_direction_t d _U_) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_set_datalink_not_initialized(pcap_t *pcap, int dlt _U_) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_getnonblock_not_initialized(pcap_t *pcap) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_stats_not_initialized(pcap_t *pcap, struct pcap_stat *ps _U_) +{ + pcap_set_not_initialized_message(pcap); /* this means 'not initialized' */ return (PCAP_ERROR_NOT_ACTIVATED); } #ifdef _WIN32 -static void * -pcap_not_initialized_ptr(pcap_t *pcap) +struct pcap_stat * +pcap_stats_ex_not_initialized(pcap_t *pcap, int *pcap_stat_size _U_) { - if (pcap->activated) { - /* A module probably forgot to set the function pointer */ - (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), - "This operation isn't properly handled by that device"); - return (NULL); - } - (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), - "This handle hasn't been activated yet"); + pcap_set_not_initialized_message(pcap); return (NULL); } +static int +pcap_setbuff_not_initialized(pcap_t *pcap, int dim _U_) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_setmode_not_initialized(pcap_t *pcap, int mode _U_) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_setmintocopy_not_initialized(pcap_t *pcap, int size _U_) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + static HANDLE pcap_getevent_not_initialized(pcap_t *pcap) { - if (pcap->activated) { - /* A module probably forgot to set the function pointer */ - (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), - "This operation isn't properly handled by that device"); - return (INVALID_HANDLE_VALUE); - } - (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), - "This handle hasn't been activated yet"); + pcap_set_not_initialized_message(pcap); return (INVALID_HANDLE_VALUE); } +static int +pcap_oid_get_request_not_initialized(pcap_t *pcap, bpf_u_int32 oid _U_, + void *data _U_, size_t *lenp _U_) +{ + pcap_set_not_initialized_message(pcap); + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_oid_set_request_not_initialized(pcap_t *pcap, bpf_u_int32 oid _U_, + const void *data _U_, size_t *lenp _U_) +{ + pcap_set_not_initialized_message(pcap); + return (PCAP_ERROR_NOT_ACTIVATED); +} + static u_int pcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue, int sync) { - if (pcap->activated) { - /* A module probably forgot to set the function pointer */ - (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), - "This operation isn't properly handled by that device"); - return (0); - } - (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), - "This handle hasn't been activated yet"); + pcap_set_not_initialized_message(pcap); return (0); } +static int +pcap_setuserbuffer_not_initialized(pcap_t *pcap, int size _U_) +{ + pcap_set_not_initialized_message(pcap); + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_live_dump_not_initialized(pcap_t *pcap, char *filename _U_, int maxsize _U_, + int maxpacks _U_) +{ + pcap_set_not_initialized_message(pcap); + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_live_dump_ended_not_initialized(pcap_t *pcap, int sync _U_) +{ + pcap_set_not_initialized_message(pcap); + return (PCAP_ERROR_NOT_ACTIVATED); +} + static PAirpcapHandle pcap_get_airpcap_handle_not_initialized(pcap_t *pcap) { - if (pcap->activated) { - /* A module probably forgot to set the function pointer */ - (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), - "This operation isn't properly handled by that device"); - return (NULL); - } - (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf), - "This handle hasn't been activated yet"); + pcap_set_not_initialized_message(pcap); return (NULL); } #endif @@ -296,8 +385,17 @@ pcap_list_tstamp_types(pcap_t *p, int **tstamp_typesp) if (p->tstamp_type_count == 0) { /* * We don't support multiple time stamp types. + * That means the only type we support is PCAP_TSTAMP_HOST; + * set up a list containing only that type. */ - *tstamp_typesp = NULL; + *tstamp_typesp = (int*)malloc(sizeof(**tstamp_typesp)); + if (*tstamp_typesp == NULL) { + pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "malloc"); + return (PCAP_ERROR); + } + **tstamp_typesp = PCAP_TSTAMP_HOST; + return (1); } else { *tstamp_typesp = (int*)calloc(sizeof(**tstamp_typesp), p->tstamp_type_count); @@ -308,8 +406,8 @@ pcap_list_tstamp_types(pcap_t *p, int **tstamp_typesp) } (void)memcpy(*tstamp_typesp, p->tstamp_type_list, sizeof(**tstamp_typesp) * p->tstamp_type_count); + return (p->tstamp_type_count); } - return (p->tstamp_type_count); } /* @@ -659,7 +757,7 @@ get_if_description(const char *name) * Get the description for the interface. */ memset(&ifrdesc, 0, sizeof ifrdesc); - strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name); + pcap_strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name); s = socket(AF_INET, SOCK_DGRAM, 0); if (s >= 0) { #ifdef __FreeBSD__ @@ -710,7 +808,7 @@ get_if_description(const char *name) } #endif /* __FreeBSD__ */ close(s); - if (description != NULL && strlen(description) == 0) { + if (description != NULL && description[0] == '\0') { /* * Description is empty, so discard it. */ @@ -741,20 +839,13 @@ get_if_description(const char *name) * OK, it's a valid number that's not * bigger than INT_MAX. Construct * a description from it. + * (If that fails, we don't worry about + * it, we just return NULL.) */ - static const char descr_prefix[] = "USB bus number "; - size_t descr_size; - - /* - * Allow enough room for a 32-bit bus number. - * sizeof (descr_prefix) includes the - * terminating NUL. - */ - descr_size = sizeof (descr_prefix) + 10; - description = malloc(descr_size); - if (description != NULL) { - pcap_snprintf(description, descr_size, - "%s%ld", descr_prefix, busnum); + if (pcap_asprintf(&description, + "USB bus number %ld", busnum) == -1) { + /* Failed. */ + description = NULL; } } } @@ -1292,14 +1383,14 @@ pcap_lookupdev(char *errbuf) * on the list, there aren't any non-loopback devices, * so why not just supply it as the default device? */ - (void)strlcpy(errbuf, "no suitable device found", + (void)pcap_strlcpy(errbuf, "no suitable device found", PCAP_ERRBUF_SIZE); ret = NULL; } else { /* * Return the name of the first device on the list. */ - (void)strlcpy(device, alldevs->name, sizeof(device)); + (void)pcap_strlcpy(device, alldevs->name, sizeof(device)); ret = device; } @@ -1366,7 +1457,7 @@ pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp, /* XXX Work around Linux kernel bug */ ifr.ifr_addr.sa_family = AF_INET; #endif - (void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + (void)pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) { if (errno == EADDRNOTAVAIL) { (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, @@ -1385,7 +1476,7 @@ pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp, /* XXX Work around Linux kernel bug */ ifr.ifr_addr.sa_family = AF_INET; #endif - (void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + (void)pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "SIOCGIFNETMASK: %s", device); @@ -1575,13 +1666,14 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop, * the pathname. */ if (pcap_strcasecmp(scheme, "file") == 0) { - *schemep = scheme; *pathp = strdup(colonp + 3); if (*pathp == NULL) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc"); + free(scheme); return (-1); } + *schemep = scheme; return (0); } @@ -1684,7 +1776,12 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop, * Treat verything up to the closing square * bracket as the IP-Literal; we don't worry * about whether it's a valid IPv6address or - * IPvFuture. + * IPvFuture (or an IPv4address, for that + * matter, just in case we get handed a + * URL with an IPv4 IP-Literal, of the sort + * that pcap_createsrcstr() used to generate, + * and that pcap_parsesrcstr(), in the original + * WinPcap code, accepted). */ bracketp = strchr(parsep, ']'); if (bracketp == NULL) { @@ -1805,9 +1902,9 @@ pcap_createsrcstr(char *source, int type, const char *host, const char *port, switch (type) { case PCAP_SRC_FILE: - strlcpy(source, PCAP_SRC_FILE_STRING, PCAP_BUF_SIZE); + pcap_strlcpy(source, PCAP_SRC_FILE_STRING, PCAP_BUF_SIZE); if (name != NULL && *name != '\0') { - strlcat(source, name, PCAP_BUF_SIZE); + pcap_strlcat(source, name, PCAP_BUF_SIZE); return (0); } else { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, @@ -1816,7 +1913,7 @@ pcap_createsrcstr(char *source, int type, const char *host, const char *port, } case PCAP_SRC_IFREMOTE: - strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE); + pcap_strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE); if (host != NULL && *host != '\0') { if (strchr(host, ':') != NULL) { /* @@ -1824,18 +1921,18 @@ pcap_createsrcstr(char *source, int type, const char *host, const char *port, * probably an IPv6 address, and needs to * be included in square brackets. */ - strlcat(source, "[", PCAP_BUF_SIZE); - strlcat(source, host, PCAP_BUF_SIZE); - strlcat(source, "]", PCAP_BUF_SIZE); + pcap_strlcat(source, "[", PCAP_BUF_SIZE); + pcap_strlcat(source, host, PCAP_BUF_SIZE); + pcap_strlcat(source, "]", PCAP_BUF_SIZE); } else - strlcat(source, host, PCAP_BUF_SIZE); + pcap_strlcat(source, host, PCAP_BUF_SIZE); if (port != NULL && *port != '\0') { - strlcat(source, ":", PCAP_BUF_SIZE); - strlcat(source, port, PCAP_BUF_SIZE); + pcap_strlcat(source, ":", PCAP_BUF_SIZE); + pcap_strlcat(source, port, PCAP_BUF_SIZE); } - strlcat(source, "/", PCAP_BUF_SIZE); + pcap_strlcat(source, "/", PCAP_BUF_SIZE); } else { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The host name cannot be NULL."); @@ -1843,15 +1940,15 @@ pcap_createsrcstr(char *source, int type, const char *host, const char *port, } if (name != NULL && *name != '\0') - strlcat(source, name, PCAP_BUF_SIZE); + pcap_strlcat(source, name, PCAP_BUF_SIZE); return (0); case PCAP_SRC_IFLOCAL: - strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE); + pcap_strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE); if (name != NULL && *name != '\0') - strlcat(source, name, PCAP_BUF_SIZE); + pcap_strlcat(source, name, PCAP_BUF_SIZE); return (0); @@ -1890,7 +1987,7 @@ pcap_parsesrcstr(const char *source, int *type, char *host, char *port, * Local device. */ if (name && tmppath) - strlcpy(name, tmppath, PCAP_BUF_SIZE); + pcap_strlcpy(name, tmppath, PCAP_BUF_SIZE); if (type) *type = PCAP_SRC_IFLOCAL; free(tmppath); @@ -1912,12 +2009,12 @@ pcap_parsesrcstr(const char *source, int *type, char *host, char *port, pcap_snprintf(host, PCAP_BUF_SIZE, "%s@%s", tmpuserinfo, tmphost); else - strlcpy(host, tmphost, PCAP_BUF_SIZE); + pcap_strlcpy(host, tmphost, PCAP_BUF_SIZE); } if (port && tmpport) - strlcpy(port, tmpport, PCAP_BUF_SIZE); + pcap_strlcpy(port, tmpport, PCAP_BUF_SIZE); if (name && tmppath) - strlcpy(name, tmppath, PCAP_BUF_SIZE); + pcap_strlcpy(name, tmppath, PCAP_BUF_SIZE); if (type) *type = PCAP_SRC_IFREMOTE; free(tmppath); @@ -1933,7 +2030,7 @@ pcap_parsesrcstr(const char *source, int *type, char *host, char *port, * file:// */ if (name && tmppath) - strlcpy(name, tmppath, PCAP_BUF_SIZE); + pcap_strlcpy(name, tmppath, PCAP_BUF_SIZE); if (type) *type = PCAP_SRC_FILE; free(tmppath); @@ -1949,7 +2046,7 @@ pcap_parsesrcstr(const char *source, int *type, char *host, char *port, * as a local device. */ if (name) - strlcpy(name, source, PCAP_BUF_SIZE); + pcap_strlcpy(name, source, PCAP_BUF_SIZE); if (type) *type = PCAP_SRC_IFLOCAL; free(tmppath); @@ -1981,11 +2078,28 @@ pcap_create(const char *device, char *errbuf) else { #ifdef _WIN32 /* - * If the string appears to be little-endian UCS-2/UTF-16, - * convert it to ASCII. + * On Windows, for backwards compatibility reasons, + * pcap_lookupdev() returns a pointer to a sequence of + * pairs of UTF-16LE device names and local code page + * description strings. * - * XXX - to UTF-8 instead? Or report an error if any - * character isn't ASCII? + * This means that if a program uses pcap_lookupdev() + * to get a default device, and hands that to an API + * that opens devices, we'll get handed a UTF-16LE + * string, not a string in the local code page. + * + * To work around that, we check whether the string + * looks as if it might be a UTF-16LE strinh and, if + * so, convert it back to the local code page's + * extended ASCII. + * + * XXX - you *cannot* reliably detect whether a + * string is UTF-16LE or not; "a" could either + * be a one-character ASCII string or the first + * character of a UTF-16LE string. This particular + * version of this heuristic dates back to WinPcap + * 4.1.1; PacketOpenAdapter() does uses the same + * heuristic, with the exact same vulnerability. */ if (device[0] != '\0' && device[1] == '\0') { size_t length; @@ -2077,25 +2191,25 @@ initialize_ops(pcap_t *p) * an activated pcap_t to point to a routine that returns * a "this isn't activated" error. */ - p->read_op = (read_op_t)pcap_not_initialized; - p->inject_op = (inject_op_t)pcap_not_initialized; - p->setfilter_op = (setfilter_op_t)pcap_not_initialized; - p->setdirection_op = (setdirection_op_t)pcap_not_initialized; - p->set_datalink_op = (set_datalink_op_t)pcap_not_initialized; - p->getnonblock_op = (getnonblock_op_t)pcap_not_initialized; - p->stats_op = (stats_op_t)pcap_not_initialized; + p->read_op = pcap_read_not_initialized; + p->inject_op = pcap_inject_not_initialized; + p->setfilter_op = pcap_setfilter_not_initialized; + p->setdirection_op = pcap_setdirection_not_initialized; + p->set_datalink_op = pcap_set_datalink_not_initialized; + p->getnonblock_op = pcap_getnonblock_not_initialized; + p->stats_op = pcap_stats_not_initialized; #ifdef _WIN32 - p->stats_ex_op = (stats_ex_op_t)pcap_not_initialized_ptr; - p->setbuff_op = (setbuff_op_t)pcap_not_initialized; - p->setmode_op = (setmode_op_t)pcap_not_initialized; - p->setmintocopy_op = (setmintocopy_op_t)pcap_not_initialized; + p->stats_ex_op = pcap_stats_ex_not_initialized; + p->setbuff_op = pcap_setbuff_not_initialized; + p->setmode_op = pcap_setmode_not_initialized; + p->setmintocopy_op = pcap_setmintocopy_not_initialized; p->getevent_op = pcap_getevent_not_initialized; - p->oid_get_request_op = (oid_get_request_op_t)pcap_not_initialized; - p->oid_set_request_op = (oid_set_request_op_t)pcap_not_initialized; + p->oid_get_request_op = pcap_oid_get_request_not_initialized; + p->oid_set_request_op = pcap_oid_set_request_not_initialized; p->sendqueue_transmit_op = pcap_sendqueue_transmit_not_initialized; - p->setuserbuffer_op = (setuserbuffer_op_t)pcap_not_initialized; - p->live_dump_op = (live_dump_op_t)pcap_not_initialized; - p->live_dump_ended_op = (live_dump_ended_op_t)pcap_not_initialized; + p->setuserbuffer_op = pcap_setuserbuffer_not_initialized; + p->live_dump_op = pcap_live_dump_not_initialized; + p->live_dump_ended_op = pcap_live_dump_ended_not_initialized; p->get_airpcap_handle_op = pcap_get_airpcap_handle_not_initialized; #endif @@ -2124,14 +2238,23 @@ pcap_alloc_pcap_t(char *ebuf, size_t size) * plus a structure following it of size "size". The * structure following it is a private data structure * for the routines that handle this pcap_t. + * + * The structure following it must be aligned on + * the appropriate alignment boundary for this platform. + * We align on an 8-byte boundary as that's probably what + * at least some platforms do, even with 32-bit integers, + * and because we can't be sure that some values won't + * require 8-byte alignment even on platforms with 32-bit + * integers. */ - chunk = malloc(sizeof (pcap_t) + size); +#define PCAP_T_ALIGNED_SIZE ((sizeof(pcap_t) + 7U) & ~0x7U) + chunk = malloc(PCAP_T_ALIGNED_SIZE + size); if (chunk == NULL) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc"); return (NULL); } - memset(chunk, 0, sizeof (pcap_t) + size); + memset(chunk, 0, PCAP_T_ALIGNED_SIZE + size); /* * Get a pointer to the pcap_t at the beginning. @@ -2156,7 +2279,7 @@ pcap_alloc_pcap_t(char *ebuf, size_t size) * Set the pointer to the private data; that's the structure * of size "size" following the pcap_t. */ - p->priv = (void *)(chunk + sizeof (pcap_t)); + p->priv = (void *)(chunk + PCAP_T_ALIGNED_SIZE); } return (p); @@ -2451,6 +2574,16 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *er char name[PCAP_BUF_SIZE + 1]; int srctype; + /* + * A null device name is equivalent to the "any" device - + * which might not be supported on this platform, but + * this means that you'll get a "not supported" error + * rather than, say, a crash when we try to dereference + * the null pointer. + */ + if (device == NULL) + device = "any"; + /* * Retrofit - we have to make older applications compatible with * remote capture. @@ -2522,13 +2655,13 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *er return (p); fail: if (status == PCAP_ERROR) - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device, - p->errbuf); + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %.*s", device, + PCAP_ERRBUF_SIZE - 3, p->errbuf); else if (status == PCAP_ERROR_NO_SUCH_DEVICE || status == PCAP_ERROR_PERM_DENIED || status == PCAP_ERROR_PROMISC_PERM_DENIED) - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)", device, - pcap_statustostr(status), p->errbuf); + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%.*s)", device, + pcap_statustostr(status), PCAP_ERRBUF_SIZE - 6, p->errbuf); else pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device, pcap_statustostr(status)); @@ -2841,7 +2974,7 @@ static struct dlt_choice dlt_choices[] = { DLT_CHOICE(FRELAY, "Frame Relay"), DLT_CHOICE(LOOP, "OpenBSD loopback"), DLT_CHOICE(ENC, "OpenBSD encapsulated IP"), - DLT_CHOICE(LINUX_SLL, "Linux cooked"), + DLT_CHOICE(LINUX_SLL, "Linux cooked v1"), DLT_CHOICE(LTALK, "Localtalk"), DLT_CHOICE(PFLOG, "OpenBSD pflog file"), DLT_CHOICE(PFSYNC, "Packet filter state syncing"), @@ -2875,7 +3008,7 @@ static struct dlt_choice dlt_choices[] = { DLT_CHOICE(GPF_T, "GPF-T"), DLT_CHOICE(GPF_F, "GPF-F"), DLT_CHOICE(JUNIPER_PIC_PEER, "Juniper PIC Peer"), - DLT_CHOICE(ERF_ETH, "Ethernet with Endace ERF header"), + DLT_CHOICE(ERF_ETH, "Ethernet with Endace ERF header"), DLT_CHOICE(ERF_POS, "Packet-over-SONET with Endace ERF header"), DLT_CHOICE(LINUX_LAPD, "Linux vISDN LAPD"), DLT_CHOICE(JUNIPER_ETHER, "Juniper Ethernet"), @@ -2899,10 +3032,11 @@ static struct dlt_choice dlt_choices[] = { DLT_CHOICE(SITA, "SITA pseudo-header"), DLT_CHOICE(ERF, "Endace ERF header"), DLT_CHOICE(RAIF1, "Ethernet with u10 Networks pseudo-header"), - DLT_CHOICE(IPMB, "IPMB"), + DLT_CHOICE(IPMB_KONTRON, "IPMB with Kontron pseudo-header"), DLT_CHOICE(JUNIPER_ST, "Juniper Secure Tunnel"), DLT_CHOICE(BLUETOOTH_HCI_H4_WITH_PHDR, "Bluetooth HCI UART transport layer plus pseudo-header"), DLT_CHOICE(AX25_KISS, "AX.25 with KISS header"), + DLT_CHOICE(IPMB_LINUX, "IPMB with Linux/Pigeon Point pseudo-header"), DLT_CHOICE(IEEE802_15_4_NONASK_PHY, "IEEE 802.15.4 with non-ASK PHY data"), DLT_CHOICE(MPLS, "MPLS with label as link-layer header"), DLT_CHOICE(LINUX_EVDEV, "Linux evdev events"), @@ -2959,6 +3093,7 @@ static struct dlt_choice dlt_choices[] = { DLT_CHOICE(DOCSIS31_XRA31, "Excentis XRA-31 DOCSIS 3.1 RF sniffer frames"), DLT_CHOICE(ETHERNET_MPACKET, "802.3br mPackets"), DLT_CHOICE(DISPLAYPORT_AUX, "DisplayPort AUX channel monitoring data"), + DLT_CHOICE(LINUX_SLL2, "Linux cooked v2"), DLT_CHOICE_SENTINEL }; @@ -2998,6 +3133,21 @@ pcap_datalink_val_to_description(int dlt) return (NULL); } +const char * +pcap_datalink_val_to_description_or_dlt(int dlt) +{ + static char unkbuf[40]; + const char *description; + + description = pcap_datalink_val_to_description(dlt); + if (description != NULL) { + return description; + } else { + (void)pcap_snprintf(unkbuf, sizeof(unkbuf), "DLT %u", dlt); + return unkbuf; + } +} + struct tstamp_type_choice { const char *name; const char *description; @@ -3150,7 +3300,7 @@ pcap_getnonblock(pcap_t *p, char *errbuf) * We copy the error message to errbuf, so callers * can find it in either place. */ - strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE); + pcap_strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE); } return (ret); } @@ -3194,7 +3344,7 @@ pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf) * We copy the error message to errbuf, so callers * can find it in either place. */ - strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE); + pcap_strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE); } return (ret); } @@ -3230,35 +3380,6 @@ pcap_setnonblock_fd(pcap_t *p, int nonblock) } #endif -#ifdef _WIN32 -/* - * Generate a string for a Win32-specific error (i.e. an error generated when - * calling a Win32 API). - * For errors occurred during standard C calls, we still use pcap_strerror() - */ -void -pcap_win32_err_to_str(DWORD error, char *errbuf) -{ - size_t errlen; - char *p; - - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf, - PCAP_ERRBUF_SIZE, NULL); - - /* - * "FormatMessage()" "helpfully" sticks CR/LF at the end of the - * message. Get rid of it. - */ - errlen = strlen(errbuf); - if (errlen >= 2) { - errbuf[errlen - 1] = '\0'; - errbuf[errlen - 2] = '\0'; - } - p = strchr(errbuf, '\0'); - pcap_snprintf (p, PCAP_ERRBUF_SIZE+1-(p-errbuf), " (%lu)", error); -} -#endif - /* * Generate error strings for PCAP_ERROR_ and PCAP_WARNING_ values. */ @@ -3330,7 +3451,7 @@ pcap_strerror(int errnum) errno_t err = strerror_s(errbuf, PCAP_ERRBUF_SIZE, errnum); if (err != 0) /* err = 0 if successful */ - strlcpy(errbuf, "strerror_s() error", PCAP_ERRBUF_SIZE); + pcap_strlcpy(errbuf, "strerror_s() error", PCAP_ERRBUF_SIZE); return (errbuf); #else return (strerror(errnum)); @@ -3552,7 +3673,7 @@ pcap_do_addexit(pcap_t *p) /* * "atexit()" failed; let our caller know. */ - strlcpy(p->errbuf, "atexit failed", PCAP_ERRBUF_SIZE); + pcap_strlcpy(p->errbuf, "atexit failed", PCAP_ERRBUF_SIZE); return (0); } did_atexit = 1; diff --git a/pcap/bpf.h b/pcap/bpf.h index 1a953a9b71d8..9d748952a0e5 100644 --- a/pcap/bpf.h +++ b/pcap/bpf.h @@ -238,16 +238,6 @@ struct bpf_insn { bpf_u_int32 k; }; -/* - * Auxiliary data, for use when interpreting a filter intended for the - * Linux kernel when the kernel rejects the filter (requiring us to - * run it in userland). It contains VLAN tag information. - */ -struct bpf_aux_data { - u_short vlan_tag_present; - u_short vlan_tag; -}; - /* * Macros for insn array initializers. */ @@ -256,7 +246,6 @@ struct bpf_aux_data { PCAP_API int bpf_validate(const struct bpf_insn *, int); PCAP_API u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); -extern u_int bpf_filter_with_aux_data(const struct bpf_insn *, const u_char *, u_int, u_int, const struct bpf_aux_data *); /* * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). diff --git a/pcap/compiler-tests.h b/pcap/compiler-tests.h index 5e17853a7734..ea5962c7bf5e 100644 --- a/pcap/compiler-tests.h +++ b/pcap/compiler-tests.h @@ -160,4 +160,4 @@ (__HP_aCC >= ((major)*10000 + (minor)*100)) #endif -#endif /* lib_pcap_funcattrs_h */ +#endif /* lib_pcap_compiler_tests_h */ diff --git a/pcap/dlt.h b/pcap/dlt.h index 44c36ef8a569..8dacf024044c 100644 --- a/pcap/dlt.h +++ b/pcap/dlt.h @@ -50,7 +50,7 @@ * * See * - * http://www.tcpdump.org/linktypes.html + * https://www.tcpdump.org/linktypes.html * * for detailed descriptions of some of these link-layer header types. */ @@ -246,7 +246,7 @@ */ /* - * This is for Linux cooked sockets. + * Linux cooked sockets. */ #define DLT_LINUX_SLL 113 @@ -769,11 +769,20 @@ #define DLT_RAIF1 198 /* - * IPMB packet for IPMI, beginning with the I2C slave address, followed - * by the netFn and LUN, etc.. Requested by Chanthy Toeung - * . + * IPMB packet for IPMI, beginning with a 2-byte header, followed by + * the I2C slave address, followed by the netFn and LUN, etc.. + * Requested by Chanthy Toeung . + * + * XXX - this used to be called DLT_IPMB, back when we got the + * impression from the email thread requesting it that the packet + * had no extra 2-byte header. We've renamed it; if anybody used + * DLT_IPMB and assumed no 2-byte header, this will cause the compile + * to fail, at which point we'll have to figure out what to do about + * the two header types using the same DLT_/LINKTYPE_ value. If that + * doesn't happen, we'll assume nobody used it and that the redefinition + * is safe. */ -#define DLT_IPMB 199 +#define DLT_IPMB_KONTRON 199 /* * Juniper-private data link type, as per request from @@ -805,15 +814,34 @@ #define DLT_LAPD 203 /* - * Variants of various link-layer headers, with a one-byte direction - * pseudo-header prepended - zero means "received by this host", - * non-zero (any non-zero value) means "sent by this host" - as per - * Will Barker . + * PPP, with a one-byte direction pseudo-header prepended - zero means + * "received by this host", non-zero (any non-zero value) means "sent by + * this host" - as per Will Barker . */ -#define DLT_PPP_WITH_DIR 204 /* PPP - don't confuse with DLT_PPP_WITH_DIRECTION */ -#define DLT_C_HDLC_WITH_DIR 205 /* Cisco HDLC */ -#define DLT_FRELAY_WITH_DIR 206 /* Frame Relay */ -#define DLT_LAPB_WITH_DIR 207 /* LAPB */ +#define DLT_PPP_WITH_DIR 204 /* Don't confuse with DLT_PPP_WITH_DIRECTION */ + +/* + * Cisco HDLC, with a one-byte direction pseudo-header prepended - zero + * means "received by this host", non-zero (any non-zero value) means + * "sent by this host" - as per Will Barker . + */ +#define DLT_C_HDLC_WITH_DIR 205 + +/* + * Frame Relay, with a one-byte direction pseudo-header prepended - zero + * means "received by this host" (DCE -> DTE), non-zero (any non-zero + * value) means "sent by this host" (DTE -> DCE) - as per Will Barker + * . + */ +#define DLT_FRELAY_WITH_DIR 206 + +/* + * LAPB, with a one-byte direction pseudo-header prepended - zero means + * "received by this host" (DCE -> DTE), non-zero (any non-zero value) + * means "sent by this host" (DTE -> DCE)- as per Will Barker + * . + */ +#define DLT_LAPB_WITH_DIR 207 /* * 208 is reserved for an as-yet-unspecified proprietary link-layer @@ -1367,6 +1395,11 @@ */ #define DLT_DISPLAYPORT_AUX 275 +/* + * Linux cooked sockets v2. + */ +#define DLT_LINUX_SLL2 276 + /* * In case the code that includes this file (directly or indirectly) * has also included OS files that happen to define DLT_MATCHING_MAX, @@ -1377,7 +1410,7 @@ #ifdef DLT_MATCHING_MAX #undef DLT_MATCHING_MAX #endif -#define DLT_MATCHING_MAX 275 /* highest value in the "matching" range */ +#define DLT_MATCHING_MAX 276 /* highest value in the "matching" range */ /* * DLT and savefile link type values are split into a class and diff --git a/pcap/funcattrs.h b/pcap/funcattrs.h index a8b1932f4c6e..e64da93aa4ce 100644 --- a/pcap/funcattrs.h +++ b/pcap/funcattrs.h @@ -164,10 +164,11 @@ || PCAP_IS_AT_LEAST_XL_C_VERSION(10,1) \ || PCAP_IS_AT_LEAST_HP_C_VERSION(6,10) /* - * Compiler with support for __attribute((noreturn)), or GCC 2.5 and - * later, or Solaris Studio 12 (Sun C 5.9) and later, or IBM XL C 10.1 - * and later (do any earlier versions of XL C support this?), or - * HP aCC A.06.10 and later. + * Compiler with support for __attribute((noreturn)), or GCC 2.5 or + * later, or some compiler asserting compatibility with GCC 2.5 or + * later, or Solaris Studio 12 (Sun C 5.9) or later, or IBM XL C 10.1 + * or later (do any earlier versions of XL C support this?), or HP aCC + * A.06.10 or later. */ #define PCAP_NORETURN __attribute((noreturn)) #define PCAP_NORETURN_DEF __attribute((noreturn)) @@ -193,7 +194,8 @@ || PCAP_IS_AT_LEAST_XL_C_VERSION(10,1) \ || PCAP_IS_AT_LEAST_HP_C_VERSION(6,10) /* - * Compiler with support for it, or GCC 2.3 and later, or IBM XL C 10.1 + * Compiler with support for it, or GCC 2.3 or later, or some compiler + * asserting compatibility with GCC 2.3 or later, or IBM XL C 10.1 * and later (do any earlier versions of XL C support this?), * or HP aCC A.06.10 and later. */ @@ -216,7 +218,7 @@ || PCAP_IS_AT_LEAST_SUNC_VERSION(5,13) /* * Compiler that supports __has_attribute and __attribute__((deprecated)), - * or GCC 4.5 and later, or Sun/Oracle C 12.4 (Sun C 5.13) or later. + * or GCC 4.5 or later, or Sun/Oracle C 12.4 (Sun C 5.13) or later. * * Those support __attribute__((deprecated(msg))) (we assume, perhaps * incorrectly, that anything that supports __has_attribute() is diff --git a/pcap/nflog.h b/pcap/nflog.h index 29a71d2d3fb5..f7c85b54de5a 100644 --- a/pcap/nflog.h +++ b/pcap/nflog.h @@ -32,7 +32,7 @@ /* * Structure of an NFLOG header and TLV parts, as described at - * http://www.tcpdump.org/linktypes/LINKTYPE_NFLOG.html + * https://www.tcpdump.org/linktypes/LINKTYPE_NFLOG.html * * The NFLOG header is big-endian. * @@ -42,27 +42,27 @@ * data, etc.). */ typedef struct nflog_hdr { - uint8_t nflog_family; /* address family */ - uint8_t nflog_version; /* version */ - uint16_t nflog_rid; /* resource ID */ + uint8_t nflog_family; /* address family */ + uint8_t nflog_version; /* version */ + uint16_t nflog_rid; /* resource ID */ } nflog_hdr_t; typedef struct nflog_tlv { - uint16_t tlv_length; /* tlv length */ - uint16_t tlv_type; /* tlv type */ + uint16_t tlv_length; /* tlv length */ + uint16_t tlv_type; /* tlv type */ /* value follows this */ } nflog_tlv_t; typedef struct nflog_packet_hdr { uint16_t hw_protocol; /* hw protocol */ - uint8_t hook; /* netfilter hook */ - uint8_t pad; /* padding to 32 bits */ + uint8_t hook; /* netfilter hook */ + uint8_t pad; /* padding to 32 bits */ } nflog_packet_hdr_t; typedef struct nflog_hwaddr { uint16_t hw_addrlen; /* address length */ uint16_t pad; /* padding to 32-bit boundary */ - uint8_t hw_addr[8]; /* address, up to 8 bytes */ + uint8_t hw_addr[8]; /* address, up to 8 bytes */ } nflog_hwaddr_t; typedef struct nflog_timestamp { diff --git a/pcap/pcap-inttypes.h b/pcap/pcap-inttypes.h index af2c23c877ed..8b1eb8b9be84 100644 --- a/pcap/pcap-inttypes.h +++ b/pcap/pcap-inttypes.h @@ -106,12 +106,23 @@ #define PRIu64 "llu" #endif #endif + + /* + * MSVC's support library doesn't support %zu to print a size_t until + * Visual Studio 2017, but supports %Iu earlier, so use that. + */ + #define PRIsize "Iu" #elif defined(__MINGW32__) || !defined(_WIN32) /* * Compiler is MinGW or target is UN*X or MS-DOS. Just use * . */ #include + + /* + * Assume the support library supports %zu; it's required by C99. + */ + #define PRIsize "zu" #endif #endif /* pcap/pcap-inttypes.h */ diff --git a/pcap/pcap.h b/pcap/pcap.h index f809dd1145e4..90614dd0156f 100644 --- a/pcap/pcap.h +++ b/pcap/pcap.h @@ -84,6 +84,8 @@ #include #endif /* _WIN32/MSDOS/UN*X */ +#include /* for SOCKET, as the active-mode rpcap APIs use it */ + #ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H #include #endif @@ -348,7 +350,7 @@ PCAP_API const char *pcap_tstamp_type_val_to_name(int); PCAP_API const char *pcap_tstamp_type_val_to_description(int); #ifdef __linux__ -PCAP_API int pcap_set_protocol(pcap_t *, int); +PCAP_API int pcap_set_protocol_linux(pcap_t *, int); #endif /* @@ -468,6 +470,7 @@ PCAP_API void pcap_free_datalinks(int *); PCAP_API int pcap_datalink_name_to_val(const char *); PCAP_API const char *pcap_datalink_val_to_name(int); PCAP_API const char *pcap_datalink_val_to_description(int); +PCAP_API const char *pcap_datalink_val_to_description_or_dlt(int); PCAP_API int pcap_snapshot(pcap_t *); PCAP_API int pcap_is_swapped(pcap_t *); PCAP_API int pcap_major_version(pcap_t *); @@ -483,7 +486,28 @@ PCAP_API int pcap_fileno(pcap_t *); #endif PCAP_API pcap_dumper_t *pcap_dump_open(pcap_t *, const char *); -PCAP_API pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp); +#ifdef _WIN32 + PCAP_API pcap_dumper_t *pcap_dump_hopen(pcap_t *, intptr_t); + /* + * If we're building libpcap, this is an internal routine in sf-pcap.c, so + * we must not define it as a macro. + * + * If we're not building libpcap, given that the version of the C runtime + * with which libpcap was built might be different from the version + * of the C runtime with which an application using libpcap was built, + * and that a FILE structure may differ between the two versions of the + * C runtime, calls to _fileno() must use the version of _fileno() in + * the C runtime used to open the FILE *, not the version in the C + * runtime with which libpcap was built. (Maybe once the Universal CRT + * rules the world, this will cease to be a problem.) + */ + #ifndef BUILDING_PCAP + #define pcap_dump_fopen(p,f) \ + pcap_dump_hopen(p, _get_osfhandle(_fileno(f))) + #endif +#else /*_WIN32*/ + PCAP_API pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp); +#endif /*_WIN32*/ PCAP_API pcap_dumper_t *pcap_dump_open_append(pcap_t *, const char *); PCAP_API FILE *pcap_dump_file(pcap_dumper_t *); PCAP_API long pcap_dump_ftell(pcap_dumper_t *); @@ -858,8 +882,8 @@ PCAP_API int pcap_parsesrcstr(const char *source, int *type, char *host, * For listing remote capture devices, pcap_findalldevs_ex() is currently * the only API available. */ -PCAP_API int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, - pcap_if_t **alldevs, char *errbuf); +PCAP_API int pcap_findalldevs_ex(const char *source, + struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf); /* * Sampling methods. @@ -937,27 +961,6 @@ PCAP_API struct pcap_samp *pcap_setsampling(pcap_t *p); /* Maximum length of an host name (needed for the RPCAP active mode) */ #define RPCAP_HOSTLIST_SIZE 1024 -/* - * Some minor differences between UN*X sockets and and Winsock sockets. - */ -#ifndef _WIN32 - /*! - * \brief In Winsock, a socket handle is of type SOCKET; in UN*X, it's - * a file descriptor, and therefore a signed integer. - * We define SOCKET to be a signed integer on UN*X, so that it can - * be used on both platforms. - */ - #define SOCKET int - - /*! - * \brief In Winsock, the error return if socket() fails is INVALID_SOCKET; - * in UN*X, it's -1. - * We define INVALID_SOCKET to be -1 on UN*X, so that it can be used on - * both platforms. - */ - #define INVALID_SOCKET -1 -#endif - PCAP_API SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf); diff --git a/pcap/sll.h b/pcap/sll.h index c4d08862d64e..392faae4d677 100644 --- a/pcap/sll.h +++ b/pcap/sll.h @@ -74,27 +74,44 @@ #ifndef lib_pcap_sll_h #define lib_pcap_sll_h +#include + /* * A DLT_LINUX_SLL fake link-layer header. */ #define SLL_HDR_LEN 16 /* total header length */ #define SLL_ADDRLEN 8 /* length of address field */ -#include - struct sll_header { uint16_t sll_pkttype; /* packet type */ uint16_t sll_hatype; /* link-layer address type */ uint16_t sll_halen; /* link-layer address length */ - uint8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ + uint8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ uint16_t sll_protocol; /* protocol */ }; /* - * The LINUX_SLL_ values for "sll_pkttype"; these correspond to the - * PACKET_ values on Linux, but are defined here so that they're - * available even on systems other than Linux, and so that they - * don't change even if the PACKET_ values change. + * A DLT_LINUX_SLL2 fake link-layer header. + */ +#define SLL2_HDR_LEN 20 /* total header length */ + +struct sll2_header { + uint16_t sll2_protocol; /* protocol */ + uint16_t sll2_reserved_mbz; /* reserved - must be zero */ + uint32_t sll2_if_index; /* 1-based interface index */ + uint16_t sll2_hatype; /* link-layer address type */ + uint8_t sll2_pkttype; /* packet type */ + uint8_t sll2_halen; /* link-layer address length */ + uint8_t sll2_addr[SLL_ADDRLEN]; /* link-layer address */ +}; + +/* + * The LINUX_SLL_ values for "sll_pkttype" and LINUX_SLL2_ values for + * "sll2_pkttype"; these correspond to the PACKET_ values on Linux, + * which are defined by a header under include/uapi in the current + * kernel source, and are thus not going to change on Linux. We + * define them here so that they're available even on systems other + * than Linux. */ #define LINUX_SLL_HOST 0 #define LINUX_SLL_BROADCAST 1 @@ -103,10 +120,11 @@ struct sll_header { #define LINUX_SLL_OUTGOING 4 /* - * The LINUX_SLL_ values for "sll_protocol"; these correspond to the - * ETH_P_ values on Linux, but are defined here so that they're - * available even on systems other than Linux. We assume, for now, - * that the ETH_P_ values won't change in Linux; if they do, then: + * The LINUX_SLL_ values for "sll_protocol" and LINUX_SLL2_ values for + * "sll2_protocol"; these correspond to the ETH_P_ values on Linux, but + * are defined here so that they're available even on systems other than + * Linux. We assume, for now, that the ETH_P_ values won't change in + * Linux; if they do, then: * * if we don't translate them in "pcap-linux.c", capture files * won't necessarily be readable if captured on a system that diff --git a/pcap/socket.h b/pcap/socket.h new file mode 100644 index 000000000000..6f27cba12f91 --- /dev/null +++ b/pcap/socket.h @@ -0,0 +1,93 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lib_pcap_socket_h +#define lib_pcap_socket_h + +/* + * Some minor differences between sockets on various platforms. + * We include whatever sockets are needed for Internet-protocol + * socket access on UN*X and Windows. + */ +#ifdef _WIN32 + /* Need windef.h for defines used in winsock2.h under MingW32 */ + #ifdef __MINGW32__ + #include + #endif + #include + #include + + /* + * Winsock doesn't have this UN*X type; it's used in the UN*X + * sockets API. + * + * XXX - do we need to worry about UN*Xes so old that *they* + * don't have it, either? + */ + typedef int socklen_t; + + /* + * Winsock doesn't have this POSIX type; it's used for the + * tv_usec value of struct timeval. + */ + typedef long suseconds_t; +#else /* _WIN32 */ + #include + #include + #include /* for struct addrinfo/getaddrinfo() */ + #include /* for sockaddr_in, in BSD at least */ + #include + + /*! + * \brief In Winsock, a socket handle is of type SOCKET; in UN*X, it's + * a file descriptor, and therefore a signed integer. + * We define SOCKET to be a signed integer on UN*X, so that it can + * be used on both platforms. + */ + #ifndef SOCKET + #define SOCKET int + #endif + + /*! + * \brief In Winsock, the error return if socket() fails is INVALID_SOCKET; + * in UN*X, it's -1. + * We define INVALID_SOCKET to be -1 on UN*X, so that it can be used on + * both platforms. + */ + #ifndef INVALID_SOCKET + #define INVALID_SOCKET -1 + #endif +#endif /* _WIN32 */ + +#endif /* lib_pcap_socket_h */ diff --git a/pcap_activate.3pcap b/pcap_activate.3pcap index 8c89939fddc0..162a929331e4 100644 --- a/pcap_activate.3pcap +++ b/pcap_activate.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_ACTIVATE 3PCAP "7 April 2014" +.TH PCAP_ACTIVATE 3PCAP "31 July 2016" .SH NAME pcap_activate \- activate a capture handle .SH SYNOPSIS @@ -50,15 +50,15 @@ promiscuous mode. .TP .B PCAP_WARNING_TSTAMP_TYPE_NOTSUP The time stamp type specified in a previous -.B pcap_set_tstamp_type() +.B pcap_set_tstamp_type(3PCAP) call isn't supported by the capture source (the time stamp type is left as the default), .TP .B PCAP_WARNING Another warning condition occurred; -.B pcap_geterr() +.B pcap_geterr(3PCAP) or -.B pcap_perror() +.B pcap_perror(3PCAP) may be called with .I p as an argument to fetch or display a message describing the warning @@ -115,7 +115,7 @@ Additional warning and error codes may be added in the future; a program should check for positive, negative, and zero return codes, and treat all positive return codes as warnings and all negative return codes as errors. -.B pcap_statustostr() +.B pcap_statustostr(3PCAP) can be called, with a warning or error code as an argument, to fetch a message describing the warning or error code. .SH SEE ALSO diff --git a/pcap_breakloop.3pcap b/pcap_breakloop.3pcap index 4818c70fc365..cc000d2e075c 100644 --- a/pcap_breakloop.3pcap +++ b/pcap_breakloop.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_BREAKLOOP 3PCAP "8 March 2015" +.TH PCAP_BREAKLOOP 3PCAP "25 July 2018" .SH NAME pcap_breakloop \- force a pcap_dispatch() or pcap_loop() call to return .SH SYNOPSIS @@ -33,12 +33,13 @@ void pcap_breakloop(pcap_t *); .SH DESCRIPTION .B pcap_breakloop() sets a flag that will force -.B pcap_dispatch() +.B pcap_dispatch(3PCAP) or -.B pcap_loop() +.B pcap_loop(3PCAP) to return rather than looping; they will return the number of packets -that have been processed so far, or \-2 if no packets have been -processed so far. +that have been processed so far, or +.B PCAP_ERROR_BREAK +if no packets have been processed so far. .PP This routine is safe to use inside a signal handler on UNIX or a console control handler on Windows, as it merely sets a flag that is checked @@ -60,7 +61,7 @@ packets arrive and the call completes. .PP .ft B Note also that, in a multi-threaded application, if one thread is -blocked in pcap_dispatch(), pcap_loop(), pcap_next(), or pcap_next_ex(), +blocked in pcap_dispatch(), pcap_loop(), pcap_next(3PCAP), or pcap_next_ex(3PCAP), a call to pcap_breakloop() in a different thread will not unblock that thread. .ft R @@ -99,12 +100,16 @@ or .B pcap_loop() after it is called; at most one more packet might be processed. .PP -If \-2 is returned from +If +.B PCAP_ERROR_BREAK +is returned from .B pcap_dispatch() or .BR pcap_loop() , the flag is cleared, so a subsequent call will resume reading packets. If a positive number is returned, the flag is not cleared, so a -subsequent call will return \-2 and clear the flag. +subsequent call will return +.B PCAP_ERROR_BREAK +and clear the flag. .SH SEE ALSO -pcap(3PCAP), pcap_loop(3PCAP), pcap_next_ex(3PCAP) +pcap(3PCAP) diff --git a/pcap_can_set_rfmon.3pcap b/pcap_can_set_rfmon.3pcap index 389e50ddaa60..0baac7a646c7 100644 --- a/pcap_can_set_rfmon.3pcap +++ b/pcap_can_set_rfmon.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_CAN_SET_RFMON 3PCAP "3 January 2014" +.TH PCAP_CAN_SET_RFMON 3PCAP "31 July 2016" .SH NAME pcap_can_set_rfmon \- check whether monitor mode can be set for a not-yet-activated capture handle @@ -54,9 +54,9 @@ The capture handle has already been activated. .TP .B PCAP_ERROR Another error occurred. -.B pcap_geterr() +.B pcap_geterr(3PCAP) or -.B pcap_perror() +.B \%pcap_perror(3PCAP) may be called with .I p as an argument to fetch or display a message describing the error. @@ -64,7 +64,7 @@ as an argument to fetch or display a message describing the error. Additional error codes may be added in the future; a program should check for 0, 1, and negative, return codes, and treat all negative return codes as errors. -.B pcap_statustostr() +.B pcap_statustostr(3PCAP) can be called, with a warning or error code as an argument, to fetch a message describing the warning or error code. .SH SEE ALSO diff --git a/pcap_compile.3pcap.in b/pcap_compile.3pcap.in index 9abeed82f251..824f52b32e7e 100644 --- a/pcap_compile.3pcap.in +++ b/pcap_compile.3pcap.in @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_COMPILE 3PCAP "7 April 2014" +.TH PCAP_COMPILE 3PCAP "22 August 2018" .SH NAME pcap_compile \- compile a filter expression .SH SYNOPSIS @@ -52,7 +52,9 @@ captured; it is used only when checking for IPv4 broadcast addresses in the filter program. If the netmask of the network on which packets are being captured isn't known to the program, or if packets are being captured on the Linux "any" pseudo-interface that can capture on more -than one network, a value of PCAP_NETMASK_UNKNOWN can be supplied; tests +than one network, a value of +.B PCAP_NETMASK_UNKNOWN +can be supplied; tests for IPv4 broadcast addresses will fail to compile, but all other tests in the filter program will be OK. .LP @@ -67,14 +69,21 @@ in multiple threads in a single process without some form of mutual exclusion allowing only one thread to call it at any given time. .SH RETURN VALUE .B pcap_compile() -returns 0 on success and \-1 on failure. -If \-1 is returned, -.B pcap_geterr() +returns 0 on success and +.B PCAP_ERROR +on failure. If +.B PCAP_ERROR +is returned, +.B pcap_geterr(3PCAP) or -.B pcap_perror() +.B pcap_perror(3PCAP) may be called with .I p as an argument to fetch or display the error text. +.SH BACKWARD COMPATIBILITY +.PP +The +.B PCAP_NETMASK_UNKNOWN +constant became available in libpcap release 1.1.0. .SH SEE ALSO pcap(3PCAP), pcap_setfilter(3PCAP), pcap_freecode(3PCAP), -pcap_geterr(3PCAP), pcap-filter(@MAN_MISC_INFO@) diff --git a/pcap_create.3pcap b/pcap_create.3pcap index 3040b3b20037..5a15007bfc30 100644 --- a/pcap_create.3pcap +++ b/pcap_create.3pcap @@ -48,7 +48,7 @@ argument of "any" or can be used to capture packets from all interfaces. .PP The returned handle must be activated with -.B pcap_activate() +.B pcap_activate(3PCAP) before packets can be captured with it; options for the capture, such as promiscuous mode, can be set on the handle before activating it. @@ -69,4 +69,4 @@ is assumed to be able to hold at least .B PCAP_ERRBUF_SIZE chars. .SH SEE ALSO -pcap(3PCAP), pcap_activate(3PCAP) +pcap(3PCAP) diff --git a/pcap_datalink.3pcap.in b/pcap_datalink.3pcap.in index be50a649ee31..26203683eddf 100644 --- a/pcap_datalink.3pcap.in +++ b/pcap_datalink.3pcap.in @@ -37,11 +37,11 @@ specified by .IR p . .PP It must not be called on a pcap descriptor created by -.B pcap_create() +.B \%pcap_create(3PCAP) that has not yet been activated by -.BR pcap_activate() . +.BR \%pcap_activate(3PCAP) . .PP -.I http://www.tcpdump.org/linktypes.html +.I https://www.tcpdump.org/linktypes.html lists the values .B pcap_datalink() can return and describes the packet formats that diff --git a/pcap_datalink_name_to_val.3pcap b/pcap_datalink_name_to_val.3pcap index 8a6905a2c576..dd4688f0a260 100644 --- a/pcap_datalink_name_to_val.3pcap +++ b/pcap_datalink_name_to_val.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_DATALINK_NAME_TO_VAL 3PCAP "5 December 2014" +.TH PCAP_DATALINK_NAME_TO_VAL 3PCAP "25 July 2018" .SH NAME pcap_datalink_name_to_val \- get the link-layer header type value corresponding to a header type name @@ -41,7 +41,9 @@ removed, to the corresponding link-layer header type value. The translation is case-insensitive. .SH RETURN VALUE .B pcap_datalink_name_to_val() -returns the type value on success and \-1 if the name is not a known +returns the type value on success and +.B PCAP_ERROR +if the name is not a known type name.. .SH SEE ALSO pcap(3PCAP) diff --git a/pcap_datalink_val_to_name.3pcap b/pcap_datalink_val_to_name.3pcap index aa3e89a6e0b2..f42165fbaca3 100644 --- a/pcap_datalink_val_to_name.3pcap +++ b/pcap_datalink_val_to_name.3pcap @@ -17,9 +17,10 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_DATALINK_VAL_TO_NAME 3PCAP "3 January 2014" +.TH PCAP_DATALINK_VAL_TO_NAME 3PCAP "12 October 2016" .SH NAME -pcap_datalink_val_to_name, pcap_datalink_val_to_description \- get a +pcap_datalink_val_to_name, pcap_datalink_val_to_description, +pcap_datalink_val_to_description_or_dlt \- get a name or description for a link-layer header type value .SH SYNOPSIS .nf @@ -30,6 +31,7 @@ name or description for a link-layer header type value .ft B const char *pcap_datalink_val_to_name(int dlt); const char *pcap_datalink_val_to_description(int dlt); +const char *pcap_datalink_val_to_description_or_dlt(int dlt); .ft .fi .SH DESCRIPTION @@ -52,3 +54,13 @@ link-layer header type. is returned if the type value does not correspond to a known .B DLT_ value. +.PP +.B pcap_datalink_val_to_description_or_dlt() +translates a link-layer header type value to a short description of that +link-layer header type just like pcap_datalink_val_to_description. +If the type value does not correspond to a known +.B DLT_ +value, the string "DLT n" is returned, where n is the value of +the dlt argument. +.SH SEE ALSO +pcap(3PCAP) diff --git a/pcap_dump.3pcap b/pcap_dump.3pcap index 6402b4b4519b..7f201b7ce7d1 100644 --- a/pcap_dump.3pcap +++ b/pcap_dump.3pcap @@ -35,11 +35,11 @@ u_char *sp); .SH DESCRIPTION .B pcap_dump() outputs a packet to the ``savefile'' opened with -.BR pcap_dump_open() . +.BR pcap_dump_open(3PCAP) . Note that its calling arguments are suitable for use with -.B pcap_dispatch() +.B pcap_dispatch(3PCAP) or -.BR pcap_loop() . +.BR pcap_loop(3PCAP) . If called directly, the .I user parameter is of type @@ -47,5 +47,4 @@ parameter is of type as returned by .BR pcap_dump_open() . .SH SEE ALSO -pcap(3PCAP), pcap_dump_open(3PCAP), pcap_dispatch(3PCAP), -pcap_loop(3PCAP) +pcap(3PCAP) diff --git a/pcap_dump_file.3pcap b/pcap_dump_file.3pcap index 8fea610a4f9a..d2074312d1ec 100644 --- a/pcap_dump_file.3pcap +++ b/pcap_dump_file.3pcap @@ -33,6 +33,6 @@ FILE *pcap_dump_file(pcap_dumper_t *p); .SH DESCRIPTION .B pcap_dump_file() returns the standard I/O stream of the ``savefile'' opened by -.BR pcap_dump_open() . +.BR pcap_dump_open(3PCAP) . .SH SEE ALSO pcap(3PCAP) diff --git a/pcap_dump_flush.3pcap b/pcap_dump_flush.3pcap index c8f110bb6f24..5d1747452d3e 100644 --- a/pcap_dump_flush.3pcap +++ b/pcap_dump_flush.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_DUMP_FLUSH 3PCAP "3 January 2014" +.TH PCAP_DUMP_FLUSH 3PCAP "25 July 2018" .SH NAME pcap_dump_flush \- flush to a savefile packets dumped .SH SYNOPSIS @@ -34,10 +34,12 @@ int pcap_dump_flush(pcap_dumper_t *p); .B pcap_dump_flush() flushes the output buffer to the ``savefile,'' so that any packets written with -.B pcap_dump() +.B pcap_dump(3PCAP) but not yet written to the ``savefile'' will be written. .SH RETURN VALUE .B pcap_dump_flush() -returns 0 on success and \-1 on failure. +returns 0 on success and +.B PCAP_ERROR +on failure. .SH SEE ALSO -pcap(3PCAP), pcap_dump_open(3PCAP), pcap_dump(3PCAP) +pcap(3PCAP), pcap_dump_open(3PCAP) diff --git a/pcap_dump_ftell.3pcap b/pcap_dump_ftell.3pcap index 01dbc64c7230..20cb995eab35 100644 --- a/pcap_dump_ftell.3pcap +++ b/pcap_dump_ftell.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_DUMP_FTELL 3PCAP "3 January 2014" +.TH PCAP_DUMP_FTELL 3PCAP "25 July 2018" .SH NAME pcap_dump_ftell, pcap_dump_ftell64 \- get the current file offset for a savefile being written .SH SYNOPSIS @@ -36,11 +36,11 @@ int64_t pcap_dump_ftell64(pcap_dumper_t *p); .B pcap_dump_ftell() returns the current file position for the ``savefile'', representing the number of bytes written by -.B pcap_dump_open() +.B pcap_dump_open(3PCAP) and -.BR pcap_dump() . -\-1 is returned on error. -If the current file position does not fit in a +.BR pcap_dump(3PCAP) . +.B PCAP_ERROR +is returned on error. If the current file position does not fit in a .BR long , it will be truncated; this can happen on 32-bit UNIX-like systems with large file support and on Windows. @@ -52,6 +52,7 @@ so if file offsets that don't fit in a but that fit in a .B int64_t are supported, this will return the file offset without truncation. -\-1 is returned on error. +.B PCAP_ERROR +is returned on error. .SH SEE ALSO -pcap(3PCAP), pcap_dump_open(3PCAP), pcap_dump(3PCAP) +pcap(3PCAP) diff --git a/pcap_dump_open.3pcap.in b/pcap_dump_open.3pcap.in index 80d1a5c62c5d..b86696f08826 100644 --- a/pcap_dump_open.3pcap.in +++ b/pcap_dump_open.3pcap.in @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_DUMP_OPEN 3PCAP "16 February 2015" +.TH PCAP_DUMP_OPEN 3PCAP "22 August 2018" .SH NAME pcap_dump_open, pcap_dump_fopen \- open a file to which to write packets .SH SYNOPSIS @@ -48,26 +48,28 @@ for .PP .B pcap_dump_fopen() is called to write data to an existing open stream -.IR fp . +.IR fp ; +this stream will be closed by a subsequent call to +.BR pcap_dump_close(3PCAP) . Note that on Windows, that stream should be opened in binary mode. .PP .I p is a capture or ``savefile'' handle returned by an earlier call to -.B pcap_create() +.B pcap_create(3PCAP) and activated by an earlier call to -.BR pcap_activate() , +.BR \%pcap_activate(3PCAP) , or returned by an earlier call to -.BR pcap_open_offline() , -.BR pcap_open_live() , +.BR \%pcap_open_offline(3PCAP) , +.BR pcap_open_live(3PCAP) , or -.BR pcap_open_dead() . +.BR pcap_open_dead(3PCAP) . The time stamp precision, link-layer type, and snapshot length from .I p are used as the link-layer type and snapshot length of the output file. .PP .B pcap_dump_open_append() is like -.B pcap_dump_open +.B pcap_dump_open() but does not create the file if it does not exist and, if it does already exist, and is a pcap file with the same byte order as the host opening the file, and has the same time stamp precision, link-layer @@ -78,19 +80,24 @@ it will write new packets at the end of the file. A pointer to a .B pcap_dumper_t structure to use in subsequent -.B pcap_dump() +.B pcap_dump(3PCAP) and -.B pcap_dump_close() +.B pcap_dump_close(3PCAP) calls is returned on success. .B NULL is returned on failure. If .B NULL is returned, -.B pcap_geterr(\fIp\fB) +.B pcap_geterr(3PCAP) can be used to get the error text. +.SH BACKWARD COMPATIBILITY +.PP +The +.B pcap_dump_open_append() +function became available in libpcap release 1.7.2. In previous +releases, there is no support for appending packets to an existing +savefile. .SH SEE ALSO -pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), -\%pcap_open_offline(3PCAP), pcap_open_live(3PCAP), pcap_open_dead(3PCAP), -pcap_dump(3PCAP), pcap_dump_close(3PCAP), pcap_geterr(3PCAP), +pcap(3PCAP), \%pcap-savefile(@MAN_FILE_FORMATS@) diff --git a/pcap_file.3pcap b/pcap_file.3pcap index cd6b06bb8a40..981451ba5684 100644 --- a/pcap_file.3pcap +++ b/pcap_file.3pcap @@ -34,13 +34,15 @@ FILE *pcap_file(pcap_t *p); .B pcap_file() returns the standard I/O stream of the ``savefile,'' if a ``savefile'' was opened with -.BR pcap_open_offline() , -or NULL, if a network device was opened with -.B pcap_create() +.BR pcap_open_offline(3PCAP) , +or +.BR NULL , +if a network device was opened with +.B pcap_create(3PCAP) and -.BR pcap_activate() , +.BR \%pcap_activate(3PCAP) , or with -.BR pcap_open_live() . +.BR pcap_open_live(3PCAP) . .PP Note that the Packet Capture library is usually built with large file support, so the standard I/O stream of the ``savefile'' might refer to @@ -50,8 +52,8 @@ should, if possible, use calls that support large files on the return value of .B pcap_file() or the value returned by -.B fileno() +.B fileno(3) when passed the return value of .BR pcap_file() . .SH SEE ALSO -pcap(3PCAP), pcap_open_offline(3PCAP) +pcap(3PCAP) diff --git a/pcap_fileno.3pcap b/pcap_fileno.3pcap index e8c9ac4d4ac6..60ac12945dd1 100644 --- a/pcap_fileno.3pcap +++ b/pcap_fileno.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_FILENO 3PCAP "7 April 2014" +.TH PCAP_FILENO 3PCAP "25 July 2018" .SH NAME pcap_fileno \- get the file descriptor for a live capture .SH SYNOPSIS @@ -35,32 +35,31 @@ If .I p refers to a network device that was opened for a live capture using a combination of -.B pcap_create() +.B pcap_create(3PCAP) and -.BR pcap_activate() , +.BR pcap_activate(3PCAP) , or using -.BR pcap_open_live() , +.BR pcap_open_live(3PCAP) , .B pcap_fileno() returns the file descriptor from which captured packets are read. .LP If .I p refers to a ``savefile'' that was opened using functions such as -.BR pcap_open_offline() +.BR pcap_open_offline(3PCAP) or -.BR pcap_fopen_offline() , +.BR pcap_fopen_offline(3PCAP) , a ``dead'' .B pcap_t opened using -.BR pcap_open_dead() , +.BR pcap_open_dead(3PCAP) , or a .B pcap_t that was created with .B pcap_create() but that has not yet been activated with .BR pcap_activate() , -it returns \-1. +it returns +.BR PCAP_ERROR . .SH SEE ALSO -pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), -pcap_open_live(3PCAP), pcap_open_offline(3PCAP), -\%pcap_fopen_offline(3PCAP), pcap_open_dead(3PCAP) +pcap(3PCAP) diff --git a/pcap_findalldevs.3pcap b/pcap_findalldevs.3pcap index 9523e008a69c..712e255a0fdf 100644 --- a/pcap_findalldevs.3pcap +++ b/pcap_findalldevs.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_FINDALLDEVS 3PCAP "7 April 2014" +.TH PCAP_FINDALLDEVS 3PCAP "22 August 2018" .SH NAME pcap_findalldevs, pcap_freealldevs \- get a list of capture devices, and free that list @@ -40,11 +40,11 @@ void pcap_freealldevs(pcap_if_t *alldevs); .SH DESCRIPTION .B pcap_findalldevs() constructs a list of network devices that can be opened with -.B pcap_create() +.B pcap_create(3PCAP) and -.B pcap_activate() +.B pcap_activate(3PCAP) or with -.BR pcap_open_live() . +.BR pcap_open_live(3PCAP) . (Note that there may be network devices that cannot be opened by the process calling .BR pcap_findalldevs() , @@ -194,21 +194,38 @@ for IPv6 addresses, it can be interpreted as if it pointed to a .BR "struct sockaddr_in6". .PP The list of devices must be freed with -.BR pcap_freealldevs() , +.BR pcap_freealldevs(3PCAP) , which frees the list pointed to by .IR alldevs . .SH RETURN VALUE .B pcap_findalldevs() -returns 0 on success and \-1 on failure; as indicated, finding no +returns 0 on success and +.B PCAP_ERROR +on failure; as indicated, finding no devices is considered success, rather than failure, so 0 will be -returned in that case. -If \-1 is returned, +returned in that case. If +.B PCAP_ERROR +is returned, .I errbuf is filled in with an appropriate error message. .I errbuf is assumed to be able to hold at least .B PCAP_ERRBUF_SIZE chars. +.SH BACKWARD COMPATIBILITY +.PP +The +.B PCAP_IF_UP +and +.B PCAP_IF_RUNNING +constants became available in libpcap release 1.6.1. The +.BR PCAP_IF_WIRELESS , +.BR PCAP_IF_CONNECTION_STATUS , +.BR PCAP_IF_CONNECTION_STATUS_UNKNOWN , +.BR PCAP_IF_CONNECTION_STATUS_CONNECTED , +.BR PCAP_IF_CONNECTION_STATUS_DISCONNECTED , +and +.B PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE +constants became available in libpcap release 1.9.0. .SH SEE ALSO -pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), -pcap_open_live(3PCAP) +pcap(3PCAP) diff --git a/pcap_freecode.3pcap b/pcap_freecode.3pcap index fac4b3df2a6d..4e71efa49cf2 100644 --- a/pcap_freecode.3pcap +++ b/pcap_freecode.3pcap @@ -35,9 +35,9 @@ void pcap_freecode(struct bpf_program *); is used to free up allocated memory pointed to by a .I bpf_program struct generated by -.B pcap_compile() +.B pcap_compile(3PCAP) when that BPF program is no longer needed, for example after it has been made the filter program for a pcap structure by a call to -.BR pcap_setfilter() . +.BR pcap_setfilter(3PCAP) . .SH SEE ALSO -pcap(3PCAP), pcap_compile(3PCAP), pcap_setfilter(3PCAP) +pcap(3PCAP) diff --git a/pcap_get_required_select_timeout.3pcap b/pcap_get_required_select_timeout.3pcap index 09b393484dee..e58cb4e78d5c 100644 --- a/pcap_get_required_select_timeout.3pcap +++ b/pcap_get_required_select_timeout.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_GET_REQUIRED_SELECT_TIMEOUT 3PCAP "19 January 2018" +.TH PCAP_GET_REQUIRED_SELECT_TIMEOUT 3PCAP "25 July 2018" .SH NAME pcap_get_required_select_timeout \- get a file descriptor on which a select() can be done for a live capture @@ -36,24 +36,27 @@ struct timeval *pcap_get_required_select_timeout(pcap_t *p); returns, on UNIX, a pointer to a .B struct timeval containing a value that must be used as the minimum timeout in -.BR select() , -.BR poll() , -.BR epoll_wait() , +.BR select(2) , +.BR poll(2) , +.BR epoll_wait(2) , and .B kevent() calls if -.B pcap_get_selectable_fd() -returns \-1. +.B pcap_get_selectable_fd(3PCAP) +returns +.BR PCAP_ERROR . .PP The timeout that should be used in those calls must be no larger than the smallest of all timeouts returned by -.B pcap_get_required_select_timeout() +.B \%pcap_get_required_select_timeout() for devices from which packets will be captured. .PP The device for which .B pcap_get_selectable_fd() -returned \-1 must be put in non-blocking mode with -.BR pcap_setnonblock() , +returned +.B PCAP_ERROR +must be put in non-blocking mode with +.BR pcap_setnonblock(3PCAP) , and an attempt must always be made to read packets from the device when the .BR select() , @@ -66,9 +69,9 @@ call returns. Note that a device on which a read can be done without blocking may, on some platforms, not have any packets to read if the packet buffer timeout has expired. A call to -.B pcap_dispatch() +.B pcap_dispatch(3PCAP) or -.B pcap_next_ex() +.B pcap_next_ex(3PCAP) will return 0 in this case, but will not block. .PP .B pcap_get_required_select_timeout() @@ -79,6 +82,17 @@ A pointer to a is returned if the timeout is required; otherwise .B NULL is returned. +.SH BACKWARD COMPATIBILITY +This function became available in libpcap release 1.9.0. In previous +releases, +.BR select() , +.BR poll() , +.BR epoll_wait() , +and +.B kevent() +cannot be used on any capture source for which +.B pcap_get_selectable_fd +returns \-1. .SH SEE ALSO pcap(3PCAP), pcap_get_selectable_fd(3PCAP), select(2), poll(2), epoll_wait(2), kqueue(2) diff --git a/pcap_get_selectable_fd.3pcap b/pcap_get_selectable_fd.3pcap index 160a23f7daca..7f43db398e61 100644 --- a/pcap_get_selectable_fd.3pcap +++ b/pcap_get_selectable_fd.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_GET_SELECTABLE_FD 3PCAP "20 January 2017" +.TH PCAP_GET_SELECTABLE_FD 3PCAP "25 July 2018" .SH NAME pcap_get_selectable_fd \- get a file descriptor on which a select() can be done for a live capture @@ -36,32 +36,38 @@ int pcap_get_selectable_fd(pcap_t *p); returns, on UNIX, a file descriptor number for a file descriptor on which one can do a -.BR select() , -.BR poll() , -.BR epoll_wait() , +.BR select(2) , +.BR poll(2) , +.BR epoll_wait(2) , .BR kevent() , or other such call to wait for it to be possible to read packets without blocking, if such -a descriptor exists, or \-1, if no such descriptor exists. +a descriptor exists, or +.BR PCAP_ERROR , +if no such descriptor exists. .PP Some network devices opened with -.B pcap_create() +.B pcap_create(3PCAP) and -.BR pcap_activate() , +.BR pcap_activate(3PCAP) , or with -.BR pcap_open_live() , +.BR pcap_open_live(3PCAP) , do not support those calls (for example, regular network devices on -FreeBSD 4.3 and 4.4, and Endace DAG devices), so \-1 is returned for +FreeBSD 4.3 and 4.4, and Endace DAG devices), so +.B PCAP_ERROR +is returned for those devices. In that case, those calls must be given a timeout less than or equal to the timeout returned by -.B pcap_get_required_select_timeout() +.B pcap_get_required_select_timeout(3PCAP) for the device for which .B pcap_get_selectable_fd() -returned \-1, the device must be put in non-blocking mode with a call to -.BR pcap_setnonblock() , +returned +.BR PCAP_ERROR , +the device must be put in non-blocking mode with a call to +.BR \%pcap_setnonblock(3PCAP) , and an attempt must always be made to read packets from the device when the call returns. If -.B pcap_get_required_select_timeout() +.B \%pcap_get_required_select_timeout() returns .BR NULL , it is not possible to wait for packets to arrive on the device in an @@ -70,9 +76,9 @@ event loop. Note that a device on which a read can be done without blocking may, on some platforms, not have any packets to read if the packet buffer timeout has expired. A call to -.B pcap_dispatch() +.B pcap_dispatch(3PCAP) or -.B pcap_next_ex() +.B pcap_next_ex(3PCAP) will return 0 in this case, but will not block. .PP Note that in: @@ -138,8 +144,8 @@ work on that descriptor in Mac OS X 10.6 and later. .B pcap_get_selectable_fd() is not available on Windows. .SH RETURN VALUE -A selectable file descriptor is returned if one exists; otherwise, \-1 +A selectable file descriptor is returned if one exists; otherwise, +.B PCAP_ERROR is returned. .SH SEE ALSO -pcap(3PCAP), pcap_get_required_select_timeout(3PCAP), -pcap_setnonblock(3PCAP), select(2), poll(2), epoll_wait(2), kqueue(2) +pcap(3PCAP), kqueue(2) diff --git a/pcap_get_tstamp_precision.3pcap.in b/pcap_get_tstamp_precision.3pcap.in index 285e77095e43..2e72e0bac14f 100644 --- a/pcap_get_tstamp_precision.3pcap.in +++ b/pcap_get_tstamp_precision.3pcap.in @@ -46,6 +46,10 @@ or which indicates that pcap captures contains time stamps in microseconds or nanoseconds respectively. +.SH BACKWARD COMPATIBILITY +This function became available in libpcap release 1.5.1. In previous +releases, time stamps from a capture device or savefile are always given +in seconds and microseconds. .SH SEE ALSO pcap(3PCAP), pcap_set_tstamp_precision(3PCAP), diff --git a/pcap_geterr.3pcap b/pcap_geterr.3pcap index 2e99c37de31c..ee681c8c2296 100644 --- a/pcap_geterr.3pcap +++ b/pcap_geterr.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_GETERR 3PCAP "3 January 2014" +.TH PCAP_GETERR 3PCAP "15 January 2016" .SH NAME pcap_geterr, pcap_perror \- get or print libpcap error message text .SH SYNOPSIS diff --git a/pcap_inject.3pcap b/pcap_inject.3pcap index ff9792d20966..92a92638849b 100644 --- a/pcap_inject.3pcap +++ b/pcap_inject.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_INJECT 3PCAP "3 January 2014" +.TH PCAP_INJECT 3PCAP "25 July 2018" .SH NAME pcap_inject, pcap_sendpacket \- transmit a packet .SH SYNOPSIS @@ -42,7 +42,7 @@ is the number of bytes in the packet. Note that, even if you successfully open the network interface, you might not have permission to send packets on it, or it might not support sending packets; as -.I pcap_open_live() +.B pcap_open_live(3PCAP) doesn't have a flag to indicate whether to open for capturing, sending, or capturing and sending, you cannot request an open that supports sending and be notified at open time whether sending will be possible. @@ -72,17 +72,23 @@ comes from OpenBSD; comes from WinPcap. Both are provided for compatibility.) .SH RETURN VALUE .B pcap_inject() -returns the number of bytes written on success and \-1 on failure. +returns the number of bytes written on success and +.B PCAP_ERROR +on failure. .PP .B pcap_sendpacket() -returns 0 on success and \-1 on failure. +returns 0 on success and +.B PCAP_ERROR +on failure. .PP -If \-1 is returned, -.B pcap_geterr() +If +.B PCAP_ERROR +is returned, +.B pcap_geterr(3PCAP) or -.B pcap_perror() +.B pcap_perror(3PCAP) may be called with .I p as an argument to fetch or display the error text. .SH SEE ALSO -pcap(3PCAP), pcap_geterr(3PCAP) +pcap(3PCAP) diff --git a/pcap_is_swapped.3pcap b/pcap_is_swapped.3pcap index c4e62ae54769..67f762fedcfa 100644 --- a/pcap_is_swapped.3pcap +++ b/pcap_is_swapped.3pcap @@ -39,11 +39,11 @@ than the current system. For a live capture, it always returns false (0). .PP It must not be called on a pcap descriptor created by -.B pcap_create() +.B \%pcap_create(3PCAP) that has not yet been activated by -.BR pcap_activate() . +.BR \%pcap_activate(3PCAP) . .SH RETURN VALUE -.B pcap_datalink() +.B pcap_is_swapped() returns true (1) or false (0) on success and .B PCAP_ERROR_NOT_ACTIVATED if called on a capture handle that has been created but not activated. diff --git a/pcap_list_datalinks.3pcap.in b/pcap_list_datalinks.3pcap.in index 9f52b63bb98c..60ba478f7466 100644 --- a/pcap_list_datalinks.3pcap.in +++ b/pcap_list_datalinks.3pcap.in @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_LIST_DATALINKS 3PCAP "8 March 2015" +.TH PCAP_LIST_DATALINKS 3PCAP "25 July 2018" .SH NAME pcap_list_datalinks, pcap_free_datalinks \- get a list of link-layer header types supported by a capture device, and free that list @@ -47,9 +47,9 @@ which frees the list of link-layer header types pointed to by .IR dlt_list . .LP It must not be called on a pcap descriptor created by -.B pcap_create() +.B \%pcap_create(3PCAP) that has not yet been activated by -.BR pcap_activate() . +.BR \%pcap_activate(3PCAP) . .SH RETURN VALUE .B pcap_list_datalinks() returns the number of link-layer header types in the array on success, @@ -57,17 +57,17 @@ returns the number of link-layer header types in the array on success, if called on a capture handle that has been created but not activated, and .B PCAP_ERROR -(\-1) on other errors. +on other errors. If .B PCAP_ERROR is returned, -.B pcap_geterr() +.B pcap_geterr(3PCAP) or -.B pcap_perror() +.B \%pcap_perror(3PCAP) may be called with .I p as an argument to fetch or display the error text. .SH SEE ALSO -pcap(3PCAP), pcap_geterr(3PCAP), +pcap(3PCAP), pcap_datalink_val_to_name(3PCAP), pcap-linktype(@MAN_MISC_INFO@) diff --git a/pcap_list_tstamp_types.3pcap.in b/pcap_list_tstamp_types.3pcap.in index a139324f31c3..e2487f704fd8 100644 --- a/pcap_list_tstamp_types.3pcap.in +++ b/pcap_list_tstamp_types.3pcap.in @@ -18,7 +18,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_LIST_TSTAMP_TYPES 3PCAP "22 August 2010" +.TH PCAP_LIST_TSTAMP_TYPES 3PCAP "22 August 2018" .SH NAME pcap_list_tstamp_types, pcap_free_tstamp_types \- get a list of time stamp types supported by a capture device, and free that list @@ -54,17 +54,28 @@ which frees the list pointed to by returns the number of time stamp types in the array on success and .B PCAP_ERROR on failure. -A return value of zero means that you cannot specify a time stamp type; -you are limited to the capture device's default time stamp type. +A return value of one means that the only time stamp type supported is +the one in the list, which is the capture device's default time stamp +type. A return value of zero means that the only time stamp type +supported is +.BR PCAP_TSTAMP_HOST , +which is the capture device's default time stamp type (only older +versions of libpcap will return that; newer versions will always return +one or more types). If .B PCAP_ERROR is returned, -.B pcap_geterr() +.B pcap_geterr(3PCAP) or -.B pcap_perror() +.B pcap_perror(3PCAP) may be called with .I p as an argument to fetch or display the error text. +.SH BACKWARD COMPATIBILITY +.PP +These functions became available in libpcap release 1.2.1. In previous +releases, the time stamp type cannot be set; only the default time stamp +type offered by a capture source is available. .SH SEE ALSO -pcap(3PCAP), pcap_geterr(3PCAP), pcap_tstamp_type_val_to_name(3PCAP), +pcap(3PCAP), pcap_tstamp_type_val_to_name(3PCAP), pcap-tstamp(@MAN_MISC_INFO@) diff --git a/pcap_lookupdev.3pcap b/pcap_lookupdev.3pcap index 45c4ef8bfb70..29f09e375297 100644 --- a/pcap_lookupdev.3pcap +++ b/pcap_lookupdev.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_LOOKUPDEV 3PCAP "3 January 2014" +.TH PCAP_LOOKUPDEV 3PCAP "8 September 2017" .SH NAME pcap_lookupdev \- find the default device on which to capture .SH SYNOPSIS @@ -47,13 +47,13 @@ possible.) .B pcap_lookupdev() returns a pointer to a string giving the name of a network device suitable for use with -.B pcap_create() +.B pcap_create(3PCAP) and -.BR pcap_activate() , +.BR \%pcap_activate(3PCAP) , or with -.BR pcap_open_live() , +.BR pcap_open_live(3PCAP) , and with -.BR pcap_lookupnet() . +.BR pcap_lookupnet(3PCAP) . If there is an error, .B NULL is returned and @@ -64,8 +64,7 @@ is assumed to be able to hold at least .B PCAP_ERRBUF_SIZE chars. .SH SEE ALSO -pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), -pcap_open_live(3PCAP), pcap_lookupnet(3PCAP) +pcap(3PCAP) .SH BUGS The pointer returned by .B pcap_lookupdev() diff --git a/pcap_lookupnet.3pcap b/pcap_lookupnet.3pcap index c38ff3a8e339..f609445311c4 100644 --- a/pcap_lookupnet.3pcap +++ b/pcap_lookupnet.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_LOOKUPNET 3PCAP "3 January 2014" +.TH PCAP_LOOKUPNET 3PCAP "25 July 2018" .SH NAME pcap_lookupnet \- find the IPv4 network number and netmask for a device .SH SYNOPSIS @@ -51,8 +51,11 @@ are pointers. .SH RETURN VALUE .B pcap_lookupnet() -returns 0 on success and \-1 on failure. -If \-1 is returned, +returns 0 on success and +.B PCAP_ERROR +on failure. If +.B PCAP_ERROR +is returned, .I errbuf is filled in with an appropriate error message. .I errbuf diff --git a/pcap_loop.3pcap b/pcap_loop.3pcap index 15ad41012b40..0193714b885b 100644 --- a/pcap_loop.3pcap +++ b/pcap_loop.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_LOOP 3PCAP "20 January 2017" +.TH PCAP_LOOP 3PCAP "25 July 2018" .SH NAME pcap_loop, pcap_dispatch \- process packets from a live capture or savefile .SH SYNOPSIS @@ -47,7 +47,7 @@ processes packets from a live capture or ``savefile'' until .I cnt packets are processed, the end of the ``savefile'' is reached when reading from a ``savefile'', -.B pcap_breakloop() +.B pcap_breakloop(3PCAP) is called, or an error occurs. It does .B not @@ -123,20 +123,20 @@ them. .PP The bytes of data from the packet begin with a link-layer header. The format of the link-layer header is indicated by the return value of the -.B pcap_datalink() +.B pcap_datalink(3PCAP) routine when handed the .B pcap_t value also passed to .B pcap_loop() or .BR pcap_dispatch() . -.I http://www.tcpdump.org/linktypes.html +.I https://www.tcpdump.org/linktypes.html lists the values .B pcap_datalink() can return and describes the packet formats that correspond to those values. The value it returns will be valid for all packets received unless and until -.B pcap_set_datalink() +.B pcap_set_datalink(3PCAP) is called; after a successful call to .BR pcap_set_datalink() , all subsequent packets will have a link-layer header of the type @@ -160,8 +160,11 @@ for Ethernet. returns 0 if .I cnt is exhausted or if, when reading from a ``savefile'', no more packets -are available. It returns \-1 if an error occurs or \-2 if the loop -terminated due to a call to +are available. It returns +.B PCAP_ERROR +if an error occurs or +.B PCAP_ERROR_BREAK +if the loop terminated due to a call to .B pcap_breakloop() before any packets were processed. It does @@ -177,23 +180,27 @@ platforms that support a packet buffer timeout that starts before any packets arrive, the timeout expires before any packets arrive, or if the file descriptor for the capture device is in non-blocking mode and no packets were available to be read) or if no more packets are available -in a ``savefile.'' It returns \-1 if an error occurs or \-2 if the loop -terminated due to a call to +in a ``savefile.'' It returns +.B PCAP_ERROR +if an error occurs or +.B PCAP_ERROR_BREAK +if the loop terminated due to a call to .B pcap_breakloop() before any packets were processed. .ft B If your application uses pcap_breakloop(), -make sure that you explicitly check for \-1 and \-2, rather than just -checking for a return value < 0. +make sure that you explicitly check for PCAP_ERROR and PCAP_ERROR_BREAK, +rather than just checking for a return value < 0. .ft R .PP -If \-1 is returned, -.B pcap_geterr() +If +.B PCAP_ERROR +is returned, +.B pcap_geterr(3PCAP) or -.B pcap_perror() +.B pcap_perror(3PCAP) may be called with .I p as an argument to fetch or display the error text. .SH SEE ALSO -pcap(3PCAP), pcap_geterr(3PCAP), pcap_breakloop(3PCAP), -pcap_datalink(3PCAP) +pcap(3PCAP) diff --git a/pcap_major_version.3pcap b/pcap_major_version.3pcap index 0793063f886e..2fedfd2d7847 100644 --- a/pcap_major_version.3pcap +++ b/pcap_major_version.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_MAJOR_VERSION 3PCAP "7 April 2014" +.TH PCAP_MAJOR_VERSION 3PCAP "8 January 2018" .SH NAME pcap_major_version, pcap_minor_version \- get the version number of a savefile .SH SYNOPSIS diff --git a/pcap_next_ex.3pcap b/pcap_next_ex.3pcap index f975ccfd0516..f0eb82d1ea0f 100644 --- a/pcap_next_ex.3pcap +++ b/pcap_next_ex.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_NEXT_EX 3PCAP "20 January 2017" +.TH PCAP_NEXT_EX 3PCAP "25 July 2018" .SH NAME pcap_next_ex, pcap_next \- read the next packet from a pcap_t .SH SYNOPSIS @@ -49,9 +49,9 @@ and the packet data are not to be freed by the caller, and are not guaranteed to be valid after the next call to .BR pcap_next_ex() , .BR pcap_next() , -.BR pcap_loop() , +.BR pcap_loop(3PCAP) , or -.BR pcap_dispatch() ; +.BR pcap_dispatch(3PCAP) ; if the code needs them to remain valid, it must make a copy of them. .PP .B pcap_next() @@ -78,20 +78,20 @@ is filled in with the appropriate values for the packet. .PP The bytes of data from the packet begin with a link-layer header. The format of the link-layer header is indicated by the return value of the -.B pcap_datalink() +.B pcap_datalink(PCAP) routine when handed the .B pcap_t value also passed to .B pcap_loop() or .BR pcap_dispatch() . -.I http://www.tcpdump.org/linktypes.html +.I https://www.tcpdump.org/linktypes.html lists the values .B pcap_datalink() can return and describes the packet formats that correspond to those values. The value it returns will be valid for all packets received unless and until -.B pcap_set_datalink() +.B pcap_set_datalink(3PCAP) is called; after a successful call to .BR pcap_set_datalink() , all subsequent packets will have a link-layer header of the type @@ -114,12 +114,17 @@ for Ethernet. .B pcap_next_ex() returns 1 if the packet was read without problems, 0 if packets are being read from a live capture and the packet buffer timeout expired, -\-1 if an error occurred while reading the packet, and \-2 if packets +.B PCAP_ERROR +if an error occurred while reading the packet, and +.B PCAP_ERROR_BREAK +if packets are being read from a ``savefile'' and there are no more packets to read -from the savefile. If \-1 is returned, -.B pcap_geterr() +from the savefile. If +.B PCAP_ERROR +is returned, +.B pcap_geterr(3PCAP) or -.B pcap_perror() +.B pcap_perror(3PCAP) may be called with .I p as an argument to fetch or display the error text. @@ -136,5 +141,4 @@ non-blocking mode and no packets were available to be read), or if no more packets are available in a ``savefile.'' Unfortunately, there is no way to determine whether an error occurred or not. .SH SEE ALSO -pcap(3PCAP), pcap_geterr(3PCAP), pcap_dispatch(3PCAP), -pcap_datalink(3PCAP) +pcap(3PCAP) diff --git a/pcap_offline_filter.3pcap b/pcap_offline_filter.3pcap index 08c0b66b3349..724f8366b496 100644 --- a/pcap_offline_filter.3pcap +++ b/pcap_offline_filter.3pcap @@ -39,7 +39,7 @@ checks whether a filter matches a packet. is a pointer to a .I bpf_program struct, usually the result of a call to -.BR pcap_compile() . +.BR pcap_compile(3PCAP) . .I h points to the .I pcap_pkthdr @@ -52,4 +52,4 @@ returns the return value of the filter program. This will be zero if the packet doesn't match the filter and non-zero if the packet matches the filter. .SH SEE ALSO -pcap(3PCAP), pcap_compile(3PCAP) +pcap(3PCAP) diff --git a/pcap_open_dead.3pcap.in b/pcap_open_dead.3pcap.in index 621e75b5b58a..97a97f3ac8c0 100644 --- a/pcap_open_dead.3pcap.in +++ b/pcap_open_dead.3pcap.in @@ -43,10 +43,10 @@ are used for creating a structure to use when calling the other functions in libpcap. It is typically used when just using libpcap for compiling BPF code; it can also be used if using -.BR pcap_dump_open() , -.BR pcap_dump() , +.BR pcap_dump_open(3PCAP) , +.BR pcap_dump(3PCAP) , and -.B pcap_dump_close() +.B pcap_dump_close(3PCAP) to write a savefile if there is no .B pcap_t that supplies the packets to be written. @@ -73,7 +73,6 @@ seconds and microseconds, and .B PCAP_TSTAMP_PRECISION_NANO should be specified if the packets to be written have time stamps in seconds and nanoseconds. Its value does not affect -.BR pcap_compile() . +.BR pcap_compile(3PCAP) . .SH SEE ALSO -pcap(3PCAP), pcap_compile(3PCAP), pcap_dump_open(3PCAP), -\%pcap-linktype(@MAN_MISC_INFO@) +pcap(3PCAP), \%pcap-linktype(@MAN_MISC_INFO@) diff --git a/pcap_open_live.3pcap b/pcap_open_live.3pcap index d9ce8eec1446..3286e294c425 100644 --- a/pcap_open_live.3pcap +++ b/pcap_open_live.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_OPEN_LIVE 3PCAP "20 January 2017" +.TH PCAP_OPEN_LIVE 3PCAP "6 December 2017" .SH NAME pcap_open_live \- open a device for capturing .SH SYNOPSIS @@ -87,4 +87,4 @@ is assumed to be able to hold at least .B PCAP_ERRBUF_SIZE chars. .SH SEE ALSO -pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP) +pcap_create(3PCAP), pcap_activate(3PCAP) diff --git a/pcap_open_offline.3pcap.in b/pcap_open_offline.3pcap.in index 9bbffcee3b07..2bfbbace202e 100644 --- a/pcap_open_offline.3pcap.in +++ b/pcap_open_offline.3pcap.in @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_OPEN_OFFLINE 3PCAP "3 January 2014" +.TH PCAP_OPEN_OFFLINE 3PCAP "8 January 2018 " .SH NAME pcap_open_offline, pcap_open_offline_with_tstamp_precision, pcap_fopen_offline, pcap_fopen_offline_with_tstamp_precision \- open a saved capture file for reading @@ -81,7 +81,8 @@ or .B pcap_fopen_offline_with_tstamp_precision() to read dumped data from an existing open stream .IR fp . -.B pcap_fopen_offline_with_tstamp_precision() takes an additional +.B pcap_fopen_offline_with_tstamp_precision() +takes an additional .I precision argument as described above. Note that on Windows, that stream should be opened in binary mode. @@ -105,5 +106,11 @@ is filled in with an appropriate error message. is assumed to be able to hold at least .B PCAP_ERRBUF_SIZE chars. +.SH BACKWARD COMPATIBILITY +.B pcap_open_offline_with_tstamp_precision +and +.B pcap_fopen_offline_with_tstamp_precision +became available in libpcap release 1.5.1. In previous releases, time +stamps from a savefile are always given in seconds and microseconds. .SH SEE ALSO pcap(3PCAP), pcap-savefile(@MAN_FILE_FORMATS@) diff --git a/pcap_set_datalink.3pcap b/pcap_set_datalink.3pcap index 24d57a541c83..66cfdb1e7a9a 100644 --- a/pcap_set_datalink.3pcap +++ b/pcap_set_datalink.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SET_DATALINK 3PCAP "3 January 2014" +.TH PCAP_SET_DATALINK 3PCAP "25 July 2018" .SH NAME pcap_set_datalink \- set the link-layer header type to be used by a capture device @@ -38,14 +38,16 @@ to the type specified by .IR dlt . .SH RETURN VALUE .B pcap_set_datalink() -returns 0 on success and \-1 on failure. -If \-1 is returned, -.B pcap_geterr() +returns 0 on success and +.B PCAP_ERROR +on failure. If +.B PCAP_ERROR +is returned, +.B pcap_geterr(3PCAP) or -.B pcap_perror() +.B pcap_perror(3PCAP) may be called with .I p as an argument to fetch or display the error text. .SH SEE ALSO -pcap(3PCAP), pcap_geterr(3PCAP), -pcap_datalink_name_to_val(3PCAP) +pcap(3PCAP), pcap_datalink_name_to_val(3PCAP) diff --git a/pcap_set_immediate_mode.3pcap b/pcap_set_immediate_mode.3pcap.in similarity index 54% rename from pcap_set_immediate_mode.3pcap rename to pcap_set_immediate_mode.3pcap.in index b3ad24315189..2fe45c5439f2 100644 --- a/pcap_set_immediate_mode.3pcap +++ b/pcap_set_immediate_mode.3pcap.in @@ -18,7 +18,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SET_IMMEDIATE_MODE 3PCAP "5 December 2013" +.TH PCAP_SET_IMMEDIATE_MODE 3PCAP "22 August 2018" .SH NAME pcap_set_immediate_mode \- set immediate mode for a not-yet-activated capture handle @@ -34,7 +34,8 @@ int pcap_set_immediate_mode(pcap_t *p, int immediate_mode); .SH DESCRIPTION .B pcap_set_immediate_mode() sets whether immediate mode should be set on a capture handle when -the handle is activated. +the handle is activated. In immediate mode, packets are always +delivered as soon as they arrive, with no buffering. If .I immediate_mode is non-zero, immediate mode will be set, otherwise it will not be set. @@ -43,5 +44,52 @@ is non-zero, immediate mode will be set, otherwise it will not be set. returns 0 on success or .B PCAP_ERROR_ACTIVATED if called on a capture handle that has been activated. +.SH BACKWARD COMPATIBILITY +.PP +This function became available in libpcap release 1.5.0. In previous +releases, if immediate delivery of packets is required: +.IP +on FreeBSD, NetBSD, OpenBSD, DragonFly BSD, macOS, and Solaris 11, +immediate mode must be turned on with a +.B BIOCIMMEDIATE +.BR ioctl (2), +as documented in +.BR bpf(@MAN_DEVICES@) , +on the descriptor returned by +.B pcap_fileno(3PCAP), +after +.BR pcap_activate(3PCAP) +is called; +.IP +on Solaris 10 and earlier versions of Solaris, immediate mode must be +turned on by using a read timeout of 0 when opening the device (this +will not provide immediate delivery of packets on other platforms, so +don't assume it's sufficient); +.IP +on Digital UNIX/Tru64 UNIX, immediate mode must be turned on by doing a +.B BIOCMBIC +.BR ioctl , +as documented in +.BR packetfilter(7) , +to clear the +.B ENBATCH +flag on the descriptor returned by +.B pcap_fileno(3PCAP), +after +.BR pcap_activate(3PCAP) +is called; +.IP +on Windows, immediate mode must be turned on by calling +.B pcap_setmintocopy() +with a size of 0. +.PP +On Linux, with previous releases of libpcap, capture devices are always +in immediate mode; however, in 1.5.0 and later, they are, by default, +.B not +in immediate mode, so if +.B pcap_set_immediate_mode() +is available, it should be used. +.PP +On other platforms, capture devices are always in immediate mode. .SH SEE ALSO pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP) diff --git a/pcap_set_protocol.3pcap b/pcap_set_protocol_linux.3pcap similarity index 84% rename from pcap_set_protocol.3pcap rename to pcap_set_protocol_linux.3pcap index 9d4a23165312..873017ba9886 100644 --- a/pcap_set_protocol.3pcap +++ b/pcap_set_protocol_linux.3pcap @@ -17,9 +17,9 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SET_PROTOCOL 3PCAP "3 January 2014" +.TH PCAP_SET_PROTOCOL_LINUX 3PCAP "24 August 2017" .SH NAME -pcap_set_protocol \- set capture protocol for a not-yet-activated +pcap_set_protocol_linux \- set capture protocol for a not-yet-activated capture handle .SH SYNOPSIS .nf @@ -27,12 +27,12 @@ capture handle #include .LP .ft B -int pcap_set_protocol(pcap_t *p, int protocol); +int pcap_set_protocol_linux(pcap_t *p, int protocol); .ft .fi .SH DESCRIPTION On network interface devices on Linux, -.B pcap_set_protocol() +.B pcap_set_protocol_linux() sets the protocol to be used in the .BR socket (2) call to create a capture socket when the handle is activated. The @@ -48,7 +48,7 @@ other than a network interface, it will have no effect. .LP It should not be used in portable code; instead, a filter should be specified with -.BR pcap_setfilter() . +.BR pcap_setfilter(3PCAP) . .LP If a given network interface provides a standard link-layer header, with a standard packet type, but provides some packet types with a different @@ -56,12 +56,13 @@ socket-layer protocol type from the one in the link-layer header, that packet type cannot be filtered with a filter specified with .B pcap_setfilter() but can be filtered by specifying the socket-layer protocol type using -.BR pcap_set_protocol() . +.BR pcap_set_protocol_linux() . .SH RETURN VALUE -.B pcap_set_protocol() +.B pcap_set_protocol_linux() returns 0 on success or .B PCAP_ERROR_ACTIVATED if called on a capture handle that has been activated. +.SH BACKWARD COMPATIBILITY +This function became available in libpcap release 1.9.0. .SH SEE ALSO -pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), socket(2), -pcap_setfilter(3PCAP) +pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP) diff --git a/pcap_set_timeout.3pcap b/pcap_set_timeout.3pcap index 8cb8cb6487d8..e67b8132f732 100644 --- a/pcap_set_timeout.3pcap +++ b/pcap_set_timeout.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SET_TIMEOUT 3PCAP "20 January 2017" +.TH PCAP_SET_TIMEOUT 3PCAP "6 December 2017" .SH NAME pcap_set_timeout \- set the packet buffer timeout for a not-yet-activated capture handle @@ -49,5 +49,5 @@ returns 0 on success or .B PCAP_ERROR_ACTIVATED if called on a capture handle that has been activated. .SH SEE ALSO -pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP), +pcap_create(3PCAP), pcap_activate(3PCAP), \%pcap_set_immediate_mode(3PCAP) diff --git a/pcap_set_tstamp_precision.3pcap.in b/pcap_set_tstamp_precision.3pcap.in index 57c4ea301cf3..dc2b4b3d2a5e 100644 --- a/pcap_set_tstamp_precision.3pcap.in +++ b/pcap_set_tstamp_precision.3pcap.in @@ -39,9 +39,9 @@ sets the precision of the time stamp desired for packets captured on the pcap descriptor to the type specified by .IR tstamp_precision . It must be called on a pcap descriptor created by -.B pcap_create() +.B pcap_create(3PCAP) that has not yet been activated by -.BR pcap_activate() . +.BR pcap_activate(3PCAP) . Two time stamp precisions are supported, microseconds and nanoseconds. One can use options .B PCAP_TSTAMP_PRECISION_MICRO and @@ -50,11 +50,16 @@ to request desired precision. By default, time stamps are in microseconds. .SH RETURN VALUE .B pcap_set_tstamp_precision() returns 0 on success if the specified time stamp precision is expected to be -supported by the operating system, +supported by the capture device, .B PCAP_ERROR_TSTAMP_PRECISION_NOTSUP -if operating system does not support requested time stamp precision, +if the capture device does not support the requested time stamp +precision, .B PCAP_ERROR_ACTIVATED if called on a capture handle that has been activated. +.SH BACKWARD COMPATIBILITY +This function became available in libpcap release 1.5.1. In previous +releases, time stamps from a capture device or savefile are always given +in seconds and microseconds. .SH SEE ALSO pcap(3PCAP), pcap_get_tstamp_precision(3PCAP), diff --git a/pcap_set_tstamp_type.3pcap.in b/pcap_set_tstamp_type.3pcap.in index 7899da3106a4..9833f46a3c43 100644 --- a/pcap_set_tstamp_type.3pcap.in +++ b/pcap_set_tstamp_type.3pcap.in @@ -18,7 +18,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SET_TSTAMP_TYPE 3PCAP "5 December 2014" +.TH PCAP_SET_TSTAMP_TYPE 3PCAP "22 August 2018" .SH NAME pcap_set_tstamp_type \- set the time stamp type to be used by a capture device @@ -38,10 +38,10 @@ sets the type of time stamp desired for packets captured on the pcap descriptor to the type specified by .IR tstamp_type . It must be called on a pcap descriptor created by -.B pcap_create() +.B pcap_create(3PCAP) that has not yet been activated by -.BR pcap_activate() . -.B pcap_list_tstamp_types() +.BR pcap_activate(3PCAP) . +.B pcap_list_tstamp_types(3PCAP) will give a list of the time stamp types supported by a given capture device. See @@ -57,9 +57,14 @@ capture device, .B PCAP_ERROR_ACTIVATED if called on a capture handle that has been activated, and .B PCAP_ERROR_CANTSET_TSTAMP_TYPE -if the capture device doesn't support setting the time stamp type. +if the capture device doesn't support setting the time stamp type (only +older versions of libpcap will return that; newer versions will always +allow the time stamp type to be set to the default type). +.SH BACKWARD COMPATIBILITY +.PP +This function became available in libpcap release 1.2.1. In previous +releases, the time stamp type cannot be set; only the default time stamp +type offered by a capture source is available. .SH SEE ALSO pcap(3PCAP), -pcap_list_tstamp_types(3PCAP), -pcap_tstamp_type_name_to_val(3PCAP), -pcap-tstamp(@MAN_MISC_INFO@) +pcap_tstamp_type_name_to_val(3PCAP) diff --git a/pcap_setdirection.3pcap b/pcap_setdirection.3pcap index 11945f5421d5..f174b98f9024 100644 --- a/pcap_setdirection.3pcap +++ b/pcap_setdirection.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SETDIRECTION 3PCAP "8 March 2015" +.TH PCAP_SETDIRECTION 3PCAP "25 July 2018" .SH NAME pcap_setdirection \- set the direction for which packets will be captured .SH SYNOPSIS @@ -57,13 +57,16 @@ support This operation is not supported if a ``savefile'' is being read. .SH RETURN VALUE .B pcap_setdirection() -returns 0 on success and \-1 on failure. -If \-1 is returned, -.B pcap_geterr() +returns 0 on success and +.B PCAP_ERROR +on failure. If +.B PCAP_ERROR +is returned, +.B pcap_geterr(3PCAP) or -.B pcap_perror() +.B pcap_perror(3PCAP) may be called with .I p as an argument to fetch or display the error text. .SH SEE ALSO -pcap(3PCAP), pcap_geterr(3PCAP) +pcap(3PCAP) diff --git a/pcap_setfilter.3pcap b/pcap_setfilter.3pcap index 6efd25398281..872969398469 100644 --- a/pcap_setfilter.3pcap +++ b/pcap_setfilter.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SETFILTER 3PCAP "7 April 2014" +.TH PCAP_SETFILTER 3PCAP "25 July 2018" .SH NAME pcap_setfilter \- set the filter .SH SYNOPSIS @@ -37,16 +37,19 @@ is used to specify a filter program. is a pointer to a .I bpf_program struct, usually the result of a call to -.BR pcap_compile() . +.BR \%pcap_compile(3PCAP) . .SH RETURN VALUE .B pcap_setfilter() -returns 0 on success and \-1 on failure. -If \-1 is returned, -.B pcap_geterr() +returns 0 on success and +.B PCAP_ERROR +on failure. If +.B PCAP_ERROR +is returned, +.B pcap_geterr(3PCAP) or -.B pcap_perror() +.B pcap_perror(3PCAP) may be called with .I p as an argument to fetch or display the error text. .SH SEE ALSO -pcap(3PCAP), pcap_compile(3PCAP), pcap_geterr(3PCAP) +pcap(3PCAP) diff --git a/pcap_setnonblock.3pcap b/pcap_setnonblock.3pcap index 695912701f5c..e8adebea0fa2 100644 --- a/pcap_setnonblock.3pcap +++ b/pcap_setnonblock.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_SETNONBLOCK 3PCAP "18 October 2014" +.TH PCAP_SETNONBLOCK 3PCAP "25 July 2018" .SH NAME pcap_setnonblock, pcap_getnonblock \- set or get the state of non-blocking mode on a capture device @@ -43,25 +43,27 @@ puts a capture handle into ``non-blocking'' mode, or takes it out of ``non-blocking'' mode, depending on whether the .I nonblock argument is non-zero or zero. It has no effect on ``savefiles''. -If there is an error, \-1 is returned and +If there is an error, +.B PCAP_ERROR +is returned and .I errbuf is filled in with an appropriate error message; otherwise, 0 is returned. In ``non-blocking'' mode, an attempt to read from the capture descriptor with -.B pcap_dispatch() +.B pcap_dispatch(3PCAP) will, if no packets are currently available to be read, return 0 immediately rather than blocking waiting for packets to arrive. -.B pcap_loop() +.B pcap_loop(3PCAP) and -.B pcap_next() +.B pcap_next(3PCAP) will not work in ``non-blocking'' mode. .PP When first activated with -.B pcap_activate() +.B pcap_activate(3PCAP) or opened with -.B pcap_open_live() , +.B pcap_open_live(3PCAP) , a capture handle is not in ``non-blocking mode''; a call to .B pcap_setnonblock() is required in order to put it into ``non-blocking'' mode. @@ -69,7 +71,9 @@ is required in order to put it into ``non-blocking'' mode. .B pcap_getnonblock() returns the current ``non-blocking'' state of the capture descriptor; it always returns 0 on ``savefiles''. -If there is an error, \-1 is returned and +If there is an error, +.B PCAP_ERROR +is returned and .I errbuf is filled in with an appropriate error message. .PP @@ -78,4 +82,4 @@ is assumed to be able to hold at least .B PCAP_ERRBUF_SIZE chars. .SH SEE ALSO -pcap(3PCAP), pcap_loop(3PCAP), pcap_next_ex(3PCAP), pcap_geterr(3PCAP) +pcap(3PCAP), pcap_next_ex(3PCAP), pcap_geterr(3PCAP) diff --git a/pcap_snapshot.3pcap b/pcap_snapshot.3pcap index 7af8c33dc437..ee54bb0834fe 100644 --- a/pcap_snapshot.3pcap +++ b/pcap_snapshot.3pcap @@ -33,16 +33,16 @@ int pcap_snapshot(pcap_t *p); .SH DESCRIPTION .B pcap_snapshot() returns the snapshot length specified when -.B pcap_set_snapshot() +.B pcap_set_snaplen(3PCAP) or -.B pcap_open_live() +.B pcap_open_live(3PCAP) was called, for a live capture, or the snapshot length from the capture file, for a ``savefile''. .PP It must not be called on a pcap descriptor created by -.B pcap_create() +.B \%pcap_create(3PCAP) that has not yet been activated by -.BR pcap_activate() . +.BR \%pcap_activate(3PCAP) . .SH RETURN VALUE .B pcap_snapshot() returns the snapshot length on success and diff --git a/pcap_stats.3pcap b/pcap_stats.3pcap index 2dce4b501c52..465dada48ea7 100644 --- a/pcap_stats.3pcap +++ b/pcap_stats.3pcap @@ -17,7 +17,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_STATS 3PCAP "3 January 2014" +.TH PCAP_STATS 3PCAP "25 July 2018" .SH NAME pcap_stats \- get capture statistics .SH SYNOPSIS @@ -83,15 +83,18 @@ statistic is unavailable, so it should not be treated as an indication that the interface did not drop any packets. .SH RETURN VALUE .B pcap_stats() -returns 0 on success and returns \-1 if there is an error or if +returns 0 on success and returns +.B PCAP_ERROR +if there is an error or if .I p -doesn't support packet statistics. -If \-1 is returned, -.B pcap_geterr() +doesn't support packet statistics. If +.B PCAP_ERROR +is returned, +.B pcap_geterr(3PCAP) or -.B pcap_perror() +.B pcap_perror(3PCAP) may be called with .I p as an argument to fetch or display the error text. .SH SEE ALSO -pcap(3PCAP), pcap_geterr(3PCAP) +pcap(3PCAP) diff --git a/pcap_strerror.3pcap b/pcap_strerror.3pcap index 7c7d53f5a941..a5775f4229a5 100644 --- a/pcap_strerror.3pcap +++ b/pcap_strerror.3pcap @@ -37,4 +37,4 @@ is provided in case isn't available. It returns an error message string corresponding to .IR error . .SH SEE ALSO -strerror(3) +pcap(3PCAP) diff --git a/pcap_tstamp_type_name_to_val.3pcap b/pcap_tstamp_type_name_to_val.3pcap index ac2e35dd76da..fdcc6c6d8d62 100644 --- a/pcap_tstamp_type_name_to_val.3pcap +++ b/pcap_tstamp_type_name_to_val.3pcap @@ -18,7 +18,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_TSTAMP_TYPE_NAME_TO_VAL 3PCAP "5 December 2014" +.TH PCAP_TSTAMP_TYPE_NAME_TO_VAL 3PCAP "22 August 2018" .SH NAME pcap_tstamp_type_name_to_val \- get the time stamp type value corresponding to a time stamp type name @@ -41,5 +41,8 @@ value. The translation is case-insensitive. returns time stamp type value on success and .B PCAP_ERROR on failure. +.SH BACKWARD COMPATIBILITY +.PP +This function became available in libpcap release 1.2.1. .SH SEE ALSO pcap(3PCAP), pcap_tstamp_type_val_to_name(3PCAP) diff --git a/pcap_tstamp_type_val_to_name.3pcap b/pcap_tstamp_type_val_to_name.3pcap index 261554ec798a..9374f489c55b 100644 --- a/pcap_tstamp_type_val_to_name.3pcap +++ b/pcap_tstamp_type_val_to_name.3pcap @@ -18,7 +18,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.TH PCAP_TSTAMP_TYPE_VAL_TO_NAME 3PCAP "12 December 2013" +.TH PCAP_TSTAMP_TYPE_VAL_TO_NAME 3PCAP "22 August 2018" .SH NAME pcap_tstamp_type_val_to_name, pcap_tstamp_type_val_to_description \- get a name or description for a time stamp type value @@ -45,5 +45,8 @@ translates a time stamp type value to a short description of that time stamp type. .B NULL is returned on failure. +.SH BACKWARD COMPATIBILITY +.PP +These functions became available in libpcap release 1.2.1. .SH SEE ALSO pcap(3PCAP), pcap_tstamp_type_name_to_val(3PCAP) diff --git a/portability.h b/portability.h index b36125421390..543846e8bd25 100644 --- a/portability.h +++ b/portability.h @@ -38,6 +38,7 @@ * Helpers for portability between Windows and UN*X and between different * flavors of UN*X. */ +#include /* we declare varargs functions on some platforms */ #include "pcap/funcattrs.h" @@ -45,49 +46,45 @@ extern "C" { #endif -#ifndef HAVE_STRLCPY - /* - * Macro that does the same thing as strlcpy(). - */ - #if defined(_MSC_VER) || defined(__MINGW32__) - /* - * strncpy_s() is supported at least back to Visual - * Studio 2005. - */ - #define strlcpy(x, y, z) \ - strncpy_s((x), (z), (y), _TRUNCATE) - - #else - #define strlcpy(x, y, z) \ - (strncpy((x), (y), (z)), \ - ((z) <= 0 ? 0 : ((x)[(z) - 1] = '\0')), \ - (void) strlen((y))) - #endif +#ifdef HAVE_STRLCAT + #define pcap_strlcat strlcat +#else + #if defined(_MSC_VER) || defined(__MINGW32__) + /* + * strncat_s() is supported at least back to Visual + * Studio 2005. + */ + #define pcap_strlcat(x, y, z) \ + strncat_s((x), (z), (y), _TRUNCATE) + #else + /* + * Define it ourselves. + */ + extern size_t pcap_strlcat(char * restrict dst, const char * restrict src, size_t dstsize); + #endif #endif -#ifndef HAVE_STRLCAT - /* - * Macro that does the same thing as strlcat(). - */ - #if defined(_MSC_VER) || defined(__MINGW32__) - /* - * strncat_s() is supported at least back to Visual - * Studio 2005. - */ - #define strlcat(x, y, z) \ - strncat_s((x), (z), (y), _TRUNCATE) - #else - /* - * ANSI C says strncat() always null-terminates its first argument, - * so 1) we don't need to explicitly null-terminate the string - * ourselves and 2) we need to leave room for the null terminator. - */ - #define strlcat(x, y, z) \ - strncat((x), (y), (z) - strlen((x)) - 1) - #endif +#ifdef HAVE_STRLCPY + #define pcap_strlcpy strlcpy +#else + #if defined(_MSC_VER) || defined(__MINGW32__) + /* + * strncpy_s() is supported at least back to Visual + * Studio 2005. + */ + #define pcap_strlcpy(x, y, z) \ + strncpy_s((x), (z), (y), _TRUNCATE) + #else + /* + * Define it ourselves. + */ + extern size_t pcap_strlcpy(char * restrict dst, const char * restrict src, size_t dstsize); + #endif #endif #ifdef _MSC_VER + #define isascii __isascii + /* * If has been included, and _DEBUG is defined, and * __STDC__ is zero, will define strdup() to call @@ -134,6 +131,23 @@ extern int pcap_snprintf(char *, size_t, PCAP_FORMAT_STRING(const char *), ...) extern int pcap_vsnprintf(char *, size_t, const char *, va_list ap); #endif +/* + * We also want asprintf(), for some cases where we use it to construct + * dynamically-allocated variable-length strings. + */ +#ifdef HAVE_ASPRINTF +#define pcap_asprintf asprintf +#else +extern int pcap_asprintf(char **, PCAP_FORMAT_STRING(const char *), ...) + PCAP_PRINTFLIKE(2, 3); +#endif + +#ifdef HAVE_VASPRINTF +#define pcap_vasprintf vasprintf +#else +extern int pcap_vasprintf(char **, const char *, va_list ap); +#endif + #ifdef HAVE_STRTOK_R #define pcap_strtok_r strtok_r #else @@ -146,7 +160,6 @@ extern int pcap_vsnprintf(char *, size_t, const char *, va_list ap); /* * Define it ourselves. */ - #define NEED_STRTOK_R extern char *pcap_strtok_r(char *, const char *, char **); #endif #endif /* HAVE_STRTOK_R */ diff --git a/rpcap-protocol.h b/rpcap-protocol.h index 83ebdc5b0063..8ae8b62d13bf 100644 --- a/rpcap-protocol.h +++ b/rpcap-protocol.h @@ -63,80 +63,20 @@ * * Version negotiation is done as part of the authentication process: * - * The client sends an authentication request, with the version number - * in the request being the maximum version it supports. + * The client sends an authentication request, with a version number + * of 0. All servers must accept authentication requests with a version + * number of 0, even if they don't support version 0 for any other + * requests. * - * If the server supports that version, it attempts to authenticate the - * client, and replies as appropriate, with the version number in the - * reply being that version. + * The server attempts to authenticate the client. If that succeeds, + * older servers - which only support version 0 - will send an + * authentication reply with no payload. Newer servers - which might + * support other versions - will send an authentication reply with + * a payload giving the minimum and maximum versions it supports. * - * If the server doesn't support that version because it's too large, - * it replies with a RPCAP_MSG_ERROR message, with the maximum version - * they support as the version number in the reply, and with the error - * code being PCAP_ERR_WRONGVER. - * - * If the server doesn't support that version because it's too small, - * it replies with a RPCAP_MSG_ERROR message, with that version as - * the version number in the reply, and with the error code being - * PCAP_ERR_WRONGVER. - * - * If the client supports that version, it retries the authentication - * with that version and, if that fails for any reason, including - * PCAP_ERR_WRONGVER, fails. Otherwise, it fails, telling its caller - * that there's no version that both support. - * - * This requires that the set of versions supported by a client or - * server be a range of integers, with no gaps. Thus: - * - * the client's version set is [Cmin, Cmax], with Cmin <= Cmax; - * - * the server's version set is [Smin, Smax], with Smin <= Smax; - * - * the client sends Cmax as the version number in the initial - * authentication request; - * - * if the server doesn't support the version sent by the client, - * either Smax < Cmax or Smin > Cmax (because the client sent Cmax - * to the server, and the server doesn't support it); - * - * if Smax < Cmax: - * - * the server sends Smax as the version number in the RPCAP_MSG_ERROR/ - * PCAP_ERR_WRONGVER message - the client will accept this because - * Cmax != 0, as these numbers are unsigned, and this means that - * this isn't an old client that rejects all messages with a non-zero - * version number, it's a new client that accepts RPCAP_MSG_ERROR - * messages no matter what the version is; - * - * if Smax >= Cmin, both the client and the server can use it, and - * the client retries with Smax; - * - * if Smax < Cmin, there is no version the client and server can - * both support. - * - * if Smin > Cmax: - * - * the server sends Cmax as the version number in the RPCAP_MSG_ERROR/ - * PCAP_ERR_WRONGVER message - the client will accept this because - * Cmax is a valid client version number. - * - * the client will retry with Cmax, get the same version failure, - * and report that there is no version the client and server can - * both support (as the version sets are disjoint). - * - * Old negotiation-unaware clients just send version 0 and, if they - * get back PCAP_ERR_WRONGVER, treat it as a fatal error. This - * means they'll fail to talk to any server that can't handle - * version 0, which is the appropriate thing to do, as they can - * only use version 0. - * - * Old negotiation-unaware servers fail if they get a version other - * than 0, sending back PCAP_ERR_WRONGVER with version 0, which is - * the only version, and thus both the minimum and maximum version, - * they support. The client will either fail if it doesn't support - * version 0, or will retry with version 0 and succeed, so it will - * fail with servers that can't handle version 0 or will negotiate - * version 0 with servers that can handle version 0. + * The client attempts to find the largest version number that is + * in both its range of supported versions and the server's supported + * versions. If it fails, it gives up; otherwise, it uses that version. */ #define RPCAP_MIN_VERSION 0 #define RPCAP_MAX_VERSION 0 @@ -148,7 +88,8 @@ * comparison will always succeed. */ #if RPCAP_MIN_VERSION == 0 -#define RPCAP_VERSION_IS_SUPPORTED(v) ((v) <= RPCAP_MAX_VERSION) +#define RPCAP_VERSION_IS_SUPPORTED(v) \ + ((v) <= RPCAP_MAX_VERSION) #else #define RPCAP_VERSION_IS_SUPPORTED(v) \ ((v) >= RPCAP_MIN_VERSION && (v) <= RPCAP_MAX_VERSION) @@ -176,6 +117,12 @@ * for better alignment. * These structures have been created in order to be correctly aligned to * a 32-bit boundary, but be careful in any case. + * + * The layout of these structures MUST not be changed. If a packet + * format is different in different versions of the protocol, versions + * of the structure should be provided for all the different versions or + * version ranges (if more than one version of the protocol has the same + * layout) that we support. */ /* @@ -199,6 +146,19 @@ struct rpcap_header uint32 plen; /* Length of the payload of this RPCAP message */ }; +/* + * Format of data that may appear at the end of an authentication reply, + * giving the minimum and maximum versions of the protocol that the + * server supports. + * + * Older servers don't provide this; they support only version 0. + */ +struct rpcap_authreply +{ + uint8 minvers; /* Minimum version supported */ + uint8 maxvers; /* Maximum version supported */ +}; + /* Format of the message for the interface description (findalldevs command) */ struct rpcap_findalldevs_if { @@ -378,7 +338,12 @@ struct rpcap_sampling uint32 value; /* Parameter related to the sampling method */ }; -/* Messages field coding */ +/* + * Messages field coding. + * + * These values are used in messages sent over the network, and MUST + * not be changed. + */ #define RPCAP_MSG_IS_REPLY 0x080 /* Flag indicating a reply */ #define RPCAP_MSG_ERROR 1 /* Message that keeps an error notification */ @@ -410,24 +375,32 @@ struct rpcap_sampling #define RPCAP_UPDATEFILTER_BPF 1 /* This code tells us that the filter is encoded with the BPF/NPF syntax */ -/* Network error codes */ -#define PCAP_ERR_NETW 1 /* Network error */ -#define PCAP_ERR_INITTIMEOUT 2 /* The RPCAP initial timeout has expired */ -#define PCAP_ERR_AUTH 3 /* Generic authentication error */ -#define PCAP_ERR_FINDALLIF 4 /* Generic findalldevs error */ -#define PCAP_ERR_NOREMOTEIF 5 /* The findalldevs was ok, but the remote end had no interfaces to list */ -#define PCAP_ERR_OPEN 6 /* Generic pcap_open error */ -#define PCAP_ERR_UPDATEFILTER 7 /* Generic updatefilter error */ -#define PCAP_ERR_GETSTATS 8 /* Generic pcap_stats error */ -#define PCAP_ERR_READEX 9 /* Generic pcap_next_ex error */ -#define PCAP_ERR_HOSTNOAUTH 10 /* The host is not authorized to connect to this server */ -#define PCAP_ERR_REMOTEACCEPT 11 /* Generic pcap_remoteaccept error */ -#define PCAP_ERR_STARTCAPTURE 12 /* Generic pcap_startcapture error */ -#define PCAP_ERR_ENDCAPTURE 13 /* Generic pcap_endcapture error */ -#define PCAP_ERR_RUNTIMETIMEOUT 14 /* The RPCAP run-time timeout has expired */ -#define PCAP_ERR_SETSAMPLING 15 /* Error during the settings of sampling parameters */ -#define PCAP_ERR_WRONGMSG 16 /* The other end endpoint sent a message which has not been recognized */ -#define PCAP_ERR_WRONGVER 17 /* The other end endpoint has a version number that is not compatible with our */ +/* + * Network error codes. + * + * These values are used in messages sent over the network, and MUST + * not be changed. + */ +#define PCAP_ERR_NETW 1 /* Network error */ +#define PCAP_ERR_INITTIMEOUT 2 /* The RPCAP initial timeout has expired */ +#define PCAP_ERR_AUTH 3 /* Generic authentication error */ +#define PCAP_ERR_FINDALLIF 4 /* Generic findalldevs error */ +#define PCAP_ERR_NOREMOTEIF 5 /* The findalldevs was ok, but the remote end had no interfaces to list */ +#define PCAP_ERR_OPEN 6 /* Generic pcap_open error */ +#define PCAP_ERR_UPDATEFILTER 7 /* Generic updatefilter error */ +#define PCAP_ERR_GETSTATS 8 /* Generic pcap_stats error */ +#define PCAP_ERR_READEX 9 /* Generic pcap_next_ex error */ +#define PCAP_ERR_HOSTNOAUTH 10 /* The host is not authorized to connect to this server */ +#define PCAP_ERR_REMOTEACCEPT 11 /* Generic pcap_remoteaccept error */ +#define PCAP_ERR_STARTCAPTURE 12 /* Generic pcap_startcapture error */ +#define PCAP_ERR_ENDCAPTURE 13 /* Generic pcap_endcapture error */ +#define PCAP_ERR_RUNTIMETIMEOUT 14 /* The RPCAP run-time timeout has expired */ +#define PCAP_ERR_SETSAMPLING 15 /* Error during the settings of sampling parameters */ +#define PCAP_ERR_WRONGMSG 16 /* The other end endpoint sent a message which has not been recognized */ +#define PCAP_ERR_WRONGVER 17 /* The other end endpoint has a version number that is not compatible with our */ +#define PCAP_ERR_AUTH_FAILED 18 /* The user couldn't be authenticated */ +#define PCAP_ERR_TLS_REQUIRED 19 /* The server requires TLS to connect */ +#define PCAP_ERR_AUTH_TYPE_NOTSUP 20 /* The authentication type isn't supported */ /* * \brief Buffer used by socket functions to send-receive packets. diff --git a/rpcapd/CMakeLists.txt b/rpcapd/CMakeLists.txt new file mode 100644 index 000000000000..1821c8566ed4 --- /dev/null +++ b/rpcapd/CMakeLists.txt @@ -0,0 +1,163 @@ +if(UNIX) + check_function_exists(crypt HAVE_CRYPT_IN_SYSTEM_LIBRARIES) + if(HAVE_CRYPT_IN_SYSTEM_LIBRARIES) + set(HAVE_CRYPT TRUE) + else(HAVE_CRYPT_IN_SYSTEM_LIBRARIES) + check_library_exists(crypt crypt "" HAVE_CRYPT_IN_LIBCRYPT) + if(HAVE_CRYPT_IN_LIBCRYPT) + set(RPCAPD_LINK_LIBRARIES ${RPCAPD_LINK_LIBRARIES} crypt) + set(HAVE_CRYPT TRUE) + else(HAVE_CRYPT_IN_LIBCRYPT) + message(WARNING "crypt() not found. Won't be able to build rpcapd.") + endif(HAVE_CRYPT_IN_LIBCRYPT) + endif(HAVE_CRYPT_IN_SYSTEM_LIBRARIES) +endif(UNIX) + +# +# On UN*X, we need pthreads and crypt(). +# +if(WIN32 OR ((CMAKE_USE_PTHREADS_INIT OR PTHREADS_FOUND) AND HAVE_CRYPT)) + if(UNIX) + # + # Do we have getspnam()? + # + check_function_exists(getspnam HAVE_GETSPNAM) + + # + # Find library needed for getaddrinfo. + # NOTE: if you hand check_library_exists as its last argument a variable + # that's been set, it skips the test, so we need different variables. + # + include(CheckLibraryExists) + check_function_exists(getaddrinfo STDLIBS_HAVE_GETADDRINFO) + if(NOT STDLIBS_HAVE_GETADDRINFO) + check_library_exists(xnet getaddrinfo "" LIBXNET_HAS_GETADDRINFO) + if(LIBXNET_HAS_GETADDRINFO) + set(RPCAPD_LINK_LIBRARIES ${RPCAPD_LINK_LIBRARIES} xnet) + else(LIBXNET_HAS_GETADDRINFO) + include(CMakePushCheckState) + cmake_push_check_state() + set(CMAKE_REQUIRED_LIBRARIES nsl) + check_library_exists(socket getaddrinfo "" LIBSOCKET_HAS_GETADDRINFO) + cmake_pop_check_state() + if(LIBSOCKET_HAS_GETADDRINFO) + set(RPCAPD_LINK_LIBRARIES ${RPCAPD_LINK_LIBRARIES} socket nsl) + endif(LIBSOCKET_HAS_GETADDRINFO) + endif(LIBXNET_HAS_GETADDRINFO) + endif(NOT STDLIBS_HAVE_GETADDRINFO) + endif(UNIX) + + if(WIN32) + set(RPCAPD_EXTRA_SOURCES + win32-svc.c + ${pcap_SOURCE_DIR}/missing/getopt.c + ${pcap_SOURCE_DIR}/missing/win_snprintf.c + rpcapd.rc) + include_directories(${pcap_SOURCE_DIR}/rpcapd ${pcap_SOURCE_DIR}/missing) + endif(WIN32) + + add_executable(rpcapd + daemon.c + fileconf.c + log.c + rpcapd.c + ${pcap_SOURCE_DIR}/rpcap-protocol.c + ${pcap_SOURCE_DIR}/sockutils.c + ${pcap_SOURCE_DIR}/fmtutils.c + ${RPCAPD_EXTRA_SOURCES} + ) + + if(NOT C_ADDITIONAL_FLAGS STREQUAL "") + set_target_properties(rpcapd PROPERTIES COMPILE_FLAGS ${C_ADDITIONAL_FLAGS}) + endif() + + # + # By default, build rpcapd universal with the appropriate set of + # architectures for the OS on which we're doing the build. + # + if(APPLE AND "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "") + # + # Get the major version of Darwin. + # + string(REGEX MATCH "^([0-9]+)" SYSTEM_VERSION_MAJOR "${CMAKE_SYSTEM_VERSION}") + + if(SYSTEM_VERSION_MAJOR EQUAL 9) + # + # Leopard. Build for 32-bit x86 and 32-bit PowerPC, with + # 32-bit x86 first. + # + set(OSX_PROGRAM_ARCHITECTURES "i386;ppc") + elseif(SYSTEM_VERSION_MAJOR EQUAL 10) + # + # Snow Leopard. Build for x86-64 and 32-bit x86, with + # x86-64 first. + # + set(OSX_PROGRAM_ARCHITECTURES "x86_64;i386") + else() + # + # Post-Snow Leopard. Build only for x86-64. + # XXX - update if and when Apple adds ARM-based Macs. + # (You're on your own for iOS etc.) + # + set(OSX_PROGRAM_ARCHITECTURES "x86_64") + endif() + + set_target_properties(rpcapd PROPERTIES + OSX_ARCHITECTURES "${OSX_PROGRAM_ARCHITECTURES}") + endif() + + if(WIN32) + target_link_libraries(rpcapd ${LIBRARY_NAME} + ${RPCAPD_LINK_LIBRARIES} ${PCAP_LINK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + else(WIN32) + target_link_libraries(rpcapd ${LIBRARY_NAME}_static + ${RPCAPD_LINK_LIBRARIES} ${PCAP_LINK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + endif(WIN32) + + ###################################### + # Install rpcap daemon and man pages + ###################################### + + # + # "Define GNU standard installation directories", which actually + # are also defined, to some degree, by autotools, and at least + # some of which are general UN*X conventions. + # + include(GNUInstallDirs) + + set(MANADMIN_EXPAND rpcapd.manadmin.in) + + set(MANFILE_EXPAND rpcapd-config.manfile.in) + + if(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8) + install(TARGETS rpcapd DESTINATION bin/amd64) + else(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8) + install(TARGETS rpcapd DESTINATION bin) + endif(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8) + + # On UN*X, and on Windows when not using MSVC, generate process man + # pages and arrange that they be installed. + if(NOT MSVC) + # + # Man pages. + # + # For each section of the manual for which we have man pages + # that require macro expansion, do the expansion. + # + set(MANADMIN "") + foreach(TEMPLATE_MANPAGE ${MANADMIN_EXPAND}) + string(REPLACE ".manadmin.in" ".${MAN_ADMIN_COMMANDS}" MANPAGE ${TEMPLATE_MANPAGE}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY) + set(MANADMIN ${MANADMIN} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE}) + endforeach(TEMPLATE_MANPAGE) + install(FILES ${MANADMIN} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_ADMIN_COMMANDS}) + + set(MANFILE "") + foreach(TEMPLATE_MANPAGE ${MANFILE_EXPAND}) + string(REPLACE ".manfile.in" ".${MAN_FILE_FORMATS}" MANPAGE ${TEMPLATE_MANPAGE}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY) + set(MANFILE ${MANFILE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE}) + endforeach(TEMPLATE_MANPAGE) + install(FILES ${MANFILE} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_FILE_FORMATS}) + endif(NOT MSVC) +endif(WIN32 OR ((CMAKE_USE_PTHREADS_INIT OR PTHREADS_FOUND) AND HAVE_CRYPT)) diff --git a/rpcapd/Makefile.in b/rpcapd/Makefile.in new file mode 100644 index 000000000000..88e632a26250 --- /dev/null +++ b/rpcapd/Makefile.in @@ -0,0 +1,141 @@ +# Copyright (c) 1993, 1994, 1995, 1996 +# The Regents of the University of California. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that: (1) source code distributions +# retain the above copyright notice and this paragraph in its entirety, (2) +# distributions including binary code include the above copyright notice and +# this paragraph in its entirety in the documentation or other materials +# provided with the distribution, and (3) all advertising materials mentioning +# features or use of this software display the following acknowledgement: +# ``This product includes software developed by the University of California, +# Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +# the University nor the names of its contributors may be used to endorse +# or promote products derived from this software without specific prior +# written permission. +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +# +# Various configurable paths (remember to edit Makefile.in, not Makefile) +# + +# Top level hierarchy +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datarootdir = @datarootdir@ +# Pathname of directory to install the configure program +bindir = @bindir@ +# Pathname of directory to install the rpcapd daemon +sbindir = @sbindir@ +# Pathname of directory to install the include files +includedir = @includedir@ +# Pathname of directory to install the library +libdir = @libdir@ +# Pathname of directory to install the man pages +mandir = @mandir@ + +# VPATH +srcdir = @srcdir@ +VPATH = @srcdir@ + +# +# You shouldn't need to edit anything below. +# + +LD = /usr/bin/ld +CC = @CC@ +AR = @AR@ +LN_S = @LN_S@ +MKDEP = @MKDEP@ +CCOPT = @V_CCOPT@ +INCLS = -I. -I.. -I@srcdir@ -I@srcdir@/.. @V_INCLS@ +DEFS = @DEFS@ @V_DEFS@ +ADDLOBJS = @ADDLOBJS@ +ADDLARCHIVEOBJS = @ADDLARCHIVEOBJS@ +LIBS = @LIBS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +CROSSFLAGS= +CFLAGS = @CFLAGS@ ${CROSSFLAGS} +LDFLAGS = @LDFLAGS@ ${CROSSFLAGS} +DYEXT = @DYEXT@ +V_RPATH_OPT = @V_RPATH_OPT@ +DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@ +PROG=libpcap +RPCAPD_LIBS = @RPCAPD_LIBS@ + +# Standard CFLAGS +FULL_CFLAGS = $(CCOPT) @V_PROG_CCOPT_FAT@ $(INCLS) $(DEFS) $(CFLAGS) + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +# Explicitly define compilation rule since SunOS 4's make doesn't like gcc. +# Also, gcc does not remove the .o before forking 'as', which can be a +# problem if you don't own the file but can write to the directory. +.c.o: + @rm -f $@ + $(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c + +SRC = daemon.c \ + fileconf.c \ + log.c \ + rpcapd.c + +OBJ = $(SRC:.c=.o) ../rpcap-protocol.o ../sockutils.o ../fmtutils.o +PUBHDR = + +HDR = $(PUBHDR) log.h + +TAGFILES = \ + $(SRC) $(HDR) + +CLEANFILES = $(OBJ) rpcapd + +MANADMIN = \ + rpcapd.manadmin.in + +MANFILE = \ + rpcapd-config.manfile.in + +rpcapd: $(OBJ) ../libpcap.a + $(CC) $(CCOPT) $(CFLAGS) $(LDFLAGS) @V_PROG_LDFLAGS_FAT@ \ + -o $@ $(OBJ) ../libpcap.a $(LIBS) $(RPCAPD_LIBS) $(PTHREAD_LIBS) +clean: + rm -f $(CLEANFILES) + +distclean: clean + rm -f Makefile config.cache config.log config.status \ + config.h stamp-h stamp-h.in + rm -f $(MANADMIN:.in=) $(MANFILE:.in=) + rm -rf autom4te.cache + +install: rpcapd + [ -d $(DESTDIR)$(sbindir) ] || \ + (mkdir -p $(DESTDIR)$(sbindir); chmod 755 $(DESTDIR)$(sbindir)) + $(INSTALL_PROGRAM) rpcapd $(DESTDIR)$(sbindir)/rpcapd + [ -d $(DESTDIR)$(mandir)/man@MAN_ADMIN_COMMANDS@ ] || \ + (mkdir -p $(DESTDIR)$(mandir)/man@MAN_ADMIN_COMMANDS@; chmod 755 $(DESTDIR)$(mandir)/man@MAN_ADMIN_COMMANDS@) + [ -d $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@ ] || \ + (mkdir -p $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@; chmod 755 $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@) + for i in $(MANADMIN); do \ + $(INSTALL_DATA) `echo $$i | sed 's/.manadmin.in/.manadmin/'` \ + $(DESTDIR)$(mandir)/man@MAN_ADMIN_COMMANDS@/`echo $$i | sed 's/.manadmin.in/.@MAN_ADMIN_COMMANDS@/'`; done + for i in $(MANFILE); do \ + $(INSTALL_DATA) `echo $$i | sed 's/.manfile.in/.manfile/'` \ + $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@/`echo $$i | sed 's/.manfile.in/.@MAN_FILE_FORMATS@/'`; done + +uninstall: + rm -f $(DESTDIR)$(sbindir)/rpcapd + for i in $(MANADMIN); do \ + rm -f $(DESTDIR)$(mandir)/man@MAN_ADMIN_COMMANDS@/`echo $$i | sed 's/.manadmin.in/.@MAN_ADMIN_COMMANDS@/'`; done + for i in $(MANFILE); do \ + rm -f $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@/`echo $$i | sed 's/.manfile.in/.@MAN_FILE_FORMATS@/'`; done + +tags: $(TAGFILES) + ctags -wtd $(TAGFILES) + +depend: + ../$(MKDEP) -c "$(CC)" -m "$(DEPENDENCY_CFLAG)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC) diff --git a/rpcapd/config_params.h b/rpcapd/config_params.h new file mode 100644 index 000000000000..c219ce1650c9 --- /dev/null +++ b/rpcapd/config_params.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __CONFIG_PARAMS_H__ +#define __CONFIG_PARAMS_H__ + +// +// Parameters set from the configuration file. +// + +#define MAX_LINE 2048 /* Maximum chars allowed for the host list (in passive mode) */ +#define MAX_HOST_LIST 64000 +#define MAX_ACTIVE_LIST 10 + +struct active_pars +{ + char address[MAX_LINE + 1]; // keeps the network address (either numeric or literal) to of the active client + char port[MAX_LINE + 1]; // keeps the network port to bind to + int ai_family; // address faimly to use +}; + +extern char hostlist[MAX_HOST_LIST + 1]; //!< Keeps the list of the hosts that are allowed to connect to this server +extern struct active_pars activelist[MAX_ACTIVE_LIST]; //!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode) +extern int nullAuthAllowed; //!< '1' if we permit NULL authentication, '0' otherwise +extern char loadfile[MAX_LINE + 1]; //!< Name of the file from which we have to load the configuration + +#endif diff --git a/rpcapd/daemon.c b/rpcapd/daemon.c new file mode 100644 index 000000000000..209dba225ea6 --- /dev/null +++ b/rpcapd/daemon.c @@ -0,0 +1,2747 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "ftmacros.h" +#include "varattrs.h" + +#include // for the errno variable +#include // for malloc(), free(), ... +#include // for strlen(), ... + +#ifdef _WIN32 + #include // for threads +#else + #include + #include + #include + #include + #include // for select() and such + #include // for password management +#endif + +#ifdef HAVE_GETSPNAM +#include // for password management +#endif + +#include // for libpcap/WinPcap calls + +#include "fmtutils.h" +#include "sockutils.h" // for socket calls +#include "portability.h" +#include "rpcap-protocol.h" +#include "daemon.h" +#include "log.h" + +// +// Timeout, in seconds, when we're waiting for a client to send us an +// authentication request; if they don't send us a request within that +// interval, we drop the connection, so we don't stay stuck forever. +// +#define RPCAP_TIMEOUT_INIT 90 + +// +// Timeout, in seconds, when we're waiting for an authenticated client +// to send us a request, if a capture isn't in progress; if they don't +// send us a request within that interval, we drop the connection, so +// we don't stay stuck forever. +// +#define RPCAP_TIMEOUT_RUNTIME 180 + +// +// Time, in seconds, that we wait after a failed authentication attempt +// before processing the next request; this prevents a client from +// rapidly trying different accounts or passwords. +// +#define RPCAP_SUSPEND_WRONGAUTH 1 + +// Parameters for the service loop. +struct daemon_slpars +{ + SOCKET sockctrl; //!< SOCKET ID of the control connection + int isactive; //!< Not null if the daemon has to run in active mode + int nullAuthAllowed; //!< '1' if we permit NULL authentication, '0' otherwise +}; + +// +// Data for a session managed by a thread. +// It includes both a Boolean indicating whether we *have* a thread, +// and a platform-dependent (UN*X vs. Windows) identifier for the +// thread; on Windows, we could use an invalid handle to indicate +// that we don't have a thread, but there *is* no portable "no thread" +// value for a pthread_t on UN*X. +// +struct session { + SOCKET sockctrl; + SOCKET sockdata; + uint8 protocol_version; + pcap_t *fp; + unsigned int TotCapt; + int have_thread; +#ifdef _WIN32 + HANDLE thread; +#else + pthread_t thread; +#endif +}; + +// Locally defined functions +static int daemon_msg_err(SOCKET sockctrl, uint32 plen); +static int daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen); +static int daemon_AuthUserPwd(char *username, char *password, char *errbuf); + +static int daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, + uint32 plen); + +static int daemon_msg_open_req(uint8 ver, struct daemon_slpars *pars, + uint32 plen, char *source, size_t sourcelen); +static int daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, + uint32 plen, char *source, struct session **sessionp, + struct rpcap_sampling *samp_param); +static int daemon_msg_endcap_req(uint8 ver, struct daemon_slpars *pars, + struct session *session); + +static int daemon_msg_updatefilter_req(uint8 ver, struct daemon_slpars *pars, + struct session *session, uint32 plen); +static int daemon_unpackapplyfilter(SOCKET sockctrl, struct session *session, uint32 *plenp, char *errbuf); + +static int daemon_msg_stats_req(uint8 ver, struct daemon_slpars *pars, + struct session *session, uint32 plen, struct pcap_stat *stats, + unsigned int svrcapt); + +static int daemon_msg_setsampling_req(uint8 ver, struct daemon_slpars *pars, + uint32 plen, struct rpcap_sampling *samp_param); + +static void daemon_seraddr(struct sockaddr_storage *sockaddrin, struct rpcap_sockaddr *sockaddrout); +#ifdef _WIN32 +static unsigned __stdcall daemon_thrdatamain(void *ptr); +#else +static void *daemon_thrdatamain(void *ptr); +static void noop_handler(int sign); +#endif + +static int rpcapd_recv_msg_header(SOCKET sock, struct rpcap_header *headerp); +static int rpcapd_recv(SOCKET sock, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf); +static int rpcapd_discard(SOCKET sock, uint32 len); +static void session_close(struct session *); + +static int is_url(const char *source); + +int +daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients, + int nullAuthAllowed) +{ + struct daemon_slpars pars; // service loop parameters + char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed + char errmsgbuf[PCAP_ERRBUF_SIZE + 1]; // buffer for errors to send to the client + int host_port_check_status; + int nrecv; + struct rpcap_header header; // RPCAP message general header + uint32 plen; // payload length from header + int authenticated = 0; // 1 if the client has successfully authenticated + char source[PCAP_BUF_SIZE+1]; // keeps the string that contains the interface to open + int got_source = 0; // 1 if we've gotten the source from an open request +#ifndef _WIN32 + struct sigaction action; +#endif + struct session *session = NULL; // struct session main variable + const char *msg_type_string; // string for message type + int client_told_us_to_close = 0; // 1 if the client told us to close the capture + + // needed to save the values of the statistics + struct pcap_stat stats; + unsigned int svrcapt; + + struct rpcap_sampling samp_param; // in case sampling has been requested + + // Structures needed for the select() call + fd_set rfds; // set of socket descriptors we have to check + struct timeval tv; // maximum time the select() can block waiting for data + int retval; // select() return value + + *errbuf = 0; // Initialize errbuf + + // Set parameters structure + pars.sockctrl = sockctrl; + pars.isactive = isactive; // active mode + pars.nullAuthAllowed = nullAuthAllowed; + + // + // We have a connection. + // + // If it's a passive mode connection, check whether the connecting + // host is among the ones allowed. + // + // In either case, we were handed a copy of the host list; free it + // as soon as we're done with it. + // + if (pars.isactive) + { + // Nothing to do. + free(passiveClients); + passiveClients = NULL; + } + else + { + struct sockaddr_storage from; + socklen_t fromlen; + + // + // Get the address of the other end of the connection. + // + fromlen = sizeof(struct sockaddr_storage); + if (getpeername(pars.sockctrl, (struct sockaddr *)&from, + &fromlen) == -1) + { + sock_geterror("getpeername()", errmsgbuf, PCAP_ERRBUF_SIZE); + if (rpcap_senderror(pars.sockctrl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1) + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + + // + // Are they in the list of host/port combinations we allow? + // + host_port_check_status = sock_check_hostlist(passiveClients, RPCAP_HOSTLIST_SEP, &from, errmsgbuf, PCAP_ERRBUF_SIZE); + free(passiveClients); + passiveClients = NULL; + if (host_port_check_status < 0) + { + if (host_port_check_status == -2) { + // + // We got an error; log it. + // + rpcapd_log(LOGPRIO_ERROR, "%s", errmsgbuf); + } + + // + // Sorry, we can't let you in. + // + if (rpcap_senderror(pars.sockctrl, 0, PCAP_ERR_HOSTNOAUTH, errmsgbuf, errbuf) == -1) + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + } + +#ifndef _WIN32 + // + // Catch SIGUSR1, but do nothing. We use it to interrupt the + // capture thread to break it out of a loop in which it's + // blocked waiting for packets to arrive. + // + // We don't want interrupted system calls to restart, so that + // the read routine for the pcap_t gets EINTR rather than + // restarting if it's blocked in a system call. + // + memset(&action, 0, sizeof (action)); + action.sa_handler = noop_handler; + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + sigaction(SIGUSR1, &action, NULL); +#endif + + // + // The client must first authenticate; loop until they send us a + // message with a version we support and credentials we accept, + // they send us a close message indicating that they're giving up, + // or we get a network error or other fatal error. + // + while (!authenticated) + { + // + // If we're not in active mode, we use select(), with a + // timeout, to wait for an authentication request; if + // the timeout expires, we drop the connection, so that + // a client can't just connect to us and leave us + // waiting forever. + // + if (!pars.isactive) + { + FD_ZERO(&rfds); + // We do not have to block here + tv.tv_sec = RPCAP_TIMEOUT_INIT; + tv.tv_usec = 0; + + FD_SET(pars.sockctrl, &rfds); + + retval = select(pars.sockctrl + 1, &rfds, NULL, NULL, &tv); + if (retval == -1) + { + sock_geterror("select() failed", errmsgbuf, PCAP_ERRBUF_SIZE); + if (rpcap_senderror(pars.sockctrl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1) + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + + // The timeout has expired + // So, this was a fake connection. Drop it down + if (retval == 0) + { + if (rpcap_senderror(pars.sockctrl, 0, PCAP_ERR_INITTIMEOUT, "The RPCAP initial timeout has expired", errbuf) == -1) + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + } + + // + // Read the message header from the client. + // + nrecv = rpcapd_recv_msg_header(pars.sockctrl, &header); + if (nrecv == -1) + { + // Fatal error. + goto end; + } + if (nrecv == -2) + { + // Client closed the connection. + goto end; + } + + plen = header.plen; + + // + // While we're in the authentication pharse, all requests + // must use version 0. + // + if (header.ver != 0) + { + // + // Send it back to them with their version. + // + if (rpcap_senderror(pars.sockctrl, header.ver, + PCAP_ERR_WRONGVER, + "RPCAP version in requests in the authentication phase must be 0", + errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + + // Discard the rest of the message and drop the + // connection. + (void)rpcapd_discard(pars.sockctrl, plen); + goto end; + } + + switch (header.type) + { + case RPCAP_MSG_AUTH_REQ: + retval = daemon_msg_auth_req(&pars, plen); + if (retval == -1) + { + // Fatal error; a message has + // been logged, so just give up. + goto end; + } + if (retval == -2) + { + // Non-fatal error; we sent back + // an error message, so let them + // try again. + continue; + } + + // OK, we're authenticated; we sent back + // a reply, so start serving requests. + authenticated = 1; + break; + + case RPCAP_MSG_CLOSE: + // + // The client is giving up. + // Discard the rest of the message, if + // there is anything more. + // + (void)rpcapd_discard(pars.sockctrl, plen); + // We're done with this client. + goto end; + + case RPCAP_MSG_ERROR: + // Log this and close the connection? + // XXX - is this what happens in active + // mode, where *we* initiate the + // connection, and the client gives us + // an error message rather than a "let + // me log in" message, indicating that + // we're not allowed to connect to them? + (void)daemon_msg_err(pars.sockctrl, plen); + goto end; + + case RPCAP_MSG_FINDALLIF_REQ: + case RPCAP_MSG_OPEN_REQ: + case RPCAP_MSG_STARTCAP_REQ: + case RPCAP_MSG_UPDATEFILTER_REQ: + case RPCAP_MSG_STATS_REQ: + case RPCAP_MSG_ENDCAP_REQ: + case RPCAP_MSG_SETSAMPLING_REQ: + // + // These requests can't be sent until + // the client is authenticated. + // + msg_type_string = rpcap_msg_type_string(header.type); + if (msg_type_string != NULL) + { + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "%s request sent before authentication was completed", msg_type_string); + } + else + { + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message of type %u sent before authentication was completed", header.type); + } + if (rpcap_senderror(pars.sockctrl, header.ver, + PCAP_ERR_WRONGMSG, errmsgbuf, errbuf) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + // Discard the rest of the message. + if (rpcapd_discard(pars.sockctrl, plen) == -1) + { + // Network error. + goto end; + } + break; + + case RPCAP_MSG_PACKET: + case RPCAP_MSG_FINDALLIF_REPLY: + case RPCAP_MSG_OPEN_REPLY: + case RPCAP_MSG_STARTCAP_REPLY: + case RPCAP_MSG_UPDATEFILTER_REPLY: + case RPCAP_MSG_AUTH_REPLY: + case RPCAP_MSG_STATS_REPLY: + case RPCAP_MSG_ENDCAP_REPLY: + case RPCAP_MSG_SETSAMPLING_REPLY: + // + // These are server-to-client messages. + // + msg_type_string = rpcap_msg_type_string(header.type); + if (msg_type_string != NULL) + { + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message %s received from client", msg_type_string); + } + else + { + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type); + } + if (rpcap_senderror(pars.sockctrl, header.ver, + PCAP_ERR_WRONGMSG, errmsgbuf, errbuf) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + // Discard the rest of the message. + if (rpcapd_discard(pars.sockctrl, plen) == -1) + { + // Fatal error. + goto end; + } + break; + + default: + // + // Unknown message type. + // + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type); + if (rpcap_senderror(pars.sockctrl, header.ver, + PCAP_ERR_WRONGMSG, errmsgbuf, errbuf) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + // Discard the rest of the message. + if (rpcapd_discard(pars.sockctrl, plen) == -1) + { + // Fatal error. + goto end; + } + break; + } + } + + // + // OK, the client has authenticated itself, and we can start + // processing regular requests from it. + // + + // + // We don't have any statistics yet. + // + stats.ps_ifdrop = 0; + stats.ps_recv = 0; + stats.ps_drop = 0; + svrcapt = 0; + + // + // Service requests. + // + for (;;) + { + errbuf[0] = 0; // clear errbuf + + // Avoid zombies connections; check if the connection is opens but no commands are performed + // from more than RPCAP_TIMEOUT_RUNTIME + // Conditions: + // - I have to be in normal mode (no active mode) + // - if the device is open, I don't have to be in the middle of a capture (session->sockdata) + // - if the device is closed, I have always to check if a new command arrives + // + // Be carefully: the capture can have been started, but an error occurred (so session != NULL, but + // sockdata is 0 + if ((!pars.isactive) && ((session == NULL) || ((session != NULL) && (session->sockdata == 0)))) + { + // Check for the initial timeout + FD_ZERO(&rfds); + // We do not have to block here + tv.tv_sec = RPCAP_TIMEOUT_RUNTIME; + tv.tv_usec = 0; + + FD_SET(pars.sockctrl, &rfds); + + retval = select(pars.sockctrl + 1, &rfds, NULL, NULL, &tv); + if (retval == -1) + { + sock_geterror("select() failed", errmsgbuf, PCAP_ERRBUF_SIZE); + if (rpcap_senderror(pars.sockctrl, 0, + PCAP_ERR_NETW, errmsgbuf, errbuf) == -1) + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + + // The timeout has expired + // So, this was a fake connection. Drop it down + if (retval == 0) + { + if (rpcap_senderror(pars.sockctrl, 0, + PCAP_ERR_INITTIMEOUT, + "The RPCAP initial timeout has expired", + errbuf) == -1) + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + } + + // + // Read the message header from the client. + // + nrecv = rpcapd_recv_msg_header(pars.sockctrl, &header); + if (nrecv == -1) + { + // Fatal error. + goto end; + } + if (nrecv == -2) + { + // Client closed the connection. + goto end; + } + + plen = header.plen; + + // + // Did the client specify a protocol version that we + // support? + // + if (!RPCAP_VERSION_IS_SUPPORTED(header.ver)) + { + // + // Tell them it's not a supported version. + // Send the error message with their version, + // so they don't reject it as having the wrong + // version. + // + if (rpcap_senderror(pars.sockctrl, + header.ver, PCAP_ERR_WRONGVER, + "RPCAP version in message isn't supported by the server", + errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + + // Discard the rest of the message. + (void)rpcapd_discard(pars.sockctrl, plen); + // Give up on them. + goto end; + } + + switch (header.type) + { + case RPCAP_MSG_ERROR: // The other endpoint reported an error + { + (void)daemon_msg_err(pars.sockctrl, plen); + // Do nothing; just exit; the error code is already into the errbuf + // XXX - actually exit.... + break; + } + + case RPCAP_MSG_FINDALLIF_REQ: + { + if (daemon_msg_findallif_req(header.ver, &pars, plen) == -1) + { + // Fatal error; a message has + // been logged, so just give up. + goto end; + } + break; + } + + case RPCAP_MSG_OPEN_REQ: + { + // + // Process the open request, and keep + // the source from it, for use later + // when the capture is started. + // + // XXX - we don't care if the client sends + // us multiple open requests, the last + // one wins. + // + retval = daemon_msg_open_req(header.ver, &pars, + plen, source, sizeof(source)); + if (retval == -1) + { + // Fatal error; a message has + // been logged, so just give up. + goto end; + } + got_source = 1; + break; + } + + case RPCAP_MSG_STARTCAP_REQ: + { + if (!got_source) + { + // They never told us what device + // to capture on! + if (rpcap_senderror(pars.sockctrl, + header.ver, + PCAP_ERR_STARTCAPTURE, + "No capture device was specified", + errbuf) == -1) + { + // Fatal error; log an + // error and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + if (rpcapd_discard(pars.sockctrl, plen) == -1) + { + goto end; + } + break; + } + + if (daemon_msg_startcap_req(header.ver, &pars, + plen, source, &session, &samp_param) == -1) + { + // Fatal error; a message has + // been logged, so just give up. + goto end; + } + break; + } + + case RPCAP_MSG_UPDATEFILTER_REQ: + { + if (session) + { + if (daemon_msg_updatefilter_req(header.ver, + &pars, session, plen) == -1) + { + // Fatal error; a message has + // been logged, so just give up. + goto end; + } + } + else + { + if (rpcap_senderror(pars.sockctrl, + header.ver, PCAP_ERR_UPDATEFILTER, + "Device not opened. Cannot update filter", + errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + } + break; + } + + case RPCAP_MSG_CLOSE: // The other endpoint close the pcap session + { + // + // Indicate to our caller that the client + // closed the control connection. + // This is used only in case of active mode. + // + client_told_us_to_close = 1; + rpcapd_log(LOGPRIO_DEBUG, "The other end system asked to close the connection."); + goto end; + } + + case RPCAP_MSG_STATS_REQ: + { + if (daemon_msg_stats_req(header.ver, &pars, + session, plen, &stats, svrcapt) == -1) + { + // Fatal error; a message has + // been logged, so just give up. + goto end; + } + break; + } + + case RPCAP_MSG_ENDCAP_REQ: // The other endpoint close the current capture session + { + if (session) + { + // Save statistics (we can need them in the future) + if (pcap_stats(session->fp, &stats)) + { + svrcapt = session->TotCapt; + } + else + { + stats.ps_ifdrop = 0; + stats.ps_recv = 0; + stats.ps_drop = 0; + svrcapt = 0; + } + + if (daemon_msg_endcap_req(header.ver, + &pars, session) == -1) + { + free(session); + session = NULL; + // Fatal error; a message has + // been logged, so just give up. + goto end; + } + free(session); + session = NULL; + } + else + { + rpcap_senderror(pars.sockctrl, + header.ver, PCAP_ERR_ENDCAPTURE, + "Device not opened. Cannot close the capture", + errbuf); + } + break; + } + + case RPCAP_MSG_SETSAMPLING_REQ: + { + if (daemon_msg_setsampling_req(header.ver, + &pars, plen, &samp_param) == -1) + { + // Fatal error; a message has + // been logged, so just give up. + goto end; + } + break; + } + + case RPCAP_MSG_AUTH_REQ: + { + // + // We're already authenticated; you don't + // get to reauthenticate. + // + rpcapd_log(LOGPRIO_INFO, "The client sent an RPCAP_MSG_AUTH_REQ message after authentication was completed"); + if (rpcap_senderror(pars.sockctrl, header.ver, + PCAP_ERR_WRONGMSG, + "RPCAP_MSG_AUTH_REQ request sent after authentication was completed", + errbuf) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + // Discard the rest of the message. + if (rpcapd_discard(pars.sockctrl, plen) == -1) + { + // Fatal error. + goto end; + } + goto end; + + case RPCAP_MSG_PACKET: + case RPCAP_MSG_FINDALLIF_REPLY: + case RPCAP_MSG_OPEN_REPLY: + case RPCAP_MSG_STARTCAP_REPLY: + case RPCAP_MSG_UPDATEFILTER_REPLY: + case RPCAP_MSG_AUTH_REPLY: + case RPCAP_MSG_STATS_REPLY: + case RPCAP_MSG_ENDCAP_REPLY: + case RPCAP_MSG_SETSAMPLING_REPLY: + // + // These are server-to-client messages. + // + msg_type_string = rpcap_msg_type_string(header.type); + if (msg_type_string != NULL) + { + rpcapd_log(LOGPRIO_INFO, "The client sent a %s server-to-client message", msg_type_string); + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message %s received from client", msg_type_string); + } + else + { + rpcapd_log(LOGPRIO_INFO, "The client sent a server-to-client message of type %u", header.type); + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type); + } + if (rpcap_senderror(pars.sockctrl, header.ver, + PCAP_ERR_WRONGMSG, errmsgbuf, errbuf) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + // Discard the rest of the message. + if (rpcapd_discard(pars.sockctrl, plen) == -1) + { + // Fatal error. + goto end; + } + goto end; + + default: + // + // Unknown message type. + // + rpcapd_log(LOGPRIO_INFO, "The client sent a message of type %u", header.type); + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type); + if (rpcap_senderror(pars.sockctrl, header.ver, + PCAP_ERR_WRONGMSG, errbuf, errmsgbuf) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + // Discard the rest of the message. + if (rpcapd_discard(pars.sockctrl, plen) == -1) + { + // Fatal error. + goto end; + } + goto end; + } + } + } + +end: + // The service loop is finishing up. + // If we have a capture session running, close it. + if (session) + { + session_close(session); + free(session); + session = NULL; + } + + sock_close(sockctrl, NULL, 0); + + // Print message and return + rpcapd_log(LOGPRIO_DEBUG, "I'm exiting from the child loop"); + + return client_told_us_to_close; +} + +/* + * This handles the RPCAP_MSG_ERR message. + */ +static int +daemon_msg_err(SOCKET sockctrl, uint32 plen) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + char remote_errbuf[PCAP_ERRBUF_SIZE]; + + if (plen >= PCAP_ERRBUF_SIZE) + { + /* + * Message is too long; just read as much of it as we + * can into the buffer provided, and discard the rest. + */ + if (sock_recv(sockctrl, remote_errbuf, PCAP_ERRBUF_SIZE - 1, + SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, + PCAP_ERRBUF_SIZE) == -1) + { + // Network error. + rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf); + return -1; + } + if (rpcapd_discard(sockctrl, plen - (PCAP_ERRBUF_SIZE - 1)) == -1) + { + // Network error. + return -1; + } + + /* + * Null-terminate it. + */ + remote_errbuf[PCAP_ERRBUF_SIZE - 1] = '\0'; + } + else if (plen == 0) + { + /* Empty error string. */ + remote_errbuf[0] = '\0'; + } + else + { + if (sock_recv(sockctrl, remote_errbuf, plen, + SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, + PCAP_ERRBUF_SIZE) == -1) + { + // Network error. + rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf); + return -1; + } + + /* + * Null-terminate it. + */ + remote_errbuf[plen] = '\0'; + } + // Log the message + rpcapd_log(LOGPRIO_ERROR, "Error from client: %s", remote_errbuf); + return 0; +} + +/* + * This handles the RPCAP_MSG_AUTH_REQ message. + * It checks if the authentication credentials supplied by the user are valid. + * + * This function is called if the daemon receives a RPCAP_MSG_AUTH_REQ + * message in its authentication loop. It reads the body of the + * authentication message from the network and checks whether the + * credentials are valid. + * + * \param sockctrl: the socket for the control connection. + * + * \param nullAuthAllowed: '1' if the NULL authentication is allowed. + * + * \param errbuf: a user-allocated buffer in which the error message + * (if one) has to be written. It must be at least PCAP_ERRBUF_SIZE + * bytes long. + * + * \return '0' if everything is fine, '-1' if an unrecoverable error occurred, + * or '-2' if the authentication failed. For errors, an error message is + * returned in the 'errbuf' variable; this gives a message for the + * unrecoverable error or for the authentication failure. + */ +static int +daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen) +{ + char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors + char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client + int status; + struct rpcap_auth auth; // RPCAP authentication header + char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered + int sendbufidx = 0; // index which keeps the number of bytes currently buffered + struct rpcap_authreply *authreply; // authentication reply message + + status = rpcapd_recv(pars->sockctrl, (char *) &auth, sizeof(struct rpcap_auth), &plen, errmsgbuf); + if (status == -1) + { + return -1; + } + if (status == -2) + { + goto error; + } + + switch (ntohs(auth.type)) + { + case RPCAP_RMTAUTH_NULL: + { + if (!pars->nullAuthAllowed) + { + // Send the client an error reply. + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, + "Authentication failed; NULL authentication not permitted."); + if (rpcap_senderror(pars->sockctrl, 0, + PCAP_ERR_AUTH_FAILED, errmsgbuf, errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + goto error_noreply; + } + break; + } + + case RPCAP_RMTAUTH_PWD: + { + char *username, *passwd; + uint32 usernamelen, passwdlen; + + usernamelen = ntohs(auth.slen1); + username = (char *) malloc (usernamelen + 1); + if (username == NULL) + { + pcap_fmt_errmsg_for_errno(errmsgbuf, + PCAP_ERRBUF_SIZE, errno, "malloc() failed"); + goto error; + } + status = rpcapd_recv(pars->sockctrl, username, usernamelen, &plen, errmsgbuf); + if (status == -1) + { + free(username); + return -1; + } + if (status == -2) + { + free(username); + goto error; + } + username[usernamelen] = '\0'; + + passwdlen = ntohs(auth.slen2); + passwd = (char *) malloc (passwdlen + 1); + if (passwd == NULL) + { + pcap_fmt_errmsg_for_errno(errmsgbuf, + PCAP_ERRBUF_SIZE, errno, "malloc() failed"); + free(username); + goto error; + } + status = rpcapd_recv(pars->sockctrl, passwd, passwdlen, &plen, errmsgbuf); + if (status == -1) + { + free(username); + free(passwd); + return -1; + } + if (status == -2) + { + free(username); + free(passwd); + goto error; + } + passwd[passwdlen] = '\0'; + + if (daemon_AuthUserPwd(username, passwd, errmsgbuf)) + { + // + // Authentication failed. Let the client + // know. + // + free(username); + free(passwd); + if (rpcap_senderror(pars->sockctrl, 0, + PCAP_ERR_AUTH_FAILED, errmsgbuf, errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + // + // Suspend for 1 second, so that they can't + // hammer us with repeated tries with an + // attack such as a dictionary attack. + // + // WARNING: this delay is inserted only + // at this point; if the client closes the + // connection and reconnects, the suspension + // time does not have any effect. + // + sleep_secs(RPCAP_SUSPEND_WRONGAUTH); + goto error_noreply; + } + + free(username); + free(passwd); + break; + } + + default: + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, + "Authentication type not recognized."); + if (rpcap_senderror(pars->sockctrl, 0, + PCAP_ERR_AUTH_TYPE_NOTSUP, errmsgbuf, errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + goto error_noreply; + } + + // The authentication succeeded; let the client know. + if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + rpcap_createhdr((struct rpcap_header *) sendbuf, 0, + RPCAP_MSG_AUTH_REPLY, 0, sizeof(struct rpcap_authreply)); + + authreply = (struct rpcap_authreply *) &sendbuf[sendbufidx]; + + if (sock_bufferize(NULL, sizeof(struct rpcap_authreply), NULL, &sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + // + // Indicate to our peer what versions we support. + // + memset(authreply, 0, sizeof(struct rpcap_authreply)); + authreply->minvers = RPCAP_MIN_VERSION; + authreply->maxvers = RPCAP_MAX_VERSION; + + // Send the reply. + if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) + { + // That failed; log a messsage and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + // Check if all the data has been read; if not, discard the data in excess + if (rpcapd_discard(pars->sockctrl, plen) == -1) + { + return -1; + } + + return 0; + +error: + if (rpcap_senderror(pars->sockctrl, 0, PCAP_ERR_AUTH, errmsgbuf, + errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + +error_noreply: + // Check if all the data has been read; if not, discard the data in excess + if (rpcapd_discard(pars->sockctrl, plen) == -1) + { + return -1; + } + + return -2; +} + +static int +daemon_AuthUserPwd(char *username, char *password, char *errbuf) +{ +#ifdef _WIN32 + /* + * Warning: the user which launches the process must have the + * SE_TCB_NAME right. + * This corresponds to have the "Act as part of the Operating System" + * turned on (administrative tools, local security settings, local + * policies, user right assignment) + * However, it seems to me that if you run it as a service, this + * right should be provided by default. + * + * XXX - hopefully, this returns errors such as ERROR_LOGON_FAILURE, + * which merely indicates that the user name or password is + * incorrect, not whether it's the user name or the password + * that's incorrect, so a client that's trying to brute-force + * accounts doesn't know whether it's the user name or the + * password that's incorrect, so it doesn't know whether to + * stop trying to log in with a given user name and move on + * to another user name. + */ + DWORD error; + HANDLE Token; + char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to log + + if (LogonUser(username, ".", password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &Token) == 0) + { + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed"); + error = GetLastError(); + if (error != ERROR_LOGON_FAILURE) + { + // Some error other than an authentication error; + // log it. + pcap_fmt_errmsg_for_win32_err(errmsgbuf, + PCAP_ERRBUF_SIZE, error, "LogonUser() failed"); + rpcapd_log(LOGPRIO_ERROR, "%s", errmsgbuf); + } + return -1; + } + + // This call should change the current thread to the selected user. + // I didn't test it. + if (ImpersonateLoggedOnUser(Token) == 0) + { + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed"); + pcap_fmt_errmsg_for_win32_err(errmsgbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "ImpersonateLoggedOnUser() failed"); + rpcapd_log(LOGPRIO_ERROR, "%s", errmsgbuf); + CloseHandle(Token); + return -1; + } + + CloseHandle(Token); + return 0; + +#else + /* + * See + * + * http://www.unixpapa.com/incnote/passwd.html + * + * We use the Solaris/Linux shadow password authentication if + * we have getspnam(), otherwise we just do traditional + * authentication, which, on some platforms, might work, even + * with shadow passwords, if we're running as root. Traditional + * authenticaion won't work if we're not running as root, as + * I think these days all UN*Xes either won't return the password + * at all with getpwnam() or will only do so if you're root. + * + * XXX - perhaps what we *should* be using is PAM, if we have + * it. That might hide all the details of username/password + * authentication, whether it's done with a visible-to-root- + * only password database or some other authentication mechanism, + * behind its API. + */ + int error; + struct passwd *user; + char *user_password; +#ifdef HAVE_GETSPNAM + struct spwd *usersp; +#endif + char *crypt_password; + + // This call is needed to get the uid + if ((user = getpwnam(username)) == NULL) + { + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed"); + return -1; + } + +#ifdef HAVE_GETSPNAM + // This call is needed to get the password; otherwise 'x' is returned + if ((usersp = getspnam(username)) == NULL) + { + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed"); + return -1; + } + user_password = usersp->sp_pwdp; +#else + /* + * XXX - what about other platforms? + * The unixpapa.com page claims this Just Works on *BSD if you're + * running as root - it's from 2000, so it doesn't indicate whether + * macOS (which didn't come out until 2001, under the name Mac OS + * X) behaves like the *BSDs or not, and might also work on AIX. + * HP-UX does something else. + * + * Again, hopefully PAM hides all that. + */ + user_password = user->pw_passwd; +#endif + + // + // The Single UNIX Specification says that if crypt() fails it + // sets errno, but some implementatons that haven't been run + // through the SUS test suite might not do so. + // + errno = 0; + crypt_password = crypt(password, user_password); + if (crypt_password == NULL) + { + error = errno; + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed"); + if (error == 0) + { + // It didn't set errno. + rpcapd_log(LOGPRIO_ERROR, "crypt() failed"); + } + else + { + rpcapd_log(LOGPRIO_ERROR, "crypt() failed: %s", + strerror(error)); + } + return -1; + } + if (strcmp(user_password, crypt_password) != 0) + { + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed"); + return -1; + } + + if (setuid(user->pw_uid)) + { + error = errno; + pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + error, "setuid"); + rpcapd_log(LOGPRIO_ERROR, "setuid() failed: %s", + strerror(error)); + return -1; + } + +/* if (setgid(user->pw_gid)) + { + error = errno; + pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "setgid"); + rpcapd_log(LOGPRIO_ERROR, "setgid() failed: %s", + strerror(error)); + return -1; + } +*/ + return 0; + +#endif + +} + +static int +daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen) +{ + char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors + char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client + char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered + int sendbufidx = 0; // index which keeps the number of bytes currently buffered + pcap_if_t *alldevs = NULL; // pointer to the header of the interface chain + pcap_if_t *d; // temp pointer needed to scan the interface chain + struct pcap_addr *address; // pcap structure that keeps a network address of an interface + struct rpcap_findalldevs_if *findalldevs_if;// rpcap structure that packet all the data of an interface together + uint32 replylen; // length of reply payload + uint16 nif = 0; // counts the number of interface listed + + // Discard the rest of the message; there shouldn't be any payload. + if (rpcapd_discard(pars->sockctrl, plen) == -1) + { + // Network error. + return -1; + } + + // Retrieve the device list + if (pcap_findalldevs(&alldevs, errmsgbuf) == -1) + goto error; + + if (alldevs == NULL) + { + if (rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_NOREMOTEIF, + "No interfaces found! Make sure libpcap/WinPcap is properly installed" + " and you have the right to access to the remote device.", + errbuf) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + return 0; + } + + // This checks the number of interfaces and computes the total + // length of the payload. + replylen = 0; + for (d = alldevs; d != NULL; d = d->next) + { + nif++; + + if (d->description) + replylen += strlen(d->description); + if (d->name) + replylen += strlen(d->name); + + replylen += sizeof(struct rpcap_findalldevs_if); + + for (address = d->addresses; address != NULL; address = address->next) + { + /* + * Send only IPv4 and IPv6 addresses over the wire. + */ + switch (address->addr->sa_family) + { + case AF_INET: +#ifdef AF_INET6 + case AF_INET6: +#endif + replylen += (sizeof(struct rpcap_sockaddr) * 4); + break; + + default: + break; + } + } + } + + // RPCAP findalldevs command + if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, + PCAP_ERRBUF_SIZE) == -1) + goto error; + + rpcap_createhdr((struct rpcap_header *) sendbuf, ver, + RPCAP_MSG_FINDALLIF_REPLY, nif, replylen); + + // send the interface list + for (d = alldevs; d != NULL; d = d->next) + { + uint16 lname, ldescr; + + findalldevs_if = (struct rpcap_findalldevs_if *) &sendbuf[sendbufidx]; + + if (sock_bufferize(NULL, sizeof(struct rpcap_findalldevs_if), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + memset(findalldevs_if, 0, sizeof(struct rpcap_findalldevs_if)); + + if (d->description) ldescr = (short) strlen(d->description); + else ldescr = 0; + if (d->name) lname = (short) strlen(d->name); + else lname = 0; + + findalldevs_if->desclen = htons(ldescr); + findalldevs_if->namelen = htons(lname); + findalldevs_if->flags = htonl(d->flags); + + for (address = d->addresses; address != NULL; address = address->next) + { + /* + * Send only IPv4 and IPv6 addresses over the wire. + */ + switch (address->addr->sa_family) + { + case AF_INET: +#ifdef AF_INET6 + case AF_INET6: +#endif + findalldevs_if->naddr++; + break; + + default: + break; + } + } + findalldevs_if->naddr = htons(findalldevs_if->naddr); + + if (sock_bufferize(d->name, lname, sendbuf, &sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errmsgbuf, + PCAP_ERRBUF_SIZE) == -1) + goto error; + + if (sock_bufferize(d->description, ldescr, sendbuf, &sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errmsgbuf, + PCAP_ERRBUF_SIZE) == -1) + goto error; + + // send all addresses + for (address = d->addresses; address != NULL; address = address->next) + { + struct rpcap_sockaddr *sockaddr; + + /* + * Send only IPv4 and IPv6 addresses over the wire. + */ + switch (address->addr->sa_family) + { + case AF_INET: +#ifdef AF_INET6 + case AF_INET6: +#endif + sockaddr = (struct rpcap_sockaddr *) &sendbuf[sendbufidx]; + if (sock_bufferize(NULL, sizeof(struct rpcap_sockaddr), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + daemon_seraddr((struct sockaddr_storage *) address->addr, sockaddr); + + sockaddr = (struct rpcap_sockaddr *) &sendbuf[sendbufidx]; + if (sock_bufferize(NULL, sizeof(struct rpcap_sockaddr), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + daemon_seraddr((struct sockaddr_storage *) address->netmask, sockaddr); + + sockaddr = (struct rpcap_sockaddr *) &sendbuf[sendbufidx]; + if (sock_bufferize(NULL, sizeof(struct rpcap_sockaddr), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + daemon_seraddr((struct sockaddr_storage *) address->broadaddr, sockaddr); + + sockaddr = (struct rpcap_sockaddr *) &sendbuf[sendbufidx]; + if (sock_bufferize(NULL, sizeof(struct rpcap_sockaddr), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + daemon_seraddr((struct sockaddr_storage *) address->dstaddr, sockaddr); + break; + + default: + break; + } + } + } + + // We no longer need the device list. Free it. + pcap_freealldevs(alldevs); + + // Send a final command that says "now send it!" + if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + return 0; + +error: + if (alldevs) + pcap_freealldevs(alldevs); + + if (rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_FINDALLIF, + errmsgbuf, errbuf) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + return 0; +} + +/* + \param plen: the length of the current message (needed in order to be able + to discard excess data in the message, if present) +*/ +static int +daemon_msg_open_req(uint8 ver, struct daemon_slpars *pars, uint32 plen, + char *source, size_t sourcelen) +{ + char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors + char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client + pcap_t *fp; // pcap_t main variable + int nread; + char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered + int sendbufidx = 0; // index which keeps the number of bytes currently buffered + struct rpcap_openreply *openreply; // open reply message + + if (plen > sourcelen - 1) + { + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Source string too long"); + goto error; + } + + nread = sock_recv(pars->sockctrl, source, plen, + SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE); + if (nread == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf); + return -1; + } + source[nread] = '\0'; + plen -= nread; + + // Is this a URL rather than a device? + // If so, reject it. + if (is_url(source)) + { + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Source string refers to a remote device"); + goto error; + } + + // Open the selected device + // This is a fake open, since we do that only to get the needed parameters, then we close the device again + if ((fp = pcap_open_live(source, + 1500 /* fake snaplen */, + 0 /* no promis */, + 1000 /* fake timeout */, + errmsgbuf)) == NULL) + goto error; + + // Now, I can send a RPCAP open reply message + if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + rpcap_createhdr((struct rpcap_header *) sendbuf, ver, + RPCAP_MSG_OPEN_REPLY, 0, sizeof(struct rpcap_openreply)); + + openreply = (struct rpcap_openreply *) &sendbuf[sendbufidx]; + + if (sock_bufferize(NULL, sizeof(struct rpcap_openreply), NULL, &sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + memset(openreply, 0, sizeof(struct rpcap_openreply)); + openreply->linktype = htonl(pcap_datalink(fp)); + openreply->tzoff = 0; /* This is always 0 for live captures */ + + // We're done with the pcap_t. + pcap_close(fp); + + // Send the reply. + if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + return 0; + +error: + if (rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_OPEN, + errmsgbuf, errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + // Check if all the data has been read; if not, discard the data in excess + if (rpcapd_discard(pars->sockctrl, plen) == -1) + { + return -1; + } + return 0; +} + +/* + \param plen: the length of the current message (needed in order to be able + to discard excess data in the message, if present) +*/ +static int +daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen, + char *source, struct session **sessionp, + struct rpcap_sampling *samp_param _U_) +{ + char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors + char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client + char portdata[PCAP_BUF_SIZE]; // temp variable needed to derive the data port + char peerhost[PCAP_BUF_SIZE]; // temp variable needed to derive the host name of our peer + struct session *session = NULL; // saves state of session + int status; + char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered + int sendbufidx = 0; // index which keeps the number of bytes currently buffered + + // socket-related variables + struct addrinfo hints; // temp, needed to open a socket connection + struct addrinfo *addrinfo; // temp, needed to open a socket connection + struct sockaddr_storage saddr; // temp, needed to retrieve the network data port chosen on the local machine + socklen_t saddrlen; // temp, needed to retrieve the network data port chosen on the local machine + int ret; // return value from functions + + // RPCAP-related variables + struct rpcap_startcapreq startcapreq; // start capture request message + struct rpcap_startcapreply *startcapreply; // start capture reply message + int serveropen_dp; // keeps who is going to open the data connection + + addrinfo = NULL; + + status = rpcapd_recv(pars->sockctrl, (char *) &startcapreq, + sizeof(struct rpcap_startcapreq), &plen, errmsgbuf); + if (status == -1) + { + goto fatal_error; + } + if (status == -2) + { + goto error; + } + + startcapreq.flags = ntohs(startcapreq.flags); + + // Create a session structure + session = malloc(sizeof(struct session)); + if (session == NULL) + { + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Can't allocate session structure"); + goto error; + } + + session->sockdata = INVALID_SOCKET; + // We don't have a thread yet. + session->have_thread = 0; + // + // We *shouldn't* have to initialize the thread indicator + // itself, because the compiler *should* realize that we + // only use this if have_thread isn't 0, but we *do* have + // to do it, because not all compilers *do* realize that. + // + // There is no "invalid thread handle" value for a UN*X + // pthread_t, so we just zero it out. + // +#ifdef _WIN32 + session->thread = INVALID_HANDLE_VALUE; +#else + memset(&session->thread, 0, sizeof(session->thread)); +#endif + + // Open the selected device + if ((session->fp = pcap_open_live(source, + ntohl(startcapreq.snaplen), + (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_PROMISC) ? 1 : 0 /* local device, other flags not needed */, + ntohl(startcapreq.read_timeout), + errmsgbuf)) == NULL) + goto error; + +#if 0 + // Apply sampling parameters + fp->rmt_samp.method = samp_param->method; + fp->rmt_samp.value = samp_param->value; +#endif + + /* + We're in active mode if: + - we're using TCP, and the user wants us to be in active mode + - we're using UDP + */ + serveropen_dp = (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_SERVEROPEN) || (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_DGRAM) || pars->isactive; + + /* + Gets the sockaddr structure referred to the other peer in the ctrl connection + + We need that because: + - if we're in passive mode, we need to know the address family we want to use + (the same used for the ctrl socket) + - if we're in active mode, we need to know the network address of the other host + we want to connect to + */ + saddrlen = sizeof(struct sockaddr_storage); + if (getpeername(pars->sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1) + { + sock_geterror("getpeername()", errmsgbuf, PCAP_ERRBUF_SIZE); + goto error; + } + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_socktype = (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_DGRAM) ? SOCK_DGRAM : SOCK_STREAM; + hints.ai_family = saddr.ss_family; + + // Now we have to create a new socket to send packets + if (serveropen_dp) // Data connection is opened by the server toward the client + { + pcap_snprintf(portdata, sizeof portdata, "%d", ntohs(startcapreq.portdata)); + + // Get the name of the other peer (needed to connect to that specific network address) + if (getnameinfo((struct sockaddr *) &saddr, saddrlen, peerhost, + sizeof(peerhost), NULL, 0, NI_NUMERICHOST)) + { + sock_geterror("getnameinfo()", errmsgbuf, PCAP_ERRBUF_SIZE); + goto error; + } + + if (sock_initaddress(peerhost, portdata, &hints, &addrinfo, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + if ((session->sockdata = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errmsgbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) + goto error; + } + else // Data connection is opened by the client toward the server + { + hints.ai_flags = AI_PASSIVE; + + // Let's the server socket pick up a free network port for us + if (sock_initaddress(NULL, "0", &hints, &addrinfo, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + if ((session->sockdata = sock_open(addrinfo, SOCKOPEN_SERVER, 1 /* max 1 connection in queue */, errmsgbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) + goto error; + + // get the complete sockaddr structure used in the data connection + saddrlen = sizeof(struct sockaddr_storage); + if (getsockname(session->sockdata, (struct sockaddr *) &saddr, &saddrlen) == -1) + { + sock_geterror("getsockname()", errmsgbuf, PCAP_ERRBUF_SIZE); + goto error; + } + + // Get the local port the system picked up + if (getnameinfo((struct sockaddr *) &saddr, saddrlen, NULL, + 0, portdata, sizeof(portdata), NI_NUMERICSERV)) + { + sock_geterror("getnameinfo()", errmsgbuf, PCAP_ERRBUF_SIZE); + goto error; + } + } + + // addrinfo is no longer used + freeaddrinfo(addrinfo); + addrinfo = NULL; + + // Needed to send an error on the ctrl connection + session->sockctrl = pars->sockctrl; + session->protocol_version = ver; + + // Now I can set the filter + ret = daemon_unpackapplyfilter(pars->sockctrl, session, &plen, errmsgbuf); + if (ret == -1) + { + // Fatal error. A message has been logged; just give up. + goto fatal_error; + } + if (ret == -2) + { + // Non-fatal error. Send an error message to the client. + goto error; + } + + // Now, I can send a RPCAP start capture reply message + if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + rpcap_createhdr((struct rpcap_header *) sendbuf, ver, + RPCAP_MSG_STARTCAP_REPLY, 0, sizeof(struct rpcap_startcapreply)); + + startcapreply = (struct rpcap_startcapreply *) &sendbuf[sendbufidx]; + + if (sock_bufferize(NULL, sizeof(struct rpcap_startcapreply), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + memset(startcapreply, 0, sizeof(struct rpcap_startcapreply)); + startcapreply->bufsize = htonl(pcap_bufsize(session->fp)); + + if (!serveropen_dp) + { + unsigned short port = (unsigned short)strtoul(portdata,NULL,10); + startcapreply->portdata = htons(port); + } + + if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto fatal_error; + } + + if (!serveropen_dp) + { + SOCKET socktemp; // We need another socket, since we're going to accept() a connection + + // Connection creation + saddrlen = sizeof(struct sockaddr_storage); + + socktemp = accept(session->sockdata, (struct sockaddr *) &saddr, &saddrlen); + + if (socktemp == INVALID_SOCKET) + { + sock_geterror("accept()", errbuf, PCAP_ERRBUF_SIZE); + rpcapd_log(LOGPRIO_ERROR, "Accept of data connection failed: %s", + errbuf); + goto error; + } + + // Now that I accepted the connection, the server socket is no longer needed + sock_close(session->sockdata, NULL, 0); + session->sockdata = socktemp; + } + + // Now we have to create a new thread to receive packets +#ifdef _WIN32 + session->thread = (HANDLE)_beginthreadex(NULL, 0, daemon_thrdatamain, + (void *) session, 0, NULL); + if (session->thread == 0) + { + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error creating the data thread"); + goto error; + } +#else + ret = pthread_create(&session->thread, NULL, daemon_thrdatamain, + (void *) session); + if (ret != 0) + { + pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + ret, "Error creating the data thread"); + goto error; + } +#endif + session->have_thread = 1; + + // Check if all the data has been read; if not, discard the data in excess + if (rpcapd_discard(pars->sockctrl, plen) == -1) + goto fatal_error; + + *sessionp = session; + return 0; + +error: + // + // Not a fatal error, so send the client an error message and + // keep serving client requests. + // + *sessionp = NULL; + + if (addrinfo) + freeaddrinfo(addrinfo); + + if (session) + { + session_close(session); + free(session); + } + + if (rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_STARTCAPTURE, + errmsgbuf, errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + // Check if all the data has been read; if not, discard the data in excess + if (rpcapd_discard(pars->sockctrl, plen) == -1) + { + // Network error. + return -1; + } + + return 0; + +fatal_error: + // + // Fatal network error, so don't try to communicate with + // the client, just give up. + // + *sessionp = NULL; + + if (session) + { + session_close(session); + free(session); + } + + return -1; +} + +static int +daemon_msg_endcap_req(uint8 ver, struct daemon_slpars *pars, + struct session *session) +{ + char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors + struct rpcap_header header; + + session_close(session); + + rpcap_createhdr(&header, ver, RPCAP_MSG_ENDCAP_REPLY, 0, 0); + + if (sock_send(pars->sockctrl, (char *) &header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + return 0; +} + +// +// We impose a limit on the filter program size, so that, on Windows, +// where there's only one server process with multiple threads, it's +// harder to eat all the server address space by sending larger filter +// programs. (This isn't an issue on UN*X, where there are multiple +// server processes, one per client connection.) +// +// We pick a value that limits each filter to 64K; that value is twice +// the in-kernel limit for Linux and 16 times the in-kernel limit for +// *BSD and macOS. +// +// It also prevents an overflow on 32-bit platforms when calculating +// the total size of the filter program. (It's not an issue on 64-bit +// platforms with a 64-bit size_t, as the filter size is 32 bits.) +// +#define RPCAP_BPF_MAXINSNS 8192 + +static int +daemon_unpackapplyfilter(SOCKET sockctrl, struct session *session, uint32 *plenp, char *errmsgbuf) +{ + int status; + struct rpcap_filter filter; + struct rpcap_filterbpf_insn insn; + struct bpf_insn *bf_insn; + struct bpf_program bf_prog; + unsigned int i; + + status = rpcapd_recv(sockctrl, (char *) &filter, + sizeof(struct rpcap_filter), plenp, errmsgbuf); + if (status == -1) + { + return -1; + } + if (status == -2) + { + return -2; + } + + bf_prog.bf_len = ntohl(filter.nitems); + + if (ntohs(filter.filtertype) != RPCAP_UPDATEFILTER_BPF) + { + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Only BPF/NPF filters are currently supported"); + return -2; + } + + if (bf_prog.bf_len > RPCAP_BPF_MAXINSNS) + { + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, + "Filter program is larger than the maximum size of %u instructions", + RPCAP_BPF_MAXINSNS); + return -2; + } + bf_insn = (struct bpf_insn *) malloc (sizeof(struct bpf_insn) * bf_prog.bf_len); + if (bf_insn == NULL) + { + pcap_fmt_errmsg_for_errno(errmsgbuf, PCAP_ERRBUF_SIZE, + errno, "malloc() failed"); + return -2; + } + + bf_prog.bf_insns = bf_insn; + + for (i = 0; i < bf_prog.bf_len; i++) + { + status = rpcapd_recv(sockctrl, (char *) &insn, + sizeof(struct rpcap_filterbpf_insn), plenp, errmsgbuf); + if (status == -1) + { + return -1; + } + if (status == -2) + { + return -2; + } + + bf_insn->code = ntohs(insn.code); + bf_insn->jf = insn.jf; + bf_insn->jt = insn.jt; + bf_insn->k = ntohl(insn.k); + + bf_insn++; + } + + if (bpf_validate(bf_prog.bf_insns, bf_prog.bf_len) == 0) + { + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "The filter contains bogus instructions"); + return -2; + } + + if (pcap_setfilter(session->fp, &bf_prog)) + { + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "RPCAP error: %s", pcap_geterr(session->fp)); + return -2; + } + + return 0; +} + +static int +daemon_msg_updatefilter_req(uint8 ver, struct daemon_slpars *pars, + struct session *session, uint32 plen) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client + int ret; // status of daemon_unpackapplyfilter() + struct rpcap_header header; // keeps the answer to the updatefilter command + + ret = daemon_unpackapplyfilter(pars->sockctrl, session, &plen, errmsgbuf); + if (ret == -1) + { + // Fatal error. A message has been logged; just give up. + return -1; + } + if (ret == -2) + { + // Non-fatal error. Send an error reply to the client. + goto error; + } + + // Check if all the data has been read; if not, discard the data in excess + if (rpcapd_discard(pars->sockctrl, plen) == -1) + { + // Network error. + return -1; + } + + // A response is needed, otherwise the other host does not know that everything went well + rpcap_createhdr(&header, ver, RPCAP_MSG_UPDATEFILTER_REPLY, 0, 0); + + if (sock_send(pars->sockctrl, (char *) &header, sizeof (struct rpcap_header), pcap_geterr(session->fp), PCAP_ERRBUF_SIZE)) + { + // That failed; log a messsage and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + return 0; + +error: + if (rpcapd_discard(pars->sockctrl, plen) == -1) + { + return -1; + } + rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_UPDATEFILTER, + errmsgbuf, NULL); + + return 0; +} + +/*! + \brief Received the sampling parameters from remote host and it stores in the pcap_t structure. +*/ +static int +daemon_msg_setsampling_req(uint8 ver, struct daemon_slpars *pars, uint32 plen, + struct rpcap_sampling *samp_param) +{ + char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors + char errmsgbuf[PCAP_ERRBUF_SIZE]; + struct rpcap_header header; + struct rpcap_sampling rpcap_samp; + int status; + + status = rpcapd_recv(pars->sockctrl, (char *) &rpcap_samp, sizeof(struct rpcap_sampling), &plen, errmsgbuf); + if (status == -1) + { + return -1; + } + if (status == -2) + { + goto error; + } + + // Save these settings in the pcap_t + samp_param->method = rpcap_samp.method; + samp_param->value = ntohl(rpcap_samp.value); + + // A response is needed, otherwise the other host does not know that everything went well + rpcap_createhdr(&header, ver, RPCAP_MSG_SETSAMPLING_REPLY, 0, 0); + + if (sock_send(pars->sockctrl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1) + { + // That failed; log a messsage and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + if (rpcapd_discard(pars->sockctrl, plen) == -1) + { + return -1; + } + + return 0; + +error: + if (rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_SETSAMPLING, + errmsgbuf, errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + // Check if all the data has been read; if not, discard the data in excess + if (rpcapd_discard(pars->sockctrl, plen) == -1) + { + return -1; + } + + return 0; +} + +static int +daemon_msg_stats_req(uint8 ver, struct daemon_slpars *pars, + struct session *session, uint32 plen, struct pcap_stat *stats, + unsigned int svrcapt) +{ + char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors + char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client + char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered + int sendbufidx = 0; // index which keeps the number of bytes currently buffered + struct rpcap_stats *netstats; // statistics sent on the network + + // Checks that the header does not contain other data; if so, discard it + if (rpcapd_discard(pars->sockctrl, plen) == -1) + { + // Network error. + return -1; + } + + if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + rpcap_createhdr((struct rpcap_header *) sendbuf, ver, + RPCAP_MSG_STATS_REPLY, 0, (uint16) sizeof(struct rpcap_stats)); + + netstats = (struct rpcap_stats *) &sendbuf[sendbufidx]; + + if (sock_bufferize(NULL, sizeof(struct rpcap_stats), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + if (session && session->fp) + { + if (pcap_stats(session->fp, stats) == -1) + { + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "%s", pcap_geterr(session->fp)); + goto error; + } + + netstats->ifdrop = htonl(stats->ps_ifdrop); + netstats->ifrecv = htonl(stats->ps_recv); + netstats->krnldrop = htonl(stats->ps_drop); + netstats->svrcapt = htonl(session->TotCapt); + } + else + { + // We have to keep compatibility with old applications, + // which ask for statistics also when the capture has + // already stopped. + netstats->ifdrop = htonl(stats->ps_ifdrop); + netstats->ifrecv = htonl(stats->ps_recv); + netstats->krnldrop = htonl(stats->ps_drop); + netstats->svrcapt = htonl(svrcapt); + } + + // Send the packet + if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + return 0; + +error: + rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_GETSTATS, + errmsgbuf, NULL); + return 0; +} + +#ifdef _WIN32 +static unsigned __stdcall +#else +static void * +#endif +daemon_thrdatamain(void *ptr) +{ + char errbuf[PCAP_ERRBUF_SIZE + 1]; // error buffer + struct session *session; // pointer to the struct session for this session + int retval; // general variable used to keep the return value of other functions + struct rpcap_pkthdr *net_pkt_header;// header of the packet + struct pcap_pkthdr *pkt_header; // pointer to the buffer that contains the header of the current packet + u_char *pkt_data; // pointer to the buffer that contains the current packet + size_t sendbufsize; // size for the send buffer + char *sendbuf; // temporary buffer in which data to be sent is buffered + int sendbufidx; // index which keeps the number of bytes currently buffered + int status; +#ifndef _WIN32 + sigset_t sigusr1; // signal set with just SIGUSR1 +#endif + + session = (struct session *) ptr; + + session->TotCapt = 0; // counter which is incremented each time a packet is received + + // Initialize errbuf + memset(errbuf, 0, sizeof(errbuf)); + + // + // We need a buffer large enough to hold a buffer large enough + // for a maximum-size packet for this pcap_t. + // + if (pcap_snapshot(session->fp) < 0) + { + // + // The snapshot length is negative. + // This "should not happen". + // + rpcapd_log(LOGPRIO_ERROR, + "Unable to allocate the buffer for this child thread: snapshot length of %d is negative", + pcap_snapshot(session->fp)); + sendbuf = NULL; // we can't allocate a buffer, so nothing to free + goto error; + } + // + // size_t is unsigned, and the result of pcap_snapshot() is signed; + // on no platform that we support is int larger than size_t. + // This means that, unless the extra information we prepend to + // a maximum-sized packet is impossibly large, the sum of the + // snapshot length and the size of that extra information will + // fit in a size_t. + // + // So we don't need to make sure that sendbufsize will overflow. + // + sendbufsize = sizeof(struct rpcap_header) + sizeof(struct rpcap_pkthdr) + pcap_snapshot(session->fp); + sendbuf = (char *) malloc (sendbufsize); + if (sendbuf == NULL) + { + rpcapd_log(LOGPRIO_ERROR, + "Unable to allocate the buffer for this child thread"); + goto error; + } + +#ifndef _WIN32 + // + // Set the signal set to include just SIGUSR1, and block that + // signal; we only want it unblocked when we're reading + // packets - we dn't want any other system calls, such as + // ones being used to send to the client or to log messages, + // to be interrupted. + // + sigemptyset(&sigusr1); + sigaddset(&sigusr1, SIGUSR1); + pthread_sigmask(SIG_BLOCK, &sigusr1, NULL); +#endif + + // Retrieve the packets + for (;;) + { +#ifndef _WIN32 + // + // Unblock SIGUSR1 while we might be waiting for packets. + // + pthread_sigmask(SIG_UNBLOCK, &sigusr1, NULL); +#endif + retval = pcap_next_ex(session->fp, &pkt_header, (const u_char **) &pkt_data); // cast to avoid a compiler warning +#ifndef _WIN32 + // + // Now block it again. + // + pthread_sigmask(SIG_BLOCK, &sigusr1, NULL); +#endif + if (retval < 0) + break; // error + if (retval == 0) // Read timeout elapsed + continue; + + sendbufidx = 0; + + // Bufferize the general header + if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, + &sendbufidx, sendbufsize, SOCKBUF_CHECKONLY, errbuf, + PCAP_ERRBUF_SIZE) == -1) + { + rpcapd_log(LOGPRIO_ERROR, + "sock_bufferize() error sending packet message: %s", + errbuf); + goto error; + } + + rpcap_createhdr((struct rpcap_header *) sendbuf, + session->protocol_version, RPCAP_MSG_PACKET, 0, + (uint16) (sizeof(struct rpcap_pkthdr) + pkt_header->caplen)); + + net_pkt_header = (struct rpcap_pkthdr *) &sendbuf[sendbufidx]; + + // Bufferize the pkt header + if (sock_bufferize(NULL, sizeof(struct rpcap_pkthdr), NULL, + &sendbufidx, sendbufsize, SOCKBUF_CHECKONLY, errbuf, + PCAP_ERRBUF_SIZE) == -1) + { + rpcapd_log(LOGPRIO_ERROR, + "sock_bufferize() error sending packet message: %s", + errbuf); + goto error; + } + + net_pkt_header->caplen = htonl(pkt_header->caplen); + net_pkt_header->len = htonl(pkt_header->len); + net_pkt_header->npkt = htonl(++(session->TotCapt)); + net_pkt_header->timestamp_sec = htonl(pkt_header->ts.tv_sec); + net_pkt_header->timestamp_usec = htonl(pkt_header->ts.tv_usec); + + // Bufferize the pkt data + if (sock_bufferize((char *) pkt_data, pkt_header->caplen, + sendbuf, &sendbufidx, sendbufsize, SOCKBUF_BUFFERIZE, + errbuf, PCAP_ERRBUF_SIZE) == -1) + { + rpcapd_log(LOGPRIO_ERROR, + "sock_bufferize() error sending packet message: %s", + errbuf); + goto error; + } + + // Send the packet + // If the client dropped the connection, don't report an + // error, just quit. + status = sock_send(session->sockdata, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE); + if (status < 0) + { + if (status == -1) + { + // + // Error other than "client closed the + // connection out from under us"; report + // it. + // + rpcapd_log(LOGPRIO_ERROR, + "Send of packet to client failed: %s", + errbuf); + } + + // + // Give up in either case. + // + goto error; + } + } + + if (retval < 0 && retval != PCAP_ERROR_BREAK) + { + // + // Failed with an error other than "we were told to break + // out of the loop". + // + // The latter just means that the client told us to stop + // capturing, so there's no error to report. + // + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error reading the packets: %s", pcap_geterr(session->fp)); + rpcap_senderror(session->sockctrl, session->protocol_version, + PCAP_ERR_READEX, errbuf, NULL); + } + +error: + // + // The main thread will clean up the session structure. + // + free(sendbuf); + + return 0; +} + +#ifndef _WIN32 +// +// Do-nothing handler for SIGUSR1; the sole purpose of SIGUSR1 is to +// interrupt the data thread if it's blocked in a system call waiting +// for packets to arrive. +// +static void noop_handler(int sign _U_) +{ +} +#endif + +/*! + \brief It serializes a network address. + + It accepts a 'sockaddr_storage' structure as input, and it converts it appropriately into a format + that can be used to be sent on the network. Basically, it applies all the hton() + conversion required to the input variable. + + \param sockaddrin a 'sockaddr_storage' pointer to the variable that has to be + serialized. This variable can be both a 'sockaddr_in' and 'sockaddr_in6'. + + \param sockaddrout an 'rpcap_sockaddr' pointer to the variable that will contain + the serialized data. This variable has to be allocated by the user. + + \warning This function supports only AF_INET and AF_INET6 address families. +*/ +static void +daemon_seraddr(struct sockaddr_storage *sockaddrin, struct rpcap_sockaddr *sockaddrout) +{ + memset(sockaddrout, 0, sizeof(struct sockaddr_storage)); + + // There can be the case in which the sockaddrin is not available + if (sockaddrin == NULL) return; + + // Warning: we support only AF_INET and AF_INET6 + switch (sockaddrin->ss_family) + { + case AF_INET: + { + struct sockaddr_in *sockaddrin_ipv4; + struct rpcap_sockaddr_in *sockaddrout_ipv4; + + sockaddrin_ipv4 = (struct sockaddr_in *) sockaddrin; + sockaddrout_ipv4 = (struct rpcap_sockaddr_in *) sockaddrout; + sockaddrout_ipv4->family = htons(RPCAP_AF_INET); + sockaddrout_ipv4->port = htons(sockaddrin_ipv4->sin_port); + memcpy(&sockaddrout_ipv4->addr, &sockaddrin_ipv4->sin_addr, sizeof(sockaddrout_ipv4->addr)); + memset(sockaddrout_ipv4->zero, 0, sizeof(sockaddrout_ipv4->zero)); + break; + } + +#ifdef AF_INET6 + case AF_INET6: + { + struct sockaddr_in6 *sockaddrin_ipv6; + struct rpcap_sockaddr_in6 *sockaddrout_ipv6; + + sockaddrin_ipv6 = (struct sockaddr_in6 *) sockaddrin; + sockaddrout_ipv6 = (struct rpcap_sockaddr_in6 *) sockaddrout; + sockaddrout_ipv6->family = htons(RPCAP_AF_INET6); + sockaddrout_ipv6->port = htons(sockaddrin_ipv6->sin6_port); + sockaddrout_ipv6->flowinfo = htonl(sockaddrin_ipv6->sin6_flowinfo); + memcpy(&sockaddrout_ipv6->addr, &sockaddrin_ipv6->sin6_addr, sizeof(sockaddrout_ipv6->addr)); + sockaddrout_ipv6->scope_id = htonl(sockaddrin_ipv6->sin6_scope_id); + break; + } +#endif + } +} + + +/*! + \brief Suspends a thread for secs seconds. +*/ +void sleep_secs(int secs) +{ +#ifdef _WIN32 + Sleep(secs*1000); +#else + unsigned secs_remaining; + + if (secs <= 0) + return; + secs_remaining = secs; + while (secs_remaining != 0) + secs_remaining = sleep(secs_remaining); +#endif +} + +/* + * Read the header of a message. + */ +static int +rpcapd_recv_msg_header(SOCKET sock, struct rpcap_header *headerp) +{ + int nread; + char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors + + nread = sock_recv(sock, (char *) headerp, sizeof(struct rpcap_header), + SOCK_RECEIVEALL_YES|SOCK_EOF_ISNT_ERROR, errbuf, PCAP_ERRBUF_SIZE); + if (nread == -1) + { + // Network error. + rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf); + return -1; + } + if (nread == 0) + { + // Immediate EOF; that's treated like a close message. + return -2; + } + headerp->plen = ntohl(headerp->plen); + return 0; +} + +/* + * Read data from a message. + * If we're trying to read more data that remains, puts an error + * message into errmsgbuf and returns -2. Otherwise, tries to read + * the data and, if that succeeds, subtracts the amount read from + * the number of bytes of data that remains. + * Returns 0 on success, logs a message and returns -1 on a network + * error. + */ +static int +rpcapd_recv(SOCKET sock, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf) +{ + int nread; + char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors + + if (toread > *plen) + { + // Tell the client and continue. + pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message payload is too short"); + return -2; + } + nread = sock_recv(sock, buffer, toread, + SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE); + if (nread == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf); + return -1; + } + *plen -= nread; + return 0; +} + +/* + * Discard data from a connection. + * Mostly used to discard wrong-sized messages. + * Returns 0 on success, logs a message and returns -1 on a network + * error. + */ +static int +rpcapd_discard(SOCKET sock, uint32 len) +{ + char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed + + if (len != 0) + { + if (sock_discard(sock, len, errbuf, PCAP_ERRBUF_SIZE) == -1) + { + // Network error. + rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf); + return -1; + } + } + return 0; +} + +// +// Shut down any packet-capture thread associated with the session, +// close the SSL handle for the data socket if we have one, close +// the data socket if we have one, and close the underlying packet +// capture handle if we have one. +// +// We do not, of course, touch the controlling socket that's also +// copied into the session, as the service loop might still use it. +// +static void session_close(struct session *session) +{ + if (session->have_thread) + { + // + // Tell the data connection thread main capture loop to + // break out of that loop. + // + // This may be sufficient to wake up a blocked thread, + // but it's not guaranteed to be sufficient. + // + pcap_breakloop(session->fp); + +#ifdef _WIN32 + // + // Set the event on which a read would block, so that, + // if it's currently blocked waiting for packets to + // arrive, it'll wake up, so it can see the "break + // out of the loop" indication. (pcap_breakloop() + // might do this, but older versions don't. Setting + // it twice should, at worst, cause an extra wakeup, + // which shouldn't be a problem.) + // + // XXX - what about modules other than NPF? + // + SetEvent(pcap_getevent(session->fp)); + + // + // Wait for the thread to exit, so we don't close + // sockets out from under it. + // + // XXX - have a timeout, so we don't wait forever? + // + WaitForSingleObject(session->thread, INFINITE); + + // + // Release the thread handle, as we're done with + // it. + // + CloseHandle(session->thread); + session->have_thread = 0; + session->thread = INVALID_HANDLE_VALUE; +#else + // + // Send a SIGUSR1 signal to the thread, so that, if + // it's currently blocked waiting for packets to arrive, + // it'll wake up (we've turned off SA_RESTART for + // SIGUSR1, so that the system call in which it's blocked + // should return EINTR rather than restarting). + // + pthread_kill(session->thread, SIGUSR1); + + // + // Wait for the thread to exit, so we don't close + // sockets out from under it. + // + // XXX - have a timeout, so we don't wait forever? + // + pthread_join(session->thread, NULL); + session->have_thread = 0; + memset(&session->thread, 0, sizeof(session->thread)); +#endif + } + + if (session->sockdata != INVALID_SOCKET) + { + sock_close(session->sockdata, NULL, 0); + session->sockdata = INVALID_SOCKET; + } + + if (session->fp) + { + pcap_close(session->fp); + session->fp = NULL; + } +} + +// +// Check whether a capture source string is a URL or not. +// This includes URLs that refer to a local device; a scheme, followed +// by ://, followed by *another* scheme and ://, is just silly, and +// anybody who supplies that will get an error. +// +static int +is_url(const char *source) +{ + char *colonp; + + /* + * RFC 3986 says: + * + * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] + * + * hier-part = "//" authority path-abempty + * / path-absolute + * / path-rootless + * / path-empty + * + * authority = [ userinfo "@" ] host [ ":" port ] + * + * userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) + * + * Step 1: look for the ":" at the end of the scheme. + * A colon in the source is *NOT* sufficient to indicate that + * this is a URL, as interface names on some platforms might + * include colons (e.g., I think some Solaris interfaces + * might). + */ + colonp = strchr(source, ':'); + if (colonp == NULL) + { + /* + * The source is the device to open. It's not a URL. + */ + return (0); + } + + /* + * All schemes must have "//" after them, i.e. we only support + * hier-part = "//" authority path-abempty, not + * hier-part = path-absolute + * hier-part = path-rootless + * hier-part = path-empty + * + * We need that in order to distinguish between a local device + * name that happens to contain a colon and a URI. + */ + if (strncmp(colonp + 1, "//", 2) != 0) + { + /* + * The source is the device to open. It's not a URL. + */ + return (0); + } + + /* + * It's a URL. + */ + return (1); +} diff --git a/rpcapd/daemon.h b/rpcapd/daemon.h new file mode 100644 index 000000000000..74e17da5a505 --- /dev/null +++ b/rpcapd/daemon.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __DAEMON_H__ +#define __DAEMON_H__ + +// +// Returns 1 if the client closed the control connection explicitly, 0 +// otherwise; the return value is used only by callers that call us +// for active mode. +// +int daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients, + int nullAuthAllowed); + +void sleep_secs(int secs); + +#endif diff --git a/rpcapd/fileconf.c b/rpcapd/fileconf.c new file mode 100644 index 000000000000..2f15c014204f --- /dev/null +++ b/rpcapd/fileconf.c @@ -0,0 +1,557 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "ftmacros.h" + +#include +#include +#include +#include +#include // for PCAP_ERRBUF_SIZE + +#include "portability.h" +#include "rpcapd.h" +#include "config_params.h" // configuration file parameters +#include "fileconf.h" +#include "rpcap-protocol.h" +#include "log.h" + +// +// Parameter names. +// +#define PARAM_ACTIVECLIENT "ActiveClient" +#define PARAM_PASSIVECLIENT "PassiveClient" +#define PARAM_NULLAUTHPERMIT "NullAuthPermit" + +static char *skipws(char *ptr); + +void fileconf_read(void) +{ + FILE *fp; + unsigned int num_active_clients; + + if ((fp = fopen(loadfile, "r")) != NULL) + { + char line[MAX_LINE + 1]; + unsigned int lineno; + + hostlist[0] = 0; + num_active_clients = 0; + lineno = 0; + + while (fgets(line, MAX_LINE, fp) != NULL) + { + size_t linelen; + char *ptr; + char *param; + size_t result; + size_t toklen; + + lineno++; + + linelen = strlen(line); + if (line[linelen - 1] != '\n') + { + int c; + + // + // Either the line doesn't fit in + // the buffer, or we got an EOF + // before the EOL. Assume it's the + // former. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u is longer than %u characters", + loadfile, lineno, MAX_LINE); + + // + // Eat characters until we get an NL. + // + while ((c = getc(fp)) != '\n') + { + if (c == EOF) + goto done; + } + + // + // Try the next line. + // + continue; + } + ptr = line; + + // + // Skip leading white space, if any. + // + ptr = skipws(ptr); + if (ptr == NULL) + { + // Blank line. + continue; + } + + // + // Is the next character a "#"? If so, this + // line is a comment; skip to the next line. + // + if (*ptr == '#') + continue; + + // + // Is the next character alphabetic? If not, + // this isn't a valid parameter name. + // + if (!isascii((unsigned char)*ptr) || + !isalpha((unsigned char)*ptr)) + { + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u doesn't have a valid parameter name", + loadfile, lineno); + continue; + } + + // + // Grab the first token, which is made of + // alphanumerics, underscores, and hyphens. + // That's the name of the parameter being set. + // + param = ptr; + while (isascii((unsigned char)*ptr) && + (isalnum((unsigned char)*ptr) || *ptr == '-' || *ptr == '_')) + ptr++; + + // + // Skip over white space, if any. + // + ptr = skipws(ptr); + if (ptr == NULL || *ptr != '=') + { + // + // We hit the end of the line before + // finding a non-white space character, + // or we found one but it's not an "=". + // That means there's no "=", so this + // line is invalid. Complain and skip + // this line. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has a parameter but no =", + loadfile, lineno); + continue; + } + + // + // We found the '='; set it to '\0', and skip + // past it. + // + *ptr++ = '\0'; + + // + // Skip past any white space after the "=". + // + ptr = skipws(ptr); + if (ptr == NULL) + { + // + // The value is empty. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has a parameter but no value", + loadfile, lineno); + continue; + } + + // + // OK, what parameter is this? + // + if (strcmp(param, PARAM_ACTIVECLIENT) == 0) { + // + // Add this to the list of active clients. + // + char *address, *port; + + // + // We can't have more than MAX_ACTIVE_LIST + // active clients. + // + if (num_active_clients >= MAX_ACTIVE_LIST) + { + // + // Too many entries for the active + // client list. Complain and + // ignore it. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has an %s parameter, but we already have %u active clients", + loadfile, lineno, PARAM_ACTIVECLIENT, + MAX_ACTIVE_LIST); + continue; + } + + // + // Get the address. + // It's terminated by a host list separator + // *or* a #; there *shouldn't* be a #, as + // that starts a comment, and that would + // mean that we have no port. + // + address = ptr; + toklen = strcspn(ptr, RPCAP_HOSTLIST_SEP "#"); + ptr += toklen; // skip to the terminator + if (toklen == 0) + { + if (isascii((unsigned char)*ptr) && + (isspace((unsigned char)*ptr) || *ptr == '#' || *ptr == '\0')) + { + // + // The first character it saw + // was a whitespace character + // or a comment character. + // This means that there's + // no value. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has a parameter but no value", + loadfile, lineno); + } + else + { + // + // This means that the first + // character it saw was a + // separator. This means that + // there's no address in the + // value, just a port. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has an %s parameter with a value containing no address", + loadfile, lineno, PARAM_ACTIVECLIENT); + } + continue; + } + + // + // Null-terminate the address, and skip past + // it. + // + *ptr++ = '\0'; + + // + // Skip any white space following the + // separating character. + // + ptr = skipws(ptr); + if (ptr == NULL) + { + // + // The value is empty, so there's + // no port in the value. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has an %s parameter with a value containing no port", + loadfile, lineno, PARAM_ACTIVECLIENT); + continue; + } + + // + // Get the port. + // We look for a white space character + // or a # as a terminator; the # introduces + // a comment that runs to the end of the + // line. + // + port = ptr; + toklen = strcspn(ptr, " \t#\r\n"); + ptr += toklen; + if (toklen == 0) + { + // + // The value is empty, so there's + // no port in the value. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has an %s parameter with a value containing no port", + loadfile, lineno, PARAM_ACTIVECLIENT); + continue; + } + + // + // Null-terminate the port, and skip past + // it. + // + *ptr++ = '\0'; + result = pcap_strlcpy(activelist[num_active_clients].address, address, sizeof(activelist[num_active_clients].address)); + if (result >= sizeof(activelist[num_active_clients].address)) + { + // + // It didn't fit. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has an %s parameter with an address with more than %u characters", + loadfile, lineno, PARAM_ACTIVECLIENT, + (unsigned int)(sizeof(activelist[num_active_clients].address) - 1)); + continue; + } + if (strcmp(port, "DEFAULT") == 0) // the user choose a custom port + result = pcap_strlcpy(activelist[num_active_clients].port, RPCAP_DEFAULT_NETPORT_ACTIVE, sizeof(activelist[num_active_clients].port)); + else + result = pcap_strlcpy(activelist[num_active_clients].port, port, sizeof(activelist[num_active_clients].port)); + if (result >= sizeof(activelist[num_active_clients].address)) + { + // + // It didn't fit. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has an %s parameter with an port with more than %u characters", + loadfile, lineno, PARAM_ACTIVECLIENT, + (unsigned int)(sizeof(activelist[num_active_clients].port) - 1)); + continue; + } + + num_active_clients++; + } + else if (strcmp(param, PARAM_PASSIVECLIENT) == 0) + { + char *eos; + char *host; + + // + // Get the host. + // We look for a white space character + // or a # as a terminator; the # introduces + // a comment that runs to the end of the + // line. + // + host = ptr; + toklen = strcspn(ptr, " \t#\r\n"); + if (toklen == 0) + { + // + // The first character it saw + // was a whitespace character + // or a comment character. + // This means that there's + // no value. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has a parameter but no value", + loadfile, lineno); + continue; + } + ptr += toklen; + *ptr++ = '\0'; + + // + // Append this to the host list. + // Save the curren end-of-string for the + // host list, in case the new host doesn't + // fit, so that we can discard the partially- + // copied host name. + // + eos = hostlist + strlen(hostlist); + if (eos != hostlist) + { + // + // The list is not empty, so prepend + // a comma before adding this host. + // + result = pcap_strlcat(hostlist, ",", sizeof(hostlist)); + if (result >= sizeof(hostlist)) + { + // + // It didn't fit. Discard + // the comma (which wasn't + // added, but...), complain, + // and ignore this line. + // + *eos = '\0'; + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has a %s parameter with a host name that doesn't fit", + loadfile, lineno, PARAM_PASSIVECLIENT); + continue; + } + } + result = pcap_strlcat(hostlist, host, sizeof(hostlist)); + if (result >= sizeof(hostlist)) + { + // + // It didn't fit. Discard the comma, + // complain, and ignore this line. + // + *eos = '\0'; + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has a %s parameter with a host name that doesn't fit", + loadfile, lineno, PARAM_PASSIVECLIENT); + continue; + } + } + else if (strcmp(param, PARAM_NULLAUTHPERMIT) == 0) + { + char *setting; + + // + // Get the setting. + // We look for a white space character + // or a # as a terminator; the # introduces + // a comment that runs to the end of the + // line. + // + setting = ptr; + toklen = strcspn(ptr, " \t#\r\n"); + ptr += toklen; + if (toklen == 0) + { + // + // The first character it saw + // was a whitespace character + // or a comment character. + // This means that there's + // no value. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has a parameter but no value", + loadfile, lineno); + continue; + } + *ptr++ = '\0'; + + // + // XXX - should we complain if it's + // neither "yes" nor "no"? + // + if (strcmp(setting, "YES") == 0) + nullAuthAllowed = 1; + else + nullAuthAllowed = 0; + } + else + { + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has an unknown parameter %s", + loadfile, lineno, param); + continue; + } + } + +done: + // clear the remaining fields of the active list + for (int i = num_active_clients; i < MAX_ACTIVE_LIST; i++) + { + activelist[i].address[0] = 0; + activelist[i].port[0] = 0; + num_active_clients++; + } + + rpcapd_log(LOGPRIO_DEBUG, "New passive host list: %s", hostlist); + fclose(fp); + } +} + +int fileconf_save(const char *savefile) +{ + FILE *fp; + + if ((fp = fopen(savefile, "w")) != NULL) + { + char *token; /*, *port;*/ // temp, needed to separate items into the hostlist + char temphostlist[MAX_HOST_LIST + 1]; + int i = 0; + char *lasts; + + fprintf(fp, "# Configuration file help.\n\n"); + + // Save list of clients which are allowed to connect to us in passive mode + fprintf(fp, "# Hosts which are allowed to connect to this server (passive mode)\n"); + fprintf(fp, "# Format: PassiveClient = \n\n"); + + strncpy(temphostlist, hostlist, MAX_HOST_LIST); + temphostlist[MAX_HOST_LIST] = 0; + + token = pcap_strtok_r(temphostlist, RPCAP_HOSTLIST_SEP, &lasts); + while(token != NULL) + { + fprintf(fp, "%s = %s\n", PARAM_PASSIVECLIENT, token); + token = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts); + } + + + // Save list of clients which are allowed to connect to us in active mode + fprintf(fp, "\n\n"); + fprintf(fp, "# Hosts to which this server is trying to connect to (active mode)\n"); + fprintf(fp, "# Format: ActiveClient = , \n\n"); + + + while ((i < MAX_ACTIVE_LIST) && (activelist[i].address[0] != 0)) + { + fprintf(fp, "%s = %s, %s\n", PARAM_ACTIVECLIENT, + activelist[i].address, activelist[i].port); + i++; + } + + // Save if we want to permit NULL authentication + fprintf(fp, "\n\n"); + fprintf(fp, "# Permit NULL authentication: YES or NO\n\n"); + + fprintf(fp, "%s = %s\n", PARAM_NULLAUTHPERMIT, + nullAuthAllowed ? "YES" : "NO"); + + fclose(fp); + return 0; + } + else + { + return -1; + } + +} + +// +// Skip over white space. +// If we hit a CR or LF, return NULL, otherwise return a pointer to +// the first non-white space character. Replace white space characters +// other than CR or LF with '\0', so that, if we're skipping white space +// after a token, the token is null-terminated. +// +static char *skipws(char *ptr) +{ + while (isascii((unsigned char)*ptr) && isspace((unsigned char)*ptr)) { + if (*ptr == '\r' || *ptr == '\n') + return NULL; + *ptr++ = '\0'; + } + return ptr; +} diff --git a/rpcapd/fileconf.h b/rpcapd/fileconf.h new file mode 100644 index 000000000000..912dd3264cd9 --- /dev/null +++ b/rpcapd/fileconf.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __FILECONF_H__ +#define __FILECONF_H__ + +void fileconf_read(void); +int fileconf_save(const char *savefile); + +#endif diff --git a/rpcapd/log.c b/rpcapd/log.c new file mode 100644 index 000000000000..7b5fee57caaf --- /dev/null +++ b/rpcapd/log.c @@ -0,0 +1,260 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +#include "portability.h" + +#include "log.h" + +static int log_to_systemlog; +static int log_debug_messages; + +static void rpcapd_vlog_stderr(log_priority, + PCAP_FORMAT_STRING(const char *), va_list) PCAP_PRINTFLIKE(2, 0); + +static void rpcapd_vlog_stderr(log_priority priority, const char *message, va_list ap) +{ + const char *tag; + + /* + * Squelch warnings from compilers that *don't* assume that + * priority always has a valid enum value and therefore don't + * assume that we'll always go through one of the case arms. + * + * If we have a default case, compilers that *do* assume that + * will then complain about the default case code being + * unreachable. + * + * Damned if you do, damned if you don't. + */ + tag = ""; + + switch (priority) { + + case LOGPRIO_DEBUG: + tag = "DEBUG: "; + break; + + case LOGPRIO_INFO: + tag = ""; + break; + + case LOGPRIO_WARNING: + tag = "warning: "; + break; + + case LOGPRIO_ERROR: + tag = "error: "; + break; + } + + fprintf(stderr, "rpcapd: %s", tag); + vfprintf(stderr, message, ap); + putc('\n', stderr); +} + +static void rpcapd_vlog_systemlog(log_priority, + PCAP_FORMAT_STRING(const char *), va_list) PCAP_PRINTFLIKE(2, 0); + +#ifdef _WIN32 +#define MESSAGE_SUBKEY \ + "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\rpcapd" + +static void rpcapd_vlog_systemlog(log_priority priority, const char *message, + va_list ap) +{ +#if 0 + static int initialized = 0; + HKEY hey_handle; + static HANDLE log_handle; + WORD eventlog_type; + DWORD event_id; + char msgbuf[1024]; + char *strings[1]; + + if (!initialized) { + /* + * Register our message stuff in the Registry. + * + * First, create the registry key for us. If the key + * already exists, this succeeds and returns a handle + * for it. + */ + if (RegCreateKey(HKEY_LOCAL_MACHINE, MESSAGE_SUBKEY, + &key_handle) != ERROR_SUCCESS) { + /* + * Failed - give up and just log this message, + * and all subsequent messages, to the + * standard error. + */ + log_to_systemlog = 0; + initialized = 1; + rpcapd_vlog_stderr(priority, message, ap); + return; + } + log_handle = RegisterEventSource(NULL, "rpcapd"); + initialized = 1; + } + + switch (priority) { + + case LOGPRIO_DEBUG: + // + // XXX - what *should* we do about debug messages? + // + eventlog_type = EVENTLOG_INFORMATION_TYPE; + event_id = RPCAPD_INFO_ID; + break; + + case LOGPRIO_INFO: + eventlog_type = EVENTLOG_INFORMATION_TYPE; + event_id = RPCAPD_INFO_ID; + break; + + case LOGPRIO_WARNING: + eventlog_type = EVENTLOG_WARNING_TYPE; + event_id = RPCAPD_WARNING_ID; + break; + + case LOGPRIO_ERROR: + eventlog_type = EVENTLOG_ERROR_TYPE; + event_id = RPCAPD_ERROR_ID; + break; + + default: + /* Don't do this. */ + return; + } + + vsprintf(msgbuf, message, ap); + + strings[0] = msgbuf; + /* + * If this fails, how are we going to report it? + */ + (void) ReportEvent(log_handle, eventlog_type, 0, event_id, NULL, 1, 0, + strings, NULL); +#else + rpcapd_vlog_stderr(priority, message, ap); +#endif +} +#else +static void rpcapd_vlog_systemlog(log_priority priority, const char *message, + va_list ap) +{ + static int initialized = 0; + int syslog_priority; + + if (!initialized) { + // + // Open the log. + // + openlog("rpcapd", LOG_PID, LOG_DAEMON); + initialized = 1; + } + + switch (priority) { + + case LOGPRIO_DEBUG: + syslog_priority = LOG_DEBUG; + break; + + case LOGPRIO_INFO: + syslog_priority = LOG_INFO; + break; + + case LOGPRIO_WARNING: + syslog_priority = LOG_WARNING; + break; + + case LOGPRIO_ERROR: + syslog_priority = LOG_ERR; + break; + + default: + /* Don't do this. */ + return; + } + +#ifdef HAVE_VSYSLOG + vsyslog(syslog_priority, message, ap); +#else + /* + * Thanks, IBM, for not providing vsyslog() in AIX! + * + * They also warn that the syslog functions shouldn't + * be used in multithreaded programs, but the only thing + * obvious that seems to make the syslog_r functions + * better is that they have an additional argument + * that points to the information that's static to + * the syslog code in non-thread-safe versions. Most + * of that data is set by openlog(); since we already + * do an openlog before doing logging, and don't + * change that data afterwards, I suspect that, in + * practice, the regular syslog routines are OK for + * us (especially given that we'd end up having one + * static struct syslog_data anyway, which means we'd + * just be like the non-thread-safe version). + */ + char logbuf[1024+1]; + + pcap_vsnprintf(logbuf, sizeof logbuf, message, ap); + syslog(syslog_priority, "%s", logbuf); +#endif +} +#endif + +void rpcapd_log_set(int log_to_systemlog_arg, int log_debug_messages_arg) +{ + log_debug_messages = log_debug_messages_arg; + log_to_systemlog = log_to_systemlog_arg; +} + +void rpcapd_log(log_priority priority, const char *message, ...) +{ + va_list ap; + + if (priority != LOGPRIO_DEBUG || log_debug_messages) { + va_start(ap, message); + if (log_to_systemlog) + { + rpcapd_vlog_systemlog(priority, message, ap); + } + else + { + rpcapd_vlog_stderr(priority, message, ap); + } + va_end(ap); + } +} diff --git a/rpcapd/log.h b/rpcapd/log.h new file mode 100644 index 000000000000..28a6cee0ae00 --- /dev/null +++ b/rpcapd/log.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "pcap/funcattrs.h" + +extern void rpcapd_log_set(int, int); + +typedef enum { + LOGPRIO_DEBUG, + LOGPRIO_INFO, + LOGPRIO_WARNING, + LOGPRIO_ERROR +} log_priority; + +extern void rpcapd_log(log_priority priority, + PCAP_FORMAT_STRING(const char *message), ...) PCAP_PRINTFLIKE(2, 3); diff --git a/rpcapd/org.tcpdump.rpcapd.plist b/rpcapd/org.tcpdump.rpcapd.plist new file mode 100644 index 000000000000..db3223a70317 --- /dev/null +++ b/rpcapd/org.tcpdump.rpcapd.plist @@ -0,0 +1,30 @@ + + + + + Disabled + + Label + com.tcpdump.rpcapd + Program + /usr/local/libexec/rpcapd + ProgramArguments + + /usr/local/libexec/rpcapd + -i + + Sockets + + Listeners + + SockServiceName + 2002 + + + inetdCompatibility + + Wait + + + + diff --git a/rpcapd/rpcapd-config.manfile.in b/rpcapd/rpcapd-config.manfile.in new file mode 100644 index 000000000000..1a87529d8abf --- /dev/null +++ b/rpcapd/rpcapd-config.manfile.in @@ -0,0 +1,78 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH RPCAPD-CONFIG @MAN_FILE_FORMATS@ "6 January 2019" +.SH NAME +rpcapd-config \- rpcapd configuration file format +.SH DESCRIPTION +An +.B rpcapd +configuration file allows parameters to be set for +.BR rpcapd (@MAN_ADMIN_COMMANDS@). +.LP +A # introduces a comment that runs to the end of the line. Blank lines, +and lines with only a comment, are ignored. Leading and trailing white +space on a line are also ignored. +.LP +Lines that set a parameter are of the form +.IP +\fIparameter\fB=\fIvalue\fR +.LP +Whitespace preceding or following the = is ignored. +.LP +The +.IR parameter s +are: +.TP +.B ActiveClient +.I value +is a host name or IP addresse, followed by a comma, +semicolon, or space, followed by a port name and address or +.BR DEFAULT . +.B DEFAULT +specifies the default active mode port for rpcapd, port 2003. +Each +.B ActiveClient +line adds the host and port to the list of clients to which the server +should connect in active mode. +.TP +.B PassiveClient +.I value +is a host name or IP addresse, followed by a comma, +semicolon, or space, followed by a port name and address or +.BR DEFAULT . +.B DEFAULT +specifies the default passive mode port for rpcapd, port 2002. +Each +.B PassiveClient +line adds the host and port to the list of clients addresses and ports +that are allowed to connect to the server in passive mode. +.TP +.B NullAuthPermit +.I value +is either +.B YES +or +.BR NO . +.B YES +means that null authentication is permitted; +.B No +means that it is not permitted. +.SH SEE ALSO +rpcapd(@MAN_ADMIN_COMMANDS@) diff --git a/rpcapd/rpcapd.c b/rpcapd/rpcapd.c new file mode 100644 index 000000000000..430acdc88e86 --- /dev/null +++ b/rpcapd/rpcapd.c @@ -0,0 +1,1359 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "ftmacros.h" + +#include // for the errno variable +#include // for strtok, etc +#include // for malloc(), free(), ... +#include // for PCAP_ERRBUF_SIZE +#include // for signal() + +#include "fmtutils.h" +#include "sockutils.h" // for socket calls +#include "varattrs.h" // for _U_ +#include "portability.h" +#include "rpcapd.h" +#include "config_params.h" // configuration file parameters +#include "fileconf.h" // for the configuration file management +#include "rpcap-protocol.h" +#include "daemon.h" // the true main() method of this daemon +#include "log.h" + +#ifdef _WIN32 + #include // for thread stuff + #include "win32-svc.h" // for Win32 service stuff + #include "getopt.h" // for getopt()-for-Windows +#else + #include // for open() + #include // for exit() + #include // waitpid() +#endif + +// +// Element in list of sockets on which we're listening for connections. +// +struct listen_sock { + struct listen_sock *next; + SOCKET sock; +}; + +// Global variables +char hostlist[MAX_HOST_LIST + 1]; //!< Keeps the list of the hosts that are allowed to connect to this server +struct active_pars activelist[MAX_ACTIVE_LIST]; //!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode) +int nullAuthAllowed; //!< '1' if we permit NULL authentication, '0' otherwise +static struct listen_sock *listen_socks; //!< sockets on which we listen +char loadfile[MAX_LINE + 1]; //!< Name of the file from which we have to load the configuration +static int passivemode = 1; //!< '1' if we want to run in passive mode as well +static struct addrinfo mainhints; //!< temporary struct to keep settings needed to open the new socket +static char address[MAX_LINE + 1]; //!< keeps the network address (either numeric or literal) to bind to +static char port[MAX_LINE + 1]; //!< keeps the network port to bind to +#ifdef _WIN32 +static HANDLE state_change_event; //!< event to signal that a state change should take place +#endif +static volatile sig_atomic_t shutdown_server; //!< '1' if the server is to shut down +static volatile sig_atomic_t reread_config; //!< '1' if the server is to re-read its configuration + +extern char *optarg; // for getopt() + +// Function definition +#ifdef _WIN32 +static unsigned __stdcall main_active(void *ptr); +static BOOL WINAPI main_ctrl_event(DWORD); +#else +static void *main_active(void *ptr); +static void main_terminate(int sign); +static void main_reread_config(int sign); +#endif +static void accept_connections(void); +static void accept_connection(SOCKET listen_sock); +#ifndef _WIN32 +static void main_reap_children(int sign); +#endif +#ifdef _WIN32 +static unsigned __stdcall main_passive_serviceloop_thread(void *ptr); +#endif + +#define RPCAP_ACTIVE_WAIT 30 /* Waiting time between two attempts to open a connection, in active mode (default: 30 sec) */ + +/*! + \brief Prints the usage screen if it is launched in console mode. +*/ +static void printusage(void) +{ + const char *usagetext = + "USAGE:" + " " PROGRAM_NAME " [-b
] [-p ] [-4] [-l ] [-a ]\n" + " [-n] [-v] [-d] " +#ifndef _WIN32 + "[-i] " +#endif + "[-D] [-s ] [-f ]\n\n" + " -b
the address to bind to (either numeric or literal).\n" + " Default: binds to all local IPv4 and IPv6 addresses\n\n" + " -p the port to bind to.\n" + " Default: binds to port " RPCAP_DEFAULT_NETPORT "\n\n" + " -4 use only IPv4.\n" + " Default: use both IPv4 and IPv6 waiting sockets\n\n" + " -l a file that contains a list of hosts that are allowed\n" + " to connect to this server (if more than one, list them one\n" + " per line).\n" + " We suggest to use literal names (instead of numeric ones)\n" + " in order to avoid problems with different address families.\n\n" + " -n permit NULL authentication (usually used with '-l')\n\n" + " -a run in active mode when connecting to 'host' on port 'port'\n" + " In case 'port' is omitted, the default port (" RPCAP_DEFAULT_NETPORT_ACTIVE ") is used\n\n" + " -v run in active mode only (default: if '-a' is specified, it\n" + " accepts passive connections as well)\n\n" + " -d run in daemon mode (UNIX only) or as a service (Win32 only)\n" + " Warning (Win32): this switch is provided automatically when\n" + " the service is started from the control panel\n\n" +#ifndef _WIN32 + " -i run in inetd mode (UNIX only)\n\n" +#endif + " -D log debugging messages\n\n" + " -s save the current configuration to file\n\n" + " -f load the current configuration from file; all switches\n" + " specified from the command line are ignored\n\n" + " -h print this help screen\n\n"; + + (void)fprintf(stderr, "RPCAPD, a remote packet capture daemon.\n" + "Compiled with %s\n\n", pcap_lib_version()); + printf("%s", usagetext); +} + + + +//! Program main +int main(int argc, char *argv[]) +{ + char savefile[MAX_LINE + 1]; // name of the file on which we have to save the configuration + int log_to_systemlog = 0; // Non-zero if we should log to the "system log" rather than the standard error + int isdaemon = 0; // Non-zero if the user wants to run this program as a daemon +#ifndef _WIN32 + int isrunbyinetd = 0; // Non-zero if this is being run by inetd or something inetd-like +#endif + int log_debug_messages = 0; // Non-zero if the user wants debug messages logged + int retval; // keeps the returning value from several functions + char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed +#ifndef _WIN32 + struct sigaction action; +#endif + + savefile[0] = 0; + loadfile[0] = 0; + hostlist[0] = 0; + + // Initialize errbuf + memset(errbuf, 0, sizeof(errbuf)); + + strncpy(address, RPCAP_DEFAULT_NETADDR, MAX_LINE); + strncpy(port, RPCAP_DEFAULT_NETPORT, MAX_LINE); + + // Prepare to open a new server socket + memset(&mainhints, 0, sizeof(struct addrinfo)); + + mainhints.ai_family = PF_UNSPEC; + mainhints.ai_flags = AI_PASSIVE; // Ready to a bind() socket + mainhints.ai_socktype = SOCK_STREAM; + + // Getting the proper command line options + while ((retval = getopt(argc, argv, "b:dDhip:4l:na:s:f:v")) != -1) + { + switch (retval) + { + case 'D': + log_debug_messages = 1; + rpcapd_log_set(log_to_systemlog, log_debug_messages); + break; + case 'b': + strncpy(address, optarg, MAX_LINE); + break; + case 'p': + strncpy(port, optarg, MAX_LINE); + break; + case '4': + mainhints.ai_family = PF_INET; // IPv4 server only + break; + case 'd': + isdaemon = 1; + log_to_systemlog = 1; + rpcapd_log_set(log_to_systemlog, log_debug_messages); + break; + case 'i': +#ifdef _WIN32 + printusage(); + exit(1); +#else + isrunbyinetd = 1; + log_to_systemlog = 1; + rpcapd_log_set(log_to_systemlog, log_debug_messages); +#endif + break; + case 'n': + nullAuthAllowed = 1; + break; + case 'v': + passivemode = 0; + break; + case 'l': + { + strncpy(hostlist, optarg, sizeof(hostlist)); + break; + } + case 'a': + { + char *tmpaddress, *tmpport; + char *lasts; + int i = 0; + + tmpaddress = pcap_strtok_r(optarg, RPCAP_HOSTLIST_SEP, &lasts); + + while ((tmpaddress != NULL) && (i < MAX_ACTIVE_LIST)) + { + tmpport = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts); + + pcap_strlcpy(activelist[i].address, tmpaddress, MAX_LINE); + + if ((tmpport == NULL) || (strcmp(tmpport, "DEFAULT") == 0)) // the user choose a custom port + pcap_strlcpy(activelist[i].port, RPCAP_DEFAULT_NETPORT_ACTIVE, MAX_LINE); + else + pcap_strlcpy(activelist[i].port, tmpport, MAX_LINE); + + tmpaddress = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts); + + i++; + } + + if (i > MAX_ACTIVE_LIST) + rpcapd_log(LOGPRIO_ERROR, "Only MAX_ACTIVE_LIST active connections are currently supported."); + + // I don't initialize the remaining part of the structure, since + // it is already zeroed (it is a global var) + break; + } + case 'f': + pcap_strlcpy(loadfile, optarg, MAX_LINE); + break; + case 's': + pcap_strlcpy(savefile, optarg, MAX_LINE); + break; + case 'h': + printusage(); + exit(0); + /*NOTREACHED*/ + default: + exit(1); + /*NOTREACHED*/ + } + } + +#ifndef _WIN32 + if (isdaemon && isrunbyinetd) + { + rpcapd_log(LOGPRIO_ERROR, "rpcapd: -d and -i can't be used together"); + exit(1); + } +#endif + + if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + exit(-1); + } + + if (savefile[0] && fileconf_save(savefile)) + rpcapd_log(LOGPRIO_DEBUG, "Error when saving the configuration to file"); + + // If the file does not exist, it keeps the settings provided by the command line + if (loadfile[0]) + fileconf_read(); + +#ifdef WIN32 + // + // Create a handle to signal the main loop to tell it to do + // something. + // + state_change_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (state_change_event == NULL) + { + sock_geterror("Can't create state change event", errbuf, + PCAP_ERRBUF_SIZE); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + exit(2); + } + + // + // Catch control signals. + // + if (!SetConsoleCtrlHandler(main_ctrl_event, TRUE)) + { + sock_geterror("Can't set control handler", errbuf, + PCAP_ERRBUF_SIZE); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + exit(2); + } +#else + memset(&action, 0, sizeof (action)); + action.sa_handler = main_terminate; + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + sigaction(SIGTERM, &action, NULL); + memset(&action, 0, sizeof (action)); + action.sa_handler = main_reap_children; + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + sigaction(SIGCHLD, &action, NULL); + // Ignore SIGPIPE - we'll get EPIPE when trying to write to a closed + // connection, we don't want to get killed by a signal in that case + signal(SIGPIPE, SIG_IGN); +#endif + +#ifndef _WIN32 + if (isrunbyinetd) + { + // + // -i was specified, indicating that this is being run + // by inetd or something that can run network daemons + // as if it were inetd (xinetd, launchd, systemd, etc.). + // + // We assume that the program that launched us just + // duplicated a single socket for the connection + // to our standard input, output, and error, so we + // can just use the standard input as our control + // socket. + // + int sockctrl; + int devnull_fd; + + // + // Duplicate the standard input as the control socket. + // + sockctrl = dup(0); + if (sockctrl == -1) + { + sock_geterror("Can't dup standard input", errbuf, + PCAP_ERRBUF_SIZE); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + exit(2); + } + + // + // Try to set the standard input, output, and error + // to /dev/null. + // + devnull_fd = open("/dev/null", O_RDWR); + if (devnull_fd != -1) + { + // + // If this fails, just drive on. + // + (void)dup2(devnull_fd, 0); + (void)dup2(devnull_fd, 1); + (void)dup2(devnull_fd, 2); + close(devnull_fd); + } + + // + // Handle this client. + // This is passive mode, so we don't care whether we were + // told by the client to close. + // + char *hostlist_copy = strdup(hostlist); + if (hostlist_copy == NULL) + { + rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list"); + exit(0); + } + (void)daemon_serviceloop(sockctrl, 0, hostlist_copy, + nullAuthAllowed); + + // + // Nothing more to do. + // + exit(0); + } +#endif + + if (isdaemon) + { + // + // This is being run as a daemon. + // On UN*X, it might be manually run, or run from an + // rc file. + // +#ifndef _WIN32 + int pid; + + // + // Daemonize ourselves. + // + // Unix Network Programming, pg 336 + // + if ((pid = fork()) != 0) + exit(0); // Parent terminates + + // First child continues + // Set daemon mode + setsid(); + + // generated under unix with 'kill -HUP', needed to reload the configuration + memset(&action, 0, sizeof (action)); + action.sa_handler = main_reread_config; + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + sigaction(SIGHUP, &action, NULL); + + if ((pid = fork()) != 0) + exit(0); // First child terminates + + // LINUX WARNING: the current linux implementation of pthreads requires a management thread + // to handle some hidden stuff. So, as soon as you create the first thread, two threads are + // created. Fom this point on, the number of threads active are always one more compared + // to the number you're expecting + + // Second child continues +// umask(0); +// chdir("/"); +#else + // + // This is being run as a service on Windows. + // + // If this call succeeds, it is blocking on Win32 + // + if (svc_start() != 1) + rpcapd_log(LOGPRIO_DEBUG, "Unable to start the service"); + + // When the previous call returns, the entire application has to be stopped. + exit(0); +#endif + } + else // Console mode + { +#ifndef _WIN32 + // Enable the catching of Ctrl+C + memset(&action, 0, sizeof (action)); + action.sa_handler = main_terminate; + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + sigaction(SIGINT, &action, NULL); + + // generated under unix with 'kill -HUP', needed to reload the configuration + // We do not have this kind of signal in Win32 + memset(&action, 0, sizeof (action)); + action.sa_handler = main_reread_config; + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + sigaction(SIGHUP, &action, NULL); +#endif + + printf("Press CTRL + C to stop the server...\n"); + } + + // If we're a Win32 service, we have already called this function in the service_main + main_startup(); + + // The code should never arrive here (since the main_startup is blocking) + // however this avoids a compiler warning + exit(0); +} + +void main_startup(void) +{ + char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed + struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket + int i; +#ifdef _WIN32 + HANDLE threadId; // handle for the subthread +#else + pid_t pid; +#endif + + i = 0; + addrinfo = NULL; + memset(errbuf, 0, sizeof(errbuf)); + + // Starts all the active threads + while ((i < MAX_ACTIVE_LIST) && (activelist[i].address[0] != 0)) + { + activelist[i].ai_family = mainhints.ai_family; + +#ifdef _WIN32 + threadId = (HANDLE)_beginthreadex(NULL, 0, main_active, + (void *)&activelist[i], 0, NULL); + if (threadId == 0) + { + rpcapd_log(LOGPRIO_DEBUG, "Error creating the active child threads"); + continue; + } + CloseHandle(threadId); +#else + if ((pid = fork()) == 0) // I am the child + { + main_active((void *) &activelist[i]); + exit(0); + } +#endif + i++; + } + + /* + * The code that manages the active connections is not blocking; + * the code that manages the passive connection is blocking. + * So, if the user does not want to run in passive mode, we have + * to block the main thread here, otherwise the program ends and + * all threads are stopped. + * + * WARNING: this means that in case we have only active mode, + * the program does not terminate even if all the child thread + * terminates. The user has always to press Ctrl+C (or send a + * SIGTERM) to terminate the program. + */ + if (passivemode) + { + struct addrinfo *tempaddrinfo; + + // + // Get a list of sockets on which to listen. + // + if (sock_initaddress((address[0]) ? address : NULL, port, &mainhints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) + { + rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf); + return; + } + + for (tempaddrinfo = addrinfo; tempaddrinfo; + tempaddrinfo = tempaddrinfo->ai_next) + { + SOCKET sock; + struct listen_sock *sock_info; + + if ((sock = sock_open(tempaddrinfo, SOCKOPEN_SERVER, SOCKET_MAXCONN, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) + { + switch (tempaddrinfo->ai_family) + { + case AF_INET: + { + struct sockaddr_in *in; + char addrbuf[INET_ADDRSTRLEN]; + + in = (struct sockaddr_in *)tempaddrinfo->ai_addr; + rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s", + inet_ntop(AF_INET, &in->sin_addr, + addrbuf, sizeof (addrbuf)), + ntohs(in->sin_port), + errbuf); + break; + } + + case AF_INET6: + { + struct sockaddr_in6 *in6; + char addrbuf[INET6_ADDRSTRLEN]; + + in6 = (struct sockaddr_in6 *)tempaddrinfo->ai_addr; + rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s", + inet_ntop(AF_INET6, &in6->sin6_addr, + addrbuf, sizeof (addrbuf)), + ntohs(in6->sin6_port), + errbuf); + break; + } + + default: + rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for address family %u: %s", + tempaddrinfo->ai_family, + errbuf); + break; + } + continue; + } + + sock_info = (struct listen_sock *) malloc(sizeof (struct listen_sock)); + if (sock_info == NULL) + { + rpcapd_log(LOGPRIO_ERROR, "Can't allocate structure for listen socket"); + exit(2); + } + sock_info->sock = sock; + sock_info->next = listen_socks; + listen_socks = sock_info; + } + + freeaddrinfo(addrinfo); + + if (listen_socks == NULL) + { + rpcapd_log(LOGPRIO_ERROR, "Can't listen on any address"); + exit(2); + } + + // + // Now listen on all of them, waiting for connections. + // + accept_connections(); + } + + // + // We're done; exit. + // + rpcapd_log(LOGPRIO_DEBUG, PROGRAM_NAME " is closing.\n"); + +#ifndef _WIN32 + // + // Sends a KILL signal to all the processes in this process's + // process group; i.e., it kills all the child processes + // we've created. + // + // XXX - that also includes us, so we will be killed as well; + // that may cause a message to be printed or logged. + // + kill(0, SIGKILL); +#endif + + // + // Just leave. We shouldn't need to clean up sockets or + // anything else, and if we try to do so, we'll could end + // up closing sockets, or shutting Winsock down, out from + // under service loops, causing all sorts of noisy error + // messages. + // + // We shouldn't need to worry about cleaning up any resources + // such as handles, sockets, threads, etc. - exit() should + // terminate the process, causing all those resources to be + // cleaned up (including the threads; Microsoft claims in the + // ExitProcess() documentation that, if ExitProcess() is called, + // "If a thread is waiting on a kernel object, it will not be + // terminated until the wait has completed.", but claims in the + // _beginthread()/_beginthreadex() documentation that "All threads + // are terminated if any thread calls abort, exit, _exit, or + // ExitProcess." - the latter appears to be the case, even for + // threads waiting on the event for a pcap_t). + // + exit(0); +} + +#ifdef _WIN32 +static void +send_state_change_event(void) +{ + char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed + + if (!SetEvent(state_change_event)) + { + sock_geterror("SetEvent on shutdown event failed", errbuf, + PCAP_ERRBUF_SIZE); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + } +} + +void +send_shutdown_notification(void) +{ + // + // Indicate that the server should shut down. + // + shutdown_server = 1; + + // + // Send a state change event, to wake up WSAWaitForMultipleEvents(). + // + send_state_change_event(); +} + +void +send_reread_configuration_notification(void) +{ + // + // Indicate that the server should re-read its configuration file. + // + reread_config = 1; + + // + // Send a state change event, to wake up WSAWaitForMultipleEvents(). + // + send_state_change_event(); +} + +static BOOL WINAPI main_ctrl_event(DWORD ctrltype) +{ + // + // ctrltype is one of: + // + // CTRL_C_EVENT - we got a ^C; this is like SIGINT + // CTRL_BREAK_EVENT - we got Ctrl+Break + // CTRL_CLOSE_EVENT - the console was closed; this is like SIGHUP + // CTRL_LOGOFF_EVENT - a user is logging off; this is received + // only by services + // CTRL_SHUTDOWN_EVENT - the systemis shutting down; this is + // received only by services + // + // For now, we treat all but CTRL_LOGOFF_EVENT as indications + // that we should shut down. + // + switch (ctrltype) + { + case CTRL_C_EVENT: + case CTRL_BREAK_EVENT: + case CTRL_CLOSE_EVENT: + case CTRL_SHUTDOWN_EVENT: + // + // Set a shutdown notification. + // + send_shutdown_notification(); + break; + + default: + break; + } + + // + // We handled this. + // + return TRUE; +} +#else +static void main_terminate(int sign _U_) +{ + // + // Note that the server should shut down. + // select() should get an EINTR error when we return, + // so it will wake up and know it needs to check the flag. + // + shutdown_server = 1; +} + +static void main_reread_config(int sign _U_) +{ + // + // Note that the server should re-read its configuration file. + // select() should get an EINTR error when we return, + // so it will wake up and know it needs to check the flag. + // + reread_config = 1; +} + +static void main_reap_children(int sign _U_) +{ + pid_t pid; + int exitstat; + + // Reap all child processes that have exited. + // For reference, Stevens, pg 128 + + while ((pid = waitpid(-1, &exitstat, WNOHANG)) > 0) + rpcapd_log(LOGPRIO_DEBUG, "Child terminated"); + + return; +} +#endif + +// +// Loop waiting for incoming connections and accepting them. +// +static void +accept_connections(void) +{ +#ifdef _WIN32 + struct listen_sock *sock_info; + DWORD num_events; + WSAEVENT *events; + int i; + char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed + + // + // How big does the set of events need to be? + // One for the shutdown event, plus one for every socket on which + // we'll be listening. + // + num_events = 1; // shutdown event + for (sock_info = listen_socks; sock_info; + sock_info = sock_info->next) + { + if (num_events == WSA_MAXIMUM_WAIT_EVENTS) + { + // + // WSAWaitForMultipleEvents() doesn't support + // more than WSA_MAXIMUM_WAIT_EVENTS events + // on which to wait. + // + rpcapd_log(LOGPRIO_ERROR, "Too many sockets on which to listen"); + exit(2); + } + num_events++; + } + + // + // Allocate the array of events. + // + events = (WSAEVENT *) malloc(num_events * sizeof (WSAEVENT)); + if (events == NULL) + { + rpcapd_log(LOGPRIO_ERROR, "Can't allocate array of events which to listen"); + exit(2); + } + + // + // Fill it in. + // + events[0] = state_change_event; // state change event first + for (sock_info = listen_socks, i = 1; sock_info; + sock_info = sock_info->next, i++) + { + WSAEVENT event; + + // + // Create an event that is signaled if there's a connection + // to accept on the socket in question. + // + event = WSACreateEvent(); + if (event == WSA_INVALID_EVENT) + { + sock_geterror("Can't create socket event", errbuf, + PCAP_ERRBUF_SIZE); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + exit(2); + } + if (WSAEventSelect(sock_info->sock, event, FD_ACCEPT) == SOCKET_ERROR) + { + sock_geterror("Can't setup socket event", errbuf, + PCAP_ERRBUF_SIZE); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + exit(2); + } + events[i] = event; + } + + for (;;) + { + // + // Wait for incoming connections. + // + DWORD ret; + + ret = WSAWaitForMultipleEvents(num_events, events, FALSE, + WSA_INFINITE, FALSE); + if (ret == WSA_WAIT_FAILED) + { + sock_geterror("WSAWaitForMultipleEvents failed", errbuf, + PCAP_ERRBUF_SIZE); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + exit(2); + } + + if (ret == WSA_WAIT_EVENT_0) + { + // + // The state change event was set. + // + if (shutdown_server) + { + // + // Time to quit. Exit the loop. + // + break; + } + if (reread_config) + { + // + // We should re-read the configuration + // file. + // + reread_config = 0; // clear the indicator + fileconf_read(); + } + } + + // + // Check each socket. + // + for (sock_info = listen_socks, i = 1; sock_info; + sock_info = sock_info->next, i++) + { + WSANETWORKEVENTS network_events; + + if (WSAEnumNetworkEvents(sock_info->sock, + events[i], &network_events) == SOCKET_ERROR) + { + sock_geterror("WSAEnumNetworkEvents failed", + errbuf, PCAP_ERRBUF_SIZE); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + exit(2); + } + if (network_events.lNetworkEvents & FD_ACCEPT) + { + // + // Did an error occur? + // + if (network_events.iErrorCode[FD_ACCEPT_BIT] != 0) + { + // + // Yes - report it and keep going. + // + sock_fmterror("Socket error", + network_events.iErrorCode[FD_ACCEPT_BIT], + errbuf, + PCAP_ERRBUF_SIZE); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + continue; + } + + // + // Accept the connection. + // + accept_connection(sock_info->sock); + } + } + } +#else + struct listen_sock *sock_info; + int num_sock_fds; + + // + // How big does the bitset of sockets on which to select() have + // to be? + // + num_sock_fds = 0; + for (sock_info = listen_socks; sock_info; sock_info = sock_info->next) + { + if (sock_info->sock + 1 > num_sock_fds) + { + if ((unsigned int)(sock_info->sock + 1) > + (unsigned int)FD_SETSIZE) + { + rpcapd_log(LOGPRIO_ERROR, "Socket FD is too bit for an fd_set"); + exit(2); + } + num_sock_fds = sock_info->sock + 1; + } + } + + for (;;) + { + fd_set sock_fds; + int ret; + + // + // Set up an fd_set for all the sockets on which we're + // listening. + // + // This set is modified by select(), so we have to + // construct it anew each time. + // + FD_ZERO(&sock_fds); + for (sock_info = listen_socks; sock_info; + sock_info = sock_info->next) + { + FD_SET(sock_info->sock, &sock_fds); + } + + // + // Wait for incoming connections. + // + ret = select(num_sock_fds, &sock_fds, NULL, NULL, NULL); + if (ret == -1) + { + if (errno == EINTR) + { + // + // If this is a "terminate the + // server" signal, exit the loop, + // otherwise just keep trying. + // + if (shutdown_server) + { + // + // Time to quit. Exit the loop. + // + break; + } + if (reread_config) + { + // + // We should re-read the configuration + // file. + // + reread_config = 0; // clear the indicator + fileconf_read(); + } + + // + // Go back and wait again. + // + continue; + } + else + { + rpcapd_log(LOGPRIO_ERROR, "select failed: %s", + strerror(errno)); + exit(2); + } + } + + // + // Check each socket. + // + for (sock_info = listen_socks; sock_info; + sock_info = sock_info->next) + { + if (FD_ISSET(sock_info->sock, &sock_fds)) + { + // + // Accept the connection. + // + accept_connection(sock_info->sock); + } + } + } +#endif + + // + // Close all the listen sockets. + // + for (sock_info = listen_socks; sock_info; sock_info = sock_info->next) + { + closesocket(sock_info->sock); + } + sock_cleanup(); +} + +#ifdef _WIN32 +// +// A structure to hold the parameters to the daemon service loop +// thread on Windows. +// +// (On UN*X, there is no need for this explicit copy since the +// fork "inherits" the parent stack.) +// +struct params_copy { + SOCKET sockctrl; + char *hostlist; +}; +#endif + +// +// Accept a connection and start a worker thread, on Windows, or a +// worker process, on UN*X, to handle the connection. +// +static void +accept_connection(SOCKET listen_sock) +{ + char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed + SOCKET sockctrl; // keeps the socket ID for this control connection + struct sockaddr_storage from; // generic sockaddr_storage variable + socklen_t fromlen; // keeps the length of the sockaddr_storage variable + +#ifdef _WIN32 + HANDLE threadId; // handle for the subthread + u_long off = 0; + struct params_copy *params_copy = NULL; +#else + pid_t pid; +#endif + + // Initialize errbuf + memset(errbuf, 0, sizeof(errbuf)); + + for (;;) + { + // Accept the connection + fromlen = sizeof(struct sockaddr_storage); + + sockctrl = accept(listen_sock, (struct sockaddr *) &from, &fromlen); + + if (sockctrl != INVALID_SOCKET) + { + // Success. + break; + } + + // The accept() call can return this error when a signal is catched + // In this case, we have simply to ignore this error code + // Stevens, pg 124 +#ifdef _WIN32 + if (WSAGetLastError() == WSAEINTR) +#else + if (errno == EINTR) +#endif + continue; + + // Don't check for errors here, since the error can be due to the fact that the thread + // has been killed + sock_geterror("accept()", errbuf, PCAP_ERRBUF_SIZE); + rpcapd_log(LOGPRIO_ERROR, "Accept of control connection from client failed: %s", + errbuf); + return; + } + +#ifdef _WIN32 + // + // Put the socket back into blocking mode; doing WSAEventSelect() + // on the listen socket makes that socket non-blocking, and it + // appears that sockets returned from an accept() on that socket + // are also non-blocking. + // + // First, we have to un-WSAEventSelect() this socket, and then + // we can turn non-blocking mode off. + // + // If this fails, we aren't guaranteed that, for example, any + // of the error message will be sent - if it can't be put in + // the socket queue, the send will just fail. + // + // So we just log the message and close the connection. + // + if (WSAEventSelect(sockctrl, NULL, 0) == SOCKET_ERROR) + { + sock_geterror("WSAEventSelect()", errbuf, PCAP_ERRBUF_SIZE); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + sock_close(sockctrl, NULL, 0); + return; + } + if (ioctlsocket(sockctrl, FIONBIO, &off) == SOCKET_ERROR) + { + sock_geterror("ioctlsocket(FIONBIO)", errbuf, PCAP_ERRBUF_SIZE); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + sock_close(sockctrl, NULL, 0); + return; + } + + // + // Make a copy of the host list to pass to the new thread, so that + // if we update it in the main thread, it won't catch us in the + // middle of updating it. + // + // daemon_serviceloop() will free it once it's done with it. + // + char *hostlist_copy = strdup(hostlist); + if (hostlist_copy == NULL) + { + rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list"); + sock_close(sockctrl, NULL, 0); + return; + } + + // + // Allocate a location to hold the values of sockctrl. + // It will be freed in the newly-created thread once it's + // finished with it. + // + params_copy = malloc(sizeof(*params_copy)); + if (params_copy == NULL) + { + rpcapd_log(LOGPRIO_ERROR, "Out of memory allocating the parameter copy structure"); + free(hostlist_copy); + sock_close(sockctrl, NULL, 0); + return; + } + params_copy->sockctrl = sockctrl; + params_copy->hostlist = hostlist_copy; + + threadId = (HANDLE)_beginthreadex(NULL, 0, + main_passive_serviceloop_thread, (void *) params_copy, 0, NULL); + if (threadId == 0) + { + rpcapd_log(LOGPRIO_ERROR, "Error creating the child thread"); + free(params_copy); + free(hostlist_copy); + sock_close(sockctrl, NULL, 0); + return; + } + CloseHandle(threadId); +#else /* _WIN32 */ + pid = fork(); + if (pid == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Error creating the child process: %s", + strerror(errno)); + sock_close(sockctrl, NULL, 0); + return; + } + if (pid == 0) + { + // + // Child process. + // + // Close the socket on which we're listening (must + // be open only in the parent). + // + closesocket(listen_sock); + +#if 0 + // + // Modify thread params so that it can be killed at any time + // XXX - is this necessary? This is the main and, currently, + // only thread in the child process, and nobody tries to + // cancel us, although *we* may cancel the thread that's + // handling the capture loop. + // + if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) + goto end; + if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) + goto end; +#endif + + // + // Run the service loop. + // This is passive mode, so we don't care whether we were + // told by the client to close. + // + char *hostlist_copy = strdup(hostlist); + if (hostlist_copy == NULL) + { + rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list"); + exit(0); + } + (void)daemon_serviceloop(sockctrl, 0, hostlist_copy, + nullAuthAllowed); + + exit(0); + } + + // I am the parent + // Close the socket for this session (must be open only in the child) + closesocket(sockctrl); +#endif /* _WIN32 */ +} + +/*! + \brief 'true' main of the program in case the active mode is turned on. + + This function loops forever trying to connect to the remote host, until the + daemon is turned down. + + \param ptr: it keeps the 'activepars' parameters. It is a 'void *' + just because the thread APIs want this format. +*/ +#ifdef _WIN32 +static unsigned __stdcall +#else +static void * +#endif +main_active(void *ptr) +{ + char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed + SOCKET sockctrl; // keeps the socket ID for this control connection + struct addrinfo hints; // temporary struct to keep settings needed to open the new socket + struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket + struct active_pars *activepars; + + activepars = (struct active_pars *) ptr; + + // Prepare to open a new server socket + memset(&hints, 0, sizeof(struct addrinfo)); + // WARNING Currently it supports only ONE socket family among IPv4 and IPv6 + hints.ai_family = AF_INET; // PF_UNSPEC to have both IPv4 and IPv6 server + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = activepars->ai_family; + + rpcapd_log(LOGPRIO_DEBUG, "Connecting to host %s, port %s, using protocol %s", + activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4": + (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified"); + + // Initialize errbuf + memset(errbuf, 0, sizeof(errbuf)); + + // Do the work + if (sock_initaddress(activepars->address, activepars->port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) + { + rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf); + return 0; + } + + for (;;) + { + int activeclose; + + if ((sockctrl = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) + { + rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf); + + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error connecting to host %s, port %s, using protocol %s", + activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4": + (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified"); + + rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf); + + sleep_secs(RPCAP_ACTIVE_WAIT); + + continue; + } + + char *hostlist_copy = strdup(hostlist); + if (hostlist_copy == NULL) + { + rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list"); + activeclose = 0; + sock_close(sockctrl, NULL, 0); + } + else + { + // + // daemon_serviceloop() will free the copy. + // + activeclose = daemon_serviceloop(sockctrl, 1, + hostlist_copy, nullAuthAllowed); + } + + // If the connection is closed by the user explicitely, don't try to connect to it again + // just exit the program + if (activeclose == 1) + break; + } + + freeaddrinfo(addrinfo); + return 0; +} + +#ifdef _WIN32 +// +// Main routine of a passive-mode service thread. +// +unsigned __stdcall main_passive_serviceloop_thread(void *ptr) +{ + struct params_copy params = *(struct params_copy *)ptr; + free(ptr); + + // + // Handle this client. + // This is passive mode, so we don't care whether we were + // told by the client to close. + // + (void)daemon_serviceloop(params.sockctrl, 0, params.hostlist, + nullAuthAllowed); + + return 0; +} +#endif diff --git a/rpcapd/rpcapd.h b/rpcapd/rpcapd.h new file mode 100644 index 000000000000..90ba7ffa712d --- /dev/null +++ b/rpcapd/rpcapd.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __RPCAPD_H__ +#define __RPCAPD_H__ + +#define PROGRAM_NAME "rpcapd" +#define SOCKET_MAXCONN 10 /* Maximum number of connections queued into the accept() */ +#ifdef _WIN32 +void send_shutdown_notification(void); // Send notification to shut down the daemon +void send_reread_configuration_notification(void); // Send notification to re-read the configuration file +#endif +void main_startup(void); + +#endif diff --git a/rpcapd/rpcapd.inetd.conf b/rpcapd/rpcapd.inetd.conf new file mode 100644 index 000000000000..86823f043ab5 --- /dev/null +++ b/rpcapd/rpcapd.inetd.conf @@ -0,0 +1 @@ +2002 stream tcp nowait root /usr/local/sbin/rpcapd rpcapd -i diff --git a/rpcapd/rpcapd.manadmin.in b/rpcapd/rpcapd.manadmin.in new file mode 100644 index 000000000000..0a9d4e031a3c --- /dev/null +++ b/rpcapd/rpcapd.manadmin.in @@ -0,0 +1,233 @@ +.\" rpcapd.8 +.\" +.\" Copyright (c) 2002-2005 NetGroup, Politecnico di Torino (Italy) +.\" Copyright (c) 2005-2009 CACE Technologies +.\" Copyright (c) 2018- The TCPdump Group +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the Politecnico di Torino nor the names of its +.\" contributors may be used to endorse or promote products derived from +.\" this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.TH RPCAPD @MAN_ADMIN_COMMANDS@ "April 20, 2018" +.SH NAME +rpcapd \- capture daemon to be controlled by a remote libpcap application +.SH SYNOPSIS +.na +rpcapd +[ +.B \-b +.I address +] [ +.B \-p +.I port +] [ +.B \-4 +] [ +.B \-l +.I host_list +] +.br +.ti +8 +[ +.B \-a +.IR host , port +] [ +.B \-n +] [ +.B \-v +] [ +.B \-d +] [ +.B \-i +] +.br +.ti +8 +[ +.B \-D +] [ +.B \-s +.I config_file +] [ +.B \-f +.I config_file +] +.br +.ad +.SH DESCRIPTION +.LP +\fIRpcapd\fP is a daemon (Unix) or service (Win32) that allows the capture +and filter part of libpcap to be run on a remote system. +.LP +Rpcapd can run in two modes: passive mode (default) and active mode. +.LP +In passive mode, the client (e.g., a network sniffer) connects to +.BR rpcapd . +It then sends hem the appropriate commands to start the capture. +.LP +In active mode, +.B rpcapd +tries to establish a connection toward the client +(e.g., a network sniffer). The client then sends the appropriate commands +to rpcapd to start the capture. +.LP +Active mode is useful in case +.B rpcapd +is run behind a firewall and +cannot receive connections from the external world. In this case, +.B rpcapd +can be configured to establish the connection to a given host, +which has to be configured in order to wait for that connection. After +establishing the connection, the protocol continues its job in almost +the same way in both active and passive mode. +.SH Configuration file +.LP +The user can create a configuration file in the same folder of the +executable, and put the configuration commands in there. In order for +rpcapd to execute the commands, you have to restart it on Win32, i.e. +the initialization file is parsed only at the beginning). The UNIX +version of rpcapd will reread the configuration file when receiving a +HUP signel. In that case, all the existing connections remain in place, +while the new connections will be created according to the new parameters. +.LP +In case a user does not want to create the configuration file manually, +they can launch rpcapd with the requested parameters plus "-s filename". +Rpcapd will parse all the parameters and save them into the specified +configuration file. +.SH Installing rpcapd on Win32 +.LP +The remote daemon is installed automatically when installing WinPcap. +The installation process places the rpcapd file into the WinPcap folder. +This file can be executed either from the command line, or as a service. +For instance, the installation process updates the list of available +services list and it creates a new item (Remote Packet Capture Protocol +v.0 (experimental) ). To avoid security problems, the service is +inactive and it has to be started manually (control panel - +administrative tools - services - start). +.LP +The service has a set of "standard" parameters, i.e. it is launched +with the +.B \-d +flag (in order to make it run as a service) and the +.B "-f rpcapd.ini" +flag. +.SH Starting rpcapd on Win32 +.LP +The rpcapd executable can be launched directly, i.e. it can run in the +foreground as well (not as a daemon/service). The procedure is quite +simple: you have to invoke the executable from the command line with all +the requested parameters except for the +.B \-d +flag. The capture server will +start in the foreground. +.SH Installing rpcapd on Unix-like systems +TBD +.SH Starting rpcapd on Unix-like systems +.B rpcapd +needs sufficient privileges to perform packet capture, e.g. +run as root or be owned by root and have suid set. Most operating +systems provide more elegant solutions when run as user than the +above solutions, all of them different. +.SH OPTIONS +.TP +.BI \-b " address" +Bind to the IP address specified by +.I address +(either numeric or literal). +By default, +.B rpcapd +binds to all local IPv4 and IPv6 addresses. +.TP +.BI \-p " port" +Bind to the port specified by +.IR port . +By default, +.B rpcapd +binds to port 2002. +.TP +.B \-4 +Listen only on IPv4 addresses. +By default, +.B rpcapd +listens on both IPv4 and IPv6 addresses. +.TP +.BI -l " host_list" +Only allow hosts specified in the +.I host_list +argument to connect to this server. +.I host_list +is a list of host names or IP addresses, separated by commas. +We suggest that you use use host names rather than literal IP addresses +in order to avoid problems with different address families. +.TP +.B \-n +Permit NULL authentication (usually used with +.BR \-l ). +.TP +.BI \-a " host" , "port" +Run in active mode, connecting to host +.I host +on port +.IR port . +In case +.I port +is omitted, the default port (2003) is used. +.TP +.B -v +Run in active mode only; by default, if +.B \-a +is specified, +.B rpcapd +it accepts passive connections as well. +.TP +.B \-d +Run in daemon mode (UNIX only) or as a service (Win32 only) +Warning (Win32): this switch is provided automatically when +the service is started from the control panel. +.TP +.B \-i +Run in inetd mode (UNIX only). +.TP +.B \-D +Log debugging messages. +.TP +.BI \-s " config_file" +Save the current configuration to +.I config_file +in the format specified by +.BR rpcapd-config (@MAN_FILE_FORMATS@). +.TP +.BI \-f " config_file" +Load the current configuration from +.I config_file +in the format specified by +.BR rpcapd-config (@MAN_FILE_FORMATS@); +all switches specified from the command line are ignored. +.TP +.B \-h +Print this help screen. +.br +.ad +.SH "SEE ALSO" +pcap(3PCAP), rpcapd-config(@MAN_FILE_FORMATS@) diff --git a/rpcapd/rpcapd.rc b/rpcapd/rpcapd.rc new file mode 100644 index 000000000000..695c00b6f24c --- /dev/null +++ b/rpcapd/rpcapd.rc @@ -0,0 +1,39 @@ +#include "config.h" +#undef PACKAGE_NAME +#include +#include +#define PACKAGE_NAME PROGRAM_NAME + + VS_VERSION_INFO VERSIONINFO + FILEVERSION PACKAGE_VERSION_DLL + PRODUCTVERSION PACKAGE_VERSION_DLL + FILEFLAGSMASK 0x3fL + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "https://github.com/the-tcpdump-group/libpcap/" + VALUE "CompanyName", "The TCPdump Group" + VALUE "FileDescription", "Remote Packet Capture Daemon" + VALUE "FileVersion", "PACKAGE_VERSION_DLL" + VALUE "InternalName", PACKAGE_NAME + VALUE "LegalCopyright", "Copyright (c) The TCPdump Group" + VALUE "LegalTrademarks", "" + VALUE "OriginalFilename", "rpcapd.exe" + VALUE "ProductName", PACKAGE_NAME + VALUE "ProductVersion", PACKAGE_VERSION + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END + END diff --git a/rpcapd/rpcapd.socket b/rpcapd/rpcapd.socket new file mode 100644 index 000000000000..9d5a0bda71a1 --- /dev/null +++ b/rpcapd/rpcapd.socket @@ -0,0 +1,9 @@ +[Unit] +Description=Rpcap Socket for Per-Connection Servers + +[Socket] +ListenStream=2002 +Accept=yes + +[Install] +WantedBy=sockets.target diff --git a/rpcapd/rpcapd.xinetd.conf b/rpcapd/rpcapd.xinetd.conf new file mode 100644 index 000000000000..2c79348e79f1 --- /dev/null +++ b/rpcapd/rpcapd.xinetd.conf @@ -0,0 +1,8 @@ +service rpcap { + socket_type = stream + protocol = tcp + wait = no + user = root + server = /usr/local/sbin/rpcapd + server_args = -i +} diff --git a/rpcapd/rpcapd@.service b/rpcapd/rpcapd@.service new file mode 100644 index 000000000000..92d11719b106 --- /dev/null +++ b/rpcapd/rpcapd@.service @@ -0,0 +1,6 @@ +[Unit] +Description=Rpcap Per-Connection Server + +[Service] +ExecStart=-/usr/local/sbin/rpcapd -i +StandardInput=socket diff --git a/rpcapd/win32-svc.c b/rpcapd/win32-svc.c new file mode 100644 index 000000000000..3a19910d77ab --- /dev/null +++ b/rpcapd/win32-svc.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include "rpcapd.h" +#include // for PCAP_ERRBUF_SIZE +#include "fmtutils.h" +#include "portability.h" +#include "fileconf.h" +#include "log.h" + +static SERVICE_STATUS_HANDLE service_status_handle; +static SERVICE_STATUS service_status; + +static void WINAPI svc_main(DWORD argc, char **argv); +static void update_svc_status(DWORD state, DWORD progress_indicator); + +int svc_start(void) +{ + int rc; + SERVICE_TABLE_ENTRY ste[] = + { + { PROGRAM_NAME, svc_main }, + { NULL, NULL } + }; + char string[PCAP_ERRBUF_SIZE]; + + // This call is blocking. A new thread is created which will launch + // the svc_main() function + if ((rc = StartServiceCtrlDispatcher(ste)) == 0) { + pcap_fmt_errmsg_for_win32_err(string, sizeof (string), + GetLastError(), "StartServiceCtrlDispatcher() failed"); + rpcapd_log(LOGPRIO_ERROR, "%s", string); + } + + return rc; // FALSE if this is not started as a service +} + +void WINAPI svc_control_handler(DWORD Opcode) +{ + switch(Opcode) + { + case SERVICE_CONTROL_STOP: + // + // XXX - is this sufficient to clean up the service? + // To be really honest, only the main socket and + // such these stuffs are cleared; however the threads + // that are running are not stopped. + // This can be seen by placing a breakpoint at the + // end of svc_main(), in which you will see that is + // never reached. However, as soon as you set the + // service status to "stopped", the + // StartServiceCtrlDispatcher() returns and the main + // thread ends. Then, Win32 has a good automatic + // cleanup, so that all the threads which are still + // running are stopped when the main thread ends. + // + send_shutdown_notification(); + + update_svc_status(SERVICE_STOP_PENDING, 0); + break; + + /* + Pause and Continue have an usual meaning and they are used just to be able + to change the running parameters at run-time. In other words, they act + like the SIGHUP signal on UNIX. All the running threads continue to run and + they are not paused at all. + Particularly, + - PAUSE does nothing + - CONTINUE re-reads the configuration file and creates the new threads that + can be needed according to the new configuration. + */ + case SERVICE_CONTROL_PAUSE: + update_svc_status(SERVICE_PAUSED, 0); + break; + + case SERVICE_CONTROL_CONTINUE: + update_svc_status(SERVICE_RUNNING, 0); + // + // Tell the main loop to re-read the configuration. + // + send_reread_configuration_notification(); + break; + + case SERVICE_CONTROL_INTERROGATE: + // Fall through to send current status. + // WARNING: not implemented + update_svc_status(SERVICE_RUNNING, 0); + MessageBox(NULL, "Not implemented", "warning", MB_OK); + break; + + case SERVICE_CONTROL_PARAMCHANGE: + // + // Tell the main loop to re-read the configuration. + // + send_reread_configuration_notification(); + break; + } + + // Send current status. + return; +} + +void WINAPI svc_main(DWORD argc, char **argv) +{ + service_status_handle = RegisterServiceCtrlHandler(PROGRAM_NAME, svc_control_handler); + + if (!service_status_handle) + return; + + service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS; + service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_PARAMCHANGE; + // | SERVICE_ACCEPT_SHUTDOWN ; + update_svc_status(SERVICE_RUNNING, 0); + + // + // Service requests until we're told to stop. + // + main_startup(); + + // + // It returned, so we were told to stop. + // + update_svc_status(SERVICE_STOPPED, 0); +} + +static void +update_svc_status(DWORD state, DWORD progress_indicator) +{ + service_status.dwWin32ExitCode = NO_ERROR; + service_status.dwCurrentState = state; + service_status.dwCheckPoint = progress_indicator; + service_status.dwWaitHint = 0; + SetServiceStatus(service_status_handle, &service_status); +} + +/* +sc create rpcapd DisplayName= "Remote Packet Capture Protocol v.0 (experimental)" binpath= "C:\cvsroot\winpcap\wpcap\PRJ\Debug\rpcapd -d -f rpcapd.ini" +sc description rpcapd "Allows to capture traffic on this host from a remote machine." +*/ diff --git a/rpcapd/win32-svc.h b/rpcapd/win32-svc.h new file mode 100644 index 000000000000..3f511d2c5587 --- /dev/null +++ b/rpcapd/win32-svc.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +int svc_start(void); diff --git a/savefile.c b/savefile.c index ec44ef4fe056..5b1e14cf3c62 100644 --- a/savefile.c +++ b/savefile.c @@ -43,6 +43,7 @@ #include #include #include +#include /* for INT_MAX */ #include "pcap-int.h" @@ -52,12 +53,13 @@ #include "sf-pcap.h" #include "sf-pcapng.h" +#include "pcap-common.h" #ifdef _WIN32 /* * These aren't exported on Windows, because they would only work if both - * WinPcap and the code using it were to use the Universal CRT; otherwise, - * a FILE structure in WinPcap and a FILE structure in the code using it + * WinPcap/Npcap and the code using it were to use the Universal CRT; otherwise, + * a FILE structure in WinPcap/Npcap and a FILE structure in the code using it * could be different if they're using different versions of the C runtime. * * Instead, pcap/pcap.h defines them as macros that wrap the hopen versions, @@ -179,7 +181,7 @@ sf_oid_set_request(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_, static u_int sf_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue, int sync) { - strlcpy(p->errbuf, "Sending packets isn't supported on savefiles", + pcap_strlcpy(p->errbuf, "Sending packets isn't supported on savefiles", PCAP_ERRBUF_SIZE); return (0); } @@ -218,7 +220,7 @@ sf_get_airpcap_handle(pcap_t *pcap) static int sf_inject(pcap_t *p, const void *buf _U_, size_t size _U_) { - strlcpy(p->errbuf, "Sending packets isn't supported on savefiles", + pcap_strlcpy(p->errbuf, "Sending packets isn't supported on savefiles", PCAP_ERRBUF_SIZE); return (-1); } @@ -317,6 +319,7 @@ pcap_t* pcap_hopen_offline_with_tstamp_precision(intptr_t osfd, u_int precision, { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "_fdopen"); + _close(fd); return NULL; } @@ -331,7 +334,34 @@ pcap_t* pcap_hopen_offline(intptr_t osfd, char *errbuf) } #endif -static pcap_t *(*check_headers[])(bpf_u_int32, FILE *, u_int, char *, int *) = { +/* + * Given a link-layer header type and snapshot length, return a + * snapshot length to use when reading the file; it's guaranteed + * to be > 0 and <= INT_MAX. + * + * XXX - the only reason why we limit it to <= INT_MAX is so that + * it fits in p->snapshot, and the only reason that p->snapshot is + * signed is that pcap_snapshot() returns an int, not an unsigned int. + */ +bpf_u_int32 +pcap_adjust_snapshot(bpf_u_int32 linktype, bpf_u_int32 snaplen) +{ + if (snaplen == 0 || snaplen > INT_MAX) { + /* + * Bogus snapshot length; use the maximum for this + * link-layer type as a fallback. + * + * XXX - we don't clamp snapshot lengths that are + * <= INT_MAX but > max_snaplen_for_dlt(linktype), + * so a capture file could cause us to allocate + * a Really Big Buffer. + */ + snaplen = max_snaplen_for_dlt(linktype); + } + return snaplen; +} + +static pcap_t *(*check_headers[])(const uint8_t *, FILE *, u_int, char *, int *) = { pcap_check_header, pcap_ng_check_header }; @@ -346,7 +376,7 @@ pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision, char *errbuf) { register pcap_t *p; - bpf_u_int32 magic; + uint8_t magic[4]; size_t amt_read; u_int i; int err; @@ -358,16 +388,15 @@ pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision, * Windows Sniffer, and Microsoft Network Monitor) all have magic * numbers that are unique in their first 4 bytes. */ - amt_read = fread((char *)&magic, 1, sizeof(magic), fp); + amt_read = fread(&magic, 1, sizeof(magic), fp); if (amt_read != sizeof(magic)) { if (ferror(fp)) { pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, "error reading dump file"); } else { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "truncated dump file; tried to read %lu file header bytes, only got %lu", - (unsigned long)sizeof(magic), - (unsigned long)amt_read); + "truncated dump file; tried to read %" PRIsize " file header bytes, only got %" PRIsize, + sizeof(magic), amt_read); } return (NULL); } diff --git a/scanner.l b/scanner.l index e0890b43b1b9..effcf815d65e 100644 --- a/scanner.l +++ b/scanner.l @@ -311,13 +311,7 @@ mask return NETMASK; port return PORT; portrange return PORTRANGE; proto return PROTO; -protochain { -#ifdef NO_PROTOCHAIN - bpf_error(yyextra, "%s not supported", yytext); -#else - return PROTOCHAIN; -#endif - } +protochain return PROTOCHAIN; gateway return GATEWAY; @@ -397,14 +391,8 @@ hsls return HSLS; "==" return '='; "<<" return LSH; ">>" return RSH; -${B} { yylval->e = pcap_ether_aton(((char *)yytext)+1); - if (yylval->e == NULL) - bpf_error(yyextra, "malloc"); - return AID; } -{MAC} { yylval->e = pcap_ether_aton((char *)yytext); - if (yylval->e == NULL) - bpf_error(yyextra, "malloc"); - return EID; } +${B} { yylval->s = sdup(yyextra, yytext); return AID; } +{MAC} { yylval->s = sdup(yyextra, yytext); return EID; } {N} { yylval->i = stoi((char *)yytext); return NUM; } ({N}\.{N})|({N}\.{N}\.{N})|({N}\.{N}\.{N}\.{N}) { yylval->s = sdup(yyextra, (char *)yytext); return HID; } @@ -414,17 +402,20 @@ ${B} { yylval->e = pcap_ether_aton(((char *)yytext)+1); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; hints.ai_flags = AI_NUMERICHOST; - if (getaddrinfo(yytext, NULL, &hints, &res)) - bpf_error(yyextra, "bogus IPv6 address %s", yytext); - else { + if (getaddrinfo(yytext, NULL, &hints, &res)) { + bpf_set_error(yyextra, "bogus IPv6 address %s", yytext); + yylval->s = NULL; + } else { freeaddrinfo(res); - yylval->s = sdup(yyextra, (char *)yytext); return HID6; + yylval->s = sdup(yyextra, (char *)yytext); } #else - bpf_error(yyextra, "IPv6 address %s not supported", yytext); + bpf_set_error(yyextra, "IPv6 address %s not supported", yytext); + yylval->s = NULL; #endif /*INET6*/ + return HID6; } -{B}:+({B}:+)+ { bpf_error(yyextra, "bogus ethernet address %s", yytext); } +{B}:+({B}:+)+ { bpf_set_error(yyextra, "bogus ethernet address %s", yytext); yylval->s = NULL; return EID; } icmptype { yylval->i = 0; return NUM; } icmpcode { yylval->i = 1; return NUM; } icmp-echoreply { yylval->i = 0; return NUM; } @@ -484,9 +475,7 @@ tcp-cwr { yylval->i = 0x80; return NUM; } [A-Za-z0-9]([-_.A-Za-z0-9]*[.A-Za-z0-9])? { yylval->s = sdup(yyextra, (char *)yytext); return ID; } "\\"[^ !()\n\t]+ { yylval->s = sdup(yyextra, (char *)yytext + 1); return ID; } -[^ \[\]\t\n\-_.A-Za-z0-9!<>()&|=]+ { - bpf_error(yyextra, "illegal token: %s", yytext); } -. { bpf_error(yyextra, "illegal char '%c'", *yytext); } +. { return LEX_ERROR; } %% /* diff --git a/sf-pcap.c b/sf-pcap.c index 96cb30801fc3..60c73a899c27 100644 --- a/sf-pcap.c +++ b/sf-pcap.c @@ -43,6 +43,7 @@ #include #include #include +#include /* for INT_MAX */ #include "pcap-int.h" @@ -109,6 +110,20 @@ static int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **datap); +#ifdef _WIN32 +/* + * This isn't exported on Windows, because it would only work if both + * libpcap and the code using it were using the same C runtime; otherwise they + * would be using different definitions of a FILE structure. + * + * Instead we define this as a macro in pcap/pcap.h that wraps the hopen + * version that we do export, passing it a raw OS HANDLE, as defined by the + * Win32 / Win64 ABI, obtained from the _fileno() and _get_osfhandle() + * functions of the appropriate CRT. + */ +static pcap_dumper_t *pcap_dump_fopen(pcap_t *p, FILE *f); +#endif /* _WIN32 */ + /* * Private data for reading pcap savefiles. */ @@ -135,9 +150,10 @@ struct pcap_sf { * relevant information from the header. */ pcap_t * -pcap_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, +pcap_check_header(const uint8_t *magic, FILE *fp, u_int precision, char *errbuf, int *err) { + bpf_u_int32 magic_int; struct pcap_file_header hdr; size_t amt_read; pcap_t *p; @@ -154,11 +170,14 @@ pcap_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, * number for a pcap savefile, or for a byte-swapped pcap * savefile. */ - if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC && - magic != NSEC_TCPDUMP_MAGIC) { - magic = SWAPLONG(magic); - if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC && - magic != NSEC_TCPDUMP_MAGIC) + memcpy(&magic_int, magic, sizeof(magic_int)); + if (magic_int != TCPDUMP_MAGIC && + magic_int != KUZNETZOV_TCPDUMP_MAGIC && + magic_int != NSEC_TCPDUMP_MAGIC) { + magic_int = SWAPLONG(magic_int); + if (magic_int != TCPDUMP_MAGIC && + magic_int != KUZNETZOV_TCPDUMP_MAGIC && + magic_int != NSEC_TCPDUMP_MAGIC) return (NULL); /* nope */ swapped = 1; } @@ -167,7 +186,7 @@ pcap_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, * They are. Put the magic number in the header, and read * the rest of the header. */ - hdr.magic = magic; + hdr.magic = magic_int; amt_read = fread(((char *)&hdr) + sizeof hdr.magic, 1, sizeof(hdr) - sizeof(hdr.magic), fp); if (amt_read != sizeof(hdr) - sizeof(hdr.magic)) { @@ -176,9 +195,8 @@ pcap_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, errno, "error reading dump file"); } else { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "truncated dump file; tried to read %lu file header bytes, only got %lu", - (unsigned long)sizeof(hdr), - (unsigned long)amt_read); + "truncated dump file; tried to read %" PRIsize " file header bytes, only got %" PRIsize, + sizeof(hdr), amt_read); } *err = 1; return (NULL); @@ -232,20 +250,9 @@ pcap_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, p->version_major = hdr.version_major; p->version_minor = hdr.version_minor; p->tzoff = hdr.thiszone; - p->snapshot = hdr.snaplen; - if (p->snapshot <= 0) { - /* - * Bogus snapshot length; use the maximum for this - * link-layer type as a fallback. - * - * XXX - the only reason why snapshot is signed is - * that pcap_snapshot() returns an int, not an - * unsigned int. - */ - p->snapshot = max_snaplen_for_dlt(hdr.linktype); - } p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype)); p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype); + p->snapshot = pcap_adjust_snapshot(p->linktype, hdr.snaplen); p->next_packet_op = pcap_next_packet; @@ -260,7 +267,7 @@ pcap_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, switch (precision) { case PCAP_TSTAMP_PRECISION_MICRO: - if (magic == NSEC_TCPDUMP_MAGIC) { + if (magic_int == NSEC_TCPDUMP_MAGIC) { /* * The file has nanoseconds, the user * wants microseconds; scale the @@ -277,7 +284,7 @@ pcap_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, break; case PCAP_TSTAMP_PRECISION_NANO: - if (magic == NSEC_TCPDUMP_MAGIC) { + if (magic_int == NSEC_TCPDUMP_MAGIC) { /* * The file has nanoseconds, the * user wants nanoseconds; nothing to do. @@ -331,7 +338,7 @@ pcap_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, break; } - if (magic == KUZNETZOV_TCPDUMP_MAGIC) { + if (magic_int == KUZNETZOV_TCPDUMP_MAGIC) { /* * XXX - the patch that's in some versions of libpcap * changes the packet header but not the magic number, @@ -371,8 +378,14 @@ pcap_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, * length will be misleading if you use it to figure * out why a capture doesn't have all the packet data, * but there's not much we can do to avoid that. + * + * But don't grow the snapshot length past the + * maximum value of an int. */ - p->snapshot += 14; + if (p->snapshot <= INT_MAX - 14) + p->snapshot += 14; + else + p->snapshot = INT_MAX; } } else ps->hdrsize = sizeof(struct pcap_sf_pkthdr); @@ -450,9 +463,8 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) } else { if (amt_read != 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "truncated dump file; tried to read %lu header bytes, only got %lu", - (unsigned long)ps->hdrsize, - (unsigned long)amt_read); + "truncated dump file; tried to read %" PRIsize " header bytes, only got %" PRIsize, + ps->hdrsize, amt_read); return (-1); } /* EOF */ @@ -611,8 +623,8 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) * the read finished. */ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "truncated dump file; tried to read %u captured bytes, only got %lu", - p->snapshot, (unsigned long)amt_read); + "truncated dump file; tried to read %u captured bytes, only got %" PRIsize, + p->snapshot, amt_read); } return (-1); } @@ -635,8 +647,8 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) "error reading dump file"); } else { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "truncated dump file; tried to read %u captured bytes, only got %lu", - hdr->caplen, (unsigned long)bytes_read); + "truncated dump file; tried to read %u captured bytes, only got %" PRIsize, + hdr->caplen, bytes_read); } return (-1); } @@ -649,6 +661,9 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) */ hdr->caplen = p->snapshot; } else { + /* + * The packet is within the snapshot length for this file. + */ if (hdr->caplen > p->bufsize) { /* * Grow the buffer to the next power of 2, or @@ -684,8 +699,8 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) "error reading dump file"); } else { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "truncated dump file; tried to read %u captured bytes, only got %lu", - hdr->caplen, (unsigned long)amt_read); + "truncated dump file; tried to read %u captured bytes, only got %" PRIsize, + hdr->caplen, amt_read); } return (-1); } @@ -817,9 +832,42 @@ pcap_dump_open(pcap_t *p, const char *fname) return (pcap_setup_dump(p, linktype, f, fname)); } +#ifdef _WIN32 +/* + * Initialize so that sf_write() will output to a stream wrapping the given raw + * OS file HANDLE. + */ +pcap_dumper_t * +pcap_dump_hopen(pcap_t *p, intptr_t osfd) +{ + int fd; + FILE *file; + + fd = _open_osfhandle(osfd, _O_APPEND); + if (fd < 0) { + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "_open_osfhandle"); + return NULL; + } + + file = _fdopen(fd, "wb"); + if (file == NULL) { + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "_fdopen"); + _close(fd); + return NULL; + } + + return pcap_dump_fopen(p, file); +} +#endif /* _WIN32 */ + /* * Initialize so that sf_write() will output to the given stream. */ +#ifdef _WIN32 +static +#endif /* _WIN32 */ pcap_dumper_t * pcap_dump_fopen(pcap_t *p, FILE *f) { @@ -862,11 +910,19 @@ pcap_dump_open_append(pcap_t *p, const char *fname) return (pcap_setup_dump(p, linktype, stdout, "standard output")); /* + * "a" will cause the file *not* to be truncated if it exists + * but will cause it to be created if it doesn't. It will + * also cause all writes to be done at the end of the file, + * but will allow reads to be done anywhere in the file. This + * is what we need, because we need to read from the beginning + * of the file to see if it already has a header and packets + * or if it doesn't. + * * "b" is supported as of C90, so *all* UN*Xes should support it, * even though it does nothing. It's required on Windows, as the * file is a binary file and must be read in binary mode. */ - f = fopen(fname, "rb+"); + f = fopen(fname, "ab+"); if (f == NULL) { pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "%s", fname); @@ -875,18 +931,33 @@ pcap_dump_open_append(pcap_t *p, const char *fname) /* * Try to read a pcap header. + * + * We do not assume that the file will be positioned at the + * beginning immediately after we've opened it - we seek to + * the beginning. ISO C says it's implementation-defined + * whether the file position indicator is at the beginning + * or the end of the file after an append-mode open, and + * it wasn't obvious from the Single UNIX Specification + * or the Microsoft documentation how that works on SUS- + * compliant systems or on Windows. */ + if (fseek(f, 0, SEEK_SET) == -1) { + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't seek to the beginning of %s", fname); + (void)fclose(f); + return (NULL); + } amt_read = fread(&ph, 1, sizeof (ph), f); if (amt_read != sizeof (ph)) { if (ferror(f)) { pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "%s", fname); - fclose(f); + (void)fclose(f); return (NULL); } else if (feof(f) && amt_read > 0) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: truncated pcap file header", fname); - fclose(f); + (void)fclose(f); return (NULL); } } @@ -922,7 +993,7 @@ pcap_dump_open_append(pcap_t *p, const char *fname) if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_MICRO) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: different time stamp precision, cannot append to file", fname); - fclose(f); + (void)fclose(f); return (NULL); } break; @@ -931,7 +1002,7 @@ pcap_dump_open_append(pcap_t *p, const char *fname) if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_NANO) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: different time stamp precision, cannot append to file", fname); - fclose(f); + (void)fclose(f); return (NULL); } break; @@ -940,7 +1011,7 @@ pcap_dump_open_append(pcap_t *p, const char *fname) case SWAPLONG(NSEC_TCPDUMP_MAGIC): pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: different byte order, cannot append to file", fname); - fclose(f); + (void)fclose(f); return (NULL); case KUZNETZOV_TCPDUMP_MAGIC: @@ -949,13 +1020,13 @@ pcap_dump_open_append(pcap_t *p, const char *fname) case SWAPLONG(NAVTEL_TCPDUMP_MAGIC): pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: not a pcap file to which we can append", fname); - fclose(f); + (void)fclose(f); return (NULL); default: pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: not a pcap file", fname); - fclose(f); + (void)fclose(f); return (NULL); } @@ -967,19 +1038,19 @@ pcap_dump_open_append(pcap_t *p, const char *fname) pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: version is %u.%u, cannot append to file", fname, ph.version_major, ph.version_minor); - fclose(f); + (void)fclose(f); return (NULL); } if ((bpf_u_int32)linktype != ph.linktype) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: different linktype, cannot append to file", fname); - fclose(f); + (void)fclose(f); return (NULL); } if ((bpf_u_int32)p->snapshot != ph.snaplen) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: different snaplen, cannot append to file", fname); - fclose(f); + (void)fclose(f); return (NULL); } } else { @@ -996,10 +1067,14 @@ pcap_dump_open_append(pcap_t *p, const char *fname) /* * Start writing at the end of the file. + * + * XXX - this shouldn't be necessary, given that we're opening + * the file in append mode, and ISO C specifies that all writes + * are done at the end of the file in that mode. */ if (fseek(f, 0, SEEK_END) == -1) { pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, - errno, "Can't seek to end of %s", fname); + errno, "Can't seek to the end of %s", fname); (void)fclose(f); return (NULL); } diff --git a/sf-pcap.h b/sf-pcap.h index e9c7eafa655d..bc7150f4f4fc 100644 --- a/sf-pcap.h +++ b/sf-pcap.h @@ -31,7 +31,7 @@ #ifndef sf_pcap_h #define sf_pcap_h -extern pcap_t *pcap_check_header(bpf_u_int32 magic, FILE *fp, +extern pcap_t *pcap_check_header(const uint8_t *magic, FILE *fp, u_int precision, char *errbuf, int *err); #endif diff --git a/sf-pcapng.c b/sf-pcapng.c index 0f155afa9788..afaeb0566571 100644 --- a/sf-pcapng.c +++ b/sf-pcapng.c @@ -85,7 +85,7 @@ struct option_header { * Section Header Block. */ #define BT_SHB 0x0A0D0D0A - +#define BT_SHB_INSANE_MAX 1024U*1024U*1U /* 1MB should be enough */ struct section_header_block { bpf_u_int32 byte_order_magic; u_short major_version; @@ -197,9 +197,9 @@ typedef enum { * Per-interface information. */ struct pcap_ng_if { - u_int tsresol; /* time stamp resolution */ + uint64_t tsresol; /* time stamp resolution */ tstamp_scale_type_t scale_type; /* how to scale */ - u_int scale_factor; /* time stamp scale factor for power-of-10 tsresol */ + uint64_t scale_factor; /* time stamp scale factor for power-of-10 tsresol */ uint64_t tsoffset; /* time stamp offset */ }; @@ -223,7 +223,7 @@ struct pcap_ng_if { * so we impose a limit regardless of the size of a pointer. */ struct pcap_ng_sf { - u_int user_tsresol; /* time stamp resolution requested by the user */ + uint64_t user_tsresol; /* time stamp resolution requested by the user */ u_int max_blocksize; /* don't grow buffer size past this */ bpf_u_int32 ifcount; /* number of interfaces seen in this capture */ bpf_u_int32 ifaces_size; /* size of array below */ @@ -231,16 +231,21 @@ struct pcap_ng_sf { }; /* - * Maximum block size for a given maximum snapshot length; we calculate - * this based - * - * We define it as the size of an EPB with a max_snaplen-sized - * packet and 128KB of options. + * The maximum block size we start with; we use an arbitrary value of + * 16 MiB. */ -#define MAX_BLOCKSIZE(max_snaplen) (sizeof (struct block_header) + \ - sizeof (struct enhanced_packet_block) + \ - (max_snaplen) + 131072 + \ - sizeof (struct block_trailer)) +#define INITIAL_MAX_BLOCKSIZE (16*1024*1024) + +/* + * Maximum block size for a given maximum snapshot length; we define it + * as the size of an EPB with a max_snaplen-sized packet and 128KB of + * options. + */ +#define MAX_BLOCKSIZE_FOR_SNAPLEN(max_snaplen) \ + (sizeof (struct block_header) + \ + sizeof (struct enhanced_packet_block) + \ + (max_snaplen) + 131072 + \ + sizeof (struct block_trailer)) static void pcap_ng_cleanup(pcap_t *p); static int pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, @@ -261,9 +266,8 @@ read_bytes(FILE *fp, void *buf, size_t bytes_to_read, int fail_on_eof, if (amt_read == 0 && !fail_on_eof) return (0); /* EOF */ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "truncated dump file; tried to read %lu bytes, only got %lu", - (unsigned long)bytes_to_read, - (unsigned long)amt_read); + "truncated pcapng dump file; tried to read %" PRIsize " bytes, only got %" PRIsize, + bytes_to_read, amt_read); } return (-1); } @@ -276,6 +280,7 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf) struct pcap_ng_sf *ps; int status; struct block_header bhdr; + struct block_trailer *btrlr; u_char *bdata; size_t data_remaining; @@ -290,20 +295,6 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf) bhdr.total_length = SWAPLONG(bhdr.total_length); } - /* - * Is this block "too big"? - * - * We choose 16MB as "too big", for now, so that we handle - * "reasonably" large buffers but don't chew up all the - * memory if we read a malformed file. - */ - if (bhdr.total_length > 16*1024*1024) { - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "pcapng block size %u > maximum %u", - bhdr.total_length, 16*1024*1024); - return (-1); - } - /* * Is this block "too small" - i.e., is it shorter than a block * header plus a block trailer? @@ -311,9 +302,22 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf) if (bhdr.total_length < sizeof(struct block_header) + sizeof(struct block_trailer)) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "block in pcapng dump file has a length of %u < %lu", + "block in pcapng dump file has a length of %u < %" PRIsize, bhdr.total_length, - (unsigned long)(sizeof(struct block_header) + sizeof(struct block_trailer))); + sizeof(struct block_header) + sizeof(struct block_trailer)); + return (-1); + } + + /* + * Is the block total length a multiple of 4? + */ + if ((bhdr.total_length % 4) != 0) { + /* + * No. Report that as an error. + */ + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "block in pcapng dump file has a length of %u that is not a multiple of 4" PRIsize, + bhdr.total_length); return (-1); } @@ -322,12 +326,13 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf) */ if (p->bufsize < bhdr.total_length) { /* - * No - make it big enough, unless it's too big. + * No - make it big enough, unless it's too big, in + * which case we fail. */ void *bigger_buffer; if (bhdr.total_length > ps->max_blocksize) { - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "block is larger than maximum block size %u", + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcapng block size %u > maximum %u", bhdr.total_length, ps->max_blocksize); return (-1); } @@ -349,6 +354,26 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf) if (read_bytes(fp, bdata, data_remaining, 1, errbuf) == -1) return (-1); + /* + * Get the block size from the trailer. + */ + btrlr = (struct block_trailer *)(bdata + data_remaining - sizeof (struct block_trailer)); + if (p->swapped) + btrlr->total_length = SWAPLONG(btrlr->total_length); + + /* + * Is the total length from the trailer the same as the total + * length from the header? + */ + if (bhdr.total_length != btrlr->total_length) { + /* + * No. + */ + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "block total length in header and trailer don't match"); + return (-1); + } + /* * Initialize the cursor. */ @@ -431,13 +456,13 @@ get_optvalue_from_block_data(struct block_cursor *cursor, } static int -process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol, +process_idb_options(pcap_t *p, struct block_cursor *cursor, uint64_t *tsresol, uint64_t *tsoffset, int *is_binary, char *errbuf) { struct option_header *opthdr; void *optvalue; int saw_tsresol, saw_tsoffset; - u_char tsresol_opt; + uint8_t tsresol_opt; u_int i; saw_tsresol = 0; @@ -495,32 +520,43 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol, /* * Resolution is negative power of 2. */ + uint8_t tsresol_shift = (tsresol_opt & 0x7F); + + if (tsresol_shift > 63) { + /* + * Resolution is too high; 2^-{res} + * won't fit in a 64-bit value. + */ + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Interface Description Block if_tsresol option resolution 2^-%u is too high", + tsresol_shift); + return (-1); + } *is_binary = 1; - *tsresol = 1 << (tsresol_opt & 0x7F); + *tsresol = ((uint64_t)1) << tsresol_shift; } else { /* * Resolution is negative power of 10. */ + if (tsresol_opt > 19) { + /* + * Resolution is too high; 2^-{res} + * won't fit in a 64-bit value (the + * largest power of 10 that fits + * in a 64-bit value is 10^19, as + * the largest 64-bit unsigned + * value is ~1.8*10^19). + */ + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Interface Description Block if_tsresol option resolution 10^-%u is too high", + tsresol_opt); + return (-1); + } *is_binary = 0; *tsresol = 1; for (i = 0; i < tsresol_opt; i++) *tsresol *= 10; } - if (*tsresol == 0) { - /* - * Resolution is too high. - */ - if (tsresol_opt & 0x80) { - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "Interface Description Block if_tsresol option resolution 2^-%u is too high", - tsresol_opt & 0x7F); - } else { - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "Interface Description Block if_tsresol option resolution 10^-%u is too high", - tsresol_opt); - } - return (-1); - } break; case IF_TSOFFSET: @@ -554,7 +590,7 @@ static int add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf) { struct pcap_ng_sf *ps; - u_int tsresol; + uint64_t tsresol; uint64_t tsoffset; int is_binary; @@ -725,9 +761,10 @@ add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf) * relevant information from the header. */ pcap_t * -pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, - int *err) +pcap_ng_check_header(const uint8_t *magic, FILE *fp, u_int precision, + char *errbuf, int *err) { + bpf_u_int32 magic_int; size_t amt_read; bpf_u_int32 total_length; bpf_u_int32 byte_order_magic; @@ -749,7 +786,8 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, * Check whether the first 4 bytes of the file are the block * type for a pcapng savefile. */ - if (magic != BT_SHB) { + memcpy(&magic_int, magic, sizeof(magic_int)); + if (magic_int != BT_SHB) { /* * XXX - check whether this looks like what the block * type would be after being munged by mapping between @@ -818,11 +856,14 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, /* * Check the sanity of the total length. */ - if (total_length < sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer)) { + if (total_length < sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer) || + (total_length > BT_SHB_INSANE_MAX)) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "Section Header Block in pcapng dump file has a length of %u < %lu", + "Section Header Block in pcapng dump file has invalid length %" PRIsize " < _%u_ < %u (BT_SHB_INSANE_MAX)", + sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer), total_length, - (unsigned long)(sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer))); + BT_SHB_INSANE_MAX); + *err = 1; return (NULL); } @@ -874,10 +915,10 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, * leaving room for some options. * * If we find a bigger block, we reallocate the buffer, up to - * the maximum size. We start out with a maximum size based - * on a maximum snapshot length of MAXIMUM_SNAPLEN; if we see - * any link-layer header types with a larger maximum snapshot - * length, we boost the maximum. + * the maximum size. We start out with a maximum size of + * INITIAL_MAX_BLOCKSIZE; if we see any link-layer header types + * with a maximum snapshot that results in a larger maximum + * block length, we boost the maximum. */ p->bufsize = 2048; if (p->bufsize < total_length) @@ -889,7 +930,7 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, *err = 1; return (NULL); } - ps->max_blocksize = MAX_BLOCKSIZE(MAXIMUM_SNAPLEN); + ps->max_blocksize = INITIAL_MAX_BLOCKSIZE; /* * Copy the stuff we've read to the buffer, and read the rest @@ -897,12 +938,12 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, */ bhdrp = (struct block_header *)p->buffer; shbp = (struct section_header_block *)((u_char *)p->buffer + sizeof(struct block_header)); - bhdrp->block_type = magic; + bhdrp->block_type = magic_int; bhdrp->total_length = total_length; shbp->byte_order_magic = byte_order_magic; if (read_bytes(fp, - (u_char *)p->buffer + (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)), - total_length - (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)), + (u_char *)p->buffer + (sizeof(magic_int) + sizeof(total_length) + sizeof(byte_order_magic)), + total_length - (sizeof(magic_int) + sizeof(total_length) + sizeof(byte_order_magic)), 1, errbuf) == -1) goto fail; @@ -999,19 +1040,8 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, done: p->tzoff = 0; /* XXX - not used in pcap */ - p->snapshot = idbp->snaplen; - if (p->snapshot <= 0) { - /* - * Bogus snapshot length; use the maximum for this - * link-layer type as a fallback. - * - * XXX - the only reason why snapshot is signed is - * that pcap_snapshot() returns an int, not an - * unsigned int. - */ - p->snapshot = max_snaplen_for_dlt(idbp->linktype); - } p->linktype = linktype_to_dlt(idbp->linktype); + p->snapshot = pcap_adjust_snapshot(p->linktype, idbp->snaplen); p->linktype_ext = 0; /* @@ -1019,8 +1049,8 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, * snapshot length for this DLT_ is bigger than the current * maximum block size, increase the maximum. */ - if (MAX_BLOCKSIZE(max_snaplen_for_dlt(p->linktype)) > ps->max_blocksize) - ps->max_blocksize = MAX_BLOCKSIZE(max_snaplen_for_dlt(p->linktype)); + if (MAX_BLOCKSIZE_FOR_SNAPLEN(max_snaplen_for_dlt(p->linktype)) > ps->max_blocksize) + ps->max_blocksize = MAX_BLOCKSIZE_FOR_SNAPLEN(max_snaplen_for_dlt(p->linktype)); p->next_packet_op = pcap_ng_next_packet; p->cleanup_op = pcap_ng_cleanup; @@ -1206,7 +1236,13 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) idbp->linktype); return (-1); } - if ((bpf_u_int32)p->snapshot != idbp->snaplen) { + + /* + * Check against the *adjusted* value of this IDB's + * snapshot length. + */ + if ((bpf_u_int32)p->snapshot != + pcap_adjust_snapshot(p->linktype, idbp->snaplen)) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "an interface has a snapshot length %u different from the type of the first interface", idbp->snaplen); diff --git a/sf-pcapng.h b/sf-pcapng.h index d99b0d4e4e3e..835082a50989 100644 --- a/sf-pcapng.h +++ b/sf-pcapng.h @@ -26,7 +26,7 @@ #ifndef sf_pcapng_h #define sf_pcapng_h -extern pcap_t *pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, +extern pcap_t *pcap_ng_check_header(const uint8_t *magic, FILE *fp, u_int precision, char *errbuf, int *err); #endif diff --git a/sockutils.c b/sockutils.c index 079c49db2cac..d3e94649d9d4 100644 --- a/sockutils.c +++ b/sockutils.c @@ -100,7 +100,7 @@ * Wth MSVC, there *is* no ssize_t. * * With MinGW, there is an ssize_t type; it is either an int (32 bit) - * or a long long (64 bit). + * or a long long (64 bit). * * So, on Windows, if we don't have ssize_t defined, define it as an * int, so we can use it, on all platforms, as the type of variables @@ -130,44 +130,15 @@ static int sock_ismcastaddr(const struct sockaddr *saddr); */ void sock_fmterror(const char *caller, int errcode, char *errbuf, int errbuflen) { + if (errbuf == NULL) + return; + #ifdef _WIN32 - int retval; - TCHAR message[SOCK_ERRBUF_SIZE]; /* It will be char (if we're using ascii) or wchar_t (if we're using unicode) */ - - if (errbuf == NULL) - return; - - retval = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_MAX_WIDTH_MASK, - NULL, errcode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - message, sizeof(message) / sizeof(TCHAR), NULL); - - if (retval == 0) - { - if ((caller) && (*caller)) - pcap_snprintf(errbuf, errbuflen, "%sUnable to get the exact error message", caller); - else - pcap_snprintf(errbuf, errbuflen, "Unable to get the exact error message"); - } - else - { - if ((caller) && (*caller)) - pcap_snprintf(errbuf, errbuflen, "%s%s (code %d)", caller, message, errcode); - else - pcap_snprintf(errbuf, errbuflen, "%s (code %d)", message, errcode); - } + pcap_fmt_errmsg_for_win32_err(errbuf, errbuflen, errcode, + "%s", caller); #else - char *message; - - if (errbuf == NULL) - return; - - message = strerror(errcode); - - if ((caller) && (*caller)) - pcap_snprintf(errbuf, errbuflen, "%s%s (code %d)", caller, message, errcode); - else - pcap_snprintf(errbuf, errbuflen, "%s (code %d)", message, errcode); + pcap_fmt_errmsg_for_errno(errbuf, errbuflen, errcode, + "%s", caller); #endif } @@ -180,7 +151,7 @@ void sock_fmterror(const char *caller, int errcode, char *errbuf, int errbuflen) * * \param caller: a pointer to a user-allocated string which contains a message that has * to be printed *before* the true error message. It could be, for example, 'this error - * comes from the recv() call at line 31'. It may be NULL. + * comes from the recv() call at line 31'. * * \param errbuf: a pointer to an user-allocated buffer that will contain the complete * error message. This buffer has to be at least 'errbuflen' in length. @@ -194,31 +165,30 @@ void sock_fmterror(const char *caller, int errcode, char *errbuf, int errbuflen) void sock_geterror(const char *caller, char *errbuf, int errbuflen) { #ifdef _WIN32 - if (errbuf == NULL) - return; sock_fmterror(caller, GetLastError(), errbuf, errbuflen); #else - if (errbuf == NULL) - return; sock_fmterror(caller, errno, errbuf, errbuflen); #endif } /* - * \brief It initializes sockets. + * \brief This function initializes the socket mechanism if it hasn't + * already been initialized or reinitializes it after it has been + * cleaned up. * - * This function is pretty useless on UNIX, since socket initialization is not required. - * However it is required on Win32. In UNIX, this function appears to be completely empty. + * On UN*Xes, it doesn't need to do anything; on Windows, it needs to + * initialize Winsock. * - * \param errbuf: a pointer to an user-allocated buffer that will contain the complete - * error message. This buffer has to be at least 'errbuflen' in length. - * It can be NULL; in this case the error cannot be printed. + * \param errbuf: a pointer to an user-allocated buffer that will contain + * the complete error message. This buffer has to be at least 'errbuflen' + * in length. It can be NULL; in this case no error message is supplied. * - * \param errbuflen: length of the buffer that will contains the error. The error message cannot be - * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. + * \param errbuflen: length of the buffer that will contains the error. + * The error message cannot be larger than 'errbuflen - 1' because the + * last char is reserved for the string terminator. * - * \return '0' if everything is fine, '-1' if some errors occurred. The error message is returned - * in the 'errbuf' variable. + * \return '0' if everything is fine, '-1' if some errors occurred. The + * error message is returned in the buffer pointed to by 'errbuf' variable. */ #ifdef _WIN32 int sock_init(char *errbuf, int errbuflen) @@ -240,18 +210,24 @@ int sock_init(char *errbuf, int errbuflen) } sockcount++; + return 0; +} #else int sock_init(char *errbuf _U_, int errbuflen _U_) { -#endif + /* + * Nothing to do on UN*Xes. + */ return 0; } +#endif /* - * \brief It deallocates sockets. + * \brief This function cleans up the socket mechanism if we have no + * sockets left open. * - * This function is pretty useless on UNIX, since socket deallocation is not required. - * However it is required on Win32. In UNIX, this function appears to be completely empty. + * On UN*Xes, it doesn't need to do anything; on Windows, it needs + * to clean up Winsock. * * \return No error values. */ @@ -327,7 +303,7 @@ SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf, sock = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol); if (sock == INVALID_SOCKET) { - sock_geterror("socket(): ", errbuf, errbuflen); + sock_geterror("socket()", errbuf, errbuflen); return INVALID_SOCKET; } @@ -350,6 +326,16 @@ SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf, /* This is a server socket */ if (server) { + /* + * Allow a new server to bind the socket after the old one + * exited, even if lingering sockets are still present. + * + * Don't treat an error as a failure. + */ + int optval = 1; + (void)setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + (char *)&optval, sizeof (optval)); + #if defined(IPV6_V6ONLY) || defined(IPV6_BINDV6ONLY) /* * Force the use of IPv6-only addresses. @@ -399,7 +385,7 @@ SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf, /* WARNING: if the address is a mcast one, I should place the proper Win32 code here */ if (bind(sock, addrinfo->ai_addr, (int) addrinfo->ai_addrlen) != 0) { - sock_geterror("bind(): ", errbuf, errbuflen); + sock_geterror("bind()", errbuf, errbuflen); closesocket(sock); return INVALID_SOCKET; } @@ -407,7 +393,7 @@ SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf, if (addrinfo->ai_socktype == SOCK_STREAM) if (listen(sock, nconn) == -1) { - sock_geterror("listen(): ", errbuf, errbuflen); + sock_geterror("listen()", errbuf, errbuflen); closesocket(sock); return INVALID_SOCKET; } @@ -444,13 +430,14 @@ SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf, * We have to retrieve the error message before any other socket call completes, otherwise * the error message is lost */ - sock_geterror(NULL, SocketErrorMessage, sizeof(SocketErrorMessage)); + sock_geterror("Connect to socket failed", + SocketErrorMessage, sizeof(SocketErrorMessage)); /* Returns the numeric address of the host that triggered the error */ sock_getascii_addrport((struct sockaddr_storage *) tempaddrinfo->ai_addr, TmpBuffer, sizeof(TmpBuffer), NULL, 0, NI_NUMERICHOST, TmpBuffer, sizeof(TmpBuffer)); pcap_snprintf(errbufptr, bufspaceleft, - "Is the server properly installed on %s? connect() failed: %s", TmpBuffer, SocketErrorMessage); + "Is the server properly installed on %s? %s", TmpBuffer, SocketErrorMessage); /* In case more then one 'connect' fails, we manage to keep all the error messages */ msglen = strlen(errbufptr); @@ -508,7 +495,7 @@ int sock_close(SOCKET sock, char *errbuf, int errbuflen) */ if (shutdown(sock, SHUT_WR)) { - sock_geterror("shutdown(): ", errbuf, errbuflen); + sock_geterror("shutdown()", errbuf, errbuflen); /* close the socket anyway */ closesocket(sock); return -1; @@ -518,6 +505,157 @@ int sock_close(SOCKET sock, char *errbuf, int errbuflen) return 0; } +/* + * gai_errstring() has some problems: + * + * 1) on Windows, Microsoft explicitly says it's not thread-safe; + * 2) on UN*X, the Single UNIX Specification doesn't say it *is* + * thread-safe, so an implementation might use a static buffer + * for unknown error codes; + * 3) the error message for the most likely error, EAI_NONAME, is + * truly horrible on several platforms ("nodename nor servname + * provided, or not known"? It's typically going to be "not + * known", not "oopsie, I passed null pointers for the host name + * and service name", not to mention they forgot the "neither"); + * + * so we roll our own. + */ +static void +get_gai_errstring(char *errbuf, int errbuflen, const char *prefix, int err, + const char *hostname, const char *portname) +{ + char hostport[PCAP_ERRBUF_SIZE]; + + if (hostname != NULL && portname != NULL) + pcap_snprintf(hostport, PCAP_ERRBUF_SIZE, "%s:%s", + hostname, portname); + else if (hostname != NULL) + pcap_snprintf(hostport, PCAP_ERRBUF_SIZE, "%s", + hostname); + else if (portname != NULL) + pcap_snprintf(hostport, PCAP_ERRBUF_SIZE, ":%s", + portname); + else + pcap_snprintf(hostport, PCAP_ERRBUF_SIZE, ""); + switch (err) + { +#ifdef EAI_ADDRFAMILY + case EAI_ADDRFAMILY: + pcap_snprintf(errbuf, errbuflen, + "%sAddress family for %s not supported", + prefix, hostport); + break; +#endif + + case EAI_AGAIN: + pcap_snprintf(errbuf, errbuflen, + "%s%s could not be resolved at this time", + prefix, hostport); + break; + + case EAI_BADFLAGS: + pcap_snprintf(errbuf, errbuflen, + "%sThe ai_flags parameter for looking up %s had an invalid value", + prefix, hostport); + break; + + case EAI_FAIL: + pcap_snprintf(errbuf, errbuflen, + "%sA non-recoverable error occurred when attempting to resolve %s", + prefix, hostport); + break; + + case EAI_FAMILY: + pcap_snprintf(errbuf, errbuflen, + "%sThe address family for looking up %s was not recognized", + prefix, hostport); + break; + + case EAI_MEMORY: + pcap_snprintf(errbuf, errbuflen, + "%sOut of memory trying to allocate storage when looking up %s", + prefix, hostport); + break; + + /* + * RFC 2553 had both EAI_NODATA and EAI_NONAME. + * + * RFC 3493 has only EAI_NONAME. + * + * Some implementations define EAI_NODATA and EAI_NONAME + * to the same value, others don't. If EAI_NODATA is + * defined and isn't the same as EAI_NONAME, we handle + * EAI_NODATA. + */ +#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME + case EAI_NODATA: + pcap_snprintf(errbuf, errbuflen, + "%sNo address associated with %s", + prefix, hostport); + break; +#endif + + case EAI_NONAME: + pcap_snprintf(errbuf, errbuflen, + "%sThe host name %s couldn't be resolved", + prefix, hostport); + break; + + case EAI_SERVICE: + pcap_snprintf(errbuf, errbuflen, + "%sThe service value specified when looking up %s as not recognized for the socket type", + prefix, hostport); + break; + + case EAI_SOCKTYPE: + pcap_snprintf(errbuf, errbuflen, + "%sThe socket type specified when looking up %s as not recognized", + prefix, hostport); + break; + +#ifdef EAI_SYSTEM + case EAI_SYSTEM: + /* + * Assumed to be UN*X. + */ + pcap_snprintf(errbuf, errbuflen, + "%sAn error occurred when looking up %s: %s", + prefix, hostport, pcap_strerror(errno)); + break; +#endif + +#ifdef EAI_BADHINTS + case EAI_BADHINTS: + pcap_snprintf(errbuf, errbuflen, + "%sInvalid value for hints when looking up %s", + prefix, hostport); + break; +#endif + +#ifdef EAI_PROTOCOL + case EAI_PROTOCOL: + pcap_snprintf(errbuf, errbuflen, + "%sResolved protocol when looking up %s is unknown", + prefix, hostport); + break; +#endif + +#ifdef EAI_OVERFLOW + case EAI_OVERFLOW: + pcap_snprintf(errbuf, errbuflen, + "%sArgument buffer overflow when looking up %s", + prefix, hostport); + break; +#endif + + default: + pcap_snprintf(errbuf, errbuflen, + "%sgetaddrinfo() error %d when looking up %s", + prefix, err, hostport); + break; + } +} + /* * \brief Checks that the address, port and flags given are valids and it returns an 'addrinfo' structure. * @@ -564,17 +702,10 @@ int sock_initaddress(const char *host, const char *port, retval = getaddrinfo(host, port, hints, addrinfo); if (retval != 0) { - /* - * if the getaddrinfo() fails, you have to use gai_strerror(), instead of using the standard - * error routines (errno) in UNIX; Winsock suggests using the GetLastError() instead. - */ if (errbuf) { -#ifdef _WIN32 - sock_geterror("getaddrinfo(): ", errbuf, errbuflen); -#else - pcap_snprintf(errbuf, errbuflen, "getaddrinfo() %s", gai_strerror(retval)); -#endif + get_gai_errstring(errbuf, errbuflen, "", retval, + host, port); } return -1; } @@ -655,7 +786,7 @@ int sock_send(SOCKET sock, const char *buffer, size_t size, if (errbuf) { pcap_snprintf(errbuf, errbuflen, - "Can't send more than %u bytes with sock_recv", + "Can't send more than %u bytes with sock_send", INT_MAX); } return -1; @@ -697,7 +828,7 @@ int sock_send(SOCKET sock, const char *buffer, size_t size, */ return -2; } - sock_fmterror("send(): ", errcode, errbuf, errbuflen); + sock_fmterror("send()", errcode, errbuf, errbuflen); #else errcode = errno; if (errcode == ECONNRESET || errcode == EPIPE) @@ -709,7 +840,7 @@ int sock_send(SOCKET sock, const char *buffer, size_t size, */ return -2; } - sock_fmterror("send(): ", errcode, errbuf, errbuflen); + sock_fmterror("send()", errcode, errbuf, errbuflen); #endif return -1; } @@ -848,7 +979,6 @@ int sock_recv(SOCKET sock, void *buffer, size_t size, int flags, if (size == 0) { - SOCK_DEBUG_MESSAGE("I have been requested to read zero bytes"); return 0; } if (size > INT_MAX) @@ -878,7 +1008,7 @@ int sock_recv(SOCKET sock, void *buffer, size_t size, int flags, if (errno == EINTR) return -3; #endif - sock_geterror("recv(): ", errbuf, errbuflen); + sock_geterror("recv()", errbuf, errbuflen); return -1; } @@ -939,7 +1069,6 @@ int sock_recv_dgram(SOCKET sock, void *buffer, size_t size, if (size == 0) { - SOCK_DEBUG_MESSAGE("I have been requested to read zero bytes"); return 0; } if (size > INT_MAX) @@ -975,7 +1104,7 @@ int sock_recv_dgram(SOCKET sock, void *buffer, size_t size, * supplied to us, the excess data is discarded, * and we'll report an error. */ - sock_geterror("recv(): ", errbuf, errbuflen); + sock_geterror("recv()", errbuf, errbuflen); return -1; } #else /* _WIN32 */ @@ -1008,7 +1137,7 @@ int sock_recv_dgram(SOCKET sock, void *buffer, size_t size, { if (errno == EINTR) return -3; - sock_geterror("recv(): ", errbuf, errbuflen); + sock_geterror("recv()", errbuf, errbuflen); return -1; } #ifdef HAVE_STRUCT_MSGHDR_MSG_FLAGS @@ -1095,8 +1224,6 @@ int sock_discard(SOCKET sock, int size, char *errbuf, int errbuflen) return -1; } - SOCK_DEBUG_MESSAGE("I'm currently discarding data\n"); - return 0; } @@ -1137,6 +1264,7 @@ int sock_check_hostlist(char *hostlist, const char *sep, struct sockaddr_storage struct addrinfo *addrinfo, *ai_next; char *temphostlist; char *lasts; + int getaddrinfo_failed = 0; /* * The problem is that strtok modifies the original variable by putting '0' at the end of each token @@ -1164,13 +1292,19 @@ int sock_check_hostlist(char *hostlist, const char *sep, struct sockaddr_storage hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - retval = getaddrinfo(token, "0", &hints, &addrinfo); + retval = getaddrinfo(token, NULL, &hints, &addrinfo); if (retval != 0) { if (errbuf) - pcap_snprintf(errbuf, errbuflen, "getaddrinfo() %s", gai_strerror(retval)); + get_gai_errstring(errbuf, errbuflen, + "Allowed host list error: ", + retval, token, NULL); - SOCK_DEBUG_MESSAGE(errbuf); + /* + * Note that at least one call to getaddrinfo() + * failed. + */ + getaddrinfo_failed = 1; /* Get next token */ token = pcap_strtok_r(NULL, sep, &lasts); @@ -1208,11 +1342,25 @@ int sock_check_hostlist(char *hostlist, const char *sep, struct sockaddr_storage addrinfo = NULL; } - if (errbuf) - pcap_snprintf(errbuf, errbuflen, "The host is not in the allowed host list. Connection refused."); - free(temphostlist); - return -1; + + if (getaddrinfo_failed) { + /* + * At least one getaddrinfo() call failed; + * treat that as an error, so rpcapd knows + * that it should log it locally as well + * as telling the client about it. + */ + return -2; + } else { + /* + * All getaddrinfo() calls succeeded, but + * the host wasn't in the list. + */ + if (errbuf) + pcap_snprintf(errbuf, errbuflen, "The host is not in the allowed host list. Connection refused."); + return -1; + } } /* No hostlist, so we have to return 'empty list' */ @@ -1311,7 +1459,7 @@ int sock_getmyinfo(SOCKET sock, char *address, int addrlen, char *port, int port if (getsockname(sock, (struct sockaddr *) &mysockaddr, &sockaddrlen) == -1) { - sock_geterror("getsockname(): ", errbuf, errbuflen); + sock_geterror("getsockname()", errbuf, errbuflen); return 0; } @@ -1389,7 +1537,7 @@ int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *addres (memcmp(&((struct sockaddr_in6 *) sockaddr)->sin6_addr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sizeof(struct in6_addr)) == 0)) { if (address) - strlcpy(address, SOCKET_NAME_NULL_DAD, addrlen); + pcap_strlcpy(address, SOCKET_NAME_NULL_DAD, addrlen); return retval; } } @@ -1399,19 +1547,19 @@ int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *addres /* If the user wants to receive an error message */ if (errbuf) { - sock_geterror("getnameinfo(): ", errbuf, errbuflen); + sock_geterror("getnameinfo()", errbuf, errbuflen); errbuf[errbuflen - 1] = 0; } if (address) { - strlcpy(address, SOCKET_NO_NAME_AVAILABLE, addrlen); + pcap_strlcpy(address, SOCKET_NO_NAME_AVAILABLE, addrlen); address[addrlen - 1] = 0; } if (port) { - strlcpy(port, SOCKET_NO_PORT_AVAILABLE, portlen); + pcap_strlcpy(port, SOCKET_NO_PORT_AVAILABLE, portlen); port[portlen - 1] = 0; } diff --git a/sockutils.h b/sockutils.h index 1df1ef7bb3ac..8a45b3df423f 100644 --- a/sockutils.h +++ b/sockutils.h @@ -37,54 +37,11 @@ #pragma once #endif -#ifdef _WIN32 - /* Need windef.h for defines used in winsock2.h under MingW32 */ - #ifdef __MINGW32__ - #include - #endif - #include - #include +#include "pcap/socket.h" - /* - * Winsock doesn't have this UN*X type; it's used in the UN*X - * sockets API. - * - * XXX - do we need to worry about UN*Xes so old that *they* - * don't have it, either? - */ - typedef int socklen_t; -#else +#ifndef _WIN32 /* UN*X */ - #include - #include /* for memset() */ - #include - #include - #include /* DNS lookup */ #include /* close() */ - #include /* errno() */ - #include /* for sockaddr_in, in BSD at least */ - #include - #include - - /*! - * \brief In Winsock, a socket handle is of type SOCKET; in UN*X, it's - * a file descriptor, and therefore a signed integer. - * We define SOCKET to be a signed integer on UN*X, so that it can - * be used on both platforms. - */ - #ifndef SOCKET - #define SOCKET int - #endif - - /*! - * \brief In Winsock, the error return if socket() fails is INVALID_SOCKET; - * in UN*X, it's -1. - * We define INVALID_SOCKET to be -1 on UN*X, so that it can be used on - * both platforms. - */ - #ifndef INVALID_SOCKET - #define INVALID_SOCKET -1 - #endif /*! * \brief In Winsock, the close() call cannot be used on a socket; @@ -122,35 +79,6 @@ int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD, * \{ */ -/* - * \brief DEBUG facility: it prints an error message on the screen (stderr) - * - * This macro prints the error on the standard error stream (stderr); - * if we are working in debug mode (i.e. there is no NDEBUG defined) and we are in - * Microsoft Visual C++, the error message will appear on the MSVC console as well. - * - * When NDEBUG is defined, this macro is empty. - * - * \param msg: the message you want to print. - * - * \param expr: 'false' if you want to abort the program, 'true' it you want - * to print the message and continue. - * - * \return No return values. - */ -#ifdef NDEBUG - #define SOCK_DEBUG_MESSAGE(msg) ((void)0) -#else - #if (defined(_WIN32) && defined(_MSC_VER)) - #include /* for _CrtDbgReport */ - /* Use MessageBox(NULL, msg, "warning", MB_OK)' instead of the other calls if you want to debug a Win32 service */ - /* Remember to activate the 'allow service to interact with desktop' flag of the service */ - #define SOCK_DEBUG_MESSAGE(msg) { _CrtDbgReport(_CRT_WARN, NULL, 0, NULL, "%s\n", msg); fprintf(stderr, "%s\n", msg); } - #else - #define SOCK_DEBUG_MESSAGE(msg) { fprintf(stderr, "%s\n", msg); } - #endif -#endif - /**************************************************** * * * Exported functions / definitions * diff --git a/testprogs/CMakeLists.txt b/testprogs/CMakeLists.txt new file mode 100644 index 000000000000..b8ef9b7d0510 --- /dev/null +++ b/testprogs/CMakeLists.txt @@ -0,0 +1,40 @@ +if(MSVC) + file(GLOB PROJECT_SOURCE_LIST_WIN32_C ${pcap_SOURCE_DIR}/missing/getopt.c) + include_directories(${pcap_SOURCE_DIR}/missing) +endif(MSVC) + +add_custom_target(testprogs) + +macro(add_test_executable _executable) + add_executable(${_executable} EXCLUDE_FROM_ALL + ${_executable}.c ${PROJECT_SOURCE_LIST_WIN32_C}) + if(NOT C_ADDITIONAL_FLAGS STREQUAL "") + set_target_properties(${_executable} PROPERTIES + COMPILE_FLAGS ${C_ADDITIONAL_FLAGS}) + endif() + if(WIN32) + target_link_libraries(${_executable} + ${ARGN} ${LIBRARY_NAME} ${PCAP_LINK_LIBRARIES}) + else(WIN32) + target_link_libraries(${_executable} + ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES}) + endif(WIN32) + add_dependencies(testprogs ${_executable}) +endmacro() + +add_test_executable(can_set_rfmon_test) +add_test_executable(capturetest) +add_test_executable(filtertest) +add_test_executable(findalldevstest) +add_test_executable(opentest) +add_test_executable(reactivatetest) + +if(NOT WIN32) + add_test_executable(selpolltest) +endif() + +add_test_executable(threadsignaltest ${CMAKE_THREAD_LIBS_INIT}) + +if(NOT WIN32) + add_test_executable(valgrindtest) +endif() diff --git a/testprogs/Makefile.in b/testprogs/Makefile.in new file mode 100644 index 000000000000..ec0a47208464 --- /dev/null +++ b/testprogs/Makefile.in @@ -0,0 +1,144 @@ +# Copyright (c) 1993, 1994, 1995, 1996 +# The Regents of the University of California. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that: (1) source code distributions +# retain the above copyright notice and this paragraph in its entirety, (2) +# distributions including binary code include the above copyright notice and +# this paragraph in its entirety in the documentation or other materials +# provided with the distribution, and (3) all advertising materials mentioning +# features or use of this software display the following acknowledgement: +# ``This product includes software developed by the University of California, +# Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +# the University nor the names of its contributors may be used to endorse +# or promote products derived from this software without specific prior +# written permission. +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +# +# Various configurable paths (remember to edit Makefile.in, not Makefile) +# + +# Top level hierarchy +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datarootdir = @datarootdir@ +# Pathname of directory to install the configure program +bindir = @bindir@ +# Pathname of directory to install the rpcapd daemon +sbindir = @sbindir@ +# Pathname of directory to install the include files +includedir = @includedir@ +# Pathname of directory to install the library +libdir = @libdir@ +# Pathname of directory to install the man pages +mandir = @mandir@ + +# VPATH +srcdir = @srcdir@ +VPATH = @srcdir@ + +# +# You shouldn't need to edit anything below. +# + +LD = /usr/bin/ld +CC = @CC@ +AR = @AR@ +LN_S = @LN_S@ +MKDEP = @MKDEP@ +CCOPT = @V_CCOPT@ +INCLS = -I. -I.. -I@srcdir@ -I@srcdir@/.. @V_INCLS@ +DEFS = @DEFS@ @V_DEFS@ +ADDLOBJS = @ADDLOBJS@ +ADDLARCHIVEOBJS = @ADDLARCHIVEOBJS@ +LIBS = @LIBS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +CROSSFLAGS= +CFLAGS = @CFLAGS@ ${CROSSFLAGS} +LDFLAGS = @LDFLAGS@ ${CROSSFLAGS} +DYEXT = @DYEXT@ +V_RPATH_OPT = @V_RPATH_OPT@ +DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@ +EXTRA_NETWORK_LIBS=@EXTRA_NETWORK_LIBS@ + +# Standard CFLAGS for building test programs +FULL_CFLAGS = $(CCOPT) $(INCLS) $(DEFS) $(CFLAGS) + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +# Explicitly define compilation rule since SunOS 4's make doesn't like gcc. +# Also, gcc does not remove the .o before forking 'as', which can be a +# problem if you don't own the file but can write to the directory. +.c.o: + @rm -f $@ + $(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c + +SRC = @VALGRINDTEST_SRC@ \ + capturetest.c \ + can_set_rfmon_test.c \ + filtertest.c \ + findalldevstest.c \ + opentest.c \ + reactivatetest.c \ + selpolltest.c \ + threadsignaltest.c + +TESTS = $(SRC:.c=) + +TAGFILES = \ + $(SRC) $(HDR) + +CLEANFILES = $(OBJ) $(TESTS) + +all: $(TESTS) + +capturetest: $(srcdir)/capturetest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o capturetest $(srcdir)/capturetest.c ../libpcap.a $(LIBS) + +can_set_rfmon_test: $(srcdir)/can_set_rfmon_test.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o can_set_rfmon_test $(srcdir)/can_set_rfmon_test.c ../libpcap.a $(LIBS) + +filtertest: $(srcdir)/filtertest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o filtertest $(srcdir)/filtertest.c ../libpcap.a $(EXTRA_NETWORK_LIBS) $(LIBS) + +findalldevstest: $(srcdir)/findalldevstest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o findalldevstest $(srcdir)/findalldevstest.c ../libpcap.a $(EXTRA_NETWORK_LIBS) $(LIBS) + +opentest: $(srcdir)/opentest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o opentest $(srcdir)/opentest.c ../libpcap.a $(LIBS) + +reactivatetest: $(srcdir)/reactivatetest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o reactivatetest $(srcdir)/reactivatetest.c ../libpcap.a $(LIBS) + +selpolltest: $(srcdir)/selpolltest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o selpolltest $(srcdir)/selpolltest.c ../libpcap.a $(LIBS) + +threadsignaltest: $(srcdir)/threadsignaltest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o threadsignaltest $(srcdir)/threadsignaltest.c ../libpcap.a $(LIBS) $(PTHREAD_LIBS) + +valgrindtest: $(srcdir)/valgrindtest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o valgrindtest $(srcdir)/valgrindtest.c ../libpcap.a $(LIBS) + +clean: + rm -f $(CLEANFILES) + rm -rf *.dSYM + +distclean: clean + rm -f Makefile config.cache config.log config.status \ + config.h stamp-h stamp-h.in + rm -rf autom4te.cache + +install: + +uninstall: + +tags: $(TAGFILES) + ctags -wtd $(TAGFILES) + +depend: + ../$(MKDEP) -c "$(CC)" -m "$(DEPENDENCY_CFLAG)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC) diff --git a/testprogs/can_set_rfmon_test.c b/testprogs/can_set_rfmon_test.c new file mode 100644 index 000000000000..f6188ba1399e --- /dev/null +++ b/testprogs/can_set_rfmon_test.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "varattrs.h" + +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include + +#include + +#include "pcap/funcattrs.h" + +static const char *program_name; + +/* Forwards */ +static void PCAP_NORETURN error(PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(1,2); + +int +main(int argc, char **argv) +{ + const char *cp; + pcap_t *pd; + char ebuf[PCAP_ERRBUF_SIZE]; + int status; + + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", program_name); + return 2; + } + + pd = pcap_create(argv[1], ebuf); + if (pd == NULL) + error("%s", ebuf); + status = pcap_can_set_rfmon(pd); + if (status < 0) { + if (status == PCAP_ERROR) + error("%s: pcap_can_set_rfmon failed: %s", argv[1], + pcap_geterr(pd)); + else + error("%s: pcap_can_set_rfmon failed: %s", argv[1], + pcap_statustostr(status)); + return 1; + } + printf("%s: Monitor mode %s be set\n", argv[1], status ? "can" : "cannot"); + return 0; +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} diff --git a/testprogs/capturetest.c b/testprogs/capturetest.c new file mode 100644 index 000000000000..d625cb4ab2b7 --- /dev/null +++ b/testprogs/capturetest.c @@ -0,0 +1,299 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "varattrs.h" + +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include +#ifdef _WIN32 + #include "getopt.h" +#else + #include +#endif +#include +#include + +#include + +#include "pcap/funcattrs.h" + +#ifdef _WIN32 + #include "portability.h" +#endif + +static char *program_name; + +/* Forwards */ +static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static char *copy_argv(char **); + +static pcap_t *pd; + +int +main(int argc, char **argv) +{ + register int op; + register char *cp, *cmdbuf, *device; + long longarg; + char *p; + int timeout = 1000; + int immediate = 0; + int nonblock = 0; + pcap_if_t *devlist; + bpf_u_int32 localnet, netmask; + struct bpf_program fcode; + char ebuf[PCAP_ERRBUF_SIZE]; + int status; + int packet_count; + + device = NULL; + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "i:mnt:")) != -1) { + switch (op) { + + case 'i': + device = optarg; + break; + + case 'm': + immediate = 1; + break; + + case 'n': + nonblock = 1; + break; + + case 't': + longarg = strtol(optarg, &p, 10); + if (p == optarg || *p != '\0') { + error("Timeout value \"%s\" is not a number", + optarg); + /* NOTREACHED */ + } + if (longarg < 0) { + error("Timeout value %ld is negative", longarg); + /* NOTREACHED */ + } + if (longarg > INT_MAX) { + error("Timeout value %ld is too large (> %d)", + longarg, INT_MAX); + /* NOTREACHED */ + } + timeout = (int)longarg; + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (device == NULL) { + if (pcap_findalldevs(&devlist, ebuf) == -1) + error("%s", ebuf); + if (devlist == NULL) + error("no interfaces available for capture"); + device = strdup(devlist->name); + pcap_freealldevs(devlist); + } + *ebuf = '\0'; + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s", ebuf); + status = pcap_set_snaplen(pd, 65535); + if (status != 0) + error("%s: pcap_set_snaplen failed: %s", + device, pcap_statustostr(status)); + if (immediate) { + status = pcap_set_immediate_mode(pd, 1); + if (status != 0) + error("%s: pcap_set_immediate_mode failed: %s", + device, pcap_statustostr(status)); + } + status = pcap_set_timeout(pd, timeout); + if (status != 0) + error("%s: pcap_set_timeout failed: %s", + device, pcap_statustostr(status)); + status = pcap_activate(pd); + if (status < 0) { + /* + * pcap_activate() failed. + */ + error("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } else if (status > 0) { + /* + * pcap_activate() succeeded, but it's warning us + * of a problem it had. + */ + warning("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } + if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { + localnet = 0; + netmask = 0; + warning("%s", ebuf); + } + cmdbuf = copy_argv(&argv[optind]); + + if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0) + error("%s", pcap_geterr(pd)); + + if (pcap_setfilter(pd, &fcode) < 0) + error("%s", pcap_geterr(pd)); + if (pcap_setnonblock(pd, nonblock, ebuf) == -1) + error("pcap_setnonblock failed: %s", ebuf); + printf("Listening on %s\n", device); + for (;;) { + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + if (status != 0) { + printf("%d packets seen, %d packets counted after pcap_dispatch returns\n", + status, packet_count); + } + } + if (status == -2) { + /* + * We got interrupted, so perhaps we didn't + * manage to finish a line we were printing. + * Print an extra newline, just in case. + */ + putchar('\n'); + } + (void)fflush(stdout); + if (status == -1) { + /* + * Error. Report it. + */ + (void)fprintf(stderr, "%s: pcap_loop: %s\n", + program_name, pcap_geterr(pd)); + } + pcap_close(pd); + pcap_freecode(&fcode); + free(cmdbuf); + exit(status == -1 ? 1 : 0); +} + +static void +countme(u_char *user, const struct pcap_pkthdr *h _U_, const u_char *sp _U_) +{ + int *counterp = (int *)user; + + (*counterp)++; +} + +static void +usage(void) +{ + (void)fprintf(stderr, "Usage: %s [ -mn ] [ -i interface ] [ -t timeout] [expression]\n", + program_name); + exit(1); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register u_int len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} diff --git a/testprogs/filtertest.c b/testprogs/filtertest.c new file mode 100644 index 000000000000..7e2d6d6e186d --- /dev/null +++ b/testprogs/filtertest.c @@ -0,0 +1,359 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "varattrs.h" + +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#ifdef _WIN32 + #include "getopt.h" + #include "unix.h" +#else + #include +#endif +#include +#include +#ifdef _WIN32 + #include + #include +#else + #include + #include +#endif +#include +#include + +#include "pcap/funcattrs.h" + +#ifdef BDEBUG +/* + * We have pcap_set_optimizer_debug() and pcap_set_print_dot_graph() in + * libpcap; declare them (they're not declared by any libpcap header, + * because they're special hacks, only available if libpcap was configured + * to include them, and only intended for use by libpcap developers trying + * to debug the optimizer for filter expressions). + */ +PCAP_API void pcap_set_optimizer_debug(int); +PCAP_API void pcap_set_print_dot_graph(int); +#endif + +static char *program_name; + +/* Forwards */ +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warn(const char *, ...) PCAP_PRINTFLIKE(1, 2); + +/* + * On Windows, we need to open the file in binary mode, so that + * we get all the bytes specified by the size we get from "fstat()". + * On UNIX, that's not necessary. O_BINARY is defined on Windows; + * we define it as 0 if it's not defined, so it does nothing. + */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +static char * +read_infile(char *fname) +{ + register int i, fd, cc; + register char *cp; + struct stat buf; + + fd = open(fname, O_RDONLY|O_BINARY); + if (fd < 0) + error("can't open %s: %s", fname, pcap_strerror(errno)); + + if (fstat(fd, &buf) < 0) + error("can't stat %s: %s", fname, pcap_strerror(errno)); + + cp = malloc((u_int)buf.st_size + 1); + if (cp == NULL) + error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, + fname, pcap_strerror(errno)); + cc = read(fd, cp, (u_int)buf.st_size); + if (cc < 0) + error("read %s: %s", fname, pcap_strerror(errno)); + if (cc != buf.st_size) + error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); + + close(fd); + /* replace "# comment" with spaces */ + for (i = 0; i < cc; i++) { + if (cp[i] == '#') + while (i < cc && cp[i] != '\n') + cp[i++] = ' '; + } + cp[cc] = '\0'; + return (cp); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warn(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register u_int len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} + +int +main(int argc, char **argv) +{ + char *cp; + int op; + int dflag; + int gflag; + char *infile; + int Oflag; + long snaplen; + char *p; + int dlt; + int have_fcode = 0; + bpf_u_int32 netmask = PCAP_NETMASK_UNKNOWN; + char *cmdbuf; + pcap_t *pd; + struct bpf_program fcode; + +#ifdef _WIN32 + if (pcap_wsockinit() != 0) + return 1; +#endif /* _WIN32 */ + + dflag = 1; + gflag = 0; + + infile = NULL; + Oflag = 1; + snaplen = 68; + + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "dF:gm:Os:")) != -1) { + switch (op) { + + case 'd': + ++dflag; + break; + + case 'g': +#ifdef BDEBUG + ++gflag; +#else + error("libpcap and filtertest not built with optimizer debugging enabled"); +#endif + break; + + case 'F': + infile = optarg; + break; + + case 'O': + Oflag = 0; + break; + + case 'm': { + bpf_u_int32 addr; + + switch (inet_pton(AF_INET, optarg, &addr)) { + + case 0: + error("invalid netmask %s", optarg); + break; + + case -1: + error("invalid netmask %s: %s", optarg, + pcap_strerror(errno)); + break; + + case 1: + netmask = addr; + break; + } + break; + } + + case 's': { + char *end; + + snaplen = strtol(optarg, &end, 0); + if (optarg == end || *end != '\0' + || snaplen < 0 || snaplen > 65535) + error("invalid snaplen %s", optarg); + else if (snaplen == 0) + snaplen = 65535; + break; + } + + default: + usage(); + /* NOTREACHED */ + } + } + + if (optind >= argc) { + usage(); + /* NOTREACHED */ + } + + dlt = pcap_datalink_name_to_val(argv[optind]); + if (dlt < 0) { + dlt = (int)strtol(argv[optind], &p, 10); + if (p == argv[optind] || *p != '\0') + error("invalid data link type %s", argv[optind]); + } + + if (infile) + cmdbuf = read_infile(infile); + else + cmdbuf = copy_argv(&argv[optind+1]); + +#ifdef BDEBUG + pcap_set_optimizer_debug(dflag); + pcap_set_print_dot_graph(gflag); +#endif + + pd = pcap_open_dead(dlt, snaplen); + if (pd == NULL) + error("Can't open fake pcap_t"); + + if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) + error("%s", pcap_geterr(pd)); + + have_fcode = 1; + if (!bpf_validate(fcode.bf_insns, fcode.bf_len)) + warn("Filter doesn't pass validation"); + +#ifdef BDEBUG + if (cmdbuf != NULL) { + // replace line feed with space + for (cp = cmdbuf; *cp != '\0'; ++cp) { + if (*cp == '\r' || *cp == '\n') { + *cp = ' '; + } + } + // only show machine code if BDEBUG defined, since dflag > 3 + printf("machine codes for filter: %s\n", cmdbuf); + } else + printf("machine codes for empty filter:\n"); +#endif + + bpf_dump(&fcode, dflag); + free(cmdbuf); + if (have_fcode) + pcap_freecode (&fcode); + pcap_close(pd); + exit(0); +} + +static void +usage(void) +{ + (void)fprintf(stderr, "%s, with %s\n", program_name, + pcap_lib_version()); + (void)fprintf(stderr, +#ifdef BDEBUG + "Usage: %s [-dgO] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expression ]\n", +#else + "Usage: %s [-dO] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expression ]\n", +#endif + program_name); + exit(1); +} diff --git a/testprogs/findalldevstest.c b/testprogs/findalldevstest.c new file mode 100644 index 000000000000..e535e25462fb --- /dev/null +++ b/testprogs/findalldevstest.c @@ -0,0 +1,311 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#ifdef _WIN32 + #include + #include + #include +#else + #include + #include + #include + #include + #include +#endif + +#include + +#include "pcap/funcattrs.h" + +static int ifprint(pcap_if_t *d); +static char *iptos(bpf_u_int32 in); + +#ifdef _WIN32 +#include "portability.h" + +/* + * Generate a string for a Win32-specific error (i.e. an error generated when + * calling a Win32 API). + * For errors occurred during standard C calls, we still use pcap_strerror() + */ +#define ERRBUF_SIZE 1024 +static const char * +win32_strerror(DWORD error) +{ + static char errbuf[ERRBUF_SIZE+1]; + size_t errlen; + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf, + ERRBUF_SIZE, NULL); + + /* + * "FormatMessage()" "helpfully" sticks CR/LF at the end of the + * message. Get rid of it. + */ + errlen = strlen(errbuf); + if (errlen >= 2) { + errbuf[errlen - 1] = '\0'; + errbuf[errlen - 2] = '\0'; + errlen -= 2; + } + return errbuf; +} + +static char * +getpass(const char *prompt) +{ + HANDLE console_handle = GetStdHandle(STD_INPUT_HANDLE); + DWORD console_mode, save_console_mode; + static char password[128+1]; + char *p; + + fprintf(stderr, "%s", prompt); + + /* + * Turn off echoing. + */ + if (!GetConsoleMode(console_handle, &console_mode)) { + fprintf(stderr, "Can't get console mode: %s\n", + win32_strerror(GetLastError())); + exit(1); + } + save_console_mode = console_mode; + console_mode &= ~ENABLE_ECHO_INPUT; + if (!SetConsoleMode(console_handle, console_mode)) { + fprintf(stderr, "Can't set console mode: %s\n", + win32_strerror(GetLastError())); + exit(1); + } + if (fgets(password, sizeof password, stdin) == NULL) { + fprintf(stderr, "\n"); + SetConsoleMode(console_handle, save_console_mode); + exit(1); + } + fprintf(stderr, "\n"); + SetConsoleMode(console_handle, save_console_mode); + p = strchr(password, '\n'); + if (p != NULL) + *p = '\0'; + return password; +} +#endif + +int main(int argc, char **argv) +{ + pcap_if_t *alldevs; + pcap_if_t *d; + bpf_u_int32 net, mask; + int exit_status = 0; + char errbuf[PCAP_ERRBUF_SIZE+1]; +#ifdef ENABLE_REMOTE + struct pcap_rmtauth auth; + char username[128+1]; + char *p; + char *password; +#endif + +#ifdef ENABLE_REMOTE + if (argc >= 2) + { + if (pcap_findalldevs_ex(argv[1], NULL, &alldevs, errbuf) == -1) + { + /* + * OK, try it with a user name and password. + */ + fprintf(stderr, "User name: "); + if (fgets(username, sizeof username, stdin) == NULL) + exit(1); + p = strchr(username, '\n'); + if (p != NULL) + *p = '\0'; + password = getpass("Password: "); + auth.type = RPCAP_RMTAUTH_PWD; + auth.username = username; + auth.password = password; + if (pcap_findalldevs_ex(argv[1], &auth, &alldevs, errbuf) == -1) + { + fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf); + exit(1); + } + } + } + else +#endif + { + if (pcap_findalldevs(&alldevs, errbuf) == -1) + { + fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf); + exit(1); + } + } + for(d=alldevs;d;d=d->next) + { + if (!ifprint(d)) + exit_status = 2; + } + + if (alldevs != NULL) + { + if (pcap_lookupnet(alldevs->name, &net, &mask, errbuf) < 0) + { + fprintf(stderr,"Error in pcap_lookupnet: %s\n",errbuf); + exit_status = 2; + } + else + { + printf("Preferred device is on network: %s/%s\n",iptos(net), iptos(mask)); + } + } + + pcap_freealldevs(alldevs); + exit(exit_status); +} + +static int ifprint(pcap_if_t *d) +{ + pcap_addr_t *a; + char ipv4_buf[INET_ADDRSTRLEN]; + char ipv6_buf[INET6_ADDRSTRLEN]; + const char *sep; + int status = 1; /* success */ + + printf("%s\n",d->name); + if (d->description) + printf("\tDescription: %s\n",d->description); + printf("\tFlags: "); + sep = ""; + if (d->flags & PCAP_IF_UP) { + printf("%sUP", sep); + sep = ", "; + } + if (d->flags & PCAP_IF_RUNNING) { + printf("%sRUNNING", sep); + sep = ", "; + } + if (d->flags & PCAP_IF_LOOPBACK) { + printf("%sLOOPBACK", sep); + sep = ", "; + } + if (d->flags & PCAP_IF_WIRELESS) { + printf("%sWIRELESS", sep); + switch (d->flags & PCAP_IF_CONNECTION_STATUS) { + + case PCAP_IF_CONNECTION_STATUS_UNKNOWN: + printf(" (association status unknown)"); + break; + + case PCAP_IF_CONNECTION_STATUS_CONNECTED: + printf(" (associated)"); + break; + + case PCAP_IF_CONNECTION_STATUS_DISCONNECTED: + printf(" (not associated)"); + break; + + case PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE: + break; + } + } else { + switch (d->flags & PCAP_IF_CONNECTION_STATUS) { + + case PCAP_IF_CONNECTION_STATUS_UNKNOWN: + printf(" (connection status unknown)"); + break; + + case PCAP_IF_CONNECTION_STATUS_CONNECTED: + printf(" (connected)"); + break; + + case PCAP_IF_CONNECTION_STATUS_DISCONNECTED: + printf(" (disconnected)"); + break; + + case PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE: + break; + } + } + sep = ", "; + printf("\n"); + + for(a=d->addresses;a;a=a->next) { + if (a->addr != NULL) + switch(a->addr->sa_family) { + case AF_INET: + printf("\tAddress Family: AF_INET\n"); + if (a->addr) + printf("\t\tAddress: %s\n", + inet_ntop(AF_INET, + &((struct sockaddr_in *)(a->addr))->sin_addr, + ipv4_buf, sizeof ipv4_buf)); + if (a->netmask) + printf("\t\tNetmask: %s\n", + inet_ntop(AF_INET, + &((struct sockaddr_in *)(a->netmask))->sin_addr, + ipv4_buf, sizeof ipv4_buf)); + if (a->broadaddr) + printf("\t\tBroadcast Address: %s\n", + inet_ntop(AF_INET, + &((struct sockaddr_in *)(a->broadaddr))->sin_addr, + ipv4_buf, sizeof ipv4_buf)); + if (a->dstaddr) + printf("\t\tDestination Address: %s\n", + inet_ntop(AF_INET, + &((struct sockaddr_in *)(a->dstaddr))->sin_addr, + ipv4_buf, sizeof ipv4_buf)); + break; +#ifdef INET6 + case AF_INET6: + printf("\tAddress Family: AF_INET6\n"); + if (a->addr) + printf("\t\tAddress: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->addr))->sin6_addr.s6_addr, + ipv6_buf, sizeof ipv6_buf)); + if (a->netmask) + printf("\t\tNetmask: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->netmask))->sin6_addr.s6_addr, + ipv6_buf, sizeof ipv6_buf)); + if (a->broadaddr) + printf("\t\tBroadcast Address: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->broadaddr))->sin6_addr.s6_addr, + ipv6_buf, sizeof ipv6_buf)); + if (a->dstaddr) + printf("\t\tDestination Address: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->dstaddr))->sin6_addr.s6_addr, + ipv6_buf, sizeof ipv6_buf)); + break; +#endif + default: + printf("\tAddress Family: Unknown (%d)\n", a->addr->sa_family); + break; + } + else + { + fprintf(stderr, "\tWarning: a->addr is NULL, skipping this address.\n"); + status = 0; + } + } + printf("\n"); + return status; +} + +/* From tcptraceroute */ +#define IPTOSBUFFERS 12 +static char *iptos(bpf_u_int32 in) +{ + static char output[IPTOSBUFFERS][3*4+3+1]; + static short which; + u_char *p; + + p = (u_char *)∈ + which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1); + sprintf(output[which], "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); + return output[which]; +} diff --git a/testprogs/opentest.c b/testprogs/opentest.c new file mode 100644 index 000000000000..bad38eb0e9fb --- /dev/null +++ b/testprogs/opentest.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "varattrs.h" + +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include +#ifdef _WIN32 + #include "getopt.h" +#else + #include +#endif +#include + +#include "pcap/funcattrs.h" + +#ifdef _WIN32 + #include "portability.h" +#endif + +#define MAXIMUM_SNAPLEN 65535 + +static char *program_name; + +/* Forwards */ +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); + +int +main(int argc, char **argv) +{ + register int op; + register char *cp, *device; + int dorfmon, dopromisc, snaplen, useactivate, bufsize; + char ebuf[PCAP_ERRBUF_SIZE]; + pcap_if_t *devlist; + pcap_t *pd; + int status = 0; + + device = NULL; + dorfmon = 0; + dopromisc = 0; + snaplen = MAXIMUM_SNAPLEN; + bufsize = 0; + useactivate = 0; + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "i:Ips:aB:")) != -1) { + switch (op) { + + case 'i': + device = optarg; + break; + + case 'I': + dorfmon = 1; + useactivate = 1; /* required for rfmon */ + break; + + case 'p': + dopromisc = 1; + break; + + case 's': { + char *end; + + snaplen = strtol(optarg, &end, 0); + if (optarg == end || *end != '\0' + || snaplen < 0 || snaplen > MAXIMUM_SNAPLEN) + error("invalid snaplen %s", optarg); + else if (snaplen == 0) + snaplen = MAXIMUM_SNAPLEN; + break; + } + + case 'B': + bufsize = atoi(optarg)*1024; + if (bufsize <= 0) + error("invalid packet buffer size %s", optarg); + useactivate = 1; /* required for bufsize */ + break; + + case 'a': + useactivate = 1; + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (device == NULL) { + if (pcap_findalldevs(&devlist, ebuf) == -1) + error("%s", ebuf); + if (devlist == NULL) + error("no interfaces available for capture"); + device = strdup(devlist->name); + pcap_freealldevs(devlist); + } + if (useactivate) { + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s: pcap_create failed: %s", device, ebuf); + status = pcap_set_snaplen(pd, snaplen); + if (status != 0) + error("%s: pcap_set_snaplen failed: %s", + device, pcap_statustostr(status)); + if (dopromisc) { + status = pcap_set_promisc(pd, 1); + if (status != 0) + error("%s: pcap_set_promisc failed: %s", + device, pcap_statustostr(status)); + } + if (dorfmon) { + status = pcap_set_rfmon(pd, 1); + if (status != 0) + error("%s: pcap_set_rfmon failed: %s", + device, pcap_statustostr(status)); + } + status = pcap_set_timeout(pd, 1000); + if (status != 0) + error("%s: pcap_set_timeout failed: %s", + device, pcap_statustostr(status)); + if (bufsize != 0) { + status = pcap_set_buffer_size(pd, bufsize); + if (status != 0) + error("%s: pcap_set_buffer_size failed: %s", + device, pcap_statustostr(status)); + } + status = pcap_activate(pd); + if (status < 0) { + /* + * pcap_activate() failed. + */ + error("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } else if (status > 0) { + /* + * pcap_activate() succeeded, but it's warning us + * of a problem it had. + */ + warning("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } else + printf("%s opened successfully\n", device); + } else { + *ebuf = '\0'; + pd = pcap_open_live(device, 65535, 0, 1000, ebuf); + if (pd == NULL) + error("%s", ebuf); + else if (*ebuf) + warning("%s", ebuf); + else + printf("%s opened successfully\n", device); + } + pcap_close(pd); + exit(status < 0 ? 1 : 0); +} + +static void +usage(void) +{ + (void)fprintf(stderr, + "Usage: %s [ -Ipa ] [ -i interface ] [ -s snaplen ] [ -B bufsize ]\n", + program_name); + exit(1); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} diff --git a/testprogs/reactivatetest.c b/testprogs/reactivatetest.c new file mode 100644 index 000000000000..d7f3e322c175 --- /dev/null +++ b/testprogs/reactivatetest.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "varattrs.h" + +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include + +#include "pcap/funcattrs.h" + +/* Forwards */ +static void PCAP_NORETURN error(PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(1,2); + +int +main(void) +{ + char ebuf[PCAP_ERRBUF_SIZE]; + pcap_t *pd; + int status = 0; + + pd = pcap_open_live("lo0", 65535, 0, 1000, ebuf); + if (pd == NULL) { + pd = pcap_open_live("lo", 65535, 0, 1000, ebuf); + if (pd == NULL) { + error("Neither lo0 nor lo could be opened: %s", + ebuf); + return 2; + } + } + status = pcap_activate(pd); + if (status != PCAP_ERROR_ACTIVATED) { + if (status == 0) + error("pcap_activate() of opened pcap_t succeeded"); + else if (status == PCAP_ERROR) + error("pcap_activate() of opened pcap_t failed with %s, not PCAP_ERROR_ACTIVATED", + pcap_geterr(pd)); + else + error("pcap_activate() of opened pcap_t failed with %s, not PCAP_ERROR_ACTIVATED", + pcap_statustostr(status)); + } + return 0; +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "reactivatetest: "); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} diff --git a/testprogs/selpolltest.c b/testprogs/selpolltest.c new file mode 100644 index 000000000000..329281dc24bc --- /dev/null +++ b/testprogs/selpolltest.c @@ -0,0 +1,443 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "varattrs.h" + +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +/* + * Tests how select() and poll() behave on the selectable file descriptor + * for a pcap_t. + * + * This would be significantly different on Windows, as it'd test + * how WaitForMultipleObjects() would work on the event handle for a + * pcap_t. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_SELECT_H +#include +#else +#include /* older UN*Xes */ +#endif +#include + +#include "pcap/funcattrs.h" + +static char *program_name; + +/* Forwards */ +static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static char *copy_argv(char **); + +static pcap_t *pd; + +int +main(int argc, char **argv) +{ + register int op; + bpf_u_int32 localnet, netmask; + register char *cp, *cmdbuf, *device; + int doselect, dopoll, dotimeout, dononblock; + const char *mechanism; + struct bpf_program fcode; + char ebuf[PCAP_ERRBUF_SIZE]; + pcap_if_t *devlist; + int selectable_fd; + struct timeval *required_timeout; + int status; + int packet_count; + + device = NULL; + doselect = 0; + dopoll = 0; + mechanism = NULL; + dotimeout = 0; + dononblock = 0; + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "i:sptn")) != -1) { + switch (op) { + + case 'i': + device = optarg; + break; + + case 's': + doselect = 1; + mechanism = "select() and pcap_dispatch()"; + break; + + case 'p': + dopoll = 1; + mechanism = "poll() and pcap_dispatch()"; + break; + + case 't': + dotimeout = 1; + break; + + case 'n': + dononblock = 1; + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (doselect && dopoll) { + fprintf(stderr, "selpolltest: choose select (-s) or poll (-p), but not both\n"); + return 1; + } + if (dotimeout && !doselect && !dopoll) { + fprintf(stderr, "selpolltest: timeout (-t) requires select (-s) or poll (-p)\n"); + return 1; + } + if (device == NULL) { + if (pcap_findalldevs(&devlist, ebuf) == -1) + error("%s", ebuf); + if (devlist == NULL) + error("no interfaces available for capture"); + device = strdup(devlist->name); + pcap_freealldevs(devlist); + } + *ebuf = '\0'; + pd = pcap_open_live(device, 65535, 0, 1000, ebuf); + if (pd == NULL) + error("%s", ebuf); + else if (*ebuf) + warning("%s", ebuf); + if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { + localnet = 0; + netmask = 0; + warning("%s", ebuf); + } + cmdbuf = copy_argv(&argv[optind]); + + if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0) + error("%s", pcap_geterr(pd)); + if (pcap_setfilter(pd, &fcode) < 0) + error("%s", pcap_geterr(pd)); + + if (doselect || dopoll) { + /* + * We need either an FD on which to do select()/poll() + * or, if there isn't one, a timeout to use in select()/ + * poll(). + */ + selectable_fd = pcap_get_selectable_fd(pd); + if (selectable_fd == -1) { + printf("Listening on %s, using %s, with a timeout\n", + device, mechanism); + required_timeout = pcap_get_required_select_timeout(pd); + if (required_timeout == NULL) + error("select()/poll() isn't supported on %s, even with a timeout", + device); + + /* + * As we won't be notified by select() or poll() + * that a read can be done, we'll have to periodically + * try reading from the device every time the required + * timeout expires, and we don't want those attempts + * to block if nothing has arrived in that interval, + * so we want to force non-blocking mode. + */ + dononblock = 1; + } else { + printf("Listening on %s, using %s\n", device, + mechanism); + required_timeout = NULL; + } + } else + printf("Listening on %s, using pcap_dispatch()\n", device); + + if (dononblock) { + if (pcap_setnonblock(pd, 1, ebuf) == -1) + error("pcap_setnonblock failed: %s", ebuf); + } + if (doselect) { + for (;;) { + fd_set setread, setexcept; + struct timeval seltimeout; + + FD_ZERO(&setread); + if (selectable_fd != -1) { + FD_SET(selectable_fd, &setread); + FD_ZERO(&setexcept); + FD_SET(selectable_fd, &setexcept); + } + if (dotimeout) { + seltimeout.tv_sec = 0; + if (required_timeout != NULL && + required_timeout->tv_usec < 1000) + seltimeout.tv_usec = required_timeout->tv_usec; + else + seltimeout.tv_usec = 1000; + status = select(selectable_fd + 1, &setread, + NULL, &setexcept, &seltimeout); + } else if (required_timeout != NULL) { + seltimeout = *required_timeout; + status = select(selectable_fd + 1, &setread, + NULL, &setexcept, &seltimeout); + } else { + status = select((selectable_fd == -1) ? + 0 : selectable_fd + 1, &setread, + NULL, &setexcept, NULL); + } + if (status == -1) { + printf("Select returns error (%s)\n", + strerror(errno)); + } else { + if (selectable_fd == -1) { + if (status != 0) + printf("Select returned a descriptor\n"); + } else { + if (status == 0) + printf("Select timed out: "); + else + printf("Select returned a descriptor: "); + if (FD_ISSET(selectable_fd, &setread)) + printf("readable, "); + else + printf("not readable, "); + if (FD_ISSET(selectable_fd, &setexcept)) + printf("exceptional condition\n"); + else + printf("no exceptional condition\n"); + } + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + /* + * Don't report this if we're using a + * required timeout and we got no packets, + * because that could be a very short timeout, + * and we don't want to spam the user with + * a ton of "no packets" reports. + */ + if (status != 0 || packet_count != 0 || + required_timeout != NULL) { + printf("%d packets seen, %d packets counted after select returns\n", + status, packet_count); + } + } + } + } else if (dopoll) { + for (;;) { + struct pollfd fd; + int polltimeout; + + fd.fd = selectable_fd; + fd.events = POLLIN; + if (dotimeout) + polltimeout = 1; + else if (required_timeout != NULL && + required_timeout->tv_usec >= 1000) + polltimeout = required_timeout->tv_usec/1000; + else + polltimeout = -1; + status = poll(&fd, (selectable_fd == -1) ? 0 : 1, polltimeout); + if (status == -1) { + printf("Poll returns error (%s)\n", + strerror(errno)); + } else { + if (selectable_fd == -1) { + if (status != 0) + printf("Poll returned a descriptor\n"); + } else { + if (status == 0) + printf("Poll timed out\n"); + else { + printf("Poll returned a descriptor: "); + if (fd.revents & POLLIN) + printf("readable, "); + else + printf("not readable, "); + if (fd.revents & POLLERR) + printf("exceptional condition, "); + else + printf("no exceptional condition, "); + if (fd.revents & POLLHUP) + printf("disconnect, "); + else + printf("no disconnect, "); + if (fd.revents & POLLNVAL) + printf("invalid\n"); + else + printf("not invalid\n"); + } + } + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + /* + * Don't report this if we're using a + * required timeout and we got no packets, + * because that could be a very short timeout, + * and we don't want to spam the user with + * a ton of "no packets" reports. + */ + if (status != 0 || packet_count != 0 || + required_timeout != NULL) { + printf("%d packets seen, %d packets counted after poll returns\n", + status, packet_count); + } + } + } + } else { + for (;;) { + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + printf("%d packets seen, %d packets counted after pcap_dispatch returns\n", + status, packet_count); + } + } + if (status == -2) { + /* + * We got interrupted, so perhaps we didn't + * manage to finish a line we were printing. + * Print an extra newline, just in case. + */ + putchar('\n'); + } + (void)fflush(stdout); + if (status == -1) { + /* + * Error. Report it. + */ + (void)fprintf(stderr, "%s: pcap_loop: %s\n", + program_name, pcap_geterr(pd)); + } + pcap_close(pd); + exit(status == -1 ? 1 : 0); +} + +static void +countme(u_char *user, const struct pcap_pkthdr *h _U_, const u_char *sp _U_) +{ + int *counterp = (int *)user; + + (*counterp)++; +} + +static void +usage(void) +{ + (void)fprintf(stderr, "Usage: %s [ -sptn ] [ -i interface ] [expression]\n", + program_name); + exit(1); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register u_int len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} diff --git a/testprogs/threadsignaltest.c b/testprogs/threadsignaltest.c new file mode 100644 index 000000000000..a60bb49523fb --- /dev/null +++ b/testprogs/threadsignaltest.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "varattrs.h" + +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include +#ifdef _WIN32 + #include + #include + + #define THREAD_HANDLE HANDLE + #define THREAD_FUNC_ARG_TYPE LPVOID + #define THREAD_FUNC_RETURN_TYPE DWORD __stdcall + + #include "getopt.h" +#else + #include + #include + #include + + #define THREAD_HANDLE pthread_t + #define THREAD_FUNC_ARG_TYPE void * + #define THREAD_FUNC_RETURN_TYPE void * +#endif +#include +#include + +#include + +#include "pcap/funcattrs.h" + +#ifdef _WIN32 + #include "portability.h" +#endif + +static char *program_name; + +/* Forwards */ +static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static char *copy_argv(char **); + +static pcap_t *pd; + +#ifdef _WIN32 +/* + * Generate a string for a Win32-specific error (i.e. an error generated when + * calling a Win32 API). + * For errors occurred during standard C calls, we still use pcap_strerror() + */ +#define ERRBUF_SIZE 1024 +static const char * +win32_strerror(DWORD error) +{ + static char errbuf[ERRBUF_SIZE+1]; + size_t errlen; + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf, + ERRBUF_SIZE, NULL); + + /* + * "FormatMessage()" "helpfully" sticks CR/LF at the end of the + * message. Get rid of it. + */ + errlen = strlen(errbuf); + if (errlen >= 2) { + errbuf[errlen - 1] = '\0'; + errbuf[errlen - 2] = '\0'; + errlen -= 2; + } + return errbuf; +} +#else +static void +catch_sigusr1(int sig _U_) +{ + printf("Got SIGUSR1\n"); +} +#endif + +static void +sleep_secs(int secs) +{ +#ifdef _WIN32 + Sleep(secs*1000); +#else + unsigned secs_remaining; + + if (secs <= 0) + return; + secs_remaining = secs; + while (secs_remaining != 0) + secs_remaining = sleep(secs_remaining); +#endif +} + +static THREAD_FUNC_RETURN_TYPE +capture_thread_func(THREAD_FUNC_ARG_TYPE arg) +{ + char *device = arg; + int packet_count; + int status; +#ifndef _WIN32 + struct sigaction action; + sigset_t mask; +#endif + +#ifndef _WIN32 + sigemptyset(&mask); + action.sa_handler = catch_sigusr1; + action.sa_mask = mask; + action.sa_flags = 0; + if (sigaction(SIGUSR1, &action, NULL) == -1) + error("Can't catch SIGUSR1: %s", strerror(errno)); +#endif + + printf("Listening on %s\n", device); + for (;;) { + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + if (status != 0) { + printf("%d packets seen, %d packets counted after pcap_dispatch returns\n", + status, packet_count); + } else + printf("No packets seen by pcap_dispatch\n"); + } + if (status == -2) { + /* + * We got interrupted, so perhaps we didn't + * manage to finish a line we were printing. + * Print an extra newline, just in case. + */ + putchar('\n'); + printf("Loop got broken\n"); + } + (void)fflush(stdout); + if (status == -1) { + /* + * Error. Report it. + */ + (void)fprintf(stderr, "%s: pcap_loop: %s\n", + program_name, pcap_geterr(pd)); + } + return 0; +} + +int +main(int argc, char **argv) +{ + register int op; + register char *cp, *cmdbuf, *device; + int immediate = 0; + pcap_if_t *devlist; + bpf_u_int32 localnet, netmask; + struct bpf_program fcode; + char ebuf[PCAP_ERRBUF_SIZE]; + int status; + THREAD_HANDLE capture_thread; +#ifndef _WIN32 + void *retval; +#endif + + device = NULL; + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "i:")) != -1) { + switch (op) { + + case 'i': + device = optarg; + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (device == NULL) { + if (pcap_findalldevs(&devlist, ebuf) == -1) + error("%s", ebuf); + if (devlist == NULL) + error("no interfaces available for capture"); + device = strdup(devlist->name); + pcap_freealldevs(devlist); + } + *ebuf = '\0'; + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s", ebuf); + status = pcap_set_snaplen(pd, 65535); + if (status != 0) + error("%s: pcap_set_snaplen failed: %s", + device, pcap_statustostr(status)); + if (immediate) { + status = pcap_set_immediate_mode(pd, 1); + if (status != 0) + error("%s: pcap_set_immediate_mode failed: %s", + device, pcap_statustostr(status)); + } + status = pcap_set_timeout(pd, 5*60*1000); + if (status != 0) + error("%s: pcap_set_timeout failed: %s", + device, pcap_statustostr(status)); + status = pcap_activate(pd); + if (status < 0) { + /* + * pcap_activate() failed. + */ + error("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } else if (status > 0) { + /* + * pcap_activate() succeeded, but it's warning us + * of a problem it had. + */ + warning("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } + if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { + localnet = 0; + netmask = 0; + warning("%s", ebuf); + } + cmdbuf = copy_argv(&argv[optind]); + + if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0) + error("%s", pcap_geterr(pd)); + + if (pcap_setfilter(pd, &fcode) < 0) + error("%s", pcap_geterr(pd)); + +#ifdef _WIN32 + capture_thread = CreateThread(NULL, 0, capture_thread_func, device, + 0, NULL); + if (capture_thread == NULL) + error("Can't create capture thread: %s", + win32_strerror(GetLastError())); +#else + status = pthread_create(&capture_thread, NULL, capture_thread_func, + device); + if (status != 0) + error("Can't create capture thread: %s", strerror(status)); +#endif + sleep_secs(60); + pcap_breakloop(pd); +#ifdef _WIN32 + printf("Setting event\n"); + if (!SetEvent(pcap_getevent(pd))) + error("Can't set event for pcap_t: %s", + win32_strerror(GetLastError())); + if (WaitForSingleObject(capture_thread, INFINITE) == WAIT_FAILED) + error("Wait for thread termination failed: %s", + win32_strerror(GetLastError())); + CloseHandle(capture_thread); +#else + printf("Sending SIGUSR1\n"); + status = pthread_kill(capture_thread, SIGUSR1); + if (status != 0) + warning("Can't interrupt capture thread: %s", strerror(status)); + status = pthread_join(capture_thread, &retval); + if (status != 0) + error("Wait for thread termination failed: %s", + strerror(status)); +#endif + + pcap_close(pd); + pcap_freecode(&fcode); + exit(status == -1 ? 1 : 0); +} + +static void +countme(u_char *user, const struct pcap_pkthdr *h _U_, const u_char *sp _U_) +{ + int *counterp = (int *)user; + + (*counterp)++; +} + +static void +usage(void) +{ + (void)fprintf(stderr, "Usage: %s [ -m ] [ -i interface ] [ -t timeout] [expression]\n", + program_name); + exit(1); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register u_int len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} diff --git a/testprogs/unix.h b/testprogs/unix.h new file mode 100644 index 000000000000..68ef4cb92a6a --- /dev/null +++ b/testprogs/unix.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef unix_h +#define unix_h + +/* + * Definitions to make MSVC C runtime library structures and functions + * look like the UNIX structures and functions they are intended to + * resemble. + */ +#ifdef _MSC_VER + #define stat _stat + #define fstat _fstat + + #define open _open + #define O_RDONLY _O_RDONLY + #define O_WRONLY _O_WRONLY + #define O_RDWR _O_RDWR + #define O_BINARY _O_BINARY + #define O_CREAT _O_CREAT + #define O_TRUNC _O_TRUNC + #define read _read + #define write _write + #define close _close +#endif + +#endif diff --git a/testprogs/valgrindtest.c b/testprogs/valgrindtest.c new file mode 100644 index 000000000000..104ef6a9feaa --- /dev/null +++ b/testprogs/valgrindtest.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "varattrs.h" + +/* + * This doesn't actually test libpcap itself; it tests whether + * valgrind properly handles the APIs libpcap uses. If it doesn't, + * we end up getting patches submitted to "fix" references that + * valgrind claims are being made to uninitialized data, when, in + * fact, the OS isn't making any such references - or we get + * valgrind *not* detecting *actual* incorrect references. + * + * Both BPF and Linux socket filters aren't handled correctly + * by some versions of valgrind. See valgrind bug 318203 for + * Linux: + * + * https://bugs.kde.org/show_bug.cgi?id=318203 + * + * and valgrind bug 312989 for macOS: + * + * https://bugs.kde.org/show_bug.cgi?id=312989 + * + * The fixes for both of those are checked into the official valgrind + * repository. + * + * The unofficial FreeBSD port has similar issues to the official macOS + * port, for similar reasons. + */ +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcap/funcattrs.h" + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(_AIX) || defined(sun) +/* OS with BPF - use BPF */ +#define USE_BPF +#elif defined(linux) +/* Linux - use socket filters */ +#define USE_SOCKET_FILTERS +#else +#error "Unknown platform or platform that doesn't support Valgrind" +#endif + +#if defined(USE_BPF) + +#include +#include + +/* + * Make "pcap.h" not include "pcap/bpf.h"; we are going to include the + * native OS version, as we're going to be doing our own ioctls to + * make sure that, in the uninitialized-data tests, the filters aren't + * checked by libpcap before being handed to BPF. + */ +#define PCAP_DONT_INCLUDE_PCAP_BPF_H + +#elif defined(USE_SOCKET_FILTERS) + +#include +#include +#include + +#endif + +#include + +static char *program_name; + +/* Forwards */ +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); + +/* + * On Windows, we need to open the file in binary mode, so that + * we get all the bytes specified by the size we get from "fstat()". + * On UNIX, that's not necessary. O_BINARY is defined on Windows; + * we define it as 0 if it's not defined, so it does nothing. + */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +static char * +read_infile(char *fname) +{ + register int i, fd, cc; + register char *cp; + struct stat buf; + + fd = open(fname, O_RDONLY|O_BINARY); + if (fd < 0) + error("can't open %s: %s", fname, pcap_strerror(errno)); + + if (fstat(fd, &buf) < 0) + error("can't stat %s: %s", fname, pcap_strerror(errno)); + + cp = malloc((u_int)buf.st_size + 1); + if (cp == NULL) + error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, + fname, pcap_strerror(errno)); + cc = read(fd, cp, (u_int)buf.st_size); + if (cc < 0) + error("read %s: %s", fname, pcap_strerror(errno)); + if (cc != buf.st_size) + error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); + + close(fd); + /* replace "# comment" with spaces */ + for (i = 0; i < cc; i++) { + if (cp[i] == '#') + while (i < cc && cp[i] != '\n') + cp[i++] = ' '; + } + cp[cc] = '\0'; + return (cp); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register u_int len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} + +#define INSN_COUNT 17 + +int +main(int argc, char **argv) +{ + char *cp, *device; + int op; + int dorfmon, useactivate; + char ebuf[PCAP_ERRBUF_SIZE]; + char *infile; + const char *cmdbuf; + pcap_if_t *devlist; + pcap_t *pd; + int status = 0; + int pcap_fd; +#if defined(USE_BPF) + struct bpf_program bad_fcode; + struct bpf_insn uninitialized[INSN_COUNT]; +#elif defined(USE_SOCKET_FILTERS) + struct sock_fprog bad_fcode; + struct sock_filter uninitialized[INSN_COUNT]; +#endif + struct bpf_program fcode; + + device = NULL; + dorfmon = 0; + useactivate = 0; + infile = NULL; + + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "aF:i:I")) != -1) { + switch (op) { + + case 'a': + useactivate = 1; + break; + + case 'F': + infile = optarg; + break; + + case 'i': + device = optarg; + break; + + case 'I': + dorfmon = 1; + useactivate = 1; /* required for rfmon */ + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (device == NULL) { + /* + * No interface specified; get whatever pcap_lookupdev() + * finds. + */ + if (pcap_findalldevs(&devlist, ebuf) == -1) + error("%s", ebuf); + if (devlist == NULL) + error("no interfaces available for capture"); + device = strdup(devlist->name); + pcap_freealldevs(devlist); + } + + if (infile != NULL) { + /* + * Filter specified with "-F" and a file containing + * a filter. + */ + cmdbuf = read_infile(infile); + } else { + if (optind < argc) { + /* + * Filter specified with arguments on the + * command line. + */ + cmdbuf = copy_argv(&argv[optind+1]); + } else { + /* + * No filter specified; use an empty string, which + * compiles to an "accept all" filter. + */ + cmdbuf = ""; + } + } + + if (useactivate) { + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s: pcap_create() failed: %s", device, ebuf); + status = pcap_set_snaplen(pd, 65535); + if (status != 0) + error("%s: pcap_set_snaplen failed: %s", + device, pcap_statustostr(status)); + status = pcap_set_promisc(pd, 1); + if (status != 0) + error("%s: pcap_set_promisc failed: %s", + device, pcap_statustostr(status)); + if (dorfmon) { + status = pcap_set_rfmon(pd, 1); + if (status != 0) + error("%s: pcap_set_rfmon failed: %s", + device, pcap_statustostr(status)); + } + status = pcap_set_timeout(pd, 1000); + if (status != 0) + error("%s: pcap_set_timeout failed: %s", + device, pcap_statustostr(status)); + status = pcap_activate(pd); + if (status < 0) { + /* + * pcap_activate() failed. + */ + error("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } else if (status > 0) { + /* + * pcap_activate() succeeded, but it's warning us + * of a problem it had. + */ + warning("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } + } else { + *ebuf = '\0'; + pd = pcap_open_live(device, 65535, 1, 1000, ebuf); + if (pd == NULL) + error("%s", ebuf); + else if (*ebuf) + warning("%s", ebuf); + } + + pcap_fd = pcap_fileno(pd); + + /* + * Try setting a filter with an uninitialized bpf_program + * structure. This should cause valgrind to report a + * problem. + * + * We don't check for errors, because it could get an + * error due to a bad pointer or count. + */ +#if defined(USE_BPF) + ioctl(pcap_fd, BIOCSETF, &bad_fcode); +#elif defined(USE_SOCKET_FILTERS) + setsockopt(pcap_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bad_fcode, + sizeof(bad_fcode)); +#endif + + /* + * Try setting a filter with an initialized bpf_program + * structure that points to an uninitialized program. + * That should also cause valgrind to report a problem. + * + * We don't check for errors, because it could get an + * error due to a bad pointer or count. + */ +#if defined(USE_BPF) + bad_fcode.bf_len = INSN_COUNT; + bad_fcode.bf_insns = uninitialized; + ioctl(pcap_fd, BIOCSETF, &bad_fcode); +#elif defined(USE_SOCKET_FILTERS) + bad_fcode.len = INSN_COUNT; + bad_fcode.filter = uninitialized; + setsockopt(pcap_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bad_fcode, + sizeof(bad_fcode)); +#endif + + /* + * Now compile a filter and set the filter with that. + * That should *not* cause valgrind to report a + * problem. + */ + if (pcap_compile(pd, &fcode, cmdbuf, 1, 0) < 0) + error("can't compile filter: %s", pcap_geterr(pd)); + if (pcap_setfilter(pd, &fcode) < 0) + error("can't set filter: %s", pcap_geterr(pd)); + + pcap_close(pd); + exit(status < 0 ? 1 : 0); +} + +static void +usage(void) +{ + (void)fprintf(stderr, "%s, with %s\n", program_name, + pcap_lib_version()); + (void)fprintf(stderr, + "Usage: %s [-aI] [ -F file ] [ -I interface ] [ expression ]\n", + program_name); + exit(1); +}