diff options
72 files changed, 3900 insertions, 1634 deletions
diff --git a/.appveyor.yml b/.appveyor.yml index fe3f547e..7b1f9f2a 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -15,8 +15,8 @@ install: - win_bison --version - appveyor DownloadFile https://www.winpcap.org/install/bin/WpdPack_4_1_2.zip - 7z x .\WpdPack_4_1_2.zip -oc:\projects\libpcap\Win32 - - appveyor DownloadFile https://npcap.com/dist/npcap-sdk-1.12.zip - - 7z x .\npcap-sdk-1.12.zip -oc:\projects\libpcap\Win32\npcap-sdk-1.12 + - appveyor DownloadFile https://npcap.com/dist/npcap-sdk-1.13.zip + - 7z x .\npcap-sdk-1.13.zip -oc:\projects\libpcap\Win32\npcap-sdk-1.13 - appveyor DownloadFile https://support.riverbed.com/bin/support/download?sid=l3vk3eu649usgu3rj60uncjqqu -FileName AirPcap_Devpack.zip - 7z x .\AirPcap_Devpack.zip -oc:\projects\libpcap\Win32 @@ -28,15 +28,6 @@ environment: AIRPCAP: -DDISABLE_AIRPCAP=YES MINGW_ROOT: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - GENERATOR: "MinGW Makefiles" - SDK: npcap-sdk-1.12 - AIRPCAP: -DDISABLE_AIRPCAP=YES - MINGW_ROOT: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0 - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - GENERATOR: "Visual Studio 14 2015" - SDK: WpdPack - AIRPCAP: -DDISABLE_AIRPCAP=YES - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 GENERATOR: "Visual Studio 14 2015 Win64" SDK: WpdPack AIRPCAP: -DDISABLE_AIRPCAP=YES diff --git a/.cirrus.yml b/.cirrus.yml index 5cbb9bea..fda4052b 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -10,15 +10,15 @@ freebsd_task: - image_family: freebsd-12-3 cpu: 2 memory: 2G - - image_family: freebsd-13-0 + - image_family: freebsd-13-1 cpu: 4 memory: 4G env: IGNORE_OSVERSION: yes MAKEFLAGS: -j 4 - MATRIX_CC: clang gcc11 + MATRIX_CC: clang14 gcc12 script: - - pkg install -qy autoconf gcc11 + - pkg install -qy autoconf gcc12 llvm14 - pkg install -qy cmake git-tiny # for build_matrix.sh and build.sh - ./build_matrix.sh @@ -26,17 +26,17 @@ linux_task: name: linux-amd64 only_if: $CIRRUS_BRANCH != 'coverity_scan' container: - image: ubuntu:20.04 + image: ubuntu:22.04 cpu: 2 memory: 1G env: DEBIAN_FRONTEND: noninteractive MAKEFLAGS: -j 3 script: - - apt-get -qy update - - apt-get -qy install libdbus-1-dev libbluetooth-dev libnl-genl-3-dev libibverbs-dev - - apt-get -qy install flex bison autoconf make clang gcc valgrind - - apt-get -qy install cmake git bc # for build_matrix.sh and build.sh + - apt-get -qy update >/dev/null + - apt-get -qy install libdbus-1-dev libbluetooth-dev libnl-genl-3-dev libibverbs-dev >/dev/null + - apt-get -qy install flex bison autoconf make clang gcc valgrind >/dev/null + - apt-get -qy install cmake git bc >/dev/null # for build_matrix.sh and build.sh - apt list --installed 'lib*-dev' - ./build_matrix.sh @@ -51,11 +51,22 @@ macos_task: - brew update >/dev/null - ./build_matrix.sh +# +# Just testing for now. +# +windows_task: + name: windows-amd64 + only_if: $CIRRUS_BRANCH != 'coverity_scan' + windows_container: + image: cirrusci/windowsservercore:2019 + script: + - set/? + coverity_task: name: Coverity Scan only_if: $CIRRUS_BRANCH == 'coverity_scan' container: - image: ubuntu:20.04 + image: ubuntu:22.04 cpu: 2 memory: 2G env: @@ -66,9 +77,9 @@ coverity_task: COVERITY_SCAN_BUILD_COMMAND_PREPEND: ./configure --enable-remote COVERITY_SCAN_BUILD_COMMAND: make script: - - apt-get -qy update - - apt-get -qy install libdbus-1-dev libbluetooth-dev libnl-genl-3-dev libibverbs-dev - - apt-get -qy install flex bison autoconf make gcc - - apt-get -qy install git curl wget ruby rubygems ruby-json # for the coverity script + - apt-get -qy update >/dev/null + - apt-get -qy install libdbus-1-dev libbluetooth-dev libnl-genl-3-dev libibverbs-dev >/dev/null + - apt-get -qy install flex bison autoconf make gcc >/dev/null + - apt-get -qy install git curl wget ruby rubygems ruby-json >/dev/null # for the coverity script - apt list --installed 'lib*-dev' - ./.ci-coverity-scan-build.sh @@ -36,6 +36,7 @@ os-proto.h pcap-config pcap-filter.manmisc pcap-linktype.manmisc +cbpf-savefile.manfile pcap-savefile.manfile pcap-tstamp.manmisc pcap.3pcap @@ -1,18 +1,29 @@ Monthday, Month DD, YYYY: Summary for 1.11.0 libpcap release (so far!) + Source code: + Use C99 fixed-width integer types, rather than self-defiined + fixed-width integer types, in rpcap code. Link-layer types: Add LINKTYPE_ETW/DLT_ETW. Add LINKTYPE_NETANALYZER_NG/DLT_NETANALYZER_NG (pull request #1008). Add LINKTYPE_ZBOSS_NCP/DLT_ZBOSS_NCP. + Add LINKTYPE_USB_2_0_LOW_SPEED/DLT_USB_2_0_LOW_SPEED, + LINKTYPE_USB_2_0_FULL_SPEED/DLT_USB_2_0_FULL_SPEED, + LINKTYPE_USB_2_0_HIGH_SPEED/DLT_USB_2_0_HIGH_SPEED Packet filtering: Add support for Block Ack Req and Block Ack frame types (pull request #1039). + Deprecate pcap_compile_nopcap(). Savefiles: Reject pcap files where one of the reserved fields in the "link-layer type plus other stuff" is non-zero. rpcap: Support user names and passwords in rpcap:// and rpcaps:// URLs. + Documentation: + Document a standard format for writing out BPF filter programs. + Building and testing: + Remove awk code from mkdep. Monthday, Month DD, YYYY: Summary for 1.10.2 libpcap release (so far!) @@ -24,9 +35,10 @@ Monthday, Month DD, YYYY: arrange for it to be used in Darwin releases. Use AS_HELP_STRING for --enable-remote. Fix some formatting string issues found by cppcheck. - Squelch some CMake warnings. Various small code and comment cleanups. - Fix diag-control.h to handle compiling with clang-cl. + Use PCAP_ERROR (defined as -1) rather than explicit -1 for + functions the documentation says return PCAP_ERROR. + Remove unused code from the filter compiler. Savefiles: Fix pcap_dispatch() to return number of packets processed, rather than 0, even at EOF. @@ -36,6 +48,8 @@ Monthday, Month DD, YYYY: when reading a LINKTYPE_PFLOG file. Put CAN ID field in CAN pseudo-headers for LINUX_SLL2, as we do for LINUX_SLL. + Fix inorrectly-computed "real" length for isochronous USB + transfers when reading savefiles. Capture: Never process more than INT_MAX packets in a pcap_dispatch() call, to avoid integer overflow (issue #1087). @@ -44,9 +58,10 @@ Monthday, Month DD, YYYY: Packet filtering: Get PFLOG header length from the length value in the header. Support all the direction, reason, and action types supported by - all systems that sypport PFLOG. + all systems that support PFLOG. Don't require PFLOG support on the target machine in order to support PFLOG filtering (also fixes issue #1076). + Expand abbreviations into "proto X" properly. Linux: Fix memory leak in capture device open (pull request #1038). Fix detection of CAN/CAN FD packets in direction check (issue @@ -63,10 +78,15 @@ Monthday, Month DD, YYYY: Fix handling of VLAN tagged packets if the link-layer type is changed from DLT_LINUX_SLL to DLT_LINUX_SLL2 (see issue #1105). Always turn on PACKET_AUXDATA (see issue #1105). + Make sure there's reserved space for a DLT_LINUX_SLL2 header + when capturing. + Correctly compute the "real" length for isochronous USB transfers. BPF capture (*BSD, macOS, AIX, Solaris 11): Fix case where a device open might fail, rather than falling back to a smaller buffer size, when the initial buffer size is too big. + Use an unsigned device number to iterate over BPF devices, to + squelch a compiler warning. NetBSD: Fix handling of LINKTYPE_HDLC/DLT_HDLC. rpcap: @@ -74,6 +94,8 @@ Monthday, Month DD, YYYY: Fix code to process port number. Clean up findalldevs code in rpcapd. Clean up bufferizing code. + Fix a file descriptor/handle leak in pcap_findalldevs_ex() + (Coverity CID 1507240). Windows: Add support for NdisMediumIP (pull request #1027). Don't require applications using pcap to be built with VS 2015 or @@ -97,6 +119,7 @@ Monthday, Month DD, YYYY: Haiku: Implement pcap_lib_version(), as now required. Handle negative or too-large snaplen values. + Fix various build issues and warnings. Building and testing: Update configure-time universal build checks for macOS. Update config.guess and config.sub. @@ -123,7 +146,20 @@ Monthday, Month DD, YYYY: Use pkg-config first when checking for libibverbs. Have CMake warn if no capture mechanism can be found. Don't do stuff requiring 3.19 or later on earlier CMakes. + Squelch some CMake warnings. + Fix diag-control.h to handle compiling with clang-cl (issues + #1101 and #1115). Cleanup various leftover cruft in the configure script. + Fix building without protochain support. (GH #852) + Check for a usable YACC (or Bison) and {F}lex in CMake, as we do + in autotools. + Only check for a C++ compiler on Haiku, as that's the only + platform with C++ code, and make sure they generate code for + the same instruction set bit-width (both 32-bit or both 64-bit) + (issue #1112). + On Solaris, check the target bit-width and set PKG_CONFIG_PATH + appropriately, to handle the mess that is the D-Bus library + package (issue #1112). Documentation: Add README.solaris.md. Add SCTP to pcap-filter(7). @@ -136,6 +172,9 @@ Monthday, Month DD, YYYY: the web site. Clean up man pages. Move README.capture-module to the web site. + Improve some protocol details in pcap-filter(7). + Refine "relop" notes in pcap-filter(7). + In pcap-filter(7) "domain" is an id. Wednesday, June 9, 2021: Summary for 1.10.1 libpcap release: @@ -373,7 +412,7 @@ Sunday, July 22, 2018 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) + Check only VID in VLAN test in filters (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) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d8fe5d9..b8cdcb82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,129 @@ endif() set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) -project(pcap) +# +# We only need a C++ compiler for Haiku; all code except for its +# pcap module is in C. +# +# We do that by specifying just C in the project() call and, after +# that finishes, checking for Haiku and, if we're building for +# Haiku, use enable_language() to check for C++. This means that +# we don't require a C++ compiler on platforms other than Haiku. +# +# CMAKE_SYSTEM_NAME is set by project(), so we can't do this by +# testing CMAKE_SYSTEM_NAME and then passing different language +# lists to project() based on the system. +# +project(pcap C) +if(CMAKE_SYSTEM_NAME STREQUAL "Haiku") + enable_language(CXX) + + # + # OK, this is a royal pain. + # + # CMake will try to determine the sizes of some data types, including + # void *, early in the process of configuration; apparently, it's done + # as part of processing the project() command. + # + # At least as of CMake 2.8.6, it does so by checking the size of + # "void *" in C, setting CMAKE_C_SIZEOF_DATA_PTR based on that, + # setting CMAKE_SIZEOF_VOID_P to that, and then checking the size + # of "void *" in C++, setting CMAKE_CXX_SIZEOF_DATA_PTR based on + # that, and then setting CMAKE_SIZEOF_VOID_P to *that*. + # + # The compile tests include whatever C flags may have been provided + # to CMake in the CFLAGS and CXXFLAGS environment variables. + # + # If you set an architecture flag such as -m32 or -m64 in CFLAGS + # but *not* in CXXFLAGS, the size for C++ will win, and hilarity + # will ensue. + # + # Or if, at least on Solaris, you have a newer version of GCC + # installed, but *not* a newer version of G++, and you have Oracle + # Studio installed, it will find GCC, which will default to building + # 64-bit, and Oracle Studio's C++ compiler, which will default to + # building 32-bit, the size for C++ will win, and, again, hilarity + # will ensue. + # + # So we make sure both languages have the same pointer sizes with + # the flags they're given; if they don't, it means that the + # compilers for the languages will, with those flags, not produce + # code that can be linked together. + # + # This is unlikely to happen on Haiku, but it *has* happened on + # Solaris; we do this for future-proofing, in case we ever need + # C++ on a platform where that can happen. + # + if(NOT ${CMAKE_C_SIZEOF_DATA_PTR} EQUAL ${CMAKE_CXX_SIZEOF_DATA_PTR}) + message(FATAL_ERROR +"C compiler ${CMAKE_C_COMPILER} produces code with \ +${CMAKE_C_SIZEOF_DATA_PTR}-byte pointers while C++ compiler \ +${CMAKE_CXX_COMPILER} produces code with \ +${CMAKE_CXX_SIZEOF_DATA_PTR}-byte pointers. \ +This prevents code in these languages from being combined.") + endif() +endif() + +# +# Solaris pkg-config is annoying. For at least one package (D-Bus, I'm +# looking at *you*!), there are separate include files for 32-bit and +# 64-bit builds (I guess using "unsigned long long" as a 64-bit integer +# type on a 64-bit build is like crossing the beams or soething), and +# there are two separate .pc files, so if we're doing a 32-bit build we +# should make sure we look in /usr/lib/pkgconfig for .pc files and if +# we're doing a 64-bit build we should make sure we look in +# /usr/lib/amd64/pkgconfig for .pc files. +# +if(CMAKE_SYSTEM_NAME STREQUAL "SunOS" AND CMAKE_SYSTEM_VERSION MATCHES "5[.][0-9.]*") + # + # Note: string(REPLACE) does not appear to support using ENV{...} + # as an argument, so we set a variable and then use set() to set + # the environment variable. + # + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + # + # 64-bit build. If /usr/lib/pkgconfig appears in the path, + # prepend /usr/lib/amd64/pkgconfig to it; otherwise, + # put /usr/lib/amd64 at the end. + # + if((NOT DEFINED ENV{PKG_CONFIG_PATH}) OR "$ENV{PKG_CONFIG_PATH}" EQUAL "") + # + # Not set, or empty. Set it to /usr/lib/amd64/pkgconfig. + # + set(fixed_path "/usr/lib/amd64/pkgconfig") + elseif("$ENV{PKG_CONFIG_PATH}" MATCHES "/usr/lib/pkgconfig") + # + # It contains /usr/lib/pkgconfig. Prepend + # /usr/lib/amd64/pkgconfig to /usr/lib/pkgconfig. + # + string(REPLACE "/usr/lib/pkgconfig" + "/usr/lib/amd64/pkgconfig:/usr/lib/pkgconfig" + fixed_path "$ENV{PKG_CONFIG_PATH}") + else() + # + # Not empty, but doesn't contain /usr/lib/pkgconfig. + # Append /usr/lib/amd64/pkgconfig to it. + # + set(fixed_path "$ENV{PKG_CONFIG_PATH}:/usr/lib/amd64/pkgconfig") + endif() + set(ENV{PKG_CONFIG_PATH} "${fixed_path}") + elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) + # + # 32-bit build. If /usr/amd64/lib/pkgconfig appears in the path, + # prepend /usr/lib/pkgconfig to it. + # + if("$ENV{PKG_CONFIG_PATH}" MATCHES "/usr/lib/amd64/pkgconfig") + # + # It contains /usr/lib/amd64/pkgconfig. Prepend + # /usr/lib/pkgconfig to /usr/lib/amd64/pkgconfig. + # + string(REPLACE "/usr/lib/amd64/pkgconfig" + "/usr/lib/pkgconfig:/usr/lib/amd64/pkgconfig" + fixed_path "$ENV{PKG_CONFIG_PATH}") + set(ENV{PKG_CONFIG_PATH} "${fixed_path}") + endif() + endif() +endif() include(CheckCCompilerFlag) @@ -580,6 +702,15 @@ else(WIN32) set(PCAP_LINK_LIBRARIES str ${PCAP_LINK_LIBRARIES}) endif(LIBSTR_HAS_PUTMSG) endif(NOT STDLIBS_HAVE_PUTMSG) + + # Haiku has getpass in libbsd + check_function_exists(getpass STDLIBS_HAVE_GETPASS) + if(NOT STDLIBS_HAVE_GETPASS) + check_library_exists(bsd getpass "" LIBBSD_HAS_GETPASS) + if(LIBBSD_HAS_GETPASS) + set(PCAP_LINK_LIBRARIES bsd ${PCAP_LINK_LIBRARIES}) + endif(LIBBSD_HAS_GETPASS) + endif(NOT STDLIBS_HAVE_GETPASS) endif(WIN32) # @@ -1063,6 +1194,8 @@ set(PROJECT_SOURCE_LIST_C optimize.c pcap-common.c pcap-options.c + pcap-usb-linux-common.c + pcap-util.c pcap.c savefile.c sf-pcapng.c @@ -2075,6 +2208,28 @@ if(LEX_EXECUTABLE STREQUAL "LEX_EXECUTABLE-NOTFOUND") endif() message(STATUS "Lexical analyzer generator: ${LEX_EXECUTABLE}") +# +# Make sure {f}lex supports the -P, --header-file, and --nounput flags +# and supports processing our scanner.l. +# +if(WIN32) + set(NULL_DEVICE "NUL:") +else() + set(NULL_DEVICE "/dev/null") +endif() +execute_process(COMMAND ${LEX_EXECUTABLE} -P pcap_ --header-file=${NULL_DEVICE} --nounput -t ${pcap_SOURCE_DIR}/scanner.l + OUTPUT_QUIET RESULT_VARIABLE EXIT_STATUS) +if(NOT EXIT_STATUS EQUAL 0) + message(FATAL_ERROR "${LEX_EXECUTABLE} is insufficient to compile libpcap. +libpcap requires Flex 2.5.31 or later, or a compatible version of lex. +If a suitable version of Lex/Flex is available as a non-standard command +and/or not in the PATH, you can specify it using the LEX environment +variable. That said, on some systems the error can mean that Flex/Lex is +actually acceptable, but m4 is not. Likewise, if a suitable version of +m4 (such as GNU M4) is available but has not been detected, you can +specify it using the M4 environment variable.") +endif() + add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/scanner.c ${CMAKE_CURRENT_BINARY_DIR}/scanner.h SOURCE ${pcap_SOURCE_DIR}/scanner.l @@ -2108,6 +2263,25 @@ endif() if(YACC_EXECUTABLE MATCHES "byacc" OR YACC_EXECUTABLE MATCHES "yacc") # + # Make sure this is Berkeley YACC, not AT&T YACC; + # the latter doesn't support reentrant parsers. + # Run it with "-V"; that succeeds and reports the + # version number with Berkeley YACC, but will + # (probably) fail with various vendor flavors + # of AT&T YACC. + # + # Hopefully this also eliminates any versions + # of Berkeley YACC that don't support reentrant + # parsers, if there are any. + # + execute_process(COMMAND ${YACC_EXECUTABLE} -V OUTPUT_QUIET + RESULT_VARIABLE EXIT_STATUS) + if(NOT EXIT_STATUS EQUAL 0) + message(FATAL_ERROR "${YACC_EXECUTABLE} is insufficient to compile libpcap. +libpcap requires Bison, a newer version of Berkeley YACC with support +for reentrant parsers, or another YACC compatible with them.") + endif() + # # Berkeley YACC doesn't support "%define api.pure", so use # "%pure-parser". # @@ -2210,7 +2384,7 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "IRIX" OR CMAKE_SYSTEM_NAME STREQUAL "IRIX64") set(MAN_MISC_INFO 5) elseif(CMAKE_SYSTEM_NAME STREQUAL "OSF1") # - # DEC OSF/1, a/k/a Digial UNIX, a/k/a Tru64 UNIX. + # DEC OSF/1, a/k/a Digital UNIX, a/k/a Tru64 UNIX. # Use Tru64 UNIX conventions for man pages; they're the same as the # System V conventions except that they use section 8 for # administrative commands and daemons. @@ -2681,7 +2855,10 @@ set(MAN3PCAP_NOEXPAND pcap_tstamp_type_name_to_val.3pcap pcap_tstamp_type_val_to_name.3pcap ) -set(MANFILE_EXPAND pcap-savefile.manfile.in) +set(MANFILE_EXPAND + cbpf-savefile.manfile.in + pcap-savefile.manfile.in +) set(MANMISC_EXPAND pcap-filter.manmisc.in pcap-linktype.manmisc.in diff --git a/Makefile.in b/Makefile.in index 1b8ad07d..b5de882d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -92,9 +92,9 @@ PLATFORM_CXX_SRC = @PLATFORM_CXX_SRC@ MODULE_C_SRC = @MODULE_C_SRC@ REMOTE_C_SRC = @REMOTE_C_SRC@ COMMON_C_SRC = pcap.c gencode.c optimize.c nametoaddr.c etherent.c \ - fmtutils.c \ + fmtutils.c pcap-util.c \ savefile.c sf-pcap.c sf-pcapng.c pcap-common.c pcap-options.c \ - bpf_image.c bpf_filter.c bpf_dump.c + pcap-usb-linux-common.c bpf_image.c bpf_filter.c bpf_dump.c GENERATED_C_SRC = scanner.c grammar.c LIBOBJS = @LIBOBJS@ @@ -114,6 +114,7 @@ PUBHDR = \ pcap.h \ pcap-bpf.h \ pcap-namedb.h \ + pcap-util.h \ pcap/bpf.h \ pcap/bluetooth.h \ pcap/can_socketcan.h \ @@ -148,6 +149,7 @@ HDR = $(PUBHDR) \ pcap-int.h \ pcap-rpcap.h \ pcap-types.h \ + pcap-usb-linux-common.h \ pflog.h \ portability.h \ ppp.h \ @@ -234,6 +236,7 @@ MAN3PCAP_NOEXPAND = \ MAN3PCAP = $(MAN3PCAP_NOEXPAND) $(MAN3PCAP_EXPAND:.in=) MANFILE = \ + cbpf-savefile.manfile.in \ pcap-savefile.manfile.in MANMISC = \ @@ -55,9 +55,7 @@ BPF is standard in 4.4BSD, BSD/OS, NetBSD, FreeBSD, OpenBSD, DragonFly BSD, macOS, and Solaris 11; an older, modified and undocumented version is standard in AIX. {DEC OSF/1, Digital UNIX, Tru64 UNIX} uses the packetfilter interface but has been extended to accept BPF filters -(which libpcap utilizes). Also, you can add BPF filter support to -Ultrix using the kernel source and/or object patches available -[here](https://www.tcpdump.org/other/bpfext42.tar.Z). +(which libpcap utilizes). 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 @@ -272,7 +272,7 @@ AC_DEFUN(AC_LBL_CHECK_COMPILER_OPT, # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # AC_COMPILE_IFELSE( @@ -78,6 +78,32 @@ suncc-5.1[45]/SunOS-5.11) # "./filtertest.c", line 281: warning: statement not reached LIBPCAP_TAINTED=yes ;; +*/Haiku-*) + # (GCC 8.3.0 and later, Clang 9.0.1.) + # pcap-haiku.cpp:55:21: warning: unused variable 'handlep' [-Wunused-variable] + # pcap-haiku.cpp:50:37: warning: unused parameter 'maxPackets' [-Wunused-parameter] + # pcap-haiku.cpp:111:47: warning: unused parameter 'buffer' [-Wunused-parameter] + # pcap-haiku.cpp:111:59: warning: unused parameter 'size' [-Wunused-parameter] + # pcap-haiku.cpp:268:26: warning: unused parameter 'name' [-Wunused-parameter] + # pcap-haiku.cpp:274:26: warning: unused parameter 'name' [-Wunused-parameter] + # pcap-haiku.cpp:274:58: warning: unused parameter 'errbuf' [-Wunused-parameter] + # + # (The warnings below come from GCC and Clang in CMake builds after installing + # all system updates.) + # gencode.c:4143:9: warning: converting a packed 'struct in6_addr' pointer + # (alignment 1) to a 'uint32_t' {aka 'unsigned int'} pointer (alignment 4) may + # result in an unaligned pointer value [-Waddress-of-packed-member] + # gencode.c:4144:9: warning: converting a packed 'struct in6_addr' pointer + # (alignment 1) to a 'uint32_t' {aka 'unsigned int'} pointer (alignment 4) may + # result in an unaligned pointer value [-Waddress-of-packed-member] + # gencode.c:7189:9: warning: converting a packed 'struct in6_addr' pointer + # (alignment 1) to a 'uint32_t' {aka 'unsigned int'} pointer (alignment 4) may + # result in an unaligned pointer value [-Waddress-of-packed-member] + # gencode.c:7190:9: warning: converting a packed 'struct in6_addr' pointer + # (alignment 1) to a 'uint32_t' {aka 'unsigned int'} pointer (alignment 4) may + # result in an unaligned pointer value [-Waddress-of-packed-member] + LIBPCAP_TAINTED=yes + ;; esac [ "$LIBPCAP_TAINTED" != yes ] && CFLAGS=`cc_werr_cflags` @@ -87,8 +113,11 @@ else # Remove the leftovers from any earlier in-source builds, so this # out-of-source build does not break because of that. # https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#what-is-an-out-of-source-build - run_after_echo rm -rf CMakeFiles/ CMakeCache.txt - [ ! -d build ] && run_after_echo mkdir build + # (The contents of build/ remaining after an earlier unsuccessful attempt + # can fail subsequent build attempts too, sometimes in non-obvious ways, + # so remove that directory as well.) + run_after_echo rm -rf CMakeFiles/ CMakeCache.txt build/ + run_after_echo mkdir build run_after_echo cd build run_after_echo cmake ${CFLAGS:+-DEXTRA_CFLAGS="$CFLAGS"} \ -DCMAKE_INSTALL_PREFIX="$PREFIX" -DENABLE_REMOTE="$REMOTE" .. diff --git a/build_common.sh b/build_common.sh index f65e6209..b5fa66b6 100644 --- a/build_common.sh +++ b/build_common.sh @@ -43,8 +43,8 @@ mktempdir() { mktempdir_diy "$mktempdir_prefix" ;; *) - # At least Linux and OpenBSD implementations require explicit trailing - # X'es in the template, so make it the same suffix as above. + # At least Haiku, Linux and OpenBSD implementations require explicit + # trailing X'es in the template, so make it the same suffix as above. mktemp -d -t "${mktempdir_prefix}.XXXXXXXX" ;; esac @@ -212,6 +212,13 @@ os_id() { # Meaningful version is usually the substring before the first dash. echo "$os_id_release" | sed 's/^\([0-9\.]*\).*$/\1/' ;; + Haiku) + # Meaningful version is the substring before the plus sign. + # "hrev55181" stands for "R1/beta3". + # "hrev54154" stands for "R1/beta2". + : "${os_id_version:=`uname -v`}" + echo "$os_id_version" | sed 's/^\(hrev.*\)+.*$/\1/' + ;; *) echo 'UNKNOWN' ;; diff --git a/cbpf-savefile.manfile.in b/cbpf-savefile.manfile.in new file mode 100644 index 00000000..e1936ab6 --- /dev/null +++ b/cbpf-savefile.manfile.in @@ -0,0 +1,244 @@ +.\" Copyright (c) 2022 +.\" The TCPDUMP project. 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. +.\" 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 CBPF-SAVEFILE @MAN_FILE_FORMATS@ "17 July 2022" +.SH NAME +cbpf-savefile \- cBPF savefile format (work in progress, DRAFT revision 6) +.SH DESCRIPTION +This man page discusses a file format for cBPF, which is the "classic" (and +for a long time the only) Berkeley Packet Filter. It does +.B NOT +apply to the newer "extended" variety of BPF (eBPF). +.LP +The main purpose of this file format is to store BPF bytecode, most commonly +compiled from a BPF filter expression (see +.BR \%pcap-filter (7) +for the filter syntax description) using libpcap. Besides that, the format +allows to encode some information about the context in which the compilation +was done. This meta-data can make it easier to reproduce the compilation +later if required. cBPF savefile design is based on the file format proposed +by C.S. Peron in 2005. +.LP +Unless stated otherwise, in the following specification integer fields are +big-endian unsigned, string fields do not use NUL character for termination +or padding. + +.SH FILE FORMAT +A savefile consists of a fixed-size header and a variable-size body as +follows: +.LP +.nf + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| 0xA1 | 0xB2 | 0xC3 | 0xCB | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| 'c' | 'B' | 'P' | 'F' | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| MajorVer=1 | MinorVer | Flags | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| SnapLen | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| LinkTypeValue | InstructionCount=n | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | +| instruction 1 | +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | +| instruction 2 | +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | +~ ~ +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | +| instruction n | +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | +| optional trailing TLV space | +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +.fi +.LP +The first four octets contain a fixed signature, also known as +a magic number, to make it easy to identify the file type automatically. +The next four octets contain the ASCII string "cBPF" to provide a hint for +manual identification. + +.SS MajorVer and MinorVer +Contain the major and the minor version numbers of this format respectively. +The current major version is 1 and the current minor version is 0. Format +changes that do not impact compatibility (e.g., new TLV types or flags) +increment the minor version only. Other format changes increment the major +version and reset the minor version to 0. All format versions have the first +part of the header up to and including MinorVer identical. + +.SS Flags +.nf + b15 b14 b13 b12 b11 b10 b09 b08 b07 b06 b05 b04 b03 b02 b01 b00 ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +| reserved |CPX|COP|XOR|MOD| ++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +.fi + +MOD, XOR, COP and CPX: if set to 1, in this BPF dialect BPF_MOD, BPF_XOR, +BPF_COP and BPF_COPX respectively are valid instructions. For the current +list of OSes that support BPF_MOD and BPF_XOR in the kernel see the +.B % +and +.B ^ +binary operators in +.BR \%pcap-filter (7). +BPF_COP and BPF_COPX are implemented in NetBSD kernel. +.LP +Note that the fact an instruction is valid in a BPF dialect does not always +mean the compiled bytecode in the savefile contains the instruction. In other +words, the purpose of the flags above is not to provide a digest of the file +contents, but to enable conclusive automatic verification of the bytecode if +required by the use case. + + +.SS SnapLen +Contains the snapshot length used for the compilation, usually this is the +.I snaplen +input argument to +.BR pcap_open_dead (3PCAP) +or +.BR pcap_set_snaplen (3PCAP). + +.SS LinkTypeValue +Contains the link-layer header type value used for the compilation, usually +this is either the +.I linktype +input argument to +.BR pcap_open_dead () +or the +.I dlt +input argument to +.BR pcap_set_datalink (3PCAP) +or the value(s) returned by +.BR pcap_datalink (3PCAP) +and +.BR pcap_list_datalinks (3PCAP). +Although these functions take and return link-layer header type values via the +.I int +C type, by convention only the low 16 bits are in use. + +.SS InstructionCount +This is the last field of the fixed header in major version 1, it contains the +number of bytecode instructions following the header. By convention, valid +BPF bytecode always ends with a "ret" instruction, so in a valid savefile this +field value is at least 1. + +.PP +The file format thus far minimizes the overhead for software that uses the BPF +bytecode. If there is any data after the last instruction, it is the trailing +TLV space, which mostly contains meta-data for human interpretation. It +contains TLVs in the format specified below. + +.SH INSTRUCTION FORMAT +.LP +.nf + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| opcode | jt | jf | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| k | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +.fi +.LP +This is the traditional encoding of a BPF instruction (a 4-tuple of +integers). Note that usually the endianness depends on the machine, but in +this format it is fixed. Some opcodes interpret k as a signed integer. + +.SH TLV FORMAT +.LP +.nf + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Type | Length=m | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | +~ Value (m octets) ~ +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +.fi +.LP +All TLVs are optional. Every TLV may appear in the same savefile at most +once. Length value does not include Type and Length. Code points for Type +and the associated Length constraints are defined below. + +.SS EOF TLV +Allows to mark the end of TLV space (hence of the savefile) explicitly to make it +clear that the file is not truncated. If this TLV is present in the TLV +space, it may appear the last only. +.LP +Type is 0, Length is 0, Value is empty. + +.SS LinkTypeName TLV +Allows to record the input argument to +.BR pcap_datalink_name_to_val (3PCAP) +if the latter was used to translate a DLT name into LinkTypeValue (the same +name can sometimes produce different values in different contexts). +.LP +Type is 1, Length is variable, Value contains an ASCII string. + +.SS Filter TLV +Allows to record the filter expression that was compiled into the +bytecode, usually this is the +.I str +input argument to +.BR pcap_compile (3PCAP). +.LP +Type is 2, Length is variable, Value contains an ASCII string. + +.SS OptReq TLV +Allows to record whether optimization was requested for the compilation or +not, usually this is the +.I optimize +input argument to +.BR pcap_compile (). +Note that some link-layer header types and filter keywords disable the +optimization automatically in libpcap. +.LP +Type is 3, Length is 1, Value contains 1 or 0. + +.SS Netmask TLV +Allows to record the value of +.I netmask +input argument to +.BR pcap_compile (). +.LP +Type is 4, Length is 4, Value contains a 32-bit IPv4 netmask. + +.SS Comment TLV +Allows to record a free-form text, for example, the name and version of the +program that generated the file. +.LP +Type is 5, Length is variable, Value contains a UTF-8 string. + +.SS Timestamp TLV +Allows to record when the compilation was performed. +.LP +Type is 6, Length is 8, Value contains a 64-bit Unix timestamp. + +.SH SOFTWARE SUPPORT +None at the time of this writing. + +.SH SEE ALSO +.BR \%pcap-savefile (@MAN_FILE_FORMATS@) diff --git a/config.h.in b/config.h.in index ab34376e..47afb7b0 100644 --- a/config.h.in +++ b/config.h.in @@ -72,6 +72,9 @@ /* Define to 1 if you have the <inttypes.h> header file. */ #undef HAVE_INTTYPES_H +/* Define to 1 if you have the `bsd' library (-lbsd). */ +#undef HAVE_LIBBSD + /* Define to 1 if you have the `dag' library (-ldag). */ #undef HAVE_LIBDAG @@ -319,6 +322,12 @@ /* target host supports RDMA sniffing */ #undef PCAP_SUPPORT_RDMASNIFF +/* The size of `const void *', as computed by sizeof. */ +#undef SIZEOF_CONST_VOID_P + +/* The size of `void *', as computed by sizeof. */ +#undef SIZEOF_VOID_P + /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS @@ -683,12 +683,12 @@ PKG_CONFIG_PATH PKG_CONFIG VALGRINDTEST_SRC LIBOBJS -EGREP -GREP -CPP ac_ct_CXX CXXFLAGS CXX +EGREP +GREP +CPP OBJEXT EXEEXT ac_ct_CC @@ -784,10 +784,10 @@ CFLAGS LDFLAGS LIBS CPPFLAGS +CPP CXX CXXFLAGS CCC -CPP PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR @@ -1470,9 +1470,9 @@ Some influential environment variables: LIBS libraries to pass to the linker, e.g. -l<library> CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if you have headers in a nonstandard directory <include dir> + CPP C preprocessor CXX C++ compiler command CXXFLAGS C++ compiler flags - CPP C preprocessor PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path @@ -1612,6 +1612,299 @@ fi } # ac_fn_c_try_compile +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES +# -------------------------------------------- +# Tries to find the compile-time value of EXPR in a program that includes +# INCLUDES, setting VAR accordingly. Returns whether the value could be +# computed +ac_fn_c_compute_int () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=0 ac_mid=0 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid; break +else + as_fn_arith $ac_mid + 1 && ac_lo=$as_val + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) < 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=-1 ac_mid=-1 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=$ac_mid; break +else + as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + ac_lo= ac_hi= +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid +else + as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in #(( +?*) eval "$3=\$ac_lo"; ac_retval=0 ;; +'') ac_retval=1 ;; +esac + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +static long int longval () { return $2; } +static unsigned long int ulongval () { return $2; } +#include <stdio.h> +#include <stdlib.h> +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (($2) < 0) + { + long int i = longval (); + if (i != ($2)) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ($2)) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + echo >>conftest.val; read $3 <conftest.val; ac_retval=0 +else + ac_retval=1 +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f conftest.val + + fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_compute_int + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. @@ -1650,42 +1943,230 @@ fi } # ac_fn_cxx_try_compile -# ac_fn_c_try_cpp LINENO -# ---------------------- -# Try to preprocess conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_cpp () +# ac_fn_cxx_try_run LINENO +# ------------------------ +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_cxx_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_cpp conftest.$ac_ext" + if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + (eval "$ac_link") 2>&5 ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } > conftest.i && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then : + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : ac_retval=0 else - $as_echo "$as_me: failed program was:" >&5 + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 + ac_retval=$ac_status fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval -} # ac_fn_c_try_cpp +} # ac_fn_cxx_try_run + +# ac_fn_cxx_compute_int LINENO EXPR VAR INCLUDES +# ---------------------------------------------- +# Tries to find the compile-time value of EXPR in a program that includes +# INCLUDES, setting VAR accordingly. Returns whether the value could be +# computed +ac_fn_cxx_compute_int () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_lo=0 ac_mid=0 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_hi=$ac_mid; break +else + as_fn_arith $ac_mid + 1 && ac_lo=$as_val + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) < 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_hi=-1 ac_mid=-1 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_lo=$ac_mid; break +else + as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + ac_lo= ac_hi= +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_hi=$ac_mid +else + as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in #(( +?*) eval "$3=\$ac_lo"; ac_retval=0 ;; +'') ac_retval=1 ;; +esac + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +static long int longval () { return $2; } +static unsigned long int ulongval () { return $2; } +#include <stdio.h> +#include <stdlib.h> +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (($2) < 0) + { + long int i = longval (); + if (i != ($2)) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ($2)) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + echo >>conftest.val; read $3 <conftest.val; ac_retval=0 +else + ac_retval=1 +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f conftest.val + + fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_compute_int # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- @@ -1774,79 +2255,6 @@ fi } # ac_fn_c_check_header_mongrel -# ac_fn_c_try_run LINENO -# ---------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes -# that executables *can* be run. -ac_fn_c_try_run () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then : - ac_retval=0 -else - $as_echo "$as_me: program exited with status $ac_status" >&5 - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=$ac_status -fi - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_run - -# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists and can be compiled using the include files in -# INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_compile - # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly @@ -3612,11 +4020,450 @@ fi if test "$ac_cv_prog_cc_c99" = "no"; then as_fn_error $? "The C compiler does not support C99" "$LINENO" 5 fi + +# +# Get the size of a void *, to determine whether this is a 32-bit +# or 64-bit build. +# + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ctype.h> +#include <stdlib.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 +$as_echo_n "checking size of void *... " >&6; } +if ${ac_cv_sizeof_void_p+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_void_p" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (void *) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_void_p=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 +$as_echo "$ac_cv_sizeof_void_p" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_VOID_P $ac_cv_sizeof_void_p +_ACEOF + + +ac_lbl_c_sizeof_void_p="$ac_cv_sizeof_void_p" + +# +# We only need a C++ compiler for Haiku; all code except for its +# pcap module is in C. +# case "$host_os" in haiku*) - # - # Haiku's platform file is in C++. - # ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -3874,6 +4721,74 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu + + # + # Make sure C and C++ have the same pointer sizes with the flags + # they're given; if they don't, it means that the compilers for the + # languages will, with those flags, not produce code that can be + # linked together. + # + # We have to use different data types, because the results of + # a test are cached, so if we test for the size of a given type + # in C, the subsequent test in C++ will use the cached variable. + # We trick autoconf by testing the size of a "void *" in C and a + # "const void *" in C++. + # + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of const void *" >&5 +$as_echo_n "checking size of const void *... " >&6; } +if ${ac_cv_sizeof_const_void_p+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_cxx_compute_int "$LINENO" "(long int) (sizeof (const void *))" "ac_cv_sizeof_const_void_p" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_const_void_p" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (const void *) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_const_void_p=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_const_void_p" >&5 +$as_echo "$ac_cv_sizeof_const_void_p" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_CONST_VOID_P $ac_cv_sizeof_const_void_p +_ACEOF + + + ac_lbl_cxx_sizeof_void_p="$ac_cv_sizeof_const_void_p" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + if test "$ac_lbl_cxx_sizeof_void_p" -eq 0; then + as_fn_error $? "No C++ compiler was found" "$LINENO" 5 + fi + if test "$ac_lbl_c_sizeof_void_p" -ne "$ac_lbl_cxx_sizeof_void_p"; then + as_fn_error $? "C compiler $CC produces code with $ac_lbl_c_sizeof_void_p-byte pointers +while C++ compiler $CXX produces code with $ac_lbl_cxx_sizeof_void_p-byte pointers. This prevents +code in those languages from being combined." "$LINENO" 5 + fi ;; esac @@ -3881,7 +4796,6 @@ esac - if test "$GCC" = yes ; then # # -Werror forces warnings to be errors. @@ -3921,7 +4835,7 @@ $as_echo_n "checking whether the compiler supports the -fvisibility=hidden optio # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4030,7 +4944,7 @@ $as_echo_n "checking whether the compiler supports the -fvisibility=hidden optio # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4201,7 +5115,7 @@ $as_echo_n "checking whether the compiler supports the -xldscope=hidden option.. # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4905,435 +5819,86 @@ $as_echo "#define HAVE_FSEEKO 1" >>confdefs.h fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -$as_echo_n "checking how to run the C preprocessor... " >&6; } -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then - if ${ac_cv_prog_CPP+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CPP needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" - do - ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since - # <limits.h> exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include <limits.h> -#else -# include <assert.h> -#endif - Syntax error +for ac_header in sys/ioccom.h sys/sockio.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : -else - # Broken: fails on valid input. -continue fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <ac_nonexistent.h> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - break -fi - done - ac_cv_prog_CPP=$CPP - -fi - CPP=$ac_cv_prog_CPP -else - ac_cv_prog_CPP=$CPP -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -$as_echo "$CPP" >&6; } -ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since - # <limits.h> exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include <limits.h> -#else -# include <assert.h> -#endif - Syntax error +for ac_header in netpacket/packet.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "netpacket/packet.h" "ac_cv_header_netpacket_packet_h" "$ac_includes_default" +if test "x$ac_cv_header_netpacket_packet_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_NETPACKET_PACKET_H 1 _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <ac_nonexistent.h> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break fi -rm -f conftest.err conftest.i conftest.$ac_ext done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -$as_echo_n "checking for egrep... " >&6; } -if ${ac_cv_path_EGREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -$as_echo "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : +case "$host_os" in +haiku*) + # + # Haiku needs _BSD_SOURCE for the _IO* macros because it doesn't use them. + # + CFLAGS="$CFLAGS -D_BSD_SOURCE" + # + # Haiku has getpass in libbsd. + # + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getpass in -lbsd" >&5 +$as_echo_n "checking for getpass in -lbsd... " >&6; } +if ${ac_cv_lib_bsd_getpass+:} false; then : $as_echo_n "(cached) " >&6 else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <float.h> - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <string.h> - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + ac_check_lib_save_LIBS=$LIBS +LIBS="-lbsd $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include <stdlib.h> - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <ctype.h> -#include <stdlib.h> -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" #endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +char getpass (); int main () { - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; +return getpass (); + ; return 0; } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : - +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_bsd_getpass=yes else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_cv_lib_bsd_getpass=no fi - -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then - -$as_echo "#define STDC_HEADERS 1" >>confdefs.h - +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS fi - -# On IRIX 5.3, sys/types and inttypes.h are conflicting. -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_getpass" >&5 +$as_echo "$ac_cv_lib_bsd_getpass" >&6; } +if test "x$ac_cv_lib_bsd_getpass" = xyes; then : cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +#define HAVE_LIBBSD 1 _ACEOF -fi - -done - - -for ac_header in sys/ioccom.h sys/sockio.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF + LIBS="-lbsd $LIBS" fi -done - -for ac_header in netpacket/packet.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "netpacket/packet.h" "ac_cv_header_netpacket_packet_h" "$ac_includes_default" -if test "x$ac_cv_header_netpacket_packet_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_NETPACKET_PACKET_H 1 -_ACEOF - -fi - -done - - -case "$host_os" in -haiku*) - # - # Haiku needs _BSD_SOURCE for the _IO* macros because it doesn't use them. - # - CFLAGS="$CFLAGS -D_BSD_SOURCE" ;; esac @@ -6874,6 +7439,64 @@ fi + +# +# Solaris pkg-config is annoying. For at least one package (D-Bus, I'm +# looking at *you*!), there are separate include files for 32-bit and +# 64-bit builds (I guess using "unsigned long long" as a 64-bit integer +# type on a 64-bit build is like crossing the beams or soething), and +# there are two separate .pc files, so if we're doing a 32-bit build we +# should make sure we look in /usr/lib/pkgconfig for .pc files and if +# we're doing a 64-bit build we should make sure we look in +# /usr/lib/amd64/pkgconfig for .pc files. +# +case "$host_os" in + +solaris*) + if test "$ac_cv_sizeof_void_p" -eq 8; then + # + # 64-bit build. If the path is empty, set it to + # /usr/lib/amd64/pkgconfig; otherwise, if + # /usr/lib/pkgconfig appears in the path, prepend + # /usr/lib/amd64/pkgconfig to it; otherwise, put + # /usr/lib/amd64/pkgconfig at the end. + # + if test -z "$PKG_CONFIG_PATH"; then + # + # Not set, or empty. Set it to + # /usr/lib/amd64/pkgconfig. + # + PKG_CONFIG_PATH=/usr/lib/amd64/pkgconfig + elif test ! -z `echo "$PKG_CONFIG_PATH" | grep "/usr/lib/pkgconfig"`; then + # + # It contains /usr/lib/pkgconfig. Prepend + # /usr/lib/amd64/pkgconfig to /usr/lib/pkgconfig. + # + PKG_CONFIG_PATH=`echo "$PKG_CONFIG_PATH" | sed "s;/usr/lib/pkgconfig;/usr/lib/amd64/pkgconfig:/usr/lib/pkgconfig;"` + else + # + # Not empty, but doesn't contain /usr/lib/pkgconfig. + # Append /usr/lib/amd64/pkgconfig to it. + # + PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/lib/amd64/pkgconfig" + fi + export PKG_CONFIG_PATH + elif test "$ac_cv_sizeof_void_p" -eq 4; then + # + # 32-bit build. If /usr/amd64/lib/pkgconfig appears + # in the path, prepend /usr/lib/pkgconfig to it. + # + if test ! -z `echo "$PKG_CONFIG_PATH" | grep "/usr/lib/amd64/pkgconfig"`; then + # + # It contains /usr/lib/amd64/pkgconfig. Prepend + # /usr/lib/pkgconfig to /usr/lib/amd64/pkgconfig. + # + PKG_CONFIG_PATH=`echo "$PKG_CONFIG_PATH" | sed "s;/usr/lib/amd64/pkgconfig;/usr/lib/pkgconfig:/usr/lib/amd64/pkgconfig;"` + export PKG_CONFIG_PATH + fi + fi +esac + # # Handle each capture type. # @@ -9570,7 +10193,7 @@ osf*) DYEXT="so" # - # DEC OSF/1, a/k/a Digial UNIX, a/k/a Tru64 UNIX. + # DEC OSF/1, a/k/a Digital UNIX, a/k/a Tru64 UNIX. # Use Tru64 UNIX conventions for man pages; they're the same as # the System V conventions except that they use section 8 for # administrative commands and daemons. @@ -9899,7 +10522,7 @@ $as_echo_n "checking whether the compiler supports the -W option... " >&6; } # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -9990,7 +10613,7 @@ $as_echo_n "checking whether the compiler supports the -Wall option... " >&6; } # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10081,7 +10704,7 @@ $as_echo_n "checking whether the compiler supports the -Wcomma option... " >&6; # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10172,7 +10795,7 @@ $as_echo_n "checking whether the compiler supports the -Wdocumentation option... # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10263,7 +10886,7 @@ $as_echo_n "checking whether the compiler supports the -Wformat-nonliteral optio # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10354,7 +10977,7 @@ $as_echo_n "checking whether the compiler supports the -Wmissing-noreturn option # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10445,7 +11068,7 @@ $as_echo_n "checking whether the compiler supports the -Wmissing-prototypes opti # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10536,7 +11159,7 @@ $as_echo_n "checking whether the compiler supports the -Wmissing-variable-declar # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10627,7 +11250,7 @@ $as_echo_n "checking whether the compiler supports the -Wpointer-arith option... # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10718,7 +11341,7 @@ $as_echo_n "checking whether the compiler supports the -Wpointer-sign option... # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10809,7 +11432,7 @@ $as_echo_n "checking whether the compiler supports the -Wshadow option... " >&6; # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10900,7 +11523,7 @@ $as_echo_n "checking whether the compiler supports the -Wsign-compare option... # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10991,7 +11614,7 @@ $as_echo_n "checking whether the compiler supports the -Wstrict-prototypes optio # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11082,7 +11705,7 @@ $as_echo_n "checking whether the compiler supports the -Wunused-parameter option # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11173,7 +11796,7 @@ $as_echo_n "checking whether the compiler supports the -Wused-but-marked-unused # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11291,7 +11914,7 @@ $as_echo_n "checking whether the compiler supports the -Wunreachable-code option # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11389,7 +12012,7 @@ $as_echo_n "checking whether the compiler supports the -Wshorten-64-to-32 option # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us # - # This may, as per those two messages, be fixed in autoonf 2.70, + # This may, as per those two messages, be fixed in autoconf 2.70, # but we only require 2.64 or newer for now. # cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12893,7 +13516,7 @@ ac_config_headers="$ac_config_headers config.h" ac_config_commands="$ac_config_commands default-1" -ac_config_files="$ac_config_files Makefile grammar.y 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" +ac_config_files="$ac_config_files Makefile grammar.y pcap-filter.manmisc pcap-linktype.manmisc pcap-tstamp.manmisc cbpf-savefile.manfile 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 @@ -13601,6 +14224,7 @@ do "pcap-filter.manmisc") CONFIG_FILES="$CONFIG_FILES pcap-filter.manmisc" ;; "pcap-linktype.manmisc") CONFIG_FILES="$CONFIG_FILES pcap-linktype.manmisc" ;; "pcap-tstamp.manmisc") CONFIG_FILES="$CONFIG_FILES pcap-tstamp.manmisc" ;; + "cbpf-savefile.manfile") CONFIG_FILES="$CONFIG_FILES cbpf-savefile.manfile" ;; "pcap-savefile.manfile") CONFIG_FILES="$CONFIG_FILES pcap-savefile.manfile" ;; "pcap.3pcap") CONFIG_FILES="$CONFIG_FILES pcap.3pcap" ;; "pcap_compile.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_compile.3pcap" ;; diff --git a/configure.ac b/configure.ac index 0a0639cb..0c669d98 100644 --- a/configure.ac +++ b/configure.ac @@ -32,12 +32,46 @@ AC_PROG_CC_C99 if test "$ac_cv_prog_cc_c99" = "no"; then AC_MSG_ERROR([The C compiler does not support C99]) fi + +# +# Get the size of a void *, to determine whether this is a 32-bit +# or 64-bit build. +# +AC_CHECK_SIZEOF([void *]) +ac_lbl_c_sizeof_void_p="$ac_cv_sizeof_void_p" + +# +# We only need a C++ compiler for Haiku; all code except for its +# pcap module is in C. +# case "$host_os" in haiku*) + AC_PROG_CXX + # - # Haiku's platform file is in C++. + # Make sure C and C++ have the same pointer sizes with the flags + # they're given; if they don't, it means that the compilers for the + # languages will, with those flags, not produce code that can be + # linked together. # - AC_PROG_CXX + # We have to use different data types, because the results of + # a test are cached, so if we test for the size of a given type + # in C, the subsequent test in C++ will use the cached variable. + # We trick autoconf by testing the size of a "void *" in C and a + # "const void *" in C++. + # + AC_LANG_PUSH([C++]) + AC_CHECK_SIZEOF([const void *]) + ac_lbl_cxx_sizeof_void_p="$ac_cv_sizeof_const_void_p" + AC_LANG_POP([C++]) + if test "$ac_lbl_cxx_sizeof_void_p" -eq 0; then + AC_MSG_ERROR([No C++ compiler was found]) + fi + if test "$ac_lbl_c_sizeof_void_p" -ne "$ac_lbl_cxx_sizeof_void_p"; then + AC_MSG_ERROR([C compiler $CC produces code with $ac_lbl_c_sizeof_void_p-byte pointers +while C++ compiler $CXX produces code with $ac_lbl_cxx_sizeof_void_p-byte pointers. This prevents +code in those languages from being combined.]) + fi ;; esac @@ -70,6 +104,10 @@ haiku*) # Haiku needs _BSD_SOURCE for the _IO* macros because it doesn't use them. # CFLAGS="$CFLAGS -D_BSD_SOURCE" + # + # Haiku has getpass in libbsd. + # + AC_CHECK_LIB(bsd, getpass) ;; esac @@ -720,6 +758,64 @@ PKG_PROG_PKG_CONFIG # AC_PATH_PROG([BREW], [brew]) + +# +# Solaris pkg-config is annoying. For at least one package (D-Bus, I'm +# looking at *you*!), there are separate include files for 32-bit and +# 64-bit builds (I guess using "unsigned long long" as a 64-bit integer +# type on a 64-bit build is like crossing the beams or soething), and +# there are two separate .pc files, so if we're doing a 32-bit build we +# should make sure we look in /usr/lib/pkgconfig for .pc files and if +# we're doing a 64-bit build we should make sure we look in +# /usr/lib/amd64/pkgconfig for .pc files. +# +case "$host_os" in + +solaris*) + if test "$ac_cv_sizeof_void_p" -eq 8; then + # + # 64-bit build. If the path is empty, set it to + # /usr/lib/amd64/pkgconfig; otherwise, if + # /usr/lib/pkgconfig appears in the path, prepend + # /usr/lib/amd64/pkgconfig to it; otherwise, put + # /usr/lib/amd64/pkgconfig at the end. + # + if test -z "$PKG_CONFIG_PATH"; then + # + # Not set, or empty. Set it to + # /usr/lib/amd64/pkgconfig. + # + PKG_CONFIG_PATH=/usr/lib/amd64/pkgconfig + elif test ! -z `echo "$PKG_CONFIG_PATH" | grep "/usr/lib/pkgconfig"`; then + # + # It contains /usr/lib/pkgconfig. Prepend + # /usr/lib/amd64/pkgconfig to /usr/lib/pkgconfig. + # + PKG_CONFIG_PATH=`echo "$PKG_CONFIG_PATH" | sed "s;/usr/lib/pkgconfig;/usr/lib/amd64/pkgconfig:/usr/lib/pkgconfig;"` + else + # + # Not empty, but doesn't contain /usr/lib/pkgconfig. + # Append /usr/lib/amd64/pkgconfig to it. + # + PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/lib/amd64/pkgconfig" + fi + export PKG_CONFIG_PATH + elif test "$ac_cv_sizeof_void_p" -eq 4; then + # + # 32-bit build. If /usr/amd64/lib/pkgconfig appears + # in the path, prepend /usr/lib/pkgconfig to it. + # + if test ! -z `echo "$PKG_CONFIG_PATH" | grep "/usr/lib/amd64/pkgconfig"`; then + # + # It contains /usr/lib/amd64/pkgconfig. Prepend + # /usr/lib/pkgconfig to /usr/lib/amd64/pkgconfig. + # + PKG_CONFIG_PATH=`echo "$PKG_CONFIG_PATH" | sed "s;/usr/lib/amd64/pkgconfig;/usr/lib/pkgconfig:/usr/lib/amd64/pkgconfig;"` + export PKG_CONFIG_PATH + fi + fi +esac + # # Handle each capture type. # @@ -2221,7 +2317,7 @@ osf*) DYEXT="so" # - # DEC OSF/1, a/k/a Digial UNIX, a/k/a Tru64 UNIX. + # DEC OSF/1, a/k/a Digital UNIX, a/k/a Tru64 UNIX. # Use Tru64 UNIX conventions for man pages; they're the same as # the System V conventions except that they use section 8 for # administrative commands and daemons. @@ -2939,7 +3035,7 @@ AC_OUTPUT_COMMANDS([if test -f .devel; then make depend || exit 1 fi]) AC_OUTPUT(Makefile grammar.y pcap-filter.manmisc pcap-linktype.manmisc - pcap-tstamp.manmisc pcap-savefile.manfile pcap.3pcap + pcap-tstamp.manmisc cbpf-savefile.manfile 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 diff --git a/diag-control.h b/diag-control.h index 28624306..ae2641b4 100644 --- a/diag-control.h +++ b/diag-control.h @@ -37,12 +37,12 @@ #include "pcap/compiler-tests.h" -#ifndef _MSC_VER +#if PCAP_IS_AT_LEAST_CLANG_VERSION(2,8) || PCAP_IS_AT_LEAST_GNUC_VERSION(4,6) /* * Clang and GCC both support this way of putting pragmas into #defines. - * We don't use it unless we have a compiler that supports it; the - * warning-suppressing pragmas differ between Clang and GCC, so we test - * for both of those separately. + * We use it only if we have a compiler that supports it; see below + * for the code that uses it and the #defines that control whether + * that code is used. */ #define PCAP_DO_PRAGMA(x) _Pragma (#x) #endif diff --git a/doc/README.Win32.md b/doc/README.Win32.md index 7ba7c22d..01879651 100644 --- a/doc/README.Win32.md +++ b/doc/README.Win32.md @@ -101,7 +101,7 @@ include built-in support for CMake-based projects: For Visual Studio 2017, make sure "Visual C++ tools for CMake" is installed; for Visual Studio 2019, make sure "C++ CMake tools for -Windows" is intalled. +Windows" is installed. ### winflexbison ### diff --git a/doc/README.hpux b/doc/README.hpux index b995eeea..4b3801b4 100644 --- a/doc/README.hpux +++ b/doc/README.hpux @@ -195,7 +195,7 @@ Here's the "hack_ip_stack" script: -----------------------------------Cut Here------------------------------------- #!/sbin/sh # -# nettune: hack kernel parms for safety +# nettune: hack kernel params for safety OKAY=0 ERROR=-1 diff --git a/doc/README.solaris.md b/doc/README.solaris.md index 07456712..06ba789d 100644 --- a/doc/README.solaris.md +++ b/doc/README.solaris.md @@ -2,8 +2,14 @@ * Autoconf works everywhere. * Neither Solaris lex nor Solaris yacc are suitable. -* Neither OpenIndiana lex nor OpenIndiana yacc are suitable. -* Solaris m4 and OpenIndiana m4 are suitable. +* Neither illumos lex nor illumos yacc are suitable. +* Solaris m4 and illumos m4 are suitable. + +## OmniOS r151042/AMD64 + +* flex 2.6.4 and GNU Bison 3.8.2 work. +* CMake 3.23.1 works. +* GCC 11.2.0 and Clang 14.0.3 work. ## OpenIndiana 2021.04/AMD64 @@ -24,6 +30,14 @@ developer/clang-90 ENDOFTEXT ``` +## Solaris 11/AMD64 + +* flex 2.6.4 and GNU Bison 3.7.3 work. +* CMake 3.21.0 works. +* Clang 11.0 works, GCC 11.2 works. + +For reference, the tests were done using Oracle Solaris 11.4.42.111.0. + ## Solaris 11/SPARC * flex 2.6.4 and GNU Bison 3.7.1 work. @@ -127,7 +127,7 @@ EXTRACT_BE_S_8(const void *p) * cast the pointer to point to one of those, and fetch through it; * the GCC manual doesn't appear to explicitly say that * __attribute__((packed)) causes the compiler to generate unaligned-safe - * code, but it apppears to do so. + * code, but it appears to do so. * * We do this in case the compiler can generate code using those * instructions to do an unaligned load and pass stuff to "ntohs()" or @@ -270,13 +270,21 @@ pcap_fmt_errmsg_for_errno(char *errbuf, size_t errbuflen, int errnum, const char *fmt, ...) { va_list ap; + + va_start(ap, fmt); + pcap_vfmt_errmsg_for_errno(errbuf, errbuflen, errnum, fmt, ap); + va_end(ap); +} + +void +pcap_vfmt_errmsg_for_errno(char *errbuf, size_t errbuflen, int errnum, + const char *fmt, va_list ap) +{ size_t msglen; char *p; size_t errbuflen_remaining; - va_start(ap, fmt); - vsnprintf(errbuf, errbuflen, fmt, ap); - va_end(ap); + (void)vsnprintf(errbuf, errbuflen, fmt, ap); msglen = strlen(errbuf); /* @@ -378,6 +386,16 @@ pcap_fmt_errmsg_for_win32_err(char *errbuf, size_t errbuflen, DWORD errnum, const char *fmt, ...) { va_list ap; + + va_start(ap, fmt); + pcap_vfmt_errmsg_for_win32_err(errbuf, errbuflen, errnum, fmt, ap); + va_end(ap); +} + +void +pcap_vfmt_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; @@ -385,9 +403,7 @@ pcap_fmt_errmsg_for_win32_err(char *errbuf, size_t errbuflen, DWORD errnum, wchar_t utf_16_errbuf[PCAP_ERRBUF_SIZE]; size_t utf_8_len; - va_start(ap, fmt); vsnprintf(errbuf, errbuflen, fmt, ap); - va_end(ap); msglen = strlen(errbuf); /* @@ -34,6 +34,8 @@ #ifndef fmtutils_h #define fmtutils_h +#include <stdarg.h> /* we declare varargs functions */ + #include "pcap/funcattrs.h" #ifdef __cplusplus @@ -44,10 +46,14 @@ void pcap_fmt_set_encoding(unsigned int); void pcap_fmt_errmsg_for_errno(char *, size_t, int, PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(4, 5); +void pcap_vfmt_errmsg_for_errno(char *, size_t, int, + PCAP_FORMAT_STRING(const char *), va_list) PCAP_PRINTFLIKE(4, 0); #ifdef _WIN32 void pcap_fmt_errmsg_for_win32_err(char *, size_t, DWORD, PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(4, 5); +void pcap_vfmt_errmsg_for_win32_err(char *, size_t, DWORD, + PCAP_FORMAT_STRING(const char *), va_list) PCAP_PRINTFLIKE(4, 0); #endif #ifdef __cplusplus @@ -1,4 +1,3 @@ -/*#define CHASE_CHAIN*/ /* * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 * The Regents of the University of California. All rights reserved. @@ -24,7 +23,6 @@ #include <config.h> #endif -#include <pcap-types.h> #ifdef _WIN32 #include <ws2tcpip.h> #else @@ -43,6 +41,7 @@ #include <memory.h> #include <setjmp.h> #include <stdarg.h> +#include <stdio.h> #ifdef MSDOS #include "pcap-dos.h" @@ -565,7 +564,9 @@ static struct block *gen_portrangeop6(compiler_state_t *, u_int, u_int, bpf_u_int32, int); static struct block *gen_portrange6(compiler_state_t *, u_int, u_int, int, int); static int lookup_proto(compiler_state_t *, const char *, int); +#if !defined(NO_PROTOCHAIN) static struct block *gen_protochain(compiler_state_t *, bpf_u_int32, int); +#endif /* !defined(NO_PROTOCHAIN) */ static struct block *gen_proto(compiler_state_t *, bpf_u_int32, int, int); static struct slist *xfer_to_x(compiler_state_t *, struct arth *); static struct slist *xfer_to_a(compiler_state_t *, struct arth *); @@ -732,7 +733,7 @@ pcap_compile(pcap_t *p, struct bpf_program *program, if (!p->activated) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "not-yet-activated pcap_t passed to pcap_compile"); - return (-1); + return (PCAP_ERROR); } #ifdef _WIN32 @@ -780,7 +781,7 @@ pcap_compile(pcap_t *p, struct bpf_program *program, if (cstate.snaplen == 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snaplen of 0 rejects all packets"); - rc = -1; + rc = PCAP_ERROR; goto quit; } @@ -796,7 +797,7 @@ pcap_compile(pcap_t *p, struct bpf_program *program, pcap_set_extra(&cstate, scanner); if (init_linktype(&cstate, p) == -1) { - rc = -1; + rc = PCAP_ERROR; goto quit; } if (pcap_parse(scanner, &cstate) != 0) { @@ -806,7 +807,7 @@ pcap_compile(pcap_t *p, struct bpf_program *program, #endif if (cstate.e != NULL) free(cstate.e); - rc = -1; + rc = PCAP_ERROR; goto quit; } @@ -815,7 +816,7 @@ pcap_compile(pcap_t *p, struct bpf_program *program, * Catch errors reported by gen_retblk(). */ if (setjmp(cstate.top_ctx)) { - rc = -1; + rc = PCAP_ERROR; goto quit; } cstate.ic.root = gen_retblk(&cstate, cstate.snaplen); @@ -824,14 +825,14 @@ pcap_compile(pcap_t *p, struct bpf_program *program, if (optimize && !cstate.no_optimize) { if (bpf_optimize(&cstate.ic, p->errbuf) == -1) { /* Failure */ - rc = -1; + rc = PCAP_ERROR; goto quit; } if (cstate.ic.root == NULL || (cstate.ic.root->s.code == (BPF_RET|BPF_K) && cstate.ic.root->s.k == 0)) { (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "expression rejects all packets"); - rc = -1; + rc = PCAP_ERROR; goto quit; } } @@ -839,7 +840,7 @@ pcap_compile(pcap_t *p, struct bpf_program *program, cstate.ic.root, &len, p->errbuf); if (program->bf_insns == NULL) { /* Failure */ - rc = -1; + rc = PCAP_ERROR; goto quit; } program->bf_len = len; @@ -877,7 +878,7 @@ pcap_compile_nopcap(int snaplen_arg, int linktype_arg, p = pcap_open_dead(linktype_arg, snaplen_arg); if (p == NULL) - return (-1); + return (PCAP_ERROR); ret = pcap_compile(p, program, buf, optimize, mask); pcap_close(p); return (ret); @@ -5358,21 +5359,15 @@ gen_proto_abbrev_internal(compiler_state_t *cstate, int proto) switch (proto) { case Q_SCTP: - b1 = gen_proto(cstate, IPPROTO_SCTP, Q_IP, Q_DEFAULT); - b0 = gen_proto(cstate, IPPROTO_SCTP, Q_IPV6, Q_DEFAULT); - gen_or(b0, b1); + b1 = gen_proto(cstate, IPPROTO_SCTP, Q_DEFAULT, Q_DEFAULT); break; case Q_TCP: - b1 = gen_proto(cstate, IPPROTO_TCP, Q_IP, Q_DEFAULT); - b0 = gen_proto(cstate, IPPROTO_TCP, Q_IPV6, Q_DEFAULT); - gen_or(b0, b1); + b1 = gen_proto(cstate, IPPROTO_TCP, Q_DEFAULT, Q_DEFAULT); break; case Q_UDP: - b1 = gen_proto(cstate, IPPROTO_UDP, Q_IP, Q_DEFAULT); - b0 = gen_proto(cstate, IPPROTO_UDP, Q_IPV6, Q_DEFAULT); - gen_or(b0, b1); + b1 = gen_proto(cstate, IPPROTO_UDP, Q_DEFAULT, Q_DEFAULT); break; case Q_ICMP: @@ -5399,9 +5394,7 @@ gen_proto_abbrev_internal(compiler_state_t *cstate, int proto) #endif case Q_PIM: - b1 = gen_proto(cstate, IPPROTO_PIM, Q_IP, Q_DEFAULT); - b0 = gen_proto(cstate, IPPROTO_PIM, Q_IPV6, Q_DEFAULT); - gen_or(b0, b1); + b1 = gen_proto(cstate, IPPROTO_PIM, Q_DEFAULT, Q_DEFAULT); break; #ifndef IPPROTO_VRRP @@ -5478,18 +5471,14 @@ gen_proto_abbrev_internal(compiler_state_t *cstate, int proto) #define IPPROTO_AH 51 #endif case Q_AH: - b1 = gen_proto(cstate, IPPROTO_AH, Q_IP, Q_DEFAULT); - b0 = gen_proto(cstate, IPPROTO_AH, Q_IPV6, Q_DEFAULT); - gen_or(b0, b1); + b1 = gen_proto(cstate, IPPROTO_AH, Q_DEFAULT, Q_DEFAULT); break; #ifndef IPPROTO_ESP #define IPPROTO_ESP 50 #endif case Q_ESP: - b1 = gen_proto(cstate, IPPROTO_ESP, Q_IP, Q_DEFAULT); - b0 = gen_proto(cstate, IPPROTO_ESP, Q_IPV6, Q_DEFAULT); - gen_or(b0, b1); + b1 = gen_proto(cstate, IPPROTO_ESP, Q_DEFAULT, Q_DEFAULT); break; case Q_ISO: @@ -6083,20 +6072,10 @@ lookup_proto(compiler_state_t *cstate, const char *name, int proto) return v; } -#if 0 -struct stmt * -gen_joinsp(struct stmt **s, int n) -{ - return NULL; -} -#endif - +#if !defined(NO_PROTOCHAIN) static struct block * gen_protochain(compiler_state_t *cstate, bpf_u_int32 v, int proto) { -#ifdef NO_PROTOCHAIN - return gen_proto(cstate, v, proto); -#else struct block *b0, *b; struct slist *s[100]; int fix2, fix3, fix4, fix5; @@ -6390,8 +6369,8 @@ gen_protochain(compiler_state_t *cstate, bpf_u_int32 v, int proto) gen_and(b0, b); return b; -#endif } +#endif /* !defined(NO_PROTOCHAIN) */ static struct block * gen_check_802_11_data_frame(compiler_state_t *cstate) @@ -6432,9 +6411,7 @@ static struct block * gen_proto(compiler_state_t *cstate, bpf_u_int32 v, int proto, int dir) { struct block *b0, *b1; -#ifndef CHASE_CHAIN struct block *b2; -#endif if (dir != Q_DEFAULT) bpf_error(cstate, "direction applied to 'proto'"); @@ -6466,11 +6443,7 @@ gen_proto(compiler_state_t *cstate, bpf_u_int32 v, int proto, int dir) * So we always check for ETHERTYPE_IP. */ b0 = gen_linktype(cstate, ETHERTYPE_IP); -#ifndef CHASE_CHAIN b1 = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, v); -#else - b1 = gen_protochain(cstate, v, Q_IP); -#endif gen_and(b0, b1); return b1; @@ -6532,7 +6505,6 @@ gen_proto(compiler_state_t *cstate, bpf_u_int32 v, int proto, int dir) case Q_IPV6: b0 = gen_linktype(cstate, ETHERTYPE_IPV6); -#ifndef CHASE_CHAIN /* * Also check for a fragment header before the final * header. @@ -6542,9 +6514,6 @@ gen_proto(compiler_state_t *cstate, bpf_u_int32 v, int proto, int dir) gen_and(b2, b1); b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, v); gen_or(b2, b1); -#else - b1 = gen_protochain(cstate, v, Q_IPV6); -#endif gen_and(b0, b1); return b1; @@ -6984,12 +6953,14 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q) else bpf_error(cstate, "unknown protocol: %s", name); +#if !defined(NO_PROTOCHAIN) case Q_PROTOCHAIN: real_proto = lookup_proto(cstate, name, proto); if (real_proto >= 0) return gen_protochain(cstate, real_proto, proto); else bpf_error(cstate, "unknown protocol: %s", name); +#endif /* !defined(NO_PROTOCHAIN) */ case Q_UNDEF: syntax(cstate); @@ -7162,8 +7133,10 @@ gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q) case Q_PROTO: return gen_proto(cstate, v, proto, dir); +#if !defined(NO_PROTOCHAIN) case Q_PROTOCHAIN: return gen_protochain(cstate, v, proto); +#endif case Q_UNDEF: syntax(cstate); @@ -23,6 +23,14 @@ #define gencode_h #include "pcap/funcattrs.h" +/* + * pcap/bpf.h (a public header) needs u_char, u_short and u_int, which can be + * made available via either pcap-types.h (a private header) or pcap/pcap.h + * (a public header), none of which pcap/bpf.h includes. Include the private + * header to keep things simple, this way this private header should compile + * even if included early from another file. + */ +#include "pcap-types.h" #include "pcap/bpf.h" /* bpf_u_int32 and BPF_MEMWORDS */ /* diff --git a/missing/asprintf.c b/missing/asprintf.c index 3aa55ed9..b65310e1 100644 --- a/missing/asprintf.c +++ b/missing/asprintf.c @@ -20,7 +20,7 @@ pcap_vasprintf(char **strp, const char *format, va_list args) int ret; /* - * XXX - the C99 standard says, in section 7.19.6.5 "Thes + * XXX - the C99 standard says, in section 7.19.6.5 "The * nprintf function": * * The snprintf function is equivalent to fprintf, except that @@ -108,26 +108,7 @@ done $CC $DEPENDENCY_CFLAG $flags $sources | sed " s; \./; ;g - $SED" | -awk '{ - if ($1 != prev) { - if (rec != "") - print rec; - rec = $0; - prev = $1; - } - else { - if (length(rec $2) > 78) { - print rec; - rec = $0; - } - else - rec = rec " " $2 - } -} -END { - print rec -}' >> $TMP + $SED" >> $TMP cat << _EOF_ >> $TMP @@ -2099,7 +2099,7 @@ opt_blks(opt_state_t *opt_state, struct icode *ic, int do_stmts) * versions of the machine code, eventually returning * to the first version. (We're really not doing a * full loop detection, we're just testing for two - * passes in a row where where we do nothing but + * passes in a row where we do nothing but * move branches.) */ return; @@ -2610,7 +2610,7 @@ opt_init(opt_state_t *opt_state, struct icode *ic) } /* - * Make sure the total memory required for both of them dosn't + * Make sure the total memory required for both of them doesn't * overflow. */ if (block_memsize > SIZE_MAX - edge_memsize) { @@ -478,7 +478,7 @@ bpf_open(char *errbuf) { int fd = -1; static const char cloning_device[] = "/dev/bpf"; - int n = 0; + u_int n = 0; char device[sizeof "/dev/bpf0000000000"]; static int no_cloning_bpf = 0; @@ -526,7 +526,7 @@ bpf_open(char *errbuf) * that isn't in use. */ do { - (void)snprintf(device, sizeof(device), "/dev/bpf%d", n++); + (void)snprintf(device, sizeof(device), "/dev/bpf%u", n++); /* * Initially try a read/write open (to allow the inject * method to work). If that fails due to permission diff --git a/pcap-common.c b/pcap-common.c index fcfe8bff..9738325b 100644 --- a/pcap-common.c +++ b/pcap-common.c @@ -28,13 +28,6 @@ #include <pcap-types.h> #include "pcap-int.h" -#include "extract.h" -#include "pcap/sll.h" -#include "pcap/usb.h" -#include "pcap/nflog.h" -#include "pcap/can_socketcan.h" - -#include "pflog.h" #include "pcap-common.h" @@ -416,7 +409,7 @@ * DLT_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>. * Every frame contains a 32bit A429 label. * More documentation on Arinc 429 can be found at - * http://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf + * https://web.archive.org/web/20040616233302/https://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf */ #define LINKTYPE_A429 184 @@ -1194,6 +1187,8 @@ /* * USB 2.0, 1.1, and 1.0 packets as transmitted over the cable. + * Deprecated in favor of speed specific LINKTYPEs: LINKTYPE_USB_2_0_LOW_SPEED, + * LINKTYPE_USB_2_0_FULL_SPEED and LINKTYPE_USB_2_0_HIGH_SPEED. */ #define LINKTYPE_USB_2_0 288 @@ -1228,7 +1223,14 @@ */ #define LINKTYPE_ZBOSS_NCP 292 -#define LINKTYPE_MATCHING_MAX 292 /* highest value in the "matching" range */ +/* + * USB 2.0, 1.1, and 1.0 packets as transmitted over the cable. + */ +#define LINKTYPE_USB_2_0_LOW_SPEED 293 +#define LINKTYPE_USB_2_0_FULL_SPEED 294 +#define LINKTYPE_USB_2_0_HIGH_SPEED 295 + +#define LINKTYPE_MATCHING_MAX 295 /* highest value in the "matching" range */ /* * The DLT_ and LINKTYPE_ values in the "matching" range should be the @@ -1429,392 +1431,3 @@ max_snaplen_for_dlt(int dlt) return MAXIMUM_SNAPLEN; } } - -/* - * Most versions of the DLT_PFLOG pseudo-header have UID and PID fields - * that are saved in host byte order. - * - * When reading a DLT_PFLOG packet, we need to convert those fields from - * the byte order of the host that wrote the file to this host's byte - * order. - */ -static void -swap_pflog_header(const struct pcap_pkthdr *hdr, u_char *buf) -{ - u_int caplen = hdr->caplen; - u_int length = hdr->len; - u_int pfloghdr_length; - struct pfloghdr *pflhdr = (struct pfloghdr *)buf; - - if (caplen < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid) || - length < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid)) { - /* Not enough data to have the uid field */ - return; - } - - pfloghdr_length = pflhdr->length; - - if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid)) { - /* Header doesn't include uid field */ - return; - } - pflhdr->uid = SWAPLONG(pflhdr->uid); - - if (caplen < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid) || - length < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid)) { - /* Not enough data to have the pid field */ - return; - } - if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid)) { - /* Header doesn't include pid field */ - return; - } - pflhdr->pid = SWAPLONG(pflhdr->pid); - - if (caplen < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid) || - length < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid)) { - /* Not enough data to have the rule_uid field */ - return; - } - if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid)) { - /* Header doesn't include rule_uid field */ - return; - } - pflhdr->rule_uid = SWAPLONG(pflhdr->rule_uid); - - if (caplen < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid) || - length < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid)) { - /* Not enough data to have the rule_pid field */ - return; - } - if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid)) { - /* Header doesn't include rule_pid field */ - return; - } - pflhdr->rule_pid = SWAPLONG(pflhdr->rule_pid); -} - -/* - * DLT_LINUX_SLL packets with a protocol type of LINUX_SLL_P_CAN or - * LINUX_SLL_P_CANFD have SocketCAN headers in front of the payload, - * with the CAN ID being in host byte order. - * - * When reading a DLT_LINUX_SLL packet, we need to check for those - * packets and convert the CAN ID from the byte order of the host that - * wrote the file to this host's byte order. - */ -static void -swap_linux_sll_header(const struct pcap_pkthdr *hdr, u_char *buf) -{ - u_int caplen = hdr->caplen; - u_int length = hdr->len; - struct sll_header *shdr = (struct sll_header *)buf; - uint16_t protocol; - pcap_can_socketcan_hdr *chdr; - - if (caplen < (u_int) sizeof(struct sll_header) || - length < (u_int) sizeof(struct sll_header)) { - /* Not enough data to have the protocol field */ - return; - } - - protocol = EXTRACT_BE_U_2(&shdr->sll_protocol); - if (protocol != LINUX_SLL_P_CAN && protocol != LINUX_SLL_P_CANFD) - return; - - /* - * SocketCAN packet; fix up the packet's header. - */ - chdr = (pcap_can_socketcan_hdr *)(buf + sizeof(struct sll_header)); - if (caplen < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id) || - length < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id)) { - /* Not enough data to have the CAN ID */ - return; - } - chdr->can_id = SWAPLONG(chdr->can_id); -} - -/* - * The same applies for DLT_LINUX_SLL2. - */ -static void -swap_linux_sll2_header(const struct pcap_pkthdr *hdr, u_char *buf) -{ - u_int caplen = hdr->caplen; - u_int length = hdr->len; - struct sll2_header *shdr = (struct sll2_header *)buf; - uint16_t protocol; - pcap_can_socketcan_hdr *chdr; - - if (caplen < (u_int) sizeof(struct sll2_header) || - length < (u_int) sizeof(struct sll2_header)) { - /* Not enough data to have the protocol field */ - return; - } - - protocol = EXTRACT_BE_U_2(&shdr->sll2_protocol); - if (protocol != LINUX_SLL_P_CAN && protocol != LINUX_SLL_P_CANFD) - return; - - /* - * SocketCAN packet; fix up the packet's header. - */ - chdr = (pcap_can_socketcan_hdr *)(buf + sizeof(struct sll2_header)); - if (caplen < (u_int) sizeof(struct sll2_header) + sizeof(chdr->can_id) || - length < (u_int) sizeof(struct sll2_header) + sizeof(chdr->can_id)) { - /* Not enough data to have the CAN ID */ - return; - } - chdr->can_id = SWAPLONG(chdr->can_id); -} - -/* - * The DLT_USB_LINUX and DLT_USB_LINUX_MMAPPED headers are in host - * byte order when capturing (it's supplied directly from a - * memory-mapped buffer shared by the kernel). - * - * When reading a DLT_USB_LINUX or DLT_USB_LINUX_MMAPPED packet, we - * need to convert it from the byte order of the host that wrote the - * file to this host's byte order. - */ -static void -swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf, - int header_len_64_bytes) -{ - pcap_usb_header_mmapped *uhdr = (pcap_usb_header_mmapped *)buf; - bpf_u_int32 offset = 0; - - /* - * "offset" is the offset *past* the field we're swapping; - * we skip the field *before* checking to make sure - * the captured data length includes the entire field. - */ - - /* - * The URB id is a totally opaque value; do we really need to - * convert it to the reading host's byte order??? - */ - offset += 8; /* skip past id */ - if (hdr->caplen < offset) - return; - uhdr->id = SWAPLL(uhdr->id); - - offset += 4; /* skip past various 1-byte fields */ - - offset += 2; /* skip past bus_id */ - if (hdr->caplen < offset) - return; - uhdr->bus_id = SWAPSHORT(uhdr->bus_id); - - offset += 2; /* skip past various 1-byte fields */ - - offset += 8; /* skip past ts_sec */ - if (hdr->caplen < offset) - return; - uhdr->ts_sec = SWAPLL(uhdr->ts_sec); - - offset += 4; /* skip past ts_usec */ - if (hdr->caplen < offset) - return; - uhdr->ts_usec = SWAPLONG(uhdr->ts_usec); - - offset += 4; /* skip past status */ - if (hdr->caplen < offset) - return; - uhdr->status = SWAPLONG(uhdr->status); - - offset += 4; /* skip past urb_len */ - if (hdr->caplen < offset) - return; - uhdr->urb_len = SWAPLONG(uhdr->urb_len); - - offset += 4; /* skip past data_len */ - if (hdr->caplen < offset) - return; - uhdr->data_len = SWAPLONG(uhdr->data_len); - - if (uhdr->transfer_type == URB_ISOCHRONOUS) { - offset += 4; /* skip past s.iso.error_count */ - if (hdr->caplen < offset) - return; - uhdr->s.iso.error_count = SWAPLONG(uhdr->s.iso.error_count); - - offset += 4; /* skip past s.iso.numdesc */ - if (hdr->caplen < offset) - return; - uhdr->s.iso.numdesc = SWAPLONG(uhdr->s.iso.numdesc); - } else - offset += 8; /* skip USB setup header */ - - /* - * With the old header, there are no isochronous descriptors - * after the header. - * - * With the new header, the actual number of descriptors in - * the header is not s.iso.numdesc, it's ndesc - only the - * first N descriptors, for some value of N, are put into - * the header, and ndesc is set to the actual number copied. - * In addition, if s.iso.numdesc is negative, no descriptors - * are captured, and ndesc is set to 0. - */ - if (header_len_64_bytes) { - /* - * This is either the "version 1" header, with - * 16 bytes of additional fields at the end, or - * a "version 0" header from a memory-mapped - * capture, with 16 bytes of zeroed-out padding - * at the end. Byte swap them as if this were - * a "version 1" header. - */ - offset += 4; /* skip past interval */ - if (hdr->caplen < offset) - return; - uhdr->interval = SWAPLONG(uhdr->interval); - - offset += 4; /* skip past start_frame */ - if (hdr->caplen < offset) - return; - uhdr->start_frame = SWAPLONG(uhdr->start_frame); - - offset += 4; /* skip past xfer_flags */ - if (hdr->caplen < offset) - return; - uhdr->xfer_flags = SWAPLONG(uhdr->xfer_flags); - - offset += 4; /* skip past ndesc */ - if (hdr->caplen < offset) - return; - uhdr->ndesc = SWAPLONG(uhdr->ndesc); - - if (uhdr->transfer_type == URB_ISOCHRONOUS) { - /* swap the values in struct linux_usb_isodesc */ - usb_isodesc *pisodesc; - uint32_t i; - - pisodesc = (usb_isodesc *)(void *)(buf+offset); - for (i = 0; i < uhdr->ndesc; i++) { - offset += 4; /* skip past status */ - if (hdr->caplen < offset) - return; - pisodesc->status = SWAPLONG(pisodesc->status); - - offset += 4; /* skip past offset */ - if (hdr->caplen < offset) - return; - pisodesc->offset = SWAPLONG(pisodesc->offset); - - offset += 4; /* skip past len */ - if (hdr->caplen < offset) - return; - pisodesc->len = SWAPLONG(pisodesc->len); - - offset += 4; /* skip past padding */ - - pisodesc++; - } - } - } -} - -/* - * The DLT_NFLOG "packets" have a mixture of big-endian and host-byte-order - * data. They begin with a fixed-length header with big-endian fields, - * followed by a set of TLVs, where the type and length are in host - * byte order but the values are either big-endian or are a raw byte - * sequence that's the same regardless of the host's byte order. - * - * When reading a DLT_NFLOG packet, we need to convert the type and - * length values from the byte order of the host that wrote the file - * to the byte order of this host. - */ -static void -swap_nflog_header(const struct pcap_pkthdr *hdr, u_char *buf) -{ - u_char *p = buf; - nflog_hdr_t *nfhdr = (nflog_hdr_t *)buf; - nflog_tlv_t *tlv; - u_int caplen = hdr->caplen; - u_int length = hdr->len; - uint16_t size; - - if (caplen < (u_int) sizeof(nflog_hdr_t) || - length < (u_int) sizeof(nflog_hdr_t)) { - /* Not enough data to have any TLVs. */ - return; - } - - if (nfhdr->nflog_version != 0) { - /* Unknown NFLOG version */ - return; - } - - length -= sizeof(nflog_hdr_t); - caplen -= sizeof(nflog_hdr_t); - p += sizeof(nflog_hdr_t); - - while (caplen >= sizeof(nflog_tlv_t)) { - tlv = (nflog_tlv_t *) p; - - /* Swap the type and length. */ - tlv->tlv_type = SWAPSHORT(tlv->tlv_type); - tlv->tlv_length = SWAPSHORT(tlv->tlv_length); - - /* Get the length of the TLV. */ - size = tlv->tlv_length; - if (size % 4 != 0) - size += 4 - size % 4; - - /* Is the TLV's length less than the minimum? */ - if (size < sizeof(nflog_tlv_t)) { - /* Yes. Give up now. */ - return; - } - - /* Do we have enough data for the full TLV? */ - if (caplen < size || length < size) { - /* No. */ - return; - } - - /* Skip over the TLV. */ - length -= size; - caplen -= size; - p += size; - } -} - -void -swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data) -{ - /* - * Convert pseudo-headers from the byte order of - * the host on which the file was saved to our - * byte order, as necessary. - */ - switch (linktype) { - - case DLT_PFLOG: - swap_pflog_header(hdr, data); - break; - - case DLT_LINUX_SLL: - swap_linux_sll_header(hdr, data); - break; - - case DLT_LINUX_SLL2: - swap_linux_sll2_header(hdr, data); - break; - - case DLT_USB_LINUX: - swap_linux_usb_header(hdr, data, 0); - break; - - case DLT_USB_LINUX_MMAPPED: - swap_linux_usb_header(hdr, data, 1); - break; - - case DLT_NFLOG: - swap_nflog_header(hdr, data); - break; - } -} diff --git a/pcap-common.h b/pcap-common.h index 8795a829..d765c947 100644 --- a/pcap-common.h +++ b/pcap-common.h @@ -21,33 +21,8 @@ * pcap-common.h - common code for pcap and pcapng files */ -/* - * We use the "receiver-makes-right" approach to byte order, - * because time is at a premium when we are writing the file. - * In other words, the pcap_file_header and pcap_pkthdr, - * records are written in host byte order. - * Note that the bytes of packet data are written out in the order in - * which they were received, so multi-byte fields in packets are not - * written in host byte order, they're written in whatever order the - * sending machine put them in. - * - * ntoh[ls] aren't sufficient because we might need to swap on a big-endian - * machine (if the file was written in little-end order). - */ -#define SWAPLONG(y) \ - (((((u_int)(y))&0xff)<<24) | \ - ((((u_int)(y))&0xff00)<<8) | \ - ((((u_int)(y))&0xff0000)>>8) | \ - ((((u_int)(y))>>24)&0xff)) -#define SWAPSHORT(y) \ - ((u_short)(((((u_int)(y))&0xff)<<8) | \ - ((((u_int)(y))&0xff00)>>8))) - extern int dlt_to_linktype(int dlt); extern int linktype_to_dlt(int linktype); -extern void swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, - u_char *data); - extern u_int max_snaplen_for_dlt(int dlt); @@ -736,7 +736,7 @@ dag_inject(pcap_t *p, const void *buf _U_, int size _U_) * API polling parameters. * * snaplen is now also ignored, until we get per-stream slen support. Set - * slen with approprite DAG tool BEFORE pcap_activate(). + * slen with appropriate DAG tool BEFORE pcap_activate(). * * See also pcap(3). */ @@ -569,7 +569,7 @@ int pcap_lookupnet (const char *device, bpf_u_int32 *localnet, /* * Get a list of all interfaces that are present and that we probe okay. * Returns -1 on error, 0 otherwise. - * The list may be NULL epty if no interfaces were up and could be opened. + * The list may be NULL empty if no interfaces were up and could be opened. */ int pcap_platform_finddevs (pcap_if_list_t *devlistp, char *errbuf) { @@ -1204,14 +1204,14 @@ static void ndis_close (struct device *dev) static int ndis_open (struct device *dev) { - int promis = (dev->flags & IFF_PROMISC); + int promisc = (dev->flags & IFF_PROMISC); #ifdef USE_NDIS2 - if (!NdisInit(promis)) + if (!NdisInit(promisc)) return (0); return (1); #else - ARGSUSED (promis); + ARGSUSED (promisc); return (0); #endif } diff --git a/pcap-dpdk.c b/pcap-dpdk.c index 94c33092..025a6748 100644 --- a/pcap-dpdk.c +++ b/pcap-dpdk.c @@ -50,7 +50,7 @@ sed -i 's/CONFIG_RTE_BUILD_SHARED_LIB=n/CONFIG_RTE_BUILD_SHARED_LIB=y/' $RTE_SDK You shall learn how to bind nic with DPDK-compatible driver by $RTE_SDK/usertools/dpdk-devbind.py, such as igb_uio. And enable hugepages by dpdk-setup.sh -Then launch the l2fwd with dynamic dirver support. For example: +Then launch the l2fwd with dynamic driver support. For example: $RTE_SDK/examples/l2fwd/$RTE_TARGET/l2fwd -dlibrte_pmd_e1000.so -dlibrte_pmd_ixgbe.so -dlibrte_mempool_ring.so -- -p 0x1 3. Compile libpcap with dpdk options. diff --git a/pcap-filter.manmisc.in b/pcap-filter.manmisc.in index 5fce8043..cd67518f 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@ "4 January 2022" +.TH PCAP-FILTER @MAN_MISC_INFO@ "8 July 2022" .SH NAME pcap-filter \- packet filter syntax .br @@ -150,40 +150,40 @@ E.g., `\fBtcp dst port\fP ftp \fBor tcp dst port\fP ftp-data \fBor tcp dst port\fP domain'. .LP Allowable primitives are: -.IP "\fBdst host \fIhost\fR" -True if the IPv4/v6 destination field of the packet is \fIhost\fP, +.IP "\fBdst host \fIhostnameaddr\fR" +True if the IPv4/v6 destination field of the packet is \fIhostnameaddr\fP, which may be either an address or a name. -.IP "\fBsrc host \fIhost\fR" -True if the IPv4/v6 source field of the packet is \fIhost\fP. -.IP "\fBhost \fIhost\fP" -True if either the IPv4/v6 source or destination of the packet is \fIhost\fP. +.IP "\fBsrc host \fIhostnameaddr\fR" +True if the IPv4/v6 source field of the packet is \fIhostnameaddr\fP. +.IP "\fBhost \fIhostnameaddr\fP" +True if either the IPv4/v6 source or destination of the packet is \fIhostnameaddr\fP. .IP Any of the above host expressions can be prepended with the keywords, \fBip\fP, \fBarp\fP, \fBrarp\fP, or \fBip6\fP as in: .in +.5i .nf -\fBip host \fIhost\fR +\fBip host \fIhostnameaddr\fR .fi .in -.5i which is equivalent to: .in +.5i .nf -\fBether proto \\ip and host \fIhost\fR +\fBether proto \\\fRip \fBand host \fIhostnameaddr\fR .fi .in -.5i -If \fIhost\fR is a name with multiple IPv4 addresses, each address will +If \fIhostnameaddr\fR is a name with multiple IPv4/v6 addresses, each address will be checked for a match. -.IP "\fBether dst \fIehost\fP" -True if the Ethernet destination address is \fIehost\fP. -\fIEhost\fP +.IP "\fBether dst \fIethernameaddr\fP" +True if the Ethernet destination address is \fIethernameaddr\fP. +\fIethernameaddr\fP may be either a name from /etc/ethers or a numerical MAC address of the form "xx:xx:xx:xx:xx:xx", "xx.xx.xx.xx.xx.xx", "xx-xx-xx-xx-xx-xx", "xxxx.xxxx.xxxx", "xxxxxxxxxxxx", or various mixes of ':', '.', and '-', where each "x" is a hex digit (0-9, a-f, or A-F). -.IP "\fBether src \fIehost\fP" -True if the Ethernet source address is \fIehost\fP. -.IP "\fBether host \fIehost\fP" -True if either the Ethernet source or destination address is \fIehost\fP. +.IP "\fBether src \fIethernameaddr\fP" +True if the Ethernet source address is \fIethernameaddr\fP. +.IP "\fBether host \fIethernameaddr\fP" +True if either the Ethernet source or destination address is \fIethernameaddr\fP. .IP "\fBgateway\fP \fIhost\fP" True if the packet used \fIhost\fP as a gateway. I.e., the Ethernet @@ -196,14 +196,14 @@ host-name-to-Ethernet-address resolution mechanism (/etc/ethers, etc.). (An equivalent expression is .in +.5i .nf -\fBether host \fIehost \fBand not host \fIhost\fR +\fBether host \fIethernameaddr \fBand not host \fIhostnameaddr\fR .fi .in -.5i -which can be used with either names or numbers for \fIhost / ehost\fP.) +which can be used with either names or numbers for \fIhostnameaddr / ethernameaddr\fP.) This syntax does not work in IPv6-enabled configuration at this moment. -.IP "\fBdst net \fInet\fR" +.IP "\fBdst net \fInetnameaddr\fR" True if the IPv4/v6 destination address of the packet has a network -number of \fInet\fP. +number of \fInetnameaddr\fP. \fINet\fP may be either a name from the networks database (/etc/networks, etc.) or a network number. An IPv4 network number can be written as a dotted quad (e.g., 192.168.1.0), @@ -214,24 +214,24 @@ triple, 255.255.0.0 for a dotted pair, or 255.0.0.0 for a single number. An IPv6 network number must be written out fully; the netmask is ff:ff:ff:ff:ff:ff:ff:ff, so IPv6 "network" matches are really always host matches, and a network match requires a netmask length. -.IP "\fBsrc net \fInet\fR" +.IP "\fBsrc net \fInetnameaddr\fR" True if the IPv4/v6 source address of the packet has a network -number of \fInet\fP. -.IP "\fBnet \fInet\fR" +number of \fInetnameaddr\fP. +.IP "\fBnet \fInetnameaddr\fR" True if either the IPv4/v6 source or destination address of the packet has a network -number of \fInet\fP. -.IP "\fBnet \fInet\fR \fBmask \fInetmask\fR" -True if the IPv4 address matches \fInet\fR with the specific \fInetmask\fR. +number of \fInetnameaddr\fP. +.IP "\fBnet \fInetaddr\fR \fBmask \fInetmask\fR" +True if the IPv4 address matches \fInetaddr\fR with the specific \fInetmask\fR. May be qualified with \fBsrc\fR or \fBdst\fR. -Note that this syntax is not valid for IPv6 \fInet\fR. -.IP "\fBnet \fInet\fR/\fIlen\fR" -True if the IPv4/v6 address matches \fInet\fR with a netmask \fIlen\fR +Note that this syntax is not valid for IPv6 \fInetaddr\fR. +.IP "\fBnet \fInetaddr\fR/\fIlen\fR" +True if the IPv4/v6 address matches \fInetaddr\fR with a netmask \fIlen\fR bits wide. May be qualified with \fBsrc\fR or \fBdst\fR. -.IP "\fBdst port \fIport\fR" +.IP "\fBdst port \fIportnamenum\fR" True if the packet is IPv4/v6 TCP, UDP or SCTP and has a -destination port value of \fIport\fP. -The \fIport\fP can be a number or a name used in /etc/services (see +destination port value of \fIportnamenum\fP. +The \fIportnamenum\fP can be a number or a name used in /etc/services (see .BR tcp (4P) and .BR udp (4P)). @@ -239,37 +239,37 @@ If a name is used, both the port number and protocol are checked. If a number or ambiguous name is used, only the port number is checked (e.g., `\fBdst port\fR 513' will print both -tcp/login traffic and udp/who traffic, and `\fBport domain\fR' will print +tcp/login traffic and udp/who traffic, and `\fBport\fR domain' will print both tcp/domain and udp/domain traffic). -.IP "\fBsrc port \fIport\fR" -True if the packet has a source port value of \fIport\fP. -.IP "\fBport \fIport\fR" -True if either the source or destination port of the packet is \fIport\fP. -.IP "\fBdst portrange \fIport1-port2\fR" +.IP "\fBsrc port \fIportnamenum\fR" +True if the packet has a source port value of \fIportnamenum\fP. +.IP "\fBport \fIportnamenum\fR" +True if either the source or destination port of the packet is \fIportnamenum\fP. +.IP "\fBdst portrange \fIportnamenum1-portnamenum2\fR" True if the packet is IPv4/v6 TCP, UDP or SCTP and has a -destination port value between \fIport1\fP and \fIport2\fP (both inclusive). -.I port1 +destination port value between \fIportnamenum1\fP and \fIportnamenum2\fP (both inclusive). +.I portnamenum1 and -.I port2 +.I portnamenum2 are interpreted in the same fashion as the -.I port +.I portnamenum parameter for .BR port . -.IP "\fBsrc portrange \fIport1-port2\fR" -True if the packet has a source port value between \fIport1\fP and -\fIport2\fP (both inclusive). -.IP "\fBportrange \fIport1-port2\fR" +.IP "\fBsrc portrange \fIportnamenum1-portnamenum2\fR" +True if the packet has a source port value between \fIportnamenum1\fP and +\fIportnamenum2\fP (both inclusive). +.IP "\fBportrange \fIportnamenum1-portnamenum2\fR" True if either the source or destination port of the packet is between -\fIport1\fP and \fIport2\fP (both inclusive). +\fIportnamenum1\fP and \fIportnamenum2\fP (both inclusive). .IP Any of the above port or port range expressions can be prepended with the keywords, \fBtcp\fP, \fBudp\fP or \fBsctp\fP, as in: .in +.5i .nf -\fBtcp src port \fIport\fR +\fBtcp src port \fIportnamenum\fR .fi .in -.5i -which matches only TCP packets whose source port is \fIport\fP. +which matches only TCP packets whose source port is \fIportnamenum\fP. .IP "\fBless \fIlength\fR" True if the packet has a length less than or equal to \fIlength\fP. This is equivalent to: @@ -290,20 +290,55 @@ This is equivalent to: True if the packet is an IPv4 packet (see .BR ip (4P)) of protocol type \fIprotocol\fP. -\fIProtocol\fP can be a number or one of the names -\fBicmp\fP, \fBicmp6\fP, \fBigmp\fP, \fBigrp\fP, \fBpim\fP, \fBah\fP, -\fBesp\fP, \fBvrrp\fP, \fBsctp\fP, \fBudp\fP, or \fBtcp\fP. -Note that the identifiers \fBtcp\fP, \fBudp\fP, \fBsctp\fP and \fBicmp\fP +\fIProtocol\fP can be a number or one of the names recognized by +.BR getprotobyname (3) +(as in e.g. `\fBgetent\fR(1) protocols'), typically from an entry in +.IR \%/etc/protocols , +for example: +.BR ah , +.BR esp , +.B eigrp +(only in Linux, FreeBSD, NetBSD, DragonFly BSD, and macOS), +.BR icmp , +.BR igmp , +.B igrp +(only in OpenBSD), +.BR pim , +.BR sctp , +.BR tcp , +.B udp +or +.BR vrrp . +Note that most of these example identifiers are also keywords and must be escaped via backslash (\\). Note that this primitive does not chase the protocol header chain. +.IP "\fBicmp\fR" +Abbreviation for: +.in +.5i +.nf +\fBip proto\fR 1 +.fi +.in -.5i .IP "\fBip6 proto \fIprotocol\fR" True if the packet is an IPv6 packet of protocol type \fIprotocol\fP. +(See `\fBip proto\fP' above for the meaning of \fIprotocol\fR.) +Note that the IPv6 variant of ICMP uses a different protocol number, named +.B \%ipv6-icmp +in AIX, FreeBSD, illumos, Linux, macOS, NetBSD, OpenBSD, Solaris and Windows. Note that this primitive does not chase the protocol header chain. +.IP "\fBicmp6\fR" +Abbreviation for: +.in +.5i +.nf +\fBip6 proto\fR 58 +.fi +.in -.5i .IP "\fBproto \fIprotocol\fR" True if the packet is an IPv4 or IPv6 packet of protocol type -\fIprotocol\fP. Note that this primitive does not chase the protocol +\fIprotocol\fP. (See `\fBip proto\fP' above for the meaning of +\fIprotocol\fP.) Note that this primitive does not chase the protocol header chain. -.IP "\fBtcp\fR, \fBudp\fR, \fBicmp\fR, \fBsctp\fR" +.IP "\fBah\fR, \fBesp\fR, \fBpim\fR, \fBsctp\fR, \fBtcp\fR, \fBudp\fR" Abbreviations for: .in +.5i .nf @@ -315,6 +350,7 @@ where \fIprotocol\fR is one of the above protocols. True if the packet is IPv6 packet, and contains protocol header with type \fIprotocol\fR in its protocol header chain. +(See `\fBip proto\fP' above for the meaning of \fIprotocol\fP.) For example, .in +.5i .nf @@ -331,9 +367,11 @@ filter engines in the kernel, so this can be somewhat slow, and may cause more packets to be dropped. .IP "\fBip protochain \fIprotocol\fR" Equivalent to \fBip6 protochain \fIprotocol\fR, but this is for IPv4. +(See `\fBip proto\fP' above for the meaning of \fIprotocol\fP.) .IP "\fBprotochain \fIprotocol\fR" True if the packet is an IPv4 or IPv6 packet of protocol type -\fIprotocol\fP. Note that this primitive chases the protocol +\fIprotocol\fP. (See `\fBip proto\fP' above for the meaning of +\fIprotocol\fP.) Note that this primitive chases the protocol header chain. .IP "\fBether broadcast\fR" True if the packet is an Ethernet broadcast packet. @@ -435,19 +473,19 @@ where \fIprotocol\fR is one of the above protocols. Note that not all applications using .BR pcap (3PCAP) currently know how to parse these protocols. -.IP "\fBdecnet src \fIhost\fR" +.IP "\fBdecnet src \fIdecnetaddr\fR" True if the DECnet source address is -.IR host , +.IR decnetaddr , which may be an address of the form ``10.123'', or a DECnet host name. [DECnet host name support is only available on ULTRIX systems that are configured to run DECnet.] -.IP "\fBdecnet dst \fIhost\fR" +.IP "\fBdecnet dst \fIdecnetaddr\fR" True if the DECnet destination address is -.IR host . -.IP "\fBdecnet host \fIhost\fR" +.IR decnetaddr . +.IP "\fBdecnet host \fIdecnetaddr\fR" True if either the DECnet source or destination address is -.IR host . +.IR decnetaddr . .IP \fBllc\fP True if the packet has an 802.2 LLC header. This includes: .IP @@ -660,9 +698,9 @@ then valid \fIwlan_subtype\fRs are: .IP "\fBsubtype \fIwlan_subtype\fR" True if the IEEE 802.11 frame subtype matches the specified \fIwlan_subtype\fR and frame has the type to which the specified \fIwlan_subtype\fR belongs. -.IP "\fBdir \fIdir\fR" +.IP "\fBdir \fIdirection\fR" True if the IEEE 802.11 frame direction matches the specified -.IR dir . +.IR direction . Valid directions are: .BR nods , .BR tods , @@ -818,30 +856,98 @@ Connect Ack, Release, or Release Done message. True if the packet is an ATM packet, for SunATM on Solaris, and is on a meta signaling circuit and is a Q.2931 Setup, Call Proceeding, Connect, Release, or Release Done message. -.IP "\fIexpr relop expr\fR" -True if the relation holds, where \fIrelop\fR is one of >, <, >=, <=, = -or ==, !=, and \fIexpr\fR is an arithmetic expression composed of integer -constants (expressed in standard C syntax), the normal binary operators -[+, -, *, /, %, &, |, ^, <<, >>], a length operator, and special packet data +.IP "\fIexpr1 relop expr2\fR" +True if the relation holds. \fIRelop\fR is one of +.RB { > , +.BR < , +.BR >= , +.BR <= , +.BR = , +.BR == , +.BR != } +(where +.B = +means the same as +.BR == ). +Each of \fIexpr1\fR and \fIexpr2\fR is an arithmetic expression composed of +integer constants (expressed in standard C syntax), the normal binary operators +.RB { + , +.BR - , +.BR * , +.BR / , +.BR % , +.BR & , +.BR | , +.BR ^ , +.BR << , +.BR >> }, +a length operator, and special packet data accessors. Note that all comparisons are unsigned, so that, for example, 0x80000000 and 0xffffffff are > 0. .IP -The % and ^ operators are currently only supported for filtering in the -kernel on Linux with 3.7 and later kernels; on all other systems, if +The +.B % +and +.B ^ +operators are currently only supported for filtering in the kernel on +particular operating systems (for example: FreeBSD, Linux with 3.7 and later +kernels, NetBSD); on all other systems (for example: AIX, illumos, Solaris, +OpenBSD), if those operators are used, filtering will be done in user mode, which will increase the overhead of capturing packets and may cause more packets to be dropped. .IP +The length operator, indicated by the keyword \fBlen\fP, gives the +length of the packet. +.IP To access data inside the packet, use the following syntax: .in +.5i .nf \fIproto\fB [ \fIexpr\fB : \fIsize\fB ]\fR .fi .in -.5i -\fIProto\fR is one of \fBether, fddi, tr, wlan, ppp, slip, link, -ip, arp, rarp, tcp, udp, sctp, icmp, ip6\fR or \fBradio\fR, and +.I Proto +is one of +.BR arp , +.BR atalk , +.BR carp , +.BR decnet , +.BR ether , +.BR fddi , +.BR icmp , +.BR icmp6 , +.BR igmp , +.BR igrp , +.BR ip , +.BR ip6 , +.BR lat , +.BR link , +.BR mopdl , +.BR moprc , +.BR pim , +.BR ppp , +.BR radio , +.BR rarp , +.BR sca , +.BR sctp , +.BR slip , +.BR tcp , +.BR tr , +.BR udp , +.B vrrp +or +.BR wlan , +and indicates the protocol layer for the index operation. -(\fBether, fddi, wlan, tr, ppp, slip\fR and \fBlink\fR all refer to the +.RB ( ether , +.BR fddi , +.BR link , +.BR ppp , +.BR slip , +.B tr +and +.BR wlan +all refer to the link layer. \fBradio\fR refers to the "radio header" added to some 802.11 captures.) Note that \fBtcp\fR, \fBudp\fR and other upper-layer protocol types only @@ -850,8 +956,6 @@ The byte offset, relative to the indicated protocol layer, is given by \fIexpr\fR. \fISize\fR is optional and indicates the number of bytes in the field of interest; it can be either one, two, or four, and defaults to one. -The length operator, indicated by the keyword \fBlen\fP, gives the -length of the packet. For example, `\fBether[\fP0\fB] &\fP 1 \fB!=\fP 0' catches all multicast traffic. The expression `\fBip[\fP0\fB] &\fP 0xf \fB!=\fP 5' @@ -1036,6 +1140,16 @@ icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply icmp6[icmp6type] != icmp6-echo and icmp6[icmp6type] != icmp6-echoreply .fi .RE +.SH BACKWARD COMPATIBILITY +The ICMPv6 type code names, as well as the +.B tcp-ece +and +.B tcp-cwr +TCP flag names became available in libpcap 1.9.0. +.PP +The +.B geneve +keyword became available in libpcap 1.8.0. .SH SEE ALSO .BR pcap (3PCAP) .SH BUGS diff --git a/pcap-haiku.cpp b/pcap-haiku.cpp index 8b0009c5..d9234f04 100644 --- a/pcap-haiku.cpp +++ b/pcap-haiku.cpp @@ -47,12 +47,11 @@ prepare_request(struct ifreq& request, const char* name) static int -pcap_read_haiku(pcap_t* handle, int maxPackets, pcap_handler callback, +pcap_read_haiku(pcap_t* handle, int maxPackets _U_, pcap_handler callback, u_char* userdata) { // Receive a single packet - struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv; u_char* buffer = (u_char*)handle->buffer + handle->offset; struct sockaddr_dl from; ssize_t bytesReceived; @@ -80,7 +79,7 @@ pcap_read_haiku(pcap_t* handle, int maxPackets, pcap_handler callback, return -1; } - int32 captureLength = bytesReceived; + int32_t captureLength = bytesReceived; if (captureLength > handle->snapshot) captureLength = handle->snapshot; @@ -249,7 +248,11 @@ pcap_create_interface(const char *device, char *errorBuffer) return NULL; } - pcap_t* handle = PCAP_CREATE_COMMON(errorBuffer, struct pcap_haiku); + struct wrapper_struct { pcap_t __common; struct pcap_haiku __private; }; + pcap_t* handle = pcap_create_common(errorBuffer, + sizeof (struct wrapper_struct), + offsetof (struct wrapper_struct, __private)); + if (handle == NULL) { snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "malloc: %s", strerror(errno)); close(socket); @@ -265,7 +268,7 @@ pcap_create_interface(const char *device, char *errorBuffer) } static int -can_be_bound(const char *name) +can_be_bound(const char *name _U_) { return 1; } @@ -485,7 +485,7 @@ pcap_t *pcap_create_interface(const char *, char *); /* * This wrapper takes an error buffer pointer and a type to use for the * private data, and calls pcap_create_common(), passing it the error - * buffer pointer, the size fo the private data type, in bytes, and the + * buffer pointer, the size for the private data type, in bytes, and the * offset of the private data from the beginning of the structure, in * bytes. */ @@ -569,7 +569,7 @@ int add_addr_to_if(pcap_if_list_t *, const char *, bpf_u_int32, /* * This wrapper takes an error buffer pointer and a type to use for the * private data, and calls pcap_create_common(), passing it the error - * buffer pointer, the size fo the private data type, in bytes, and the + * buffer pointer, the size for the private data type, in bytes, and the * offset of the private data from the beginning of the structure, in * bytes. */ diff --git a/pcap-linux.c b/pcap-linux.c index 42ad9249..43d2a9f0 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -1489,7 +1489,7 @@ get_if_ioctl_socket(void) * capture on them, "why do no interfaces show up?" - when the * real problem is a permissions problem. Error reports of that * type require a lot more back-and-forth to debug, as evidenced - * by many Wireshark bugs/mailing list questions/Q&A questoins.) + * by many Wireshark bugs/mailing list questions/Q&A questions.) * * So: * @@ -3978,7 +3978,7 @@ static int pcap_handle_packet_mmap( } else { /* * Clear CANFD_FDF if it's set (probably - * again meaning that that field is + * again meaning that this field is * uninitialized junk). */ canhdr->fd_flags &= ~CANFD_FDF; @@ -241,6 +241,7 @@ int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t DIAG_OFF_FORMAT_TRUNCATION snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path); DIAG_ON_FORMAT_TRUNCATION + closedir(unixdir); return -1; } #endif @@ -273,6 +274,11 @@ int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t PCAP_ERRBUF_SIZE, errno, "malloc() failed"); pcap_freealldevs(*alldevs); +#ifdef _WIN32 + FindClose(filehandle); +#else + closedir(unixdir); +#endif return -1; } @@ -302,6 +308,11 @@ int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t if (pcap_createsrcstr(tmpstring, PCAP_SRC_FILE, NULL, NULL, filename, errbuf) == -1) { pcap_freealldevs(*alldevs); +#ifdef _WIN32 + FindClose(filehandle); +#else + closedir(unixdir); +#endif return -1; } @@ -312,6 +323,11 @@ int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t PCAP_ERRBUF_SIZE, errno, "malloc() failed"); pcap_freealldevs(*alldevs); +#ifdef _WIN32 + FindClose(filehandle); +#else + closedir(unixdir); +#endif return -1; } @@ -326,6 +342,11 @@ int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t PCAP_ERRBUF_SIZE, errno, "malloc() failed"); pcap_freealldevs(*alldevs); +#ifdef _WIN32 + FindClose(filehandle); +#else + closedir(unixdir); +#endif return -1; } @@ -339,9 +360,11 @@ int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t #endif -#ifdef _WIN32 /* Close the search handle. */ +#ifdef _WIN32 FindClose(filehandle); +#else + closedir(unixdir); #endif return 0; @@ -912,7 +912,7 @@ pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user) } } - /* Fill the header for the user suppplied callback function */ + /* Fill the header for the user supplied callback function */ pcap_header.caplen = caplen; pcap_header.len = packet_len; diff --git a/pcap-options.c b/pcap-options.c index 52ce849f..b425f500 100644 --- a/pcap-options.c +++ b/pcap-options.c @@ -62,7 +62,7 @@ void pcap_free_option(pcap_options *po) } } -/* Return 0 on success, -1 on failure invalid option, -2 on type mis-match */ +/* Return 0 on success, -1 on failure invalid option, -2 on type mismatch */ int pcap_set_option_string(pcap_options *po, enum pcap_option_name pon, const char *value) @@ -86,7 +86,7 @@ int pcap_set_option_string(pcap_options *po, return 0; } -/* Return 0 on success, -1 on failure invalid option, -2 on type mis-match */ +/* Return 0 on success, -1 on failure invalid option, -2 on type mismatch */ int pcap_set_option_int(pcap_options *po, enum pcap_option_name pon, const int value) diff --git a/pcap-rpcap-int.h b/pcap-rpcap-int.h index e707a85f..6b07d1fb 100644 --- a/pcap-rpcap-int.h +++ b/pcap-rpcap-int.h @@ -69,7 +69,7 @@ * Exported function prototypes * * * *********************************************************/ -void rpcap_createhdr(struct rpcap_header *header, uint8 type, uint16 value, uint32 length); +void rpcap_createhdr(struct rpcap_header *header, uint8_t type, uint16_t value, uint32_t length); int rpcap_senderror(SOCKET sock, char *error, unsigned short errcode, char *errbuf); #endif diff --git a/pcap-rpcap.c b/pcap-rpcap.c index 062f1107..f7d4e0cc 100644 --- a/pcap-rpcap.c +++ b/pcap-rpcap.c @@ -45,6 +45,7 @@ #include <limits.h> /* for INT_MAX */ #include "sockutils.h" #include "pcap-int.h" +#include "pcap-util.h" #include "rpcap-protocol.h" #include "pcap-rpcap.h" @@ -94,7 +95,8 @@ struct activehosts struct sockaddr_storage host; SOCKET sockctrl; SSL *ssl; - uint8 protocol_version; + uint8_t protocol_version; + int byte_swapped; struct activehosts *next; }; @@ -128,8 +130,9 @@ struct pcap_rpcap { int rmt_capstarted; /* 'true' if the capture is already started (needed to knoe if we have to call the pcap_startcapture() */ char *currentfilter; /* Pointer to a buffer (allocated at run-time) that stores the current filter. Needed when flag PCAP_OPENFLAG_NOCAPTURE_RPCAP is turned on. */ - uint8 protocol_version; /* negotiated protocol version */ - uint8 uses_ssl; /* User asked for rpcaps scheme */ + uint8_t protocol_version; /* negotiated protocol version */ + uint8_t uses_ssl; /* User asked for rpcaps scheme */ + int byte_swapped; /* Server byte order is swapped from ours */ unsigned int TotNetDrops; /* keeps the number of packets that have been dropped by the network */ @@ -170,12 +173,12 @@ 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_recv_msg_header(SOCKET sock, SSL *, struct rpcap_header *header, char *errbuf); -static int rpcap_check_msg_ver(SOCKET sock, SSL *, uint8 expected_ver, struct rpcap_header *header, char *errbuf); -static int rpcap_check_msg_type(SOCKET sock, SSL *, uint8 request_type, struct rpcap_header *header, uint16 *errcode, char *errbuf); -static int rpcap_process_msg_header(SOCKET sock, SSL *, uint8 ver, uint8 request_type, struct rpcap_header *header, char *errbuf); -static int rpcap_recv(SOCKET sock, SSL *, void *buffer, size_t toread, uint32 *plen, char *errbuf); -static void rpcap_msg_err(SOCKET sockctrl, SSL *, uint32 plen, char *remote_errbuf); -static int rpcap_discard(SOCKET sock, SSL *, uint32 len, char *errbuf); +static int rpcap_check_msg_ver(SOCKET sock, SSL *, uint8_t expected_ver, struct rpcap_header *header, char *errbuf); +static int rpcap_check_msg_type(SOCKET sock, SSL *, uint8_t request_type, struct rpcap_header *header, uint16_t *errcode, char *errbuf); +static int rpcap_process_msg_header(SOCKET sock, SSL *, uint8_t ver, uint8_t request_type, struct rpcap_header *header, char *errbuf); +static int rpcap_recv(SOCKET sock, SSL *, void *buffer, size_t toread, uint32_t *plen, char *errbuf); +static void rpcap_msg_err(SOCKET sockctrl, SSL *, uint32_t plen, char *remote_errbuf); +static int rpcap_discard(SOCKET sock, SSL *, uint32_t len, char *errbuf); static int rpcap_read_packet_msg(struct pcap_rpcap const *, pcap_t *p, size_t size); /**************************************************** @@ -388,7 +391,7 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch struct rpcap_header *header; /* general header according to the RPCAP format */ struct rpcap_pkthdr *net_pkt_header; /* header of the packet, from the message */ u_char *net_pkt_data; /* packet data from the message */ - uint32 plen; + uint32_t plen; int retval = 0; /* generic return value */ int msglen; @@ -434,7 +437,8 @@ 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_geterrmsg(p->errbuf, PCAP_ERRBUF_SIZE, + "select() failed"); return -1; } } @@ -683,9 +687,14 @@ static int pcap_read_rpcap(pcap_t *p, int cnt, pcap_handler callback, u_char *us if (ret == 1) { /* - * We got a packet. Hand it to the callback - * and count it so we can return the count. + * We got a packet. + * + * Do whatever post-processing is necessary, hand + * it to the callback, and count it so we can + * return the count. */ + pcap_post_process(p->linktype, pr->byte_swapped, + &pkt_header, pkt_data); (*callback)(user, &pkt_header, pkt_data); n++; } @@ -903,7 +912,7 @@ static struct pcap_stat *rpcap_stats_rpcap(pcap_t *p, struct pcap_stat *ps, int struct pcap_rpcap *pr = p->priv; /* structure used when doing a remote live capture */ struct rpcap_header header; /* header of the RPCAP packet */ struct rpcap_stats netstats; /* statistics sent on the network */ - uint32 plen; /* data remaining in the message */ + uint32_t plen; /* data remaining in the message */ #ifdef _WIN32 if (mode != PCAP_STATS_STANDARD && mode != PCAP_STATS_EX) @@ -1020,7 +1029,7 @@ rpcap_remoteact_getsock(const char *host, int *error, char *errbuf) hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - retval = sock_initaddress(host, "0", &hints, &addrinfo, errbuf, + retval = sock_initaddress(host, NULL, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE); if (retval != 0) { @@ -1076,8 +1085,8 @@ static int pcap_startcapture_remote(pcap_t *fp) struct pcap_rpcap *pr = fp->priv; /* structure used when doing a remote live capture */ 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 */ - uint16 portdata = 0; /* temp variable needed to keep the network port for the data connection */ - uint32 plen; + uint16_t portdata = 0; /* temp variable needed to keep the network port for the data connection */ + uint32_t plen; int active = 0; /* '1' if we're in active mode */ struct activehosts *temp; /* temp var needed to scan the host list chain, to detect if we're in active mode */ char host[INET6_ADDRSTRLEN + 1]; /* numeric name of the other host */ @@ -1101,7 +1110,7 @@ static int pcap_startcapture_remote(pcap_t *fp) int res; socklen_t itemp; int sockbufsize = 0; - uint32 server_sockbufsize; + uint32_t server_sockbufsize; // Take the opportunity to clear pr->data_ssl before any goto error, // as it seems p->priv is not zeroed after its malloced. @@ -1140,7 +1149,8 @@ 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_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "getsockname() failed"); goto error_nodiscard; } ai_family = ((struct sockaddr_storage *) &saddr)->ss_family; @@ -1149,7 +1159,8 @@ 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_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "getnameinfo() failed"); goto error_nodiscard; } @@ -1172,10 +1183,10 @@ static int pcap_startcapture_remote(pcap_t *fp) hints.ai_flags = AI_PASSIVE; /* Data connection is opened by the server toward the client */ /* Let's the server pick up a free network port for us */ - if (sock_initaddress(NULL, "0", &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1) + if (sock_initaddress(NULL, NULL, &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1) goto error_nodiscard; - if ((sockdata = sock_open(addrinfo, SOCKOPEN_SERVER, + if ((sockdata = sock_open(NULL, addrinfo, SOCKOPEN_SERVER, 1 /* max 1 connection in queue */, fp->errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) goto error_nodiscard; @@ -1187,7 +1198,8 @@ 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_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "getsockname() failed"); goto error_nodiscard; } @@ -1299,7 +1311,7 @@ static int pcap_startcapture_remote(pcap_t *fp) if (sock_initaddress(host, portstring, &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1) goto error; - if ((sockdata = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, fp->errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) + if ((sockdata = sock_open(host, addrinfo, SOCKOPEN_CLIENT, 0, fp->errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) goto error; /* addrinfo is no longer used */ @@ -1317,7 +1329,8 @@ static int pcap_startcapture_remote(pcap_t *fp) if (socktemp == INVALID_SOCKET) { - sock_geterror("accept()", fp->errbuf, PCAP_ERRBUF_SIZE); + sock_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "accept() failed"); goto error; } @@ -1351,7 +1364,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(): getsockopt() failed", fp->errbuf, PCAP_ERRBUF_SIZE); + sock_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "pcap_startcapture_remote(): getsockopt() failed"); goto error; } @@ -1561,7 +1575,7 @@ static int pcap_pack_bpffilter(pcap_t *fp, char *sendbuf, int *sendbufidx, struc return -1; filter->filtertype = htons(RPCAP_UPDATEFILTER_BPF); - filter->nitems = htonl((int32)prog->bf_len); + filter->nitems = htonl((int32_t)prog->bf_len); if (sock_bufferize(NULL, prog->bf_len * sizeof(struct rpcap_filterbpf_insn), NULL, sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE)) @@ -1730,14 +1744,16 @@ static int pcap_createfilter_norpcappkt(pcap_t *fp, struct bpf_program *prog) saddrlen = sizeof(struct sockaddr_storage); if (getpeername(pr->rmt_sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1) { - sock_geterror("getpeername()", fp->errbuf, PCAP_ERRBUF_SIZE); + sock_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "getpeername() failed"); 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_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "getnameinfo() failed"); return -1; } @@ -1745,7 +1761,8 @@ 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_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "getsockname() failed"); return -1; } @@ -1753,21 +1770,24 @@ 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_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "getnameinfo() failed"); 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_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "getsockname() failed"); 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_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "getnameinfo() failed"); return -1; } @@ -1884,8 +1904,8 @@ static int pcap_setsampling_remote(pcap_t *fp) memset(sampling_pars, 0, sizeof(struct rpcap_sampling)); - sampling_pars->method = (uint8)fp->rmt_samp.method; - sampling_pars->value = (uint16)htonl(fp->rmt_samp.value); + sampling_pars->method = (uint8_t)fp->rmt_samp.method; + sampling_pars->value = (uint16_t)htonl(fp->rmt_samp.value); if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, sendbuf, sendbufidx, fp->errbuf, PCAP_ERRBUF_SIZE) < 0) @@ -1933,6 +1953,10 @@ static int pcap_setsampling_remote(pcap_t *fp) * \param ver: pointer to variable to which to set the protocol version * number we selected. * + * \param byte_swapped: pointer to variable to which to set 1 if the + * byte order the server says it has is byte-swapped from ours, 0 + * otherwise (whether it's the same as ours or is unknown). + * * \param auth: authentication parameters that have to be sent. * * \param errbuf: a pointer to a user-allocated buffer (of size @@ -1943,18 +1967,21 @@ static int pcap_setsampling_remote(pcap_t *fp) * \return '0' if everything is fine, '-1' for an error. For errors, * an error message string is returned in the 'errbuf' variable. */ -static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8 *ver, struct pcap_rmtauth *auth, char *errbuf) +static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8_t *ver, + int *byte_swapped, 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_t length; /* length of the payload of this message */ struct rpcap_auth *rpauth; - uint16 auth_type; + uint16_t auth_type; struct rpcap_header header; size_t str_length; - uint32 plen; + uint32_t plen; struct rpcap_authreply authreply; /* authentication reply message */ - uint8 ourvers; + uint8_t ourvers; + int has_byte_order; /* The server sent its version of the byte-order magic number */ + u_int their_byte_order_magic; /* Here's what it is */ if (auth) { @@ -1974,7 +2001,7 @@ static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8 *ver, struct pcap_rmtau snprintf(errbuf, PCAP_ERRBUF_SIZE, "User name is too long (> 65535 bytes)"); return -1; } - length += (uint16)str_length; + length += (uint16_t)str_length; } if (auth->password) { @@ -1984,7 +2011,7 @@ static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8 *ver, struct pcap_rmtau snprintf(errbuf, PCAP_ERRBUF_SIZE, "Password is too long (> 65535 bytes)"); return -1; } - length += (uint16)str_length; + length += (uint16_t)str_length; } break; @@ -1993,7 +2020,7 @@ static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8 *ver, struct pcap_rmtau return -1; } - auth_type = (uint16)auth->type; + auth_type = (uint16_t)auth->type; } else { @@ -2021,7 +2048,7 @@ static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8 *ver, struct pcap_rmtau if (auth_type == RPCAP_RMTAUTH_PWD) { if (auth->username) - rpauth->slen1 = (uint16)strlen(auth->username); + rpauth->slen1 = (uint16_t)strlen(auth->username); else rpauth->slen1 = 0; @@ -2030,7 +2057,7 @@ static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8 *ver, struct pcap_rmtau return -1; if (auth->password) - rpauth->slen2 = (uint16)strlen(auth->password); + rpauth->slen2 = (uint16_t)strlen(auth->password); else rpauth->slen2 = 0; @@ -2059,17 +2086,46 @@ static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8 *ver, struct pcap_rmtau plen = header.plen; if (plen != 0) { - /* Yes - is it big enough to be version information? */ - if (plen < sizeof(struct rpcap_authreply)) + size_t reply_len; + + /* Yes - is it big enough to include version information? */ + if (plen < sizeof(struct rpcap_authreply_old)) { /* No - discard it and fail. */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Authenticaton reply from server is too short"); + (void)rpcap_discard(sockctrl, ssl, plen, NULL); + return -1; + } + + /* Yes - does it include server byte order information? */ + if (plen == sizeof(struct rpcap_authreply_old)) + { + /* No - just read the version information */ + has_byte_order = 0; + reply_len = sizeof(struct rpcap_authreply_old); + } + else if (plen >= sizeof(struct rpcap_authreply_old)) + { + /* Yes - read it all. */ + has_byte_order = 1; + reply_len = sizeof(struct rpcap_authreply); + } + else + { + /* + * Too long for old reply, too short for new reply. + * Discard it and fail. + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Authenticaton reply from server is too short"); (void)rpcap_discard(sockctrl, ssl, plen, NULL); return -1; } /* Read the reply body */ if (rpcap_recv(sockctrl, ssl, (char *)&authreply, - sizeof(struct rpcap_authreply), &plen, errbuf) == -1) + reply_len, &plen, errbuf) == -1) { (void)rpcap_discard(sockctrl, ssl, plen, NULL); return -1; @@ -2092,12 +2148,32 @@ static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8 *ver, struct pcap_rmtau "The server's minimum supported protocol version is greater than its maximum supported protocol version"); return -1; } + + if (has_byte_order) + { + their_byte_order_magic = authreply.byte_order_magic; + } + else + { + /* + * The server didn't tell us what its byte + * order is; assume it's ours. + */ + their_byte_order_magic = RPCAP_BYTE_ORDER_MAGIC;; + } } else { /* No - it supports only version 0. */ authreply.minvers = 0; authreply.maxvers = 0; + + /* + * And it didn't tell us what its byte order is; assume + * it's ours. + */ + has_byte_order = 0; + their_byte_order_magic = RPCAP_BYTE_ORDER_MAGIC; } /* @@ -2130,6 +2206,27 @@ static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8 *ver, struct pcap_rmtau goto novers; } + /* + * Is the server byte order the opposite of ours? + */ + if (their_byte_order_magic == RPCAP_BYTE_ORDER_MAGIC) + { + /* No, it's the same. */ + *byte_swapped = 0; + } + else if (their_byte_order_magic == RPCAP_BYTE_ORDER_MAGIC_SWAPPED) + { + /* Yes, it's the opposite of ours. */ + *byte_swapped = 1; + } + else + { + /* They sent us something bogus. */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "The server did not send us a valid byte order value"); + return -1; + } + *ver = ourvers; return 0; @@ -2150,7 +2247,8 @@ static const char userinfo_allowed_symbols[] = "-._~!&'()*+,;="; * struct created from a username and password parsed out of the userinfo * portion of a URI. */ -static int rpcap_doauth_userinfo(SOCKET sockctrl, SSL *ssl, uint8 *ver, const char *userinfo, char *errbuf) +static int rpcap_doauth_userinfo(SOCKET sockctrl, SSL *ssl, uint8_t *ver, + int *byte_swapped, const char *userinfo, char *errbuf) { struct pcap_rmtauth auth; const char *ptr; @@ -2208,10 +2306,11 @@ static int rpcap_doauth_userinfo(SOCKET sockctrl, SSL *ssl, uint8 *ver, const ch } } - return rpcap_doauth(sockctrl, ssl, ver, &auth, errbuf); + return rpcap_doauth(sockctrl, ssl, ver, byte_swapped, &auth, + errbuf); } - return rpcap_doauth(sockctrl, ssl, ver, NULL, errbuf); + return rpcap_doauth(sockctrl, ssl, ver, byte_swapped, NULL, errbuf); } @@ -2234,9 +2333,9 @@ pcap_setnonblock_rpcap(pcap_t *p, int nonblock _U_) static int rpcap_setup_session(const char *source, struct pcap_rmtauth *auth, - int *activep, SOCKET *sockctrlp, uint8 *uses_sslp, SSL **sslp, - int rmt_flags, uint8 *protocol_versionp, char *host, char *port, - char *iface, char *errbuf) + int *activep, SOCKET *sockctrlp, uint8_t *uses_sslp, SSL **sslp, + int rmt_flags, uint8_t *protocol_versionp, int *byte_swappedp, + char *host, char *port, char *iface, char *errbuf) { int type; int auth_result; @@ -2289,6 +2388,7 @@ rpcap_setup_session(const char *source, struct pcap_rmtauth *auth, *sockctrlp = activeconn->sockctrl; *sslp = activeconn->ssl; *protocol_versionp = activeconn->protocol_version; + *byte_swappedp = activeconn->byte_swapped; } else { @@ -2326,7 +2426,7 @@ rpcap_setup_session(const char *source, struct pcap_rmtauth *auth, return -1; } - if ((*sockctrlp = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, + if ((*sockctrlp = sock_open(host, addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) { freeaddrinfo(addrinfo); @@ -2357,13 +2457,13 @@ rpcap_setup_session(const char *source, struct pcap_rmtauth *auth, if (auth == NULL && *userinfo != '\0') { - auth_result = rpcap_doauth_userinfo(*sockctrlp, *sslp, protocol_versionp, - userinfo, errbuf); + auth_result = rpcap_doauth_userinfo(*sockctrlp, *sslp, + protocol_versionp, byte_swappedp, userinfo, errbuf); } else { - auth_result = rpcap_doauth(*sockctrlp, *sslp, protocol_versionp, auth, - errbuf); + auth_result = rpcap_doauth(*sockctrlp, *sslp, + protocol_versionp, byte_swappedp, auth, errbuf); } if (auth_result == -1) @@ -2431,9 +2531,10 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim char host[PCAP_BUF_SIZE], ctrlport[PCAP_BUF_SIZE], iface[PCAP_BUF_SIZE]; SOCKET sockctrl; SSL *ssl = NULL; - uint8 protocol_version; /* negotiated protocol version */ + uint8_t protocol_version; /* negotiated protocol version */ + int byte_swapped; /* server is known to be byte-swapped */ int active; - uint32 plen; + uint32_t 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 */ @@ -2477,8 +2578,8 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim * Attempt to set up the session with the server. */ if (rpcap_setup_session(fp->opt.device, auth, &active, &sockctrl, - &pr->uses_ssl, &ssl, flags, &protocol_version, host, ctrlport, - iface, errbuf) == -1) + &pr->uses_ssl, &ssl, flags, &protocol_version, &byte_swapped, + host, ctrlport, iface, errbuf) == -1) { /* Session setup failed. */ pcap_close(fp); @@ -2497,7 +2598,7 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim goto error_nodiscard; rpcap_createhdr((struct rpcap_header *) sendbuf, protocol_version, - RPCAP_MSG_OPEN_REQ, 0, (uint32) strlen(iface)); + RPCAP_MSG_OPEN_REQ, 0, (uint32_t) strlen(iface)); if (sock_bufferize(iface, (int) strlen(iface), sendbuf, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE)) @@ -2527,6 +2628,7 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim pr->rmt_sockctrl = sockctrl; pr->ctrl_ssl = ssl; pr->protocol_version = protocol_version; + pr->byte_swapped = byte_swapped; pr->rmt_clientside = 1; /* This code is duplicated from the end of this function */ @@ -2597,15 +2699,16 @@ freeaddr(struct pcap_addr *addr) int pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf) { - uint8 protocol_version; /* protocol version */ + uint8_t protocol_version; /* protocol version */ + int byte_swapped; /* Server byte order is swapped from ours */ SOCKET sockctrl; /* socket descriptor of the control connection */ SSL *ssl = NULL; /* optional SSL handler for sockctrl */ - uint32 plen; + uint32_t plen; struct rpcap_header header; /* structure that keeps the general header of the rpcap protocol */ int i, j; /* temp variables */ int nif; /* Number of interfaces listed */ int active; /* 'true' if we the other end-party is in active mode */ - uint8 uses_ssl; + uint8_t uses_ssl; 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 */ @@ -2619,7 +2722,8 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i * Attempt to set up the session with the server. */ if (rpcap_setup_session(source, auth, &active, &sockctrl, &uses_ssl, - &ssl, 0, &protocol_version, host, port, NULL, errbuf) == -1) + &ssl, 0, &protocol_version, &byte_swapped, host, port, NULL, + errbuf) == -1) { /* Session setup failed. */ return -1; @@ -2910,7 +3014,8 @@ SOCKET pcap_remoteact_accept_ex(const char *address, const char *port, const cha socklen_t fromlen; /* keeps the length of the sockaddr_storage variable */ SOCKET sockctrl; /* keeps the main socket identifier */ SSL *ssl = NULL; /* Optional SSL handler for sockctrl */ - uint8 protocol_version; /* negotiated protocol version */ + uint8_t protocol_version; /* negotiated protocol version */ + int byte_swapped; /* 1 if server byte order is known to be the reverse of ours */ struct activehosts *temp, *prev; /* temp var needed to scan he host list chain */ *connectinghost = 0; /* just in case */ @@ -2944,7 +3049,7 @@ SOCKET pcap_remoteact_accept_ex(const char *address, const char *port, const cha } - if ((sockmain = sock_open(addrinfo, SOCKOPEN_SERVER, 1, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) + if ((sockmain = sock_open(NULL, addrinfo, SOCKOPEN_SERVER, 1, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) { freeaddrinfo(addrinfo); return (SOCKET)-2; @@ -2963,7 +3068,7 @@ SOCKET pcap_remoteact_accept_ex(const char *address, const char *port, const cha if (sockctrl == INVALID_SOCKET) { - sock_geterror("accept()", errbuf, PCAP_ERRBUF_SIZE); + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, "accept() failed"); return (SOCKET)-2; } @@ -2987,7 +3092,8 @@ SOCKET pcap_remoteact_accept_ex(const char *address, const char *port, const cha /* 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_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "getnameinfo() failed"); rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL); #ifdef HAVE_OPENSSL if (ssl) @@ -3020,7 +3126,8 @@ SOCKET pcap_remoteact_accept_ex(const char *address, const char *port, const cha /* * Send authentication to the remote machine. */ - if (rpcap_doauth(sockctrl, ssl, &protocol_version, auth, errbuf) == -1) + if (rpcap_doauth(sockctrl, ssl, &protocol_version, &byte_swapped, + auth, errbuf) == -1) { /* Unrecoverable error. */ rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL); @@ -3085,6 +3192,7 @@ SOCKET pcap_remoteact_accept_ex(const char *address, const char *port, const cha temp->sockctrl = sockctrl; temp->ssl = ssl; temp->protocol_version = protocol_version; + temp->byte_swapped = byte_swapped; temp->next = NULL; return sockctrl; @@ -3110,7 +3218,7 @@ int pcap_remoteact_close(const char *host, char *errbuf) hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - retval = sock_initaddress(host, "0", &hints, &addrinfo, errbuf, + retval = sock_initaddress(host, NULL, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE); if (retval != 0) { @@ -3253,7 +3361,8 @@ 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_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, */ + /* "getnameinfo() failed"); */ return -1; } @@ -3299,7 +3408,7 @@ static int rpcap_recv_msg_header(SOCKET sock, SSL *ssl, struct rpcap_header *hea * Make sure the protocol version of a received message is what we were * expecting. */ -static int rpcap_check_msg_ver(SOCKET sock, SSL *ssl, uint8 expected_ver, struct rpcap_header *header, char *errbuf) +static int rpcap_check_msg_ver(SOCKET sock, SSL *ssl, uint8_t expected_ver, struct rpcap_header *header, char *errbuf) { /* * Did the server specify the version we negotiated? @@ -3330,7 +3439,7 @@ static int rpcap_check_msg_ver(SOCKET sock, SSL *ssl, uint8 expected_ver, struct * Check the message type of a received message, which should either be * the expected message type or RPCAP_MSG_ERROR. */ -static int rpcap_check_msg_type(SOCKET sock, SSL *ssl, uint8 request_type, struct rpcap_header *header, uint16 *errcode, char *errbuf) +static int rpcap_check_msg_type(SOCKET sock, SSL *ssl, uint8_t request_type, struct rpcap_header *header, uint16_t *errcode, char *errbuf) { const char *request_type_string; const char *msg_type_string; @@ -3400,9 +3509,9 @@ static int rpcap_check_msg_type(SOCKET sock, SSL *ssl, uint8 request_type, struc /* * Receive and process the header of a message. */ -static int rpcap_process_msg_header(SOCKET sock, SSL *ssl, uint8 expected_ver, uint8 request_type, struct rpcap_header *header, char *errbuf) +static int rpcap_process_msg_header(SOCKET sock, SSL *ssl, uint8_t expected_ver, uint8_t request_type, struct rpcap_header *header, char *errbuf) { - uint16 errcode; + uint16_t errcode; if (rpcap_recv_msg_header(sock, ssl, header, errbuf) == -1) { @@ -3432,7 +3541,7 @@ static int rpcap_process_msg_header(SOCKET sock, SSL *ssl, uint8 expected_ver, u * Returns 0 on success, logs a message and returns -1 on a network * error. */ -static int rpcap_recv(SOCKET sock, SSL *ssl, void *buffer, size_t toread, uint32 *plen, char *errbuf) +static int rpcap_recv(SOCKET sock, SSL *ssl, void *buffer, size_t toread, uint32_t *plen, char *errbuf) { int nread; @@ -3455,7 +3564,7 @@ static int rpcap_recv(SOCKET sock, SSL *ssl, void *buffer, size_t toread, uint32 /* * This handles the RPCAP_MSG_ERROR message. */ -static void rpcap_msg_err(SOCKET sockctrl, SSL *ssl, uint32 plen, char *remote_errbuf) +static void rpcap_msg_err(SOCKET sockctrl, SSL *ssl, uint32_t plen, char *remote_errbuf) { char errbuf[PCAP_ERRBUF_SIZE]; @@ -3526,7 +3635,7 @@ static void rpcap_msg_err(SOCKET sockctrl, SSL *ssl, uint32 plen, char *remote_e * Returns 0 on success, logs a message and returns -1 on a network * error. */ -static int rpcap_discard(SOCKET sock, SSL *ssl, uint32 len, char *errbuf) +static int rpcap_discard(SOCKET sock, SSL *ssl, uint32_t len, char *errbuf) { if (len != 0) { diff --git a/pcap-septel.c b/pcap-septel.c index e917edd7..6d1d9047 100644 --- a/pcap-septel.c +++ b/pcap-septel.c @@ -93,7 +93,7 @@ loop: h = GCT_grab(id); m = (MSG*)h; - /* a couter is added here to avoid an infinite loop + /* a counter is added here to avoid an infinite loop * that will cause our capture program GUI to freeze while waiting * for a packet*/ counter++ ; @@ -105,7 +105,7 @@ loop: t = h->type ; - /* catch only messages with type = 0xcf00 or 0x8f01 corrsponding to ss7 messages*/ + /* catch only messages with type = 0xcf00 or 0x8f01 corresponding to ss7 messages*/ /* XXX = why not use API_MSG_TX_REQ for 0xcf00 and API_MSG_RX_IND * for 0x8f01? */ if ((t != 0xcf00) && (t != 0x8f01)) { diff --git a/pcap-sita.c b/pcap-sita.c index 16475729..2e5d4426 100644 --- a/pcap-sita.c +++ b/pcap-sita.c @@ -492,7 +492,7 @@ static char *translate_IOP_to_pcap_name(unit_t *u, char *IOPname, bpf_u_int32 if u->iface = iface; /* stick this entry at the head of the list */ } else { iface_ptr = u->iface; - while (iface_ptr->next) { /* othewise scan the list */ + while (iface_ptr->next) { /* otherwise scan the list */ iface_ptr = iface_ptr->next; /* till we're at the last entry */ } iface_ptr->next = iface; /* then tack this entry on the end of the list */ diff --git a/pcap-sita.html b/pcap-sita.html index 33f1e10f..27ae94a3 100644 --- a/pcap-sita.html +++ b/pcap-sita.html @@ -788,10 +788,10 @@ A { text-decoration:none } <FONT SIZE=-1> <PRE> - uint32 tv_sec; /* timestamp seconds */ - uint32 tv_usec; /* timestamp microseconds */ - uint32 caplen; /* number of octets in the following packet */ - uint32 len; /* original length of packet on the wire */ + uint32_t tv_sec; /* timestamp seconds */ + uint32_t tv_usec; /* timestamp microseconds */ + uint32_t caplen; /* number of octets in the following packet */ + uint32_t len; /* original length of packet on the wire */ </PRE> </FONT> diff --git a/pcap-usb-linux-common.c b/pcap-usb-linux-common.c new file mode 100644 index 00000000..fb4a8c19 --- /dev/null +++ b/pcap-usb-linux-common.c @@ -0,0 +1,130 @@ +/* + * 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: (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. + * + * pcap-usb-linux-common.c - common code for everything that needs to + * deal with Linux USB captures. + */ + +#include "pcap/pcap.h" +#include "pcap/usb.h" + +#include "pcap-usb-linux-common.h" + +/* + * Compute, from the data provided by the Linux USB memory-mapped capture + * mechanism, the amount of packet data that would have been provided + * had the capture mechanism not chopped off any data at the end, if, in + * fact, it did so. + * + * Set the "unsliced length" field of the packet header to that value. + */ +void +fix_linux_usb_mmapped_length(struct pcap_pkthdr *pkth, const u_char *bp) +{ + const pcap_usb_header_mmapped *hdr; + u_int bytes_left; + + /* + * All callers of this routine must ensure that pkth->caplen is + * >= sizeof (pcap_usb_header_mmapped). + */ + bytes_left = pkth->caplen; + bytes_left -= sizeof (pcap_usb_header_mmapped); + + hdr = (const pcap_usb_header_mmapped *) bp; + if (!hdr->data_flag && hdr->transfer_type == URB_ISOCHRONOUS && + hdr->event_type == URB_COMPLETE && + (hdr->endpoint_number & URB_TRANSFER_IN) && + pkth->len == sizeof(pcap_usb_header_mmapped) + + (hdr->ndesc * sizeof (usb_isodesc)) + hdr->urb_len) { + usb_isodesc *descs; + u_int pre_truncation_data_len, pre_truncation_len; + + descs = (usb_isodesc *) (bp + sizeof(pcap_usb_header_mmapped)); + + /* + * We have data (yes, data_flag is 0 if we *do* have data), + * and this is a "this is complete" incoming isochronous + * transfer event, and the length was calculated based + * on the URB length. + * + * That's not correct, because the data isn't contiguous, + * and the isochronous descriptos show how it's scattered. + * + * Find the end of the last chunk of data in the buffer + * referred to by the isochronous descriptors; that indicates + * how far into the buffer the data would have gone. + * + * Make sure we don't run past the end of the captured data + * while processing the isochronous descriptors. + */ + pre_truncation_data_len = 0; + for (uint32_t desc = 0; + desc < hdr->ndesc && bytes_left >= sizeof (usb_isodesc); + desc++, bytes_left -= sizeof (usb_isodesc)) { + u_int desc_end; + + if (descs[desc].len != 0) { + desc_end = descs[desc].offset + descs[desc].len; + if (desc_end > pre_truncation_data_len) + pre_truncation_data_len = desc_end; + } + } + + /* + * Now calculate the total length based on that data + * length. + */ + pre_truncation_len = sizeof(pcap_usb_header_mmapped) + + (hdr->ndesc * sizeof (usb_isodesc)) + + pre_truncation_data_len; + + /* + * If that's greater than or equal to the captured length, + * use that as the length. + */ + if (pre_truncation_len >= pkth->caplen) + pkth->len = pre_truncation_len; + + /* + * If the captured length is greater than the length, + * use the captured length. + * + * For completion events for incoming isochronous transfers, + * it's based on data_len, which is calculated the same way + * we calculated pre_truncation_data_len above, except that + * it has access to all the isochronous descriptors, not + * just the ones that the kernel were able to provide us or, + * for a capture file, that weren't sliced off by a snapshot + * length. + * + * However, it might have been reduced by the USB capture + * mechanism arbitrarily limiting the amount of data it + * provides to userland, or by the libpcap capture code + * limiting it to being no more than the snapshot, so + * we don't want to just use it all the time; we only + * do so to try to get a better estimate of the actual + * length - and to make sure the on-the-network length + * is always >= the captured length. + */ + if (pkth->caplen > pkth->len) + pkth->len = pkth->caplen; + } +} diff --git a/pcap-usb-linux-common.h b/pcap-usb-linux-common.h new file mode 100644 index 00000000..8cff7ba1 --- /dev/null +++ b/pcap-usb-linux-common.h @@ -0,0 +1,26 @@ +/* + * 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: (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. + * + * pcap-usb-linux-common.h - common code for everything that needs to + * deal with Linux USB captures. + */ + +extern void fix_linux_usb_mmapped_length(struct pcap_pkthdr *pkth, + const u_char *bp); diff --git a/pcap-usb-linux.c b/pcap-usb-linux.c index d62f17dd..7020577c 100644 --- a/pcap-usb-linux.c +++ b/pcap-usb-linux.c @@ -39,6 +39,7 @@ #include "pcap-int.h" #include "pcap-usb-linux.h" +#include "pcap-usb-linux-common.h" #include "pcap/usb.h" #include "extract.h" @@ -756,6 +757,7 @@ 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; + u_char *bp; pcap_usb_header_mmapped* hdr; int nflush = 0; int packets = 0; @@ -839,8 +841,13 @@ usb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_ch * packets if we break out of the loop here. */ + /* Get a pointer to this packet's buffer */ + bp = &handlep->mmapbuf[vec[i]]; + + /* That begins with a metadata header */ + hdr = (pcap_usb_header_mmapped*) bp; + /* discard filler */ - hdr = (pcap_usb_header_mmapped*) &handlep->mmapbuf[vec[i]]; if (hdr->event_type == '@') continue; @@ -885,6 +892,13 @@ usb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_ch */ pkth.len = sizeof(pcap_usb_header_mmapped) + (hdr->ndesc * sizeof (usb_isodesc)) + hdr->urb_len; + + /* + * Now clean it up if it's a completion + * event for an incoming isochronous + * transfer. + */ + fix_linux_usb_mmapped_length(&pkth, bp); } pkth.ts.tv_sec = (time_t)hdr->ts_sec; pkth.ts.tv_usec = hdr->ts_usec; diff --git a/pcap-util.c b/pcap-util.c new file mode 100644 index 00000000..8b5669e9 --- /dev/null +++ b/pcap-util.c @@ -0,0 +1,474 @@ +/* + * 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: (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. + * + * pcap-common.c - common code for pcap and pcapng files + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <pcap-types.h> + +#include "pcap-int.h" +#include "extract.h" +#include "pcap-usb-linux-common.h" + +#include "pcap-util.h" + +#include "pflog.h" +#include "pcap/can_socketcan.h" +#include "pcap/sll.h" +#include "pcap/usb.h" +#include "pcap/nflog.h" + +/* + * Most versions of the DLT_PFLOG pseudo-header have UID and PID fields + * that are saved in host byte order. + * + * When reading a DLT_PFLOG packet, we need to convert those fields from + * the byte order of the host that wrote the file to this host's byte + * order. + */ +static void +swap_pflog_header(const struct pcap_pkthdr *hdr, u_char *buf) +{ + u_int caplen = hdr->caplen; + u_int length = hdr->len; + u_int pfloghdr_length; + struct pfloghdr *pflhdr = (struct pfloghdr *)buf; + + if (caplen < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid) || + length < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid)) { + /* Not enough data to have the uid field */ + return; + } + + pfloghdr_length = pflhdr->length; + + if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid)) { + /* Header doesn't include uid field */ + return; + } + pflhdr->uid = SWAPLONG(pflhdr->uid); + + if (caplen < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid) || + length < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid)) { + /* Not enough data to have the pid field */ + return; + } + if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid)) { + /* Header doesn't include pid field */ + return; + } + pflhdr->pid = SWAPLONG(pflhdr->pid); + + if (caplen < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid) || + length < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid)) { + /* Not enough data to have the rule_uid field */ + return; + } + if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid)) { + /* Header doesn't include rule_uid field */ + return; + } + pflhdr->rule_uid = SWAPLONG(pflhdr->rule_uid); + + if (caplen < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid) || + length < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid)) { + /* Not enough data to have the rule_pid field */ + return; + } + if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid)) { + /* Header doesn't include rule_pid field */ + return; + } + pflhdr->rule_pid = SWAPLONG(pflhdr->rule_pid); +} + +/* + * DLT_LINUX_SLL packets with a protocol type of LINUX_SLL_P_CAN or + * LINUX_SLL_P_CANFD have SocketCAN headers in front of the payload, + * with the CAN ID being in host byte order. + * + * When reading a DLT_LINUX_SLL packet, we need to check for those + * packets and convert the CAN ID from the byte order of the host that + * wrote the file to this host's byte order. + */ +static void +swap_linux_sll_header(const struct pcap_pkthdr *hdr, u_char *buf) +{ + u_int caplen = hdr->caplen; + u_int length = hdr->len; + struct sll_header *shdr = (struct sll_header *)buf; + uint16_t protocol; + pcap_can_socketcan_hdr *chdr; + + if (caplen < (u_int) sizeof(struct sll_header) || + length < (u_int) sizeof(struct sll_header)) { + /* Not enough data to have the protocol field */ + return; + } + + protocol = EXTRACT_BE_U_2(&shdr->sll_protocol); + if (protocol != LINUX_SLL_P_CAN && protocol != LINUX_SLL_P_CANFD) + return; + + /* + * SocketCAN packet; fix up the packet's header. + */ + chdr = (pcap_can_socketcan_hdr *)(buf + sizeof(struct sll_header)); + if (caplen < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id) || + length < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id)) { + /* Not enough data to have the CAN ID */ + return; + } + chdr->can_id = SWAPLONG(chdr->can_id); +} + +/* + * The same applies for DLT_LINUX_SLL2. + */ +static void +swap_linux_sll2_header(const struct pcap_pkthdr *hdr, u_char *buf) +{ + u_int caplen = hdr->caplen; + u_int length = hdr->len; + struct sll2_header *shdr = (struct sll2_header *)buf; + uint16_t protocol; + pcap_can_socketcan_hdr *chdr; + + if (caplen < (u_int) sizeof(struct sll2_header) || + length < (u_int) sizeof(struct sll2_header)) { + /* Not enough data to have the protocol field */ + return; + } + + protocol = EXTRACT_BE_U_2(&shdr->sll2_protocol); + if (protocol != LINUX_SLL_P_CAN && protocol != LINUX_SLL_P_CANFD) + return; + + /* + * SocketCAN packet; fix up the packet's header. + */ + chdr = (pcap_can_socketcan_hdr *)(buf + sizeof(struct sll2_header)); + if (caplen < (u_int) sizeof(struct sll2_header) + sizeof(chdr->can_id) || + length < (u_int) sizeof(struct sll2_header) + sizeof(chdr->can_id)) { + /* Not enough data to have the CAN ID */ + return; + } + chdr->can_id = SWAPLONG(chdr->can_id); +} + +/* + * The DLT_USB_LINUX and DLT_USB_LINUX_MMAPPED headers are in host + * byte order when capturing (it's supplied directly from a + * memory-mapped buffer shared by the kernel). + * + * When reading a DLT_USB_LINUX or DLT_USB_LINUX_MMAPPED packet, we + * need to convert it from the byte order of the host that wrote the + * file to this host's byte order. + */ +static void +swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf, + int header_len_64_bytes) +{ + pcap_usb_header_mmapped *uhdr = (pcap_usb_header_mmapped *)buf; + bpf_u_int32 offset = 0; + + /* + * "offset" is the offset *past* the field we're swapping; + * we skip the field *before* checking to make sure + * the captured data length includes the entire field. + */ + + /* + * The URB id is a totally opaque value; do we really need to + * convert it to the reading host's byte order??? + */ + offset += 8; /* skip past id */ + if (hdr->caplen < offset) + return; + uhdr->id = SWAPLL(uhdr->id); + + offset += 4; /* skip past various 1-byte fields */ + + offset += 2; /* skip past bus_id */ + if (hdr->caplen < offset) + return; + uhdr->bus_id = SWAPSHORT(uhdr->bus_id); + + offset += 2; /* skip past various 1-byte fields */ + + offset += 8; /* skip past ts_sec */ + if (hdr->caplen < offset) + return; + uhdr->ts_sec = SWAPLL(uhdr->ts_sec); + + offset += 4; /* skip past ts_usec */ + if (hdr->caplen < offset) + return; + uhdr->ts_usec = SWAPLONG(uhdr->ts_usec); + + offset += 4; /* skip past status */ + if (hdr->caplen < offset) + return; + uhdr->status = SWAPLONG(uhdr->status); + + offset += 4; /* skip past urb_len */ + if (hdr->caplen < offset) + return; + uhdr->urb_len = SWAPLONG(uhdr->urb_len); + + offset += 4; /* skip past data_len */ + if (hdr->caplen < offset) + return; + uhdr->data_len = SWAPLONG(uhdr->data_len); + + if (uhdr->transfer_type == URB_ISOCHRONOUS) { + offset += 4; /* skip past s.iso.error_count */ + if (hdr->caplen < offset) + return; + uhdr->s.iso.error_count = SWAPLONG(uhdr->s.iso.error_count); + + offset += 4; /* skip past s.iso.numdesc */ + if (hdr->caplen < offset) + return; + uhdr->s.iso.numdesc = SWAPLONG(uhdr->s.iso.numdesc); + } else + offset += 8; /* skip USB setup header */ + + /* + * With the old header, there are no isochronous descriptors + * after the header. + * + * With the new header, the actual number of descriptors in + * the header is not s.iso.numdesc, it's ndesc - only the + * first N descriptors, for some value of N, are put into + * the header, and ndesc is set to the actual number copied. + * In addition, if s.iso.numdesc is negative, no descriptors + * are captured, and ndesc is set to 0. + */ + if (header_len_64_bytes) { + /* + * This is either the "version 1" header, with + * 16 bytes of additional fields at the end, or + * a "version 0" header from a memory-mapped + * capture, with 16 bytes of zeroed-out padding + * at the end. Byte swap them as if this were + * a "version 1" header. + */ + offset += 4; /* skip past interval */ + if (hdr->caplen < offset) + return; + uhdr->interval = SWAPLONG(uhdr->interval); + + offset += 4; /* skip past start_frame */ + if (hdr->caplen < offset) + return; + uhdr->start_frame = SWAPLONG(uhdr->start_frame); + + offset += 4; /* skip past xfer_flags */ + if (hdr->caplen < offset) + return; + uhdr->xfer_flags = SWAPLONG(uhdr->xfer_flags); + + offset += 4; /* skip past ndesc */ + if (hdr->caplen < offset) + return; + uhdr->ndesc = SWAPLONG(uhdr->ndesc); + + if (uhdr->transfer_type == URB_ISOCHRONOUS) { + /* swap the values in struct linux_usb_isodesc */ + usb_isodesc *pisodesc; + uint32_t i; + + pisodesc = (usb_isodesc *)(void *)(buf+offset); + for (i = 0; i < uhdr->ndesc; i++) { + offset += 4; /* skip past status */ + if (hdr->caplen < offset) + return; + pisodesc->status = SWAPLONG(pisodesc->status); + + offset += 4; /* skip past offset */ + if (hdr->caplen < offset) + return; + pisodesc->offset = SWAPLONG(pisodesc->offset); + + offset += 4; /* skip past len */ + if (hdr->caplen < offset) + return; + pisodesc->len = SWAPLONG(pisodesc->len); + + offset += 4; /* skip past padding */ + + pisodesc++; + } + } + } +} + +/* + * The DLT_NFLOG "packets" have a mixture of big-endian and host-byte-order + * data. They begin with a fixed-length header with big-endian fields, + * followed by a set of TLVs, where the type and length are in host + * byte order but the values are either big-endian or are a raw byte + * sequence that's the same regardless of the host's byte order. + * + * When reading a DLT_NFLOG packet, we need to convert the type and + * length values from the byte order of the host that wrote the file + * to the byte order of this host. + */ +static void +swap_nflog_header(const struct pcap_pkthdr *hdr, u_char *buf) +{ + u_char *p = buf; + nflog_hdr_t *nfhdr = (nflog_hdr_t *)buf; + nflog_tlv_t *tlv; + u_int caplen = hdr->caplen; + u_int length = hdr->len; + uint16_t size; + + if (caplen < (u_int) sizeof(nflog_hdr_t) || + length < (u_int) sizeof(nflog_hdr_t)) { + /* Not enough data to have any TLVs. */ + return; + } + + if (nfhdr->nflog_version != 0) { + /* Unknown NFLOG version */ + return; + } + + length -= sizeof(nflog_hdr_t); + caplen -= sizeof(nflog_hdr_t); + p += sizeof(nflog_hdr_t); + + while (caplen >= sizeof(nflog_tlv_t)) { + tlv = (nflog_tlv_t *) p; + + /* Swap the type and length. */ + tlv->tlv_type = SWAPSHORT(tlv->tlv_type); + tlv->tlv_length = SWAPSHORT(tlv->tlv_length); + + /* Get the length of the TLV. */ + size = tlv->tlv_length; + if (size % 4 != 0) + size += 4 - size % 4; + + /* Is the TLV's length less than the minimum? */ + if (size < sizeof(nflog_tlv_t)) { + /* Yes. Give up now. */ + return; + } + + /* Do we have enough data for the full TLV? */ + if (caplen < size || length < size) { + /* No. */ + return; + } + + /* Skip over the TLV. */ + length -= size; + caplen -= size; + p += size; + } +} + +static void +swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data) +{ + /* + * Convert pseudo-headers from the byte order of + * the host on which the file was saved to our + * byte order, as necessary. + */ + switch (linktype) { + + case DLT_PFLOG: + swap_pflog_header(hdr, data); + break; + + case DLT_LINUX_SLL: + swap_linux_sll_header(hdr, data); + break; + + case DLT_LINUX_SLL2: + swap_linux_sll2_header(hdr, data); + break; + + case DLT_USB_LINUX: + swap_linux_usb_header(hdr, data, 0); + break; + + case DLT_USB_LINUX_MMAPPED: + swap_linux_usb_header(hdr, data, 1); + break; + + case DLT_NFLOG: + swap_nflog_header(hdr, data); + break; + } +} + +void +pcap_post_process(int linktype, int swapped, struct pcap_pkthdr *hdr, + u_char *data) +{ + if (swapped) + swap_pseudo_headers(linktype, hdr, data); + + fixup_pcap_pkthdr(linktype, hdr, data); +} + +void +fixup_pcap_pkthdr(int linktype, struct pcap_pkthdr *hdr, const u_char *data) +{ + const pcap_usb_header_mmapped *usb_hdr; + + usb_hdr = (const pcap_usb_header_mmapped *) data; + if (linktype == DLT_USB_LINUX_MMAPPED && + hdr->caplen >= sizeof (pcap_usb_header_mmapped)) { + /* + * In older versions of libpcap, in memory-mapped captures, + * the "on-the-bus length" for completion events for + * incoming isochronous transfers was miscalculated; it + * needed to be calculated based on the* offsets and lengths + * in the descriptors, not on the raw URB length, but it + * wasn't. + * + * If this packet contains transferred data (yes, data_flag + * is 0 if we *do* have data), and the total on-the-network + * length is equal to the value calculated from the raw URB + * length, then it might be one of those transfers. + * + * We only do this if we have the full USB pseudo-header. + */ + if (!usb_hdr->data_flag && + hdr->len == sizeof(pcap_usb_header_mmapped) + + (usb_hdr->ndesc * sizeof (usb_isodesc)) + usb_hdr->urb_len) { + /* + * It might need fixing; fix it if it's a completion + * event for an incoming isochronous transfer. + */ + fix_linux_usb_mmapped_length(hdr, data); + } + } +} diff --git a/pcap-util.h b/pcap-util.h new file mode 100644 index 00000000..de958191 --- /dev/null +++ b/pcap-util.h @@ -0,0 +1,55 @@ +/* + * 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: (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. + * + * pcap-util.h - common code for various files + */ + +/* + * We use the "receiver-makes-right" approach to byte order; + * because time is at a premium when we are writing the file. + * In other words, the pcap_file_header and pcap_pkthdr, + * records are written in host byte order. + * Note that the bytes of packet data are written out in the order in + * which they were received, so multi-byte fields in packets are not + * written in host byte order, they're written in whatever order the + * sending machine put them in. + * + * We also use this for fixing up packet data headers from a remote + * capture, where the server may have a different byte order from the + * client. + * + * ntoh[ls] aren't sufficient because we might need to swap on a big-endian + * machine (if the file was written in little-end order). + */ +#define SWAPLONG(y) \ + (((((u_int)(y))&0xff)<<24) | \ + ((((u_int)(y))&0xff00)<<8) | \ + ((((u_int)(y))&0xff0000)>>8) | \ + ((((u_int)(y))>>24)&0xff)) +#define SWAPSHORT(y) \ + ((u_short)(((((u_int)(y))&0xff)<<8) | \ + ((((u_int)(y))&0xff00)>>8))) + +extern void pcap_post_process(int linktype, int swapped, + struct pcap_pkthdr *hdr, u_char *data); + +extern void fixup_pcap_pkthdr(int linktype, struct pcap_pkthdr *hdr, + const u_char *data); + diff --git a/pcap.3pcap.in b/pcap.3pcap.in index a43f7a09..e98932d8 100644 --- a/pcap.3pcap.in +++ b/pcap.3pcap.in @@ -720,7 +720,7 @@ periodically for packets; in that case, 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 +routine returns, an attempt should be made to read packets from the device. If .BR pcap_get_required_select_timeout () returns @@ -3336,6 +3336,9 @@ static struct dlt_choice dlt_choices[] = { DLT_CHOICE(ETW, "Event Tracing for Windows messages"), DLT_CHOICE(NETANALYZER_NG, "Hilscher netANALYZER NG pseudo-footer"), DLT_CHOICE(ZBOSS_NCP, "ZBOSS NCP protocol with pseudo-header"), + DLT_CHOICE(USB_2_0_LOW_SPEED, "Low-Speed USB 2.0/1.1/1.0 as transmitted over the cable"), + DLT_CHOICE(USB_2_0_FULL_SPEED, "Full-Speed USB 2.0/1.1/1.0 as transmitted over the cable"), + DLT_CHOICE(USB_2_0_HIGH_SPEED, "High-Speed USB 2.0 as transmitted over the cable"), DLT_CHOICE_SENTINEL }; @@ -4108,7 +4111,7 @@ pcap_close(pcap_t *p) } /* - * Helpers for safely loding code at run time. + * Helpers for safely loading code at run time. * Currently Windows-only. */ #ifdef _WIN32 @@ -79,13 +79,6 @@ #if !defined(_NET_BPF_H_) && !defined(_NET_BPF_H_INCLUDED) && !defined(_BPF_H_) && !defined(_H_BPF) && !defined(lib_pcap_bpf_h) #define lib_pcap_bpf_h -/* u_char, u_short and u_int */ -#if defined(_WIN32) - #include <winsock2.h> -#elif defined(HAVE_SYS_TYPES_H) - #include <sys/types.h> -#endif - #include <pcap/funcattrs.h> #include <pcap/dlt.h> @@ -723,7 +723,7 @@ * DLT_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>. * Every frame contains a 32bit A429 label. * More documentation on Arinc 429 can be found at - * http://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf + * https://web.archive.org/web/20040616233302/https://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf */ #define DLT_A429 184 @@ -1544,6 +1544,8 @@ /* * USB 2.0, 1.1, and 1.0 packets as transmitted over the cable. + * Deprecated in favor of speed specific DLTs: DLT_USB_2_0_LOW_SPEED, + * DLT_USB_2_0_FULL_SPEED and DLT_USB_2_0_HIGH_SPEED. */ #define DLT_USB_2_0 288 @@ -1579,6 +1581,13 @@ #define DLT_ZBOSS_NCP 292 /* + * USB 2.0, 1.1, and 1.0 packets as transmitted over the cable. + */ +#define DLT_USB_2_0_LOW_SPEED 293 +#define DLT_USB_2_0_FULL_SPEED 294 +#define DLT_USB_2_0_HIGH_SPEED 295 + +/* * In case the code that includes this file (directly or indirectly) * has also included OS files that happen to define DLT_MATCHING_MAX, * with a different value (perhaps because that OS hasn't picked up @@ -1588,6 +1597,6 @@ #ifdef DLT_MATCHING_MAX #undef DLT_MATCHING_MAX #endif -#define DLT_MATCHING_MAX 292 /* highest value in the "matching" range */ +#define DLT_MATCHING_MAX 295 /* highest value in the "matching" range */ #endif /* !defined(lib_pcap_dlt_h) */ diff --git a/pcap/funcattrs.h b/pcap/funcattrs.h index 5dbc428c..3dcf6e61 100644 --- a/pcap/funcattrs.h +++ b/pcap/funcattrs.h @@ -290,10 +290,8 @@ * PCAP_DEPRECATED(func, msg), after a function declaration, marks the * function as deprecated. * - * The first argument is the name of the function; the second argument is - * a string giving the warning message to use if the compiler supports that. - * - * (Thank you, Microsoft, for requiring the function name.) + * The argument is a string giving the warning message to use if the + * compiler supports that. */ #if __has_attribute(deprecated) \ || PCAP_IS_AT_LEAST_GNUC_VERSION(4,5) \ @@ -306,7 +304,7 @@ * incorrectly, that anything that supports __has_attribute() is * recent enough to support __attribute__((deprecated(msg)))). */ - #define PCAP_DEPRECATED(func, msg) __attribute__((deprecated(msg))) + #define PCAP_DEPRECATED(msg) __attribute__((deprecated(msg))) #elif PCAP_IS_AT_LEAST_GNUC_VERSION(3,1) /* * GCC 3.1 through 4.4. @@ -314,7 +312,7 @@ * Those support __attribute__((deprecated)) but not * __attribute__((deprecated(msg))). */ - #define PCAP_DEPRECATED(func, msg) __attribute__((deprecated)) + #define PCAP_DEPRECATED(msg) __attribute__((deprecated)) #elif defined(_MSC_VER) && !defined(BUILDING_PCAP) /* * MSVC, and we're not building libpcap itself; it's VS 2015 @@ -323,9 +321,9 @@ * If we *are* building libpcap, we don't want this, as it'll warn * us even if we *define* the function. */ - #define PCAP_DEPRECATED(func, msg) __pragma(deprecated(func)) + #define PCAP_DEPRECATED(msg) _declspec(deprecated(msg)) #else - #define PCAP_DEPRECATED(func, msg) + #define PCAP_DEPRECATED(msg) #endif /* diff --git a/pcap/namedb.h b/pcap/namedb.h index 34a0ae7e..51d1e318 100644 --- a/pcap/namedb.h +++ b/pcap/namedb.h @@ -59,8 +59,9 @@ PCAP_API struct pcap_etherent *pcap_next_etherent(FILE *); PCAP_API u_char *pcap_ether_hostton(const char*); PCAP_API u_char *pcap_ether_aton(const char *); -PCAP_API bpf_u_int32 **pcap_nametoaddr(const char *) -PCAP_DEPRECATED(pcap_nametoaddr, "this is not reentrant; use 'pcap_nametoaddrinfo' instead"); +PCAP_API +PCAP_DEPRECATED("this is not reentrant; use 'pcap_nametoaddrinfo' instead") +bpf_u_int32 **pcap_nametoaddr(const char *); PCAP_API struct addrinfo *pcap_nametoaddrinfo(const char *); PCAP_API bpf_u_int32 pcap_nametonetaddr(const char *); diff --git a/pcap/pcap.h b/pcap/pcap.h index 7b06b413..78570744 100644 --- a/pcap/pcap.h +++ b/pcap/pcap.h @@ -71,7 +71,7 @@ /* * Some software that uses libpcap/WinPcap/Npcap defines _MSC_VER before - * includeing pcap.h if it's not defined - and it defines it to 1500. + * including pcap.h if it's not defined - and it defines it to 1500. * (I'm looking at *you*, lwIP!) * * Attempt to detect this, and undefine _MSC_VER so that we can *reliably* @@ -439,8 +439,8 @@ PCAP_API int pcap_init(unsigned int, char *); * should use pcap_findalldevs() and use the first device. */ PCAP_AVAILABLE_0_4 -PCAP_API char *pcap_lookupdev(char *) -PCAP_DEPRECATED(pcap_lookupdev, "use 'pcap_findalldevs' and use the first device"); +PCAP_DEPRECATED("use 'pcap_findalldevs' and use the first device") +PCAP_API char *pcap_lookupdev(char *); PCAP_AVAILABLE_0_4 PCAP_API int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *); @@ -662,6 +662,7 @@ PCAP_API int pcap_compile(pcap_t *, struct bpf_program *, const char *, int, bpf_u_int32); PCAP_AVAILABLE_0_5 +PCAP_DEPRECATED("use pcap_open_dead(), pcap_compile() and pcap_close()") PCAP_API int pcap_compile_nopcap(int, int, struct bpf_program *, const char *, int, bpf_u_int32); @@ -728,8 +729,8 @@ PCAP_API FILE *pcap_file(pcap_t *); * a Windows-only pcap_handle() API that returns the HANDLE. */ PCAP_AVAILABLE_0_4 -PCAP_API int pcap_fileno(pcap_t *) -PCAP_DEPRECATED(pcap_fileno, "request a 'pcap_handle' that returns a HANDLE if you need it"); +PCAP_DEPRECATED("request a 'pcap_handle' that returns a HANDLE if you need it") +PCAP_API int pcap_fileno(pcap_t *); #else /* _WIN32 */ PCAP_AVAILABLE_0_4 PCAP_API int pcap_fileno(pcap_t *); diff --git a/pcap_compile.3pcap.in b/pcap_compile.3pcap.in index f9fa483b..67001fa4 100644 --- a/pcap_compile.3pcap.in +++ b/pcap_compile.3pcap.in @@ -39,7 +39,7 @@ is used to compile the string into a filter program. See .BR \%pcap-filter (@MAN_MISC_INFO@) for the syntax of that string. -.I program +.I fp is a pointer to a .I bpf_program struct and is filled in by diff --git a/pcap_setnonblock.3pcap b/pcap_setnonblock.3pcap index f194b949..1f336474 100644 --- a/pcap_setnonblock.3pcap +++ b/pcap_setnonblock.3pcap @@ -64,7 +64,7 @@ immediately rather than blocking waiting for packets to arrive. .BR pcap_loop (3PCAP) will loop forever, consuming CPU time when no packets are currently available; -.BR pacp_dispatch () +.BR pcap_dispatch () should be used instead. .BR pcap_next (3PCAP) will return diff --git a/rpcap-protocol.c b/rpcap-protocol.c index 0cdc0ba3..08da7aff 100644 --- a/rpcap-protocol.c +++ b/rpcap-protocol.c @@ -38,6 +38,7 @@ #include <string.h> /* for strlen(), ... */ #include <stdlib.h> /* for malloc(), free(), ... */ #include <stdarg.h> /* for functions with variable number of arguments */ +#include <stdint.h> /* for intN_t and uintN_t types */ #include <errno.h> /* for the errno variable */ #include "sockutils.h" #include "portability.h" @@ -80,13 +81,13 @@ * error message is returned in the 'errbuf' variable. */ int -rpcap_senderror(SOCKET sock, SSL *ssl, uint8 ver, unsigned short errcode, const char *error, char *errbuf) +rpcap_senderror(SOCKET sock, SSL *ssl, uint8_t ver, unsigned short errcode, const char *error, char *errbuf) { 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 */ - uint16 length; + uint16_t length; - length = (uint16)strlen(error); + length = (uint16_t)strlen(error); if (length > PCAP_ERRBUF_SIZE) length = PCAP_ERRBUF_SIZE; @@ -134,7 +135,7 @@ rpcap_senderror(SOCKET sock, SSL *ssl, uint8 ver, unsigned short errcode, const * variable. */ void -rpcap_createhdr(struct rpcap_header *header, uint8 ver, uint8 type, uint16 value, uint32 length) +rpcap_createhdr(struct rpcap_header *header, uint8_t ver, uint8_t type, uint16_t value, uint32_t length) { memset(header, 0, sizeof(struct rpcap_header)); @@ -182,7 +183,7 @@ static const char *replies[] = #define NUM_REPLY_TYPES (sizeof replies / sizeof replies[0]) const char * -rpcap_msg_type_string(uint8 type) +rpcap_msg_type_string(uint8_t type) { if (type & RPCAP_MSG_IS_REPLY) { type &= ~RPCAP_MSG_IS_REPLY; diff --git a/rpcap-protocol.h b/rpcap-protocol.h index a69cf802..ffb401d3 100644 --- a/rpcap-protocol.h +++ b/rpcap-protocol.h @@ -123,27 +123,24 @@ * 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. - */ - -/* - * WARNING: These typedefs MUST be of a specific size. - * You might have to change them on your platform. * - * XXX - use the C99 types? Microsoft's newer versions of Visual Studio - * support them. + * We use the C99 intN_t and uintN_t types to indicate fields that are + * exactly N bits long on the network. Do not use types that might + * differ in their lengths. + * + * XXX - both libpcap and programs that use it will require significant + * work if you have machines where integral data types are not multiples + * of 8-bit bytes. If, for example, you're trying to get this to work + * on a PDP-10x, good luck. */ -typedef unsigned char uint8; /* 8-bit unsigned integer */ -typedef unsigned short uint16; /* 16-bit unsigned integer */ -typedef unsigned int uint32; /* 32-bit unsigned integer */ -typedef int int32; /* 32-bit signed integer */ /* Common header for all the RPCAP messages */ struct rpcap_header { - uint8 ver; /* RPCAP version number */ - uint8 type; /* RPCAP message type (error, findalldevs, ...) */ - uint16 value; /* Message-dependent value (not always used) */ - uint32 plen; /* Length of the payload of this RPCAP message */ + uint8_t ver; /* RPCAP version number */ + uint8_t type; /* RPCAP message type (error, findalldevs, ...) */ + uint16_t value; /* Message-dependent value (not always used) */ + uint32_t plen; /* Length of the payload of this RPCAP message */ }; /* @@ -155,18 +152,37 @@ struct rpcap_header */ struct rpcap_authreply { - uint8 minvers; /* Minimum version supported */ - uint8 maxvers; /* Maximum version supported */ + uint8_t minvers; /* Minimum version supported */ + uint8_t maxvers; /* Maximum version supported */ + uint8_t pad[2]; /* Pad to 4-byte boundary **/ + uint32_t byte_order_magic; /* RPCAP_BYTE_ORDER_MAGIC, in server byte order */ +}; + +/* + * Any resemblance between this and the pcap file magic number + * is purely coincidental, trust me. + */ +#define RPCAP_BYTE_ORDER_MAGIC 0xa1b2c3d4U +#define RPCAP_BYTE_ORDER_MAGIC_SWAPPED 0xd4c3b2a1U + +/* + * Older version of authentication reply, without byte order indication + * and padding. + */ +struct rpcap_authreply_old +{ + uint8_t minvers; /* Minimum version supported */ + uint8_t maxvers; /* Maximum version supported */ }; /* Format of the message for the interface description (findalldevs command) */ struct rpcap_findalldevs_if { - uint16 namelen; /* Length of the interface name */ - uint16 desclen; /* Length of the interface description */ - uint32 flags; /* Interface flags */ - uint16 naddr; /* Number of addresses */ - uint16 dummy; /* Must be zero */ + uint16_t namelen; /* Length of the interface name */ + uint16_t desclen; /* Length of the interface description */ + uint32_t flags; /* Interface flags */ + uint16_t naddr; /* Number of addresses */ + uint16_t dummy; /* Must be zero */ }; /* @@ -213,8 +229,8 @@ struct rpcap_findalldevs_if */ struct rpcap_sockaddr { - uint16 family; /* Address family */ - char data[128-2]; /* Data */ + uint16_t family; /* Address family */ + char data[128-2]; /* Data */ }; /* @@ -223,10 +239,10 @@ struct rpcap_sockaddr #define RPCAP_AF_INET 2 /* Value on all OSes */ struct rpcap_sockaddr_in { - uint16 family; /* Address family */ - uint16 port; /* Port number */ - uint32 addr; /* IPv4 address */ - uint8 zero[8]; /* Padding */ + uint16_t family; /* Address family */ + uint16_t port; /* Port number */ + uint32_t addr; /* IPv4 address */ + uint8_t zero[8]; /* Padding */ }; /* @@ -235,11 +251,11 @@ struct rpcap_sockaddr_in #define RPCAP_AF_INET6 23 /* Value on Windows */ struct rpcap_sockaddr_in6 { - uint16 family; /* Address family */ - uint16 port; /* Port number */ - uint32 flowinfo; /* IPv6 flow information */ - uint8 addr[16]; /* IPv6 address */ - uint32 scope_id; /* Scope zone index */ + uint16_t family; /* Address family */ + uint16_t port; /* Port number */ + uint32_t flowinfo; /* IPv6 flow information */ + uint8_t addr[16]; /* IPv6 address */ + uint32_t scope_id; /* Scope zone index */ }; /* Format of the message for the address listing (findalldevs command) */ @@ -258,25 +274,25 @@ struct rpcap_findalldevs_ifaddr */ struct rpcap_openreply { - int32 linktype; /* Link type */ - int32 tzoff; /* Timezone offset - not used by newer clients */ + int32_t linktype; /* Link type */ + int32_t tzoff; /* Timezone offset - not used by newer clients */ }; /* Format of the message that starts a remote capture (startcap command) */ struct rpcap_startcapreq { - uint32 snaplen; /* Length of the snapshot (number of bytes to capture for each packet) */ - uint32 read_timeout; /* Read timeout in milliseconds */ - uint16 flags; /* Flags (see RPCAP_STARTCAPREQ_FLAG_xxx) */ - uint16 portdata; /* Network port on which the client is waiting at (if 'serveropen') */ + uint32_t snaplen; /* Length of the snapshot (number of bytes to capture for each packet) */ + uint32_t read_timeout; /* Read timeout in milliseconds */ + uint16_t flags; /* Flags (see RPCAP_STARTCAPREQ_FLAG_xxx) */ + uint16_t portdata; /* Network port on which the client is waiting at (if 'serveropen') */ }; /* Format of the reply message that devoted to start a remote capture (startcap reply command) */ struct rpcap_startcapreply { - int32 bufsize; /* Size of the user buffer allocated by WinPcap; it can be different from the one we chose */ - uint16 portdata; /* Network port on which the server is waiting at (passive mode only) */ - uint16 dummy; /* Must be zero */ + int32_t bufsize; /* Size of the user buffer allocated by WinPcap; it can be different from the one we chose */ + uint16_t portdata; /* Network port on which the server is waiting at (passive mode only) */ + uint16_t dummy; /* Must be zero */ }; /* @@ -291,55 +307,55 @@ struct rpcap_pkthdr * This protocol needs to be updated with a new version before * 2038-01-19 03:14:07 UTC. */ - uint32 timestamp_sec; /* 'struct timeval' compatible, it represents the 'tv_sec' field */ - uint32 timestamp_usec; /* 'struct timeval' compatible, it represents the 'tv_usec' field */ - uint32 caplen; /* Length of portion present in the capture */ - uint32 len; /* Real length of this packet (off wire) */ - uint32 npkt; /* Ordinal number of the packet (i.e. the first one captured has '1', the second one '2', etc) */ + uint32_t timestamp_sec; /* 'struct timeval' compatible, it represents the 'tv_sec' field */ + uint32_t timestamp_usec; /* 'struct timeval' compatible, it represents the 'tv_usec' field */ + uint32_t caplen; /* Length of portion present in the capture */ + uint32_t len; /* Real length of this packet (off wire) */ + uint32_t npkt; /* Ordinal number of the packet (i.e. the first one captured has '1', the second one '2', etc) */ }; /* General header used for the pcap_setfilter() command; keeps just the number of BPF instructions */ struct rpcap_filter { - uint16 filtertype; /* type of the filter transferred (BPF instructions, ...) */ - uint16 dummy; /* Must be zero */ - uint32 nitems; /* Number of items contained into the filter (e.g. BPF instructions for BPF filters) */ + uint16_t filtertype; /* type of the filter transferred (BPF instructions, ...) */ + uint16_t dummy; /* Must be zero */ + uint32_t nitems; /* Number of items contained into the filter (e.g. BPF instructions for BPF filters) */ }; /* Structure that keeps a single BPF instruction; it is repeated 'ninsn' times according to the 'rpcap_filterbpf' header */ struct rpcap_filterbpf_insn { - uint16 code; /* opcode of the instruction */ - uint8 jt; /* relative offset to jump to in case of 'true' */ - uint8 jf; /* relative offset to jump to in case of 'false' */ - int32 k; /* instruction-dependent value */ + uint16_t code; /* opcode of the instruction */ + uint8_t jt; /* relative offset to jump to in case of 'true' */ + uint8_t jf; /* relative offset to jump to in case of 'false' */ + int32_t k; /* instruction-dependent value */ }; /* Structure that keeps the data required for the authentication on the remote host */ struct rpcap_auth { - uint16 type; /* Authentication type */ - uint16 dummy; /* Must be zero */ - uint16 slen1; /* Length of the first authentication item (e.g. username) */ - uint16 slen2; /* Length of the second authentication item (e.g. password) */ + uint16_t type; /* Authentication type */ + uint16_t dummy; /* Must be zero */ + uint16_t slen1; /* Length of the first authentication item (e.g. username) */ + uint16_t slen2; /* Length of the second authentication item (e.g. password) */ }; /* Structure that keeps the statistics about the number of packets captured, dropped, etc. */ struct rpcap_stats { - uint32 ifrecv; /* Packets received by the kernel filter (i.e. pcap_stats.ps_recv) */ - uint32 ifdrop; /* Packets dropped by the network interface (e.g. not enough buffers) (i.e. pcap_stats.ps_ifdrop) */ - uint32 krnldrop; /* Packets dropped by the kernel filter (i.e. pcap_stats.ps_drop) */ - uint32 svrcapt; /* Packets captured by the RPCAP daemon and sent on the network */ + uint32_t ifrecv; /* Packets received by the kernel filter (i.e. pcap_stats.ps_recv) */ + uint32_t ifdrop; /* Packets dropped by the network interface (e.g. not enough buffers) (i.e. pcap_stats.ps_ifdrop) */ + uint32_t krnldrop; /* Packets dropped by the kernel filter (i.e. pcap_stats.ps_drop) */ + uint32_t svrcapt; /* Packets captured by the RPCAP daemon and sent on the network */ }; /* Structure that is needed to set sampling parameters */ struct rpcap_sampling { - uint8 method; /* Sampling method */ - uint8 dummy1; /* Must be zero */ - uint16 dummy2; /* Must be zero */ - uint32 value; /* Parameter related to the sampling method */ + uint8_t method; /* Sampling method */ + uint8_t dummy1; /* Must be zero */ + uint16_t dummy2; /* Must be zero */ + uint32_t value; /* Parameter related to the sampling method */ }; /* @@ -421,8 +437,8 @@ struct rpcap_sampling #include "sockutils.h" #include "sslutils.h" -extern void rpcap_createhdr(struct rpcap_header *header, uint8 ver, uint8 type, uint16 value, uint32 length); -extern const char *rpcap_msg_type_string(uint8 type); -extern int rpcap_senderror(SOCKET sock, SSL *ssl, uint8 ver, uint16 errcode, const char *error, char *errbuf); +extern void rpcap_createhdr(struct rpcap_header *header, uint8_t ver, uint8_t type, uint16_t value, uint32_t length); +extern const char *rpcap_msg_type_string(uint8_t type); +extern int rpcap_senderror(SOCKET sock, SSL *ssl, uint8_t ver, uint16_t errcode, const char *error, char *errbuf); #endif diff --git a/rpcapd/daemon.c b/rpcapd/daemon.c index 362f4b9b..0f3dd271 100644 --- a/rpcapd/daemon.c +++ b/rpcapd/daemon.c @@ -113,7 +113,7 @@ struct session { SOCKET sockctrl; SOCKET sockdata; SSL *ctrl_ssl, *data_ssl; // optional SSL handlers for sockctrl and sockdata. - uint8 protocol_version; + uint8_t protocol_version; pcap_t *fp; unsigned int TotCapt; int have_thread; @@ -125,31 +125,31 @@ struct session { }; // Locally defined functions -static int daemon_msg_err(SOCKET sockctrl, SSL *, uint32 plen); -static int daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen); +static int daemon_msg_err(SOCKET sockctrl, SSL *, uint32_t plen); +static int daemon_msg_auth_req(struct daemon_slpars *pars, uint32_t 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_findallif_req(uint8_t ver, struct daemon_slpars *pars, + uint32_t 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, +static int daemon_msg_open_req(uint8_t ver, struct daemon_slpars *pars, + uint32_t plen, char *source, size_t sourcelen); +static int daemon_msg_startcap_req(uint8_t ver, struct daemon_slpars *pars, + uint32_t plen, char *source, char *data_port, struct session **sessionp, struct rpcap_sampling *samp_param, int uses_ssl); -static int daemon_msg_endcap_req(uint8 ver, struct daemon_slpars *pars, +static int daemon_msg_endcap_req(uint8_t 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, SSL *, struct session *session, uint32 *plenp, char *errbuf); +static int daemon_msg_updatefilter_req(uint8_t ver, struct daemon_slpars *pars, + struct session *session, uint32_t plen); +static int daemon_unpackapplyfilter(SOCKET sockctrl, SSL *, struct session *session, uint32_t *plenp, char *errbuf); -static int daemon_msg_stats_req(uint8 ver, struct daemon_slpars *pars, - struct session *session, uint32 plen, struct pcap_stat *stats, +static int daemon_msg_stats_req(uint8_t ver, struct daemon_slpars *pars, + struct session *session, uint32_t 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 int daemon_msg_setsampling_req(uint8_t ver, struct daemon_slpars *pars, + uint32_t plen, struct rpcap_sampling *samp_param); static void daemon_seraddr(struct sockaddr_storage *sockaddrin, struct rpcap_sockaddr *sockaddrout); #ifdef _WIN32 @@ -160,8 +160,8 @@ static void noop_handler(int sign); #endif static int rpcapd_recv_msg_header(SOCKET sock, SSL *, struct rpcap_header *headerp); -static int rpcapd_recv(SOCKET sock, SSL *, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf); -static int rpcapd_discard(SOCKET sock, SSL *, uint32 len); +static int rpcapd_recv(SOCKET sock, SSL *, char *buffer, size_t toread, uint32_t *plen, char *errmsgbuf); +static int rpcapd_discard(SOCKET sock, SSL *, uint32_t len); static void session_close(struct session *); // @@ -169,14 +169,14 @@ static void session_close(struct session *); // the client, in case we aren't doing TLS but they are. // struct tls_record_header { - uint8 type; // ContentType - will be 22, for Handshake - uint8 version_major; // TLS protocol major version - uint8 version_injor; // TLS protocol minor version + uint8_t type; // ContentType - will be 22, for Handshake + uint8_t version_major; // TLS protocol major version + uint8_t version_injor; // TLS protocol minor version // This is *not* aligned on a 2-byte boundary; we just // declare it as two bytes. Don't assume any particular // compiler's mechanism for saying "packed"! - uint8 length_hi; // Upper 8 bits of payload length - uint8 length_lo; // Low 8 bits of payload length + uint8_t length_hi; // Upper 8 bits of payload length + uint8_t length_lo; // Low 8 bits of payload length }; #define TLS_RECORD_HEADER_LEN 5 // Don't use sizeof in case it's padded @@ -188,8 +188,8 @@ struct tls_record_header { // TLS alert message. // struct tls_alert { - uint8 alert_level; - uint8 alert_description; + uint8_t alert_level; + uint8_t alert_description; }; #define TLS_ALERT_LEN 2 @@ -212,9 +212,9 @@ static int is_url(const char *source); int daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients, - int nullAuthAllowed, int uses_ssl) + int nullAuthAllowed, char *data_port, int uses_ssl) { - uint8 first_octet; + uint8_t first_octet; struct tls_record_header tls_header; struct tls_alert tls_alert; struct daemon_slpars pars; // service loop parameters @@ -224,7 +224,7 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients, SSL *ssl = NULL; int nrecv; struct rpcap_header header; // RPCAP message general header - uint32 plen; // payload length from header + uint32_t 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 @@ -449,7 +449,8 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients, if (getpeername(pars.sockctrl, (struct sockaddr *)&from, &fromlen) == -1) { - sock_geterror("getpeername()", errmsgbuf, PCAP_ERRBUF_SIZE); + sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE, + "getpeername() failed"); if (rpcap_senderror(pars.sockctrl, pars.ssl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1) rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); goto end; @@ -523,7 +524,8 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients, retval = select((int)pars.sockctrl + 1, &rfds, NULL, NULL, &tv); if (retval == -1) { - sock_geterror("select() failed", errmsgbuf, PCAP_ERRBUF_SIZE); + sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE, + "select() failed"); if (rpcap_senderror(pars.sockctrl, pars.ssl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1) rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); goto end; @@ -763,7 +765,8 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients, #endif if (retval == -1) { - sock_geterror("select() failed", errmsgbuf, PCAP_ERRBUF_SIZE); + sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE, + "select() failed"); if (rpcap_senderror(pars.sockctrl, pars.ssl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1) @@ -898,8 +901,8 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients, } if (daemon_msg_startcap_req(header.ver, &pars, - plen, source, &session, &samp_param, - uses_ssl) == -1) + plen, source, data_port, &session, + &samp_param, uses_ssl) == -1) { // Fatal error; a message has // been logged, so just give up. @@ -1135,7 +1138,7 @@ end: * This handles the RPCAP_MSG_ERR message. */ static int -daemon_msg_err(SOCKET sockctrl, SSL *ssl, uint32 plen) +daemon_msg_err(SOCKET sockctrl, SSL *ssl, uint32_t plen) { char errbuf[PCAP_ERRBUF_SIZE]; char remote_errbuf[PCAP_ERRBUF_SIZE]; @@ -1214,7 +1217,7 @@ daemon_msg_err(SOCKET sockctrl, SSL *ssl, uint32 plen) * unrecoverable error or for the authentication failure. */ static int -daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen) +daemon_msg_auth_req(struct daemon_slpars *pars, uint32_t plen) { char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client @@ -1258,7 +1261,7 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen) case RPCAP_RMTAUTH_PWD: { char *username, *passwd; - uint32 usernamelen, passwdlen; + uint32_t usernamelen, passwdlen; usernamelen = ntohs(auth.slen1); username = (char *) malloc (usernamelen + 1); @@ -1368,11 +1371,16 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen) goto error; // - // Indicate to our peer what versions we support. + // Indicate to our peer what versions we support and what our + // version of the byte-order magic is (which will tell the + // client whether our byte order differs from theirs, in which + // case they will need to byte-swap some fields in some + // link-layer types' headers). // memset(authreply, 0, sizeof(struct rpcap_authreply)); authreply->minvers = RPCAP_MIN_VERSION; authreply->maxvers = RPCAP_MAX_VERSION; + authreply->byte_order_magic = RPCAP_BYTE_ORDER_MAGIC; // Send the reply. if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) @@ -1590,10 +1598,10 @@ daemon_AuthUserPwd(char *username, char *password, char *errbuf) sizeof (errmsgbuf)); \ goto error; \ } \ - replylen += (uint32)(itemlen) + replylen += (uint32_t)(itemlen) static int -daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen) +daemon_msg_findallif_req(uint8_t ver, struct daemon_slpars *pars, uint32_t plen) { char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client @@ -1602,8 +1610,8 @@ daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen) 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 - uint32 replylen; // length of reply payload - uint16 nif = 0; // counts the number of interface listed + uint32_t replylen; // length of reply payload + uint16_t 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, pars->ssl, plen) == -1) @@ -1700,7 +1708,7 @@ daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen) // send the interface list for (d = alldevs; d != NULL; d = d->next) { - uint16 lname, ldescr; + uint16_t lname, ldescr; // Note: the findalldevs_if entries are *not* neatly // aligned on 4-byte boundaries, because they're @@ -1719,11 +1727,11 @@ daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen) * fit in 16 bits. */ if (d->description) - ldescr = (uint16) strlen(d->description); + ldescr = (uint16_t) strlen(d->description); else ldescr = 0; if (d->name) - lname = (uint16) strlen(d->name); + lname = (uint16_t) strlen(d->name); else lname = 0; @@ -1843,7 +1851,7 @@ error: to discard excess data in the message, if present) */ static int -daemon_msg_open_req(uint8 ver, struct daemon_slpars *pars, uint32 plen, +daemon_msg_open_req(uint8_t ver, struct daemon_slpars *pars, uint32_t plen, char *source, size_t sourcelen) { char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors @@ -1882,7 +1890,7 @@ daemon_msg_open_req(uint8 ver, struct daemon_slpars *pars, uint32 plen, // 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 */, + 0 /* no promisc */, 1000 /* fake timeout */, errmsgbuf)) == NULL) goto error; @@ -1945,8 +1953,8 @@ error: 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, +daemon_msg_startcap_req(uint8_t ver, struct daemon_slpars *pars, uint32_t plen, + char *source, char *data_port, struct session **sessionp, struct rpcap_sampling *samp_param _U_, int uses_ssl) { char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors @@ -2054,7 +2062,8 @@ daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen, saddrlen = sizeof(struct sockaddr_storage); if (getpeername(pars->sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1) { - sock_geterror("getpeername()", errmsgbuf, PCAP_ERRBUF_SIZE); + sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE, + "getpeername() failed"); goto error; } @@ -2071,32 +2080,43 @@ daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen, if (getnameinfo((struct sockaddr *) &saddr, saddrlen, peerhost, sizeof(peerhost), NULL, 0, NI_NUMERICHOST)) { - sock_geterror("getnameinfo()", errmsgbuf, PCAP_ERRBUF_SIZE); + sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE, + "getnameinfo() failed"); 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) + if ((session->sockdata = sock_open(peerhost, 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 (data_port[0] != '\0') + { + // Use the specified network port + if (sock_initaddress(NULL, data_port, &hints, &addrinfo, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + } + else + { + // Make the server socket pick up a free network port for us + if (sock_initaddress(NULL, NULL, &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) + if ((session->sockdata = sock_open(NULL, 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); + sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE, + "getsockname() failed"); goto error; } @@ -2104,7 +2124,8 @@ daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen, if (getnameinfo((struct sockaddr *) &saddr, saddrlen, NULL, 0, portdata, sizeof(portdata), NI_NUMERICSERV)) { - sock_geterror("getnameinfo()", errmsgbuf, PCAP_ERRBUF_SIZE); + sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE, + "getnameinfo() failed"); goto error; } } @@ -2172,7 +2193,8 @@ daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen, if (socktemp == INVALID_SOCKET) { - sock_geterror("accept()", errbuf, PCAP_ERRBUF_SIZE); + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "accept() failed"); rpcapd_log(LOGPRIO_ERROR, "Accept of data connection failed: %s", errbuf); goto error; @@ -2278,7 +2300,7 @@ fatal_error: } static int -daemon_msg_endcap_req(uint8 ver, struct daemon_slpars *pars, +daemon_msg_endcap_req(uint8_t ver, struct daemon_slpars *pars, struct session *session) { char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors @@ -2316,7 +2338,7 @@ daemon_msg_endcap_req(uint8 ver, struct daemon_slpars *pars, #define RPCAP_BPF_MAXINSNS 8192 static int -daemon_unpackapplyfilter(SOCKET sockctrl, SSL *ctrl_ssl, struct session *session, uint32 *plenp, char *errmsgbuf) +daemon_unpackapplyfilter(SOCKET sockctrl, SSL *ctrl_ssl, struct session *session, uint32_t *plenp, char *errmsgbuf) { int status; struct rpcap_filter filter; @@ -2401,8 +2423,8 @@ daemon_unpackapplyfilter(SOCKET sockctrl, SSL *ctrl_ssl, struct session *session } static int -daemon_msg_updatefilter_req(uint8 ver, struct daemon_slpars *pars, - struct session *session, uint32 plen) +daemon_msg_updatefilter_req(uint8_t ver, struct daemon_slpars *pars, + struct session *session, uint32_t plen) { char errbuf[PCAP_ERRBUF_SIZE]; char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client @@ -2455,7 +2477,7 @@ error: \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, +daemon_msg_setsampling_req(uint8_t ver, struct daemon_slpars *pars, uint32_t plen, struct rpcap_sampling *samp_param) { char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors @@ -2514,8 +2536,8 @@ error: } static int -daemon_msg_stats_req(uint8 ver, struct daemon_slpars *pars, - struct session *session, uint32 plen, struct pcap_stat *stats, +daemon_msg_stats_req(uint8_t ver, struct daemon_slpars *pars, + struct session *session, uint32_t plen, struct pcap_stat *stats, unsigned int svrcapt) { char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors @@ -2536,7 +2558,7 @@ daemon_msg_stats_req(uint8 ver, struct daemon_slpars *pars, goto error; rpcap_createhdr((struct rpcap_header *) sendbuf, ver, - RPCAP_MSG_STATS_REPLY, 0, (uint16) sizeof(struct rpcap_stats)); + RPCAP_MSG_STATS_REPLY, 0, (uint16_t) sizeof(struct rpcap_stats)); netstats = (struct rpcap_stats *) &sendbuf[sendbufidx]; @@ -2709,7 +2731,7 @@ daemon_thrdatamain(void *ptr) rpcap_createhdr((struct rpcap_header *) sendbuf, session->protocol_version, RPCAP_MSG_PACKET, 0, - (uint16) (sizeof(struct rpcap_pkthdr) + pkt_header->caplen)); + (uint16_t) (sizeof(struct rpcap_pkthdr) + pkt_header->caplen)); net_pkt_header = (struct rpcap_pkthdr *) &sendbuf[sendbufidx]; @@ -2731,8 +2753,8 @@ daemon_thrdatamain(void *ptr) // This protocol needs to be updated with a new version // before 2038-01-19 03:14:07 UTC. // - net_pkt_header->timestamp_sec = htonl((uint32)pkt_header->ts.tv_sec); - net_pkt_header->timestamp_usec = htonl((uint32)pkt_header->ts.tv_usec); + net_pkt_header->timestamp_sec = htonl((uint32_t)pkt_header->ts.tv_sec); + net_pkt_header->timestamp_usec = htonl((uint32_t)pkt_header->ts.tv_usec); // Bufferize the pkt data if (sock_bufferize((char *) pkt_data, pkt_header->caplen, @@ -2927,7 +2949,7 @@ rpcapd_recv_msg_header(SOCKET sock, SSL *ssl, struct rpcap_header *headerp) * error. */ static int -rpcapd_recv(SOCKET sock, SSL *ssl, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf) +rpcapd_recv(SOCKET sock, SSL *ssl, char *buffer, size_t toread, uint32_t *plen, char *errmsgbuf) { int nread; char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors @@ -2956,7 +2978,7 @@ rpcapd_recv(SOCKET sock, SSL *ssl, char *buffer, size_t toread, uint32 *plen, ch * error. */ static int -rpcapd_discard(SOCKET sock, SSL *ssl, uint32 len) +rpcapd_discard(SOCKET sock, SSL *ssl, uint32_t len) { char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed diff --git a/rpcapd/daemon.h b/rpcapd/daemon.h index dbbdb62c..8df3bbe0 100644 --- a/rpcapd/daemon.h +++ b/rpcapd/daemon.h @@ -45,7 +45,7 @@ // for active mode. // int daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients, - int nullAuthAllowed, int uses_ssl); + int nullAuthAllowed, char *data_port, int uses_ssl); void sleep_secs(int secs); diff --git a/rpcapd/fileconf.c b/rpcapd/fileconf.c index b79dda18..c051f887 100644 --- a/rpcapd/fileconf.c +++ b/rpcapd/fileconf.c @@ -386,7 +386,7 @@ void fileconf_read(void) // // Append this to the host list. - // Save the curren end-of-string for the + // Save the current 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. diff --git a/rpcapd/rpcapd.c b/rpcapd/rpcapd.c index 19da87f8..ee24432d 100644 --- a/rpcapd/rpcapd.c +++ b/rpcapd/rpcapd.c @@ -87,6 +87,7 @@ 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 +static char data_port[MAX_LINE + 1]; //!< keeps the network port to use to transfer data #ifdef _WIN32 static HANDLE state_change_event; //!< event to signal that a state change should take place #endif @@ -123,16 +124,19 @@ static void printusage(FILE * f) { const char *usagetext = "USAGE:" - " " PROGRAM_NAME " [-b <address>] [-p <port>] [-4] [-l <host_list>] [-a <host,port>]\n" - " [-n] [-v] [-d] " + " " PROGRAM_NAME " [-b <address>] [-p <port>] [-t <data_port>] [-4] [-l <host_list>]\n" + " [-a <host,port>] [-n] [-v] [-d] " #ifndef _WIN32 "[-i] " #endif - "[-D] [-s <config_file>] [-f <config_file>]\n\n" + "[-D] [-s <config_file>]\n" + " [-f <config_file>]\n\n" " -b <address> the address to bind to (either numeric or literal).\n" " Default: binds to all local IPv4 and IPv6 addresses\n\n" " -p <port> the port to bind to.\n" " Default: binds to port " RPCAP_DEFAULT_NETPORT "\n\n" + " -t <data port>: the port to use to transfer data.\n" + " Default: an unused port is chosen by the operating system\n\n" " -4 use only IPv4.\n" " Default: use both IPv4 and IPv6 waiting sockets\n\n" " -l <host_list> a file that contains a list of hosts that are allowed\n" @@ -216,7 +220,7 @@ int main(int argc, char *argv[]) # define SSL_CLOPTS "" # endif -# define CLOPTS "b:dDhip:4l:na:s:f:v" SSL_CLOPTS +# define CLOPTS "b:dDhip:4l:na:s:f:t:v" SSL_CLOPTS while ((retval = getopt(argc, argv, CLOPTS)) != -1) { @@ -232,6 +236,9 @@ int main(int argc, char *argv[]) case 'p': pcap_strlcpy(port, optarg, sizeof (port)); break; + case 't': + pcap_strlcpy(data_port, optarg, sizeof (data_port)); + break; case '4': mainhints.ai_family = PF_INET; // IPv4 server only break; @@ -361,8 +368,8 @@ int main(int argc, char *argv[]) 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); + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "Can't create state change event"); rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); exit(2); } @@ -372,8 +379,8 @@ int main(int argc, char *argv[]) // if (!SetConsoleCtrlHandler(main_ctrl_event, TRUE)) { - sock_geterror("Can't set control handler", errbuf, - PCAP_ERRBUF_SIZE); + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "Can't set control handler"); rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); exit(2); } @@ -427,8 +434,8 @@ int main(int argc, char *argv[]) sockctrl = dup(0); if (sockctrl == -1) { - sock_geterror("Can't dup standard input", errbuf, - PCAP_ERRBUF_SIZE); + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "Can't dup standard input"); rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); exit(2); } @@ -461,7 +468,7 @@ int main(int argc, char *argv[]) exit(0); } (void)daemon_serviceloop(sockctrl, 0, hostlist_copy, - nullAuthAllowed, uses_ssl); + nullAuthAllowed, data_port, uses_ssl); // // Nothing more to do. @@ -504,7 +511,7 @@ int main(int argc, char *argv[]) // 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 + // created. From this point on, the number of threads active are always one more compared // to the number you're expecting // Second child continues @@ -623,7 +630,7 @@ void main_startup(void) SOCKET sock; struct listen_sock *sock_info; - if ((sock = sock_open(tempaddrinfo, SOCKOPEN_SERVER, SOCKET_MAXCONN, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) + if ((sock = sock_open(NULL, tempaddrinfo, SOCKOPEN_SERVER, SOCKET_MAXCONN, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) { switch (tempaddrinfo->ai_family) { @@ -736,8 +743,8 @@ send_state_change_event(void) if (!SetEvent(state_change_event)) { - sock_geterror("SetEvent on shutdown event failed", errbuf, - PCAP_ERRBUF_SIZE); + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "SetEvent on shutdown event failed"); rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); } } @@ -904,15 +911,15 @@ accept_connections(void) event = WSACreateEvent(); if (event == WSA_INVALID_EVENT) { - sock_geterror("Can't create socket event", errbuf, - PCAP_ERRBUF_SIZE); + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "Can't create socket event"); 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); + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "Can't setup socket event"); rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); exit(2); } @@ -930,8 +937,8 @@ accept_connections(void) WSA_INFINITE, FALSE); if (ret == WSA_WAIT_FAILED) { - sock_geterror("WSAWaitForMultipleEvents failed", errbuf, - PCAP_ERRBUF_SIZE); + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "WSAWaitForMultipleEvents failed"); rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); exit(2); } @@ -970,8 +977,8 @@ accept_connections(void) if (WSAEnumNetworkEvents(sock_info->sock, events[i], &network_events) == SOCKET_ERROR) { - sock_geterror("WSAEnumNetworkEvents failed", - errbuf, PCAP_ERRBUF_SIZE); + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "WSAEnumNetworkEvents failed"); rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); exit(2); } @@ -985,10 +992,10 @@ accept_connections(void) // // Yes - report it and keep going. // - sock_fmterror("Socket error", + sock_fmterrmsg(errbuf, + PCAP_ERRBUF_SIZE, network_events.iErrorCode[FD_ACCEPT_BIT], - errbuf, - PCAP_ERRBUF_SIZE); + "Socket error"); rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); continue; } @@ -1174,7 +1181,7 @@ accept_connection(SOCKET listen_sock) // 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); + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, "accept() failed"); rpcapd_log(LOGPRIO_ERROR, "Accept of control connection from client failed: %s", errbuf); return; @@ -1198,14 +1205,16 @@ accept_connection(SOCKET listen_sock) // if (WSAEventSelect(sockctrl, NULL, 0) == SOCKET_ERROR) { - sock_geterror("WSAEventSelect()", errbuf, PCAP_ERRBUF_SIZE); + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "WSAEventSelect() failed"); 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); + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "ioctlsocket(FIONBIO) failed"); rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); sock_close(sockctrl, NULL, 0); return; @@ -1298,7 +1307,7 @@ accept_connection(SOCKET listen_sock) exit(0); } (void)daemon_serviceloop(sockctrl, 0, hostlist_copy, - nullAuthAllowed, uses_ssl); + nullAuthAllowed, data_port, uses_ssl); exit(0); } @@ -1358,7 +1367,7 @@ main_active(void *ptr) { int activeclose; - if ((sockctrl = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) + if ((sockctrl = sock_open(activepars->address, addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) { rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf); @@ -1388,7 +1397,8 @@ main_active(void *ptr) // daemon_serviceloop() will free the copy. // activeclose = daemon_serviceloop(sockctrl, 1, - hostlist_copy, nullAuthAllowed, uses_ssl); + hostlist_copy, nullAuthAllowed, data_port, + uses_ssl); } // If the connection is closed by the user explicitly, don't try to connect to it again @@ -1416,7 +1426,7 @@ unsigned __stdcall main_passive_serviceloop_thread(void *ptr) // told by the client to close. // (void)daemon_serviceloop(params.sockctrl, 0, params.hostlist, - nullAuthAllowed, uses_ssl); + nullAuthAllowed, data_port, uses_ssl); return 0; } diff --git a/rpcapd/rpcapd.manadmin.in b/rpcapd/rpcapd.manadmin.in index ea6046e4..49c75eb5 100644 --- a/rpcapd/rpcapd.manadmin.in +++ b/rpcapd/rpcapd.manadmin.in @@ -43,14 +43,16 @@ rpcapd .B \-p .I port ] [ -.B \-4 +.B \-t +.I data_port ] [ -.B \-l -.I host_list +.B \-4 ] -.br .ti +8 [ +.B \-l +.I host_list +] [ .B \-a .IR host , port ] [ @@ -62,7 +64,6 @@ rpcapd ] [ .B \-i ] -.br .ti +8 [ .B \-D @@ -77,7 +78,6 @@ rpcapd [ .B \-S ] -.br .ti +8 [ .B \-K @@ -193,13 +193,21 @@ By default, .B rpcapd binds to port 2002. .TP +.BI \-t " data_port" +Use the port specified by +.I data_port +as the port for data transfer. +By default, +.B rpcapd +uses a port chosen by the operating system. +.TP .B \-4 Listen only on IPv4 addresses. By default, .B rpcapd listens on both IPv4 and IPv6 addresses. .TP -.BI -l " host_list" +.BI \-l " host_list" Only allow hosts specified in the .I host_list argument to connect to this server. @@ -46,6 +46,7 @@ #include <limits.h> /* for INT_MAX */ #include "pcap-int.h" +#include "pcap-util.h" #include "pcap-common.h" @@ -70,6 +71,7 @@ /* * Standard libpcap format. + * rpcapd can too use this number in its network protocol to tell endianness. */ #define TCPDUMP_MAGIC 0xa1b2c3d4 @@ -96,6 +98,11 @@ */ #define NSEC_TCPDUMP_MAGIC 0xa1b23c4d +/* + * Used for identification of cbpf-savefile(5). + */ +#define CBPF_SAVEFILE_MAGIC 0xa1b2c3cb + static int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **datap); #ifdef _WIN32 @@ -578,7 +585,7 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) * userland. * * However, perhaps some versions of libpcap failed to - * set the snapshot length currectly in the file header + * set the snapshot length correctly in the file header * or the per-packet header, or perhaps this is a * corrupted safefile or a savefile built/modified by a * fuzz tester, so we check anyway. We grow the buffer @@ -705,8 +712,7 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) } *data = p->buffer; - if (p->swapped) - swap_pseudo_headers(p->linktype, hdr, *data); + pcap_post_process(p->linktype, p->swapped, hdr, *data); return (1); } diff --git a/sf-pcapng.c b/sf-pcapng.c index 9e0a72e5..058a7244 100644 --- a/sf-pcapng.c +++ b/sf-pcapng.c @@ -34,6 +34,7 @@ #include <string.h> #include "pcap-int.h" +#include "pcap-util.h" #include "pcap-common.h" @@ -1511,8 +1512,7 @@ found: if (*data == NULL) return (-1); - if (p->swapped) - swap_pseudo_headers(p->linktype, hdr, *data); + pcap_post_process(p->linktype, p->swapped, hdr, *data); return (1); } diff --git a/sockutils.c b/sockutils.c index d9762dd5..c2c1528c 100644 --- a/sockutils.c +++ b/sockutils.c @@ -93,7 +93,7 @@ * * On Windows, send() and recv() return an int. * - * Wth MSVC, there *is* no ssize_t. + * With 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). @@ -143,52 +143,165 @@ static int fuzz_recv(char *bufp, int remaining) { } #endif +int sock_geterrcode(void) +{ +#ifdef _WIN32 + return GetLastError(); +#else + return errno; +#endif +} + /* * Format an error message given an errno value (UN*X) or a Winsock error * (Windows). */ -void sock_fmterror(const char *caller, int errcode, char *errbuf, int errbuflen) +void sock_vfmterrmsg(char *errbuf, size_t errbuflen, int errcode, + const char *fmt, va_list ap) { if (errbuf == NULL) return; #ifdef _WIN32 - pcap_fmt_errmsg_for_win32_err(errbuf, errbuflen, errcode, - "%s", caller); + pcap_vfmt_errmsg_for_win32_err(errbuf, errbuflen, errcode, + fmt, ap); #else - pcap_fmt_errmsg_for_errno(errbuf, errbuflen, errcode, - "%s", caller); + pcap_vfmt_errmsg_for_errno(errbuf, errbuflen, errcode, + fmt, ap); #endif } +void sock_fmterrmsg(char *errbuf, size_t errbuflen, int errcode, + const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + sock_vfmterrmsg(errbuf, errbuflen, errcode, fmt, ap); + va_end(ap); +} + /* - * \brief It retrieves the error message after an error occurred in the socket interface. - * - * This function is defined because of the different way errors are returned in UNIX - * and Win32. This function provides a consistent way to retrieve the error message - * (after a socket error occurred) on all the platforms. - * - * \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'. - * - * \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 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. + * Format an error message for the last socket error. + */ +void sock_geterrmsg(char *errbuf, size_t errbuflen, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + sock_vfmterrmsg(errbuf, errbuflen, sock_geterrcode(), fmt, ap); + va_end(ap); +} + +/* + * Types of error. * - * \return No return values. The error message is returned in the 'string' parameter. + * These are sorted by how likely they are to be the "underlying" problem, + * so that lower-rated errors for a given address in a given family + * should not overwrite higher-rated errors for another address in that + * family, and higher-rated errors should overwrit elower-rated errors. */ -void sock_geterror(const char *caller, char *errbuf, int errbuflen) +typedef enum { + SOCK_CONNERR, /* connection error */ + SOCK_HOSTERR, /* host error */ + SOCK_NETERR, /* network error */ + SOCK_AFNOTSUPERR, /* address family not supported */ + SOCK_UNKNOWNERR, /* unknown error */ + SOCK_NOERR /* no error */ +} sock_errtype; + +static sock_errtype sock_geterrtype(int errcode) { + switch (errcode) { + #ifdef _WIN32 - sock_fmterror(caller, GetLastError(), errbuf, errbuflen); + case WSAECONNRESET: + case WSAECONNABORTED: + case WSAECONNREFUSED: #else - sock_fmterror(caller, errno, errbuf, errbuflen); + case ECONNRESET: + case ECONNABORTED: + case ECONNREFUSED: #endif -} + /* + * Connection error; this means the problem is probably + * that there's no server set up on the remote machine, + * or that it is set up, but it's IPv4-only or IPv6-only + * and we're trying the wrong address family. + * + * These overwrite all other errors, as they indicate + * that, even if somethng else went wrong in another + * attempt, this probably wouldn't work even if the + * other problems were fixed. + */ + return (SOCK_CONNERR); + +#ifdef _WIN32 + case WSAENETUNREACH: + case WSAETIMEDOUT: + case WSAEHOSTDOWN: + case WSAEHOSTUNREACH: +#else + case ENETUNREACH: + case ETIMEDOUT: + case EHOSTDOWN: + case EHOSTUNREACH: +#endif + /* + * Network errors that could be IPv4-specific, IPv6- + * specific, or present with both. + * + * Don't overwrite connection errors, but overwrite + * everything else. + */ + return (SOCK_HOSTERR); + +#ifdef _WIN32 + case WSAENETDOWN: + case WSAENETRESET: +#else + case ENETDOWN: + case ENETRESET: +#endif + /* + * Network error; this means we don't know whether + * there's a server set up on the remote machine, + * and we don't have a reason to believe that IPv6 + * any worse or better than IPv4. + * + * These probably indicate a local failure, e.g. + * an interface is down. + * + * Don't overwrite connection errors or host errors, + * but overwrite everything else. + */ + return (SOCK_NETERR); + +#ifdef _WIN32 + case WSAEAFNOSUPPORT: +#else + case EAFNOSUPPORT: +#endif + /* + * "Address family not supported" probably means + * "No soup^WIPv6 for you!". + * + * Don't overwrite connection errors, host errors, or + * network errors (none of which we should get for this + * address family if it's not supported), but overwrite + * everything else. + */ + return (SOCK_AFNOTSUPERR); + + default: + /* + * Anything else. + * + * Don't overwrite any errors. + */ + return (SOCK_UNKNOWNERR); + } +} /* * \brief This function initializes the socket mechanism if it hasn't @@ -281,6 +394,79 @@ static int sock_ismcastaddr(const struct sockaddr *saddr) } } +struct addr_status { + struct addrinfo *info; + int errcode; + sock_errtype errtype; +}; + +/* + * Sort by IPv4 address vs. IPv6 address. + */ +static int compare_addrs_to_try_by_address_family(const void *a, const void *b) +{ + const struct addr_status *addr_a = (const struct addr_status *)a; + const struct addr_status *addr_b = (const struct addr_status *)b; + + return addr_a->info->ai_family - addr_b->info->ai_family; +} + +/* + * Sort by error type and, within a given error type, by error code and, + * within a given error code, by IPv4 address vs. IPv6 address. + */ +static int compare_addrs_to_try_by_status(const void *a, const void *b) +{ + const struct addr_status *addr_a = (const struct addr_status *)a; + const struct addr_status *addr_b = (const struct addr_status *)b; + + if (addr_a->errtype == addr_b->errtype) + { + if (addr_a->errcode == addr_b->errcode) + { + return addr_a->info->ai_family - addr_b->info->ai_family; + } + return addr_a->errcode - addr_b->errcode; + } + + return addr_a->errtype - addr_b->errtype; +} + +static SOCKET sock_create_socket(struct addrinfo *addrinfo, char *errbuf, + int errbuflen) +{ + SOCKET sock; +#ifdef SO_NOSIGPIPE + int on = 1; +#endif + + sock = socket(addrinfo->ai_family, addrinfo->ai_socktype, + addrinfo->ai_protocol); + if (sock == INVALID_SOCKET) + { + sock_geterrmsg(errbuf, errbuflen, "socket() failed"); + return INVALID_SOCKET; + } + + /* + * Disable SIGPIPE, if we have SO_NOSIGPIPE. We don't want to + * have to deal with signals if the peer closes the connection, + * especially in client programs, which may not even be aware that + * they're sending to sockets. + */ +#ifdef SO_NOSIGPIPE + if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (char *)&on, + sizeof (int)) == -1) + { + sock_geterrmsg(errbuf, errbuflen, + "setsockopt(SO_NOSIGPIPE) failed"); + closesocket(sock); + return INVALID_SOCKET; + } +#endif + return sock; +} + /* * \brief It initializes a network connection both from the client and the server side. * @@ -292,6 +478,9 @@ static int sock_ismcastaddr(const struct sockaddr *saddr) * * This function is usually preceded by the sock_initaddress(). * + * \param host: for client sockets, the host name to which we're trying + * to connect. + * * \param addrinfo: pointer to an addrinfo variable which will be used to * open the socket and such. This variable is the one returned by the previous call to * sock_initaddress(). @@ -312,48 +501,33 @@ static int sock_ismcastaddr(const struct sockaddr *saddr) * if everything is fine, INVALID_SOCKET if some errors occurred. The error message is returned * in the 'errbuf' variable. */ -SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf, int errbuflen) +SOCKET sock_open(const char *host, struct addrinfo *addrinfo, int server, int nconn, char *errbuf, int errbuflen) { SOCKET sock; -#if defined(SO_NOSIGPIPE) || defined(IPV6_V6ONLY) || defined(IPV6_BINDV6ONLY) - int on = 1; -#endif - - sock = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol); - if (sock == INVALID_SOCKET) - { - sock_geterror("socket()", errbuf, errbuflen); - return INVALID_SOCKET; - } - - /* - * Disable SIGPIPE, if we have SO_NOSIGPIPE. We don't want to - * have to deal with signals if the peer closes the connection, - * especially in client programs, which may not even be aware that - * they're sending to sockets. - */ -#ifdef SO_NOSIGPIPE - if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (char *)&on, - sizeof (int)) == -1) - { - sock_geterror("setsockopt(SO_NOSIGPIPE)", errbuf, errbuflen); - closesocket(sock); - return INVALID_SOCKET; - } -#endif /* This is a server socket */ if (server) { + int on; + + /* + * Attempt to create the socket. + */ + sock = sock_create_socket(addrinfo, errbuf, errbuflen); + if (sock == INVALID_SOCKET) + { + return INVALID_SOCKET; + } + /* * 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; + on = 1; (void)setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, - (char *)&optval, sizeof (optval)); + (char *)&on, sizeof (on)); #if defined(IPV6_V6ONLY) || defined(IPV6_BINDV6ONLY) /* @@ -390,6 +564,7 @@ SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf, #endif /* IPV6_V6ONLY */ if (addrinfo->ai_family == PF_INET6) { + on = 1; if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof (int)) == -1) { @@ -404,7 +579,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_geterrmsg(errbuf, errbuflen, "bind() failed"); closesocket(sock); return INVALID_SOCKET; } @@ -412,7 +587,8 @@ 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_geterrmsg(errbuf, errbuflen, + "listen() failed"); closesocket(sock); return INVALID_SOCKET; } @@ -422,70 +598,259 @@ SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf, } else /* we're the client */ { + struct addr_status *addrs_to_try; struct addrinfo *tempaddrinfo; - char *errbufptr; - size_t bufspaceleft; - - tempaddrinfo = addrinfo; - errbufptr = errbuf; - bufspaceleft = errbuflen; - *errbufptr = 0; + size_t numaddrinfos; + size_t i; + int current_af = AF_UNSPEC; /* - * We have to loop though all the addinfo returned. - * For instance, we can have both IPv6 and IPv4 addresses, but the service we're trying - * to connect to is unavailable in IPv6, so we have to try in IPv4 as well + * We have to loop though all the addrinfos returned. + * For instance, we can have both IPv6 and IPv4 addresses, + * but the service we're trying to connect to is unavailable + * in IPv6, so we have to try in IPv4 as well. + * + * How many addrinfos do we have? */ - while (tempaddrinfo) + numaddrinfos = 0; + for (tempaddrinfo = addrinfo; tempaddrinfo != NULL; + tempaddrinfo = tempaddrinfo->ai_next) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - break; -#endif - if (connect(sock, tempaddrinfo->ai_addr, (int) tempaddrinfo->ai_addrlen) == -1) - { - size_t msglen; - char TmpBuffer[100]; - char SocketErrorMessage[SOCK_ERRBUF_SIZE]; + numaddrinfos++; + } - /* - * We have to retrieve the error message before any other socket call completes, otherwise - * the error message is lost - */ - sock_geterror("Connect to socket failed", - SocketErrorMessage, sizeof(SocketErrorMessage)); + if (numaddrinfos == 0) + { + snprintf(errbuf, errbuflen, + "There are no addresses in the address list"); + return INVALID_SOCKET; + } - /* 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)); + /* + * Allocate an array of struct addr_status and fill it in. + */ + addrs_to_try = calloc(numaddrinfos, sizeof *addrs_to_try); + if (addrs_to_try == NULL) + { + snprintf(errbuf, errbuflen, + "Out of memory connecting to %s", host); + return INVALID_SOCKET; + } - snprintf(errbufptr, bufspaceleft, - "Is the server properly installed on %s? %s", TmpBuffer, SocketErrorMessage); + for (tempaddrinfo = addrinfo, i = 0; tempaddrinfo != NULL; + tempaddrinfo = tempaddrinfo->ai_next, i++) + { + addrs_to_try[i].info = tempaddrinfo; + addrs_to_try[i].errcode = 0; + addrs_to_try[i].errtype = SOCK_NOERR; + } - /* In case more then one 'connect' fails, we manage to keep all the error messages */ - msglen = strlen(errbufptr); + /* + * Sort the structures to put the IPv4 addresses before the + * IPv6 addresses; we will have to create an IPv4 socket + * for the IPv4 addresses and an IPv6 socket for the IPv6 + * addresses (one of the arguments to socket() is the + * address/protocol family to use, and IPv4 and IPv6 are + * separate address/protocol families). + */ + qsort(addrs_to_try, numaddrinfos, sizeof *addrs_to_try, + compare_addrs_to_try_by_address_family); - errbufptr[msglen] = ' '; - errbufptr[msglen + 1] = 0; + /* Start out with no socket. */ + sock = INVALID_SOCKET; - bufspaceleft = bufspaceleft - (msglen + 1); - errbufptr += (msglen + 1); + /* + * Now try them all. + */ + for (i = 0; i < numaddrinfos; i++) + { + tempaddrinfo = addrs_to_try[i].info; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + break; +#endif + /* + * If we have a socket, but it's for a + * different address family, close it. + */ + if (sock != INVALID_SOCKET && + current_af != tempaddrinfo->ai_family) + { + closesocket(sock); + sock = INVALID_SOCKET; + } - tempaddrinfo = tempaddrinfo->ai_next; + /* + * If we don't have a socket, open one + * for *this* address's address family. + */ + if (sock == INVALID_SOCKET) + { + sock = sock_create_socket(tempaddrinfo, + errbuf, errbuflen); + if (sock == INVALID_SOCKET) + { + free(addrs_to_try); + return INVALID_SOCKET; + } + } + if (connect(sock, tempaddrinfo->ai_addr, (int) tempaddrinfo->ai_addrlen) == -1) + { + addrs_to_try[i].errcode = sock_geterrcode(); + addrs_to_try[i].errtype = + sock_geterrtype(addrs_to_try[i].errcode); } else break; } /* - * Check how we exit from the previous loop - * If tempaddrinfo is equal to NULL, it means that all the connect() failed. + * Check how we exited from the previous loop. + * If tempaddrinfo is equal to NULL, it means that all + * the connect() attempts failed. Construct an + * error message. */ - if (tempaddrinfo == NULL) + if (i == numaddrinfos) { + int same_error_for_all; + int first_error; + closesocket(sock); + + /* + * Sort the statuses to group together categories + * of errors, errors within categories, and + * address families within error sets. + */ + qsort(addrs_to_try, numaddrinfos, sizeof *addrs_to_try, + compare_addrs_to_try_by_status); + + /* + * Are all the errors the same? + */ + same_error_for_all = 1; + first_error = addrs_to_try[0].errcode; + for (i = 1; i < numaddrinfos; i++) + { + if (addrs_to_try[i].errcode != first_error) + { + same_error_for_all = 0; + break; + } + } + + if (same_error_for_all) { + /* + * Yes. No need to show the IP + * addresses. + */ + if (addrs_to_try[0].errtype == SOCK_CONNERR) { + /* + * Connection error; note that + * the daemon might not be set + * up correctly, or set up at all. + */ + sock_fmterrmsg(errbuf, errbuflen, + addrs_to_try[0].errcode, + "Is the server properly installed? Cannot connect to %s", + host); + } else { + sock_fmterrmsg(errbuf, errbuflen, + addrs_to_try[0].errcode, + "Cannot connect to %s", host); + } + } else { + /* + * Show all the errors and the IP addresses + * to which they apply. + */ + char *errbufptr; + size_t bufspaceleft; + size_t msglen; + + snprintf(errbuf, errbuflen, + "Connect to %s failed: ", host); + + msglen = strlen(errbuf); + errbufptr = errbuf + msglen; + bufspaceleft = errbuflen - msglen; + + for (i = 0; i < numaddrinfos && + addrs_to_try[i].errcode != SOCK_NOERR; + i++) + { + /* + * Get the string for the address + * and port that got this error. + */ + sock_getascii_addrport((struct sockaddr_storage *) addrs_to_try[i].info->ai_addr, + errbufptr, (int)bufspaceleft, + NULL, 0, NI_NUMERICHOST, NULL, 0); + msglen = strlen(errbuf); + errbufptr = errbuf + msglen; + bufspaceleft = errbuflen - msglen; + + if (i + 1 < numaddrinfos && + addrs_to_try[i + 1].errcode == addrs_to_try[i].errcode) + { + /* + * There's another error + * after this, and it has + * the same error code. + * + * Append a comma, as the + * list of addresses with + * this error has another + * entry. + */ + snprintf(errbufptr, bufspaceleft, + ", "); + } + else + { + /* + * Either there are no + * more errors after this, + * or the next error is + * different. + * + * Append a colon and + * the message for tis + * error, followed by a + * comma if there are + * more errors. + */ + sock_fmterrmsg(errbufptr, + bufspaceleft, + addrs_to_try[i].errcode, + "%s", ""); + msglen = strlen(errbuf); + errbufptr = errbuf + msglen; + bufspaceleft = errbuflen - msglen; + + if (i + 1 < numaddrinfos && + addrs_to_try[i + 1].errcode != SOCK_NOERR) + { + /* + * More to come. + */ + snprintf(errbufptr, + bufspaceleft, + ", "); + } + } + msglen = strlen(errbuf); + errbufptr = errbuf + msglen; + bufspaceleft = errbuflen - msglen; + } + } + free(addrs_to_try); return INVALID_SOCKET; } else + { + free(addrs_to_try); return sock; + } } } @@ -516,7 +881,7 @@ int sock_close(SOCKET sock, char *errbuf, int errbuflen) */ if (shutdown(sock, SHUT_WR)) { - sock_geterror("shutdown()", errbuf, errbuflen); + sock_geterrmsg(errbuf, errbuflen, "shutdown() feiled"); /* close the socket anyway */ closesocket(sock); return -1; @@ -548,13 +913,13 @@ get_gai_errstring(char *errbuf, int errbuflen, const char *prefix, int err, char hostport[PCAP_ERRBUF_SIZE]; if (hostname != NULL && portname != NULL) - snprintf(hostport, PCAP_ERRBUF_SIZE, "%s:%s", + snprintf(hostport, PCAP_ERRBUF_SIZE, "host and port %s:%s", hostname, portname); else if (hostname != NULL) - snprintf(hostport, PCAP_ERRBUF_SIZE, "%s", + snprintf(hostport, PCAP_ERRBUF_SIZE, "host %s", hostname); else if (portname != NULL) - snprintf(hostport, PCAP_ERRBUF_SIZE, ":%s", + snprintf(hostport, PCAP_ERRBUF_SIZE, "port %s", portname); else snprintf(hostport, PCAP_ERRBUF_SIZE, "<no host or port!>"); @@ -618,7 +983,7 @@ get_gai_errstring(char *errbuf, int errbuflen, const char *prefix, int err, case EAI_NONAME: snprintf(errbuf, errbuflen, - "%sThe host name %s couldn't be resolved", + "%sThe %s couldn't be resolved", prefix, hostport); break; @@ -720,13 +1085,58 @@ int sock_initaddress(const char *host, const char *port, { int retval; - retval = getaddrinfo(host, port, hints, addrinfo); + /* + * We allow both the host and port to be null, but getaddrinfo() + * is not guaranteed to do so; to handle that, if port is null, + * we provide "0" as the port number. + * + * This results in better error messages from get_gai_errstring(), + * as those messages won't talk about a problem with the port if + * no port was specified. + */ + retval = getaddrinfo(host, port == NULL ? "0" : port, hints, addrinfo); if (retval != 0) { if (errbuf) { - get_gai_errstring(errbuf, errbuflen, "", retval, - host, port); + if (host != NULL && port != NULL) { + /* + * Try with just a host, to distinguish + * between "host is bad" and "port is + * bad". + */ + int try_retval; + + try_retval = getaddrinfo(host, NULL, hints, + addrinfo); + if (try_retval == 0) { + /* + * Worked with just the host, + * so assume the problem is + * with the port. + * + * Free up the address info first. + */ + freeaddrinfo(*addrinfo); + get_gai_errstring(errbuf, errbuflen, + "", retval, NULL, port); + } else { + /* + * Didn't work with just the host, + * so assume the problem is + * with the host. + */ + get_gai_errstring(errbuf, errbuflen, + "", retval, host, NULL); + } + } else { + /* + * Either the host or port was null, so + * there's nothing to determine. + */ + get_gai_errstring(errbuf, errbuflen, "", + retval, host, port); + } } return -1; } @@ -857,7 +1267,8 @@ int sock_send(SOCKET sock, SSL *ssl _U_NOSSL_, const char *buffer, size_t size, */ return -2; } - sock_fmterror("send()", errcode, errbuf, errbuflen); + sock_fmterrmsg(errbuf, errbuflen, errcode, + "send() failed"); #else errcode = errno; if (errcode == ECONNRESET || errcode == EPIPE) @@ -869,7 +1280,8 @@ int sock_send(SOCKET sock, SSL *ssl _U_NOSSL_, const char *buffer, size_t size, */ return -2; } - sock_fmterror("send()", errcode, errbuf, errbuflen); + sock_fmterrmsg(errbuf, errbuflen, errcode, + "send() failed"); #endif return -1; } @@ -1055,7 +1467,7 @@ int sock_recv(SOCKET sock, SSL *ssl _U_NOSSL_, void *buffer, size_t size, if (errno == EINTR) return -3; #endif - sock_geterror("recv()", errbuf, errbuflen); + sock_geterrmsg(errbuf, errbuflen, "recv() failed"); return -1; } @@ -1160,7 +1572,8 @@ int sock_recv_dgram(SOCKET sock, SSL *ssl _U_NOSSL_, 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_fmterrmsg(errbuf, errbuflen, sock_geterrcode(), + "recv() failed"); return -1; } #else /* _WIN32 */ @@ -1197,7 +1610,7 @@ int sock_recv_dgram(SOCKET sock, SSL *ssl _U_NOSSL_, void *buffer, size_t size, { if (errno == EINTR) return -3; - sock_geterror("recv()", errbuf, errbuflen); + sock_geterrmsg(errbuf, errbuflen, "recv() failed"); return -1; } #ifdef HAVE_STRUCT_MSGHDR_MSG_FLAGS @@ -1333,7 +1746,8 @@ int sock_check_hostlist(char *hostlist, const char *sep, struct sockaddr_storage temphostlist = strdup(hostlist); if (temphostlist == NULL) { - sock_geterror("sock_check_hostlist(), malloc() failed", errbuf, errbuflen); + sock_geterrmsg(errbuf, errbuflen, + "sock_check_hostlist(), malloc() failed"); return -2; } @@ -1519,7 +1933,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_geterrmsg(errbuf, errbuflen, "getsockname() failed"); return 0; } @@ -1575,7 +1989,7 @@ int sock_getmyinfo(SOCKET sock, char *address, int addrlen, char *port, int port * and 'port'. * In any case, the returned strings are '0' terminated. */ -int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen) +int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, size_t errbuflen) { socklen_t sockaddrlen; int retval; /* Variable that keeps the return value; */ @@ -1607,7 +2021,8 @@ 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_geterrmsg(errbuf, errbuflen, + "getnameinfo() failed"); errbuf[errbuflen - 1] = 0; } diff --git a/sockutils.h b/sockutils.h index 5e3ac49c..a488d8fc 100644 --- a/sockutils.h +++ b/sockutils.h @@ -37,6 +37,10 @@ #pragma once #endif +#include <stdarg.h> /* we declare varargs functions */ + +#include "pcap/funcattrs.h" + #include "pcap/socket.h" #ifndef _WIN32 @@ -127,8 +131,13 @@ extern "C" { int sock_init(char *errbuf, int errbuflen); void sock_cleanup(void); -void sock_fmterror(const char *caller, int errcode, char *errbuf, int errbuflen); -void sock_geterror(const char *caller, char *errbuf, int errbufsize); +int sock_geterrcode(void); +void sock_vfmterrmsg(char *errbuf, size_t errbuflen, int errcode, + PCAP_FORMAT_STRING(const char *fmt), va_list ap) PCAP_PRINTFLIKE(4, 0); +void sock_fmterrmsg(char *errbuf, size_t errbuflen, int errcode, + PCAP_FORMAT_STRING(const char *fmt), ...) PCAP_PRINTFLIKE(4, 5); +void sock_geterrmsg(char *errbuf, size_t errbuflen, + PCAP_FORMAT_STRING(const char *fmt), ...) PCAP_PRINTFLIKE(3, 4); int sock_initaddress(const char *address, const char *port, struct addrinfo *hints, struct addrinfo **addrinfo, char *errbuf, int errbuflen); @@ -136,7 +145,7 @@ int sock_recv(SOCKET sock, SSL *, void *buffer, size_t size, int receiveall, char *errbuf, int errbuflen); int sock_recv_dgram(SOCKET sock, SSL *, void *buffer, size_t size, char *errbuf, int errbuflen); -SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf, int errbuflen); +SOCKET sock_open(const char *host, struct addrinfo *addrinfo, int server, int nconn, char *errbuf, int errbuflen); int sock_close(SOCKET sock, char *errbuf, int errbuflen); int sock_send(SOCKET sock, SSL *, const char *buffer, size_t size, @@ -148,7 +157,7 @@ int sock_cmpaddr(struct sockaddr_storage *first, struct sockaddr_storage *second int sock_getmyinfo(SOCKET sock, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen); -int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen); +int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, size_t errbuflen); int sock_present2network(const char *address, struct sockaddr_storage *sockaddr, int addr_family, char *errbuf, int errbuflen); #ifdef __cplusplus diff --git a/testprogs/Makefile.in b/testprogs/Makefile.in index 293ed888..f1956937 100644 --- a/testprogs/Makefile.in +++ b/testprogs/Makefile.in @@ -102,7 +102,7 @@ all: $(TESTS) capturetest: $(srcdir)/capturetest.c ../libpcap.a $(CC) $(FULL_CFLAGS) -I. -L. -o capturetest $(srcdir)/capturetest.c \ - ../libpcap.a $(LIBS) + ../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 \ diff --git a/testprogs/valgrindtest.c b/testprogs/valgrindtest.c index 058b18be..55055ca3 100644 --- a/testprogs/valgrindtest.c +++ b/testprogs/valgrindtest.c @@ -109,7 +109,7 @@ The Regents of the University of California. All rights reserved.\n"; * also include <pcap.h> to open the device in the first place, and that * means that we may get collisions between their definitions of * BPF_STMT and BPF_JUMP - and do, in fact, get them on Linux (the - * definitons may be semantically the same, but that's not sufficient to + * definitions may be semantically the same, but that's not sufficient to * avoid the warnings, as the preprocessor doesn't know that u_short is * just unsigned short). * diff --git a/testprogs/visopts.py b/testprogs/visopts.py index 80c14639..f7df45a5 100755 --- a/testprogs/visopts.py +++ b/testprogs/visopts.py @@ -1,11 +1,11 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ This program parses the output from pcap_compile() to visualize the CFG after each optimize phase. Usage guide: -1. Enable optimizier debugging code when configure libpcap, +1. Enable optimizer debugging code when configure libpcap, and build libpcap & the test programs ./configure --enable-optimizer-dbg make @@ -37,13 +37,11 @@ Note: import sys, os import string -import subprocess -import json html_template = string.Template(""" <html> <head> - <title>BPF compiler optimization phases for $expr </title> + <title>BPF compiler optimization phases for "${expr_html}"</title> <style type="text/css"> .hc { /* half width container */ @@ -56,10 +54,10 @@ html_template = string.Template(""" <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"/></script> <!--script type="text/javascript" src="./jquery.min.js"/></script--> <script type="text/javascript"> - var expr = '$expr'; + var expr = '${expr_json}'; var exprid = 1; - var gcount = $gcount; - var logs = JSON.parse('$logs'); + var gcount = ${gcount}; + var logs = JSON.parse('${logs}'); logs[gcount] = ""; var leftsvg = null; @@ -196,7 +194,7 @@ html_template = string.Template(""" </head> <body style="width: 96%"> <div> - <h1>$expr</h1> + <h1>${expr_html}</h1> <div style="text-align: center;"> <button id="backward" type="button"><<</button> @@ -226,14 +224,29 @@ html_template = string.Template(""" """) def write_html(expr, gcount, logs): - logs = map(lambda s: s.strip().replace("\n", "<br/>"), logs) + import html + import json - global html_template - html = html_template.safe_substitute(expr=expr.encode("string-escape"), gcount=gcount, logs=json.dumps(logs).encode("string-escape")) - with file("expr1.html", "wt") as f: - f.write(html) + # In the Python 2.7 version this used to be str.encode('string-escape'), + # which was a normal string, but in Python 3 the "string_escape" encoding + # no longer exists and even with the "unicode_escape" encoding encode() + # always returns a binary string. So let's just escape the single quotes + # here and hope the result is a valid JavaScript string literal. + def encode(s): + return s.replace("'", "\'") + + mapping = { + 'expr_html': html.escape(expr), + 'expr_json': encode(expr), + 'gcount': gcount, + 'logs': encode(json.dumps([s.strip().replace("\n", "<br/>") for s in logs])), + } + with open("expr1.html", "wt") as f: + f.write(html_template.safe_substitute(mapping)) def render_on_html(infile): + import subprocess + expr = None gid = 1 log = "" @@ -257,14 +270,16 @@ def render_on_html(infile): if indot == 2: try: - p = subprocess.Popen(['dot', '-Tsvg'], stdin=subprocess.PIPE, stdout=subprocess.PIPE) + svg=subprocess.check_output(['dot', '-Tsvg'], input=dot, universal_newlines=True) except OSError as ose: - print "Failed to run 'dot':", ose - print "(Is Graphviz installed?)" - exit(1) + print("Failed to run 'dot':", ose) + print("(Is Graphviz installed?)") + return False + except subprocess.CalledProcessError as cpe: + print("Got an error from the 'dot' process: ", cpe) + return False - svg = p.communicate(dot)[0] - with file("expr1_g%03d.svg" % (gid), "wt") as f: + with open("expr1_g%03d.svg" % gid, "wt") as f: f.write(svg) logs.append(log) @@ -283,14 +298,10 @@ def render_on_html(infile): return True def run_httpd(): - import SimpleHTTPServer - import SocketServer + import http.server - class MySocketServer(SocketServer.TCPServer): - allow_reuse_address = True - Handler = SimpleHTTPServer.SimpleHTTPRequestHandler - httpd = MySocketServer(("localhost", 0), Handler) - print "open this link: http://localhost:%d/expr1.html" % (httpd.server_address[1]) + httpd = http.server.HTTPServer(("localhost", 0), http.server.SimpleHTTPRequestHandler) + print("open this link: http://localhost:%d/expr1.html" % httpd.server_port) try: httpd.serve_forever() except KeyboardInterrupt as e: @@ -302,8 +313,8 @@ def main(): import shutil os.chdir(tempfile.mkdtemp(prefix="visopts-")) atexit.register(shutil.rmtree, os.getcwd()) - print "generated files under directory: %s" % os.getcwd() - print " the directory will be removed when this program has finished." + print("generated files under directory: %s" % os.getcwd()) + print(" the directory will be removed when this program has finished.") if not render_on_html(sys.stdin): return 1 @@ -312,6 +323,6 @@ def main(): if __name__ == "__main__": if '-h' in sys.argv or '--help' in sys.argv: - print __doc__ + print(__doc__) exit(0) exit(main()) |