summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml14
-rw-r--r--.gitignore1
-rw-r--r--CHANGES9
-rw-r--r--CMakeLists.txt124
-rw-r--r--Makefile.in21
-rw-r--r--aclocal.m42
-rw-r--r--bpf_image.c4
-rwxr-xr-xbuild.sh30
-rw-r--r--build_common.sh4
-rwxr-xr-xconfig.guess12
-rwxr-xr-xconfig.sub33
-rw-r--r--etherent.c4
-rw-r--r--gencode.c316
-rw-r--r--gencode.h4
-rw-r--r--grammar.y.in122
-rw-r--r--instrument-functions.c5
-rw-r--r--msdos/makefile.dj4
-rw-r--r--msdos/makefile.wc6
-rw-r--r--nametoaddr.c53
-rw-r--r--pcap-bpf.c4
-rw-r--r--pcap-config.122
-rw-r--r--pcap-dpdk.c4
-rw-r--r--pcap-npf.c107
-rw-r--r--pcap.c27
-rw-r--r--rpcapd/rpcapd-config.manfile.in12
-rw-r--r--rpcapd/rpcapd.manadmin.in56
-rw-r--r--scanner.l169
-rw-r--r--thread-local.h69
28 files changed, 953 insertions, 285 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index e77460ed..904808d1 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -10,15 +10,15 @@ freebsd_task:
- image_family: freebsd-12-4
cpu: 2
memory: 2G
- - image_family: freebsd-13-1
- cpu: 4
- memory: 4G
+ - image_family: freebsd-13-2
+ cpu: 2
+ memory: 2G
env:
IGNORE_OSVERSION: yes
MAKEFLAGS: -j 4
- MATRIX_CC: clang14 gcc12
+ MATRIX_CC: clang15 gcc12
script:
- - pkg install -qy autoconf gcc12 llvm14
+ - pkg install -qy autoconf gcc12 llvm15
- pkg install -qy cmake git-tiny # for build_matrix.sh and build.sh
- ./build_matrix.sh
@@ -32,10 +32,12 @@ linux_task:
env:
DEBIAN_FRONTEND: noninteractive
MAKEFLAGS: -j 3
+ MATRIX_CC: gcc clang-15
+ LANG: C
script:
- apt-get -qy update >/dev/null
- apt-get -qy install libdbus-1-dev libbluetooth-dev libnl-genl-3-dev libibverbs-dev libssl-dev >/dev/null
- - apt-get -qy install flex bison autoconf make clang gcc valgrind >/dev/null
+ - apt-get -qy install flex bison autoconf make clang-15 gcc >/dev/null
- apt-get -qy install cmake git bc >/dev/null # for build_matrix.sh and build.sh
- apt list --installed 'lib*-dev'
- ./autogen.sh
diff --git a/.gitignore b/.gitignore
index 8c9cbacf..d0c50eb6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,6 @@
/Makefile
*~
/*.o
-/bpf_filter.c
CMakeCache.txt
cmake_install.cmake
CMakeFiles/
diff --git a/CHANGES b/CHANGES
index 1ba056a4..86db3d59 100644
--- a/CHANGES
+++ b/CHANGES
@@ -5,6 +5,8 @@ DayOfTheWeek, Month DD, YYYY / The Tcpdump Group
fixed-width integer types, in rpcap code.
Remove an always-false pointer test from snf_read().
Clean up DECnet address handling.
+ Finalize moving of bpf_filter.c. (GH #1166)
+ Address a few compiler warnings on Haiku.
Link-layer types:
Add LINKTYPE_ETW/DLT_ETW.
Add LINKTYPE_NETANALYZER_NG/DLT_NETANALYZER_NG (pull request
@@ -46,8 +48,10 @@ DayOfTheWeek, Month DD, YYYY / The Tcpdump Group
these generated files in the release tarball.
autoconf: Add the option to print functions and files names.
-DayOfTheWeek, Month DD, YYYY / The Tcpdump Group
- Summary for 1.10.4 libpcap release (so far!)
+Friday, April 7, 2023 / The Tcpdump Group
+ Summary for 1.10.4 libpcap release
+ Source code:
+ Fix spaces before tabs in indentation.
rpcap:
Fix name of launchd service.
Documentation:
@@ -56,6 +60,7 @@ DayOfTheWeek, Month DD, YYYY / The Tcpdump Group
Require at least pkg-config 0.17.0, as we use --static.
Get rid of the remains of gnuc.h.
Require at least autoconf 2.69.
+ Update config.{guess,sub}, timestamps 2023-01-01,2023-01-21.
Thursday, January 12, 2023 / The Tcpdump Group
Summary for 1.10.3 libpcap release
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 270b6593..982166f8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1303,17 +1303,25 @@ endif()
# obvious CMake debugging flag reveals, it doesn't realize that if we
# turn sanitizer stuff on).
#
-set(SANITIZER_FLAGS "")
-foreach(sanitizer IN LISTS ENABLE_SANITIZERS)
+# Note: apparently, some projects have decided that ENABLE_SANITIZERS
+# is a Boolean, with OFF meaning "no sanitizers" and ON meaning "all
+# sanitizers". Whoever decided that didn't put it up as a common
+# CMake idiom, as far as I can tell; we only discovered this because
+# JetBrains' CLion "helpfully" appears to pass -DENABLE_SANITIZERS=OFF
+# to CMake by default, which causes CMake to fail on libpcap. Thanks!
+#
+# We thus also allow a setting of OFF to mean "no sanitizers" and ON to
+# mean "all supported sanitizers that we know about and that can all
+# be used together".
+#
+macro(test_sanitizer _sanitizer _sanitizer_flag)
+ message(STATUS "Checking sanitizer ${_sanitizer}")
+ set(sanitizer_variable "sanitize_${_sanitizer}")
# Set -Werror to catch "argument unused during compilation" warnings
-
- message(STATUS "Checking sanitizer ${sanitizer}")
- set(sanitizer_variable "sanitize_${sanitizer}")
- set(CMAKE_REQUIRED_FLAGS "-Werror -fsanitize=${sanitizer}")
- check_c_compiler_flag("-fsanitize=${sanitizer}" ${sanitizer_variable})
+ set(CMAKE_REQUIRED_FLAGS "-Werror -fsanitize=${_sanitizer}")
+ check_c_compiler_flag("-fsanitize=${_sanitizer}" ${sanitizer_variable})
if(${${sanitizer_variable}})
- set(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fsanitize=${sanitizer}")
- message(STATUS "${sanitizer} sanitizer supported using -fsanitizer=${sanitizer}")
+ set(${_sanitizer_flag} "-fsanitize=${_sanitizer}")
else()
#
# Try the versions supported prior to Clang 3.2.
@@ -1322,31 +1330,101 @@ foreach(sanitizer IN LISTS ENABLE_SANITIZERS)
# Otherwise, give up.
#
set(sanitizer_variable "OLD_${sanitizer_variable}")
- if ("${sanitizer}" STREQUAL "address")
+ if ("${_sanitizer}" STREQUAL "address")
set(CMAKE_REQUIRED_FLAGS "-Werror -fsanitize-address")
check_c_compiler_flag("-fsanitize-address" ${sanitizer_variable})
if(${${sanitizer_variable}})
- set(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fsanitize-address")
- message(STATUS "${sanitizer} sanitizer supported using -fsanitize-address")
- else()
- message(FATAL_ERROR "${sanitizer} isn't a supported sanitizer")
+ set(${_sanitizer_flag} "-fsanitize-address")
endif()
- elseif("${sanitizer}" STREQUAL "undefined")
+ elseif("${_sanitizer}" STREQUAL "undefined")
set(CMAKE_REQUIRED_FLAGS "-Werror -fcatch-undefined-behavior")
check_c_compiler_flag("-fcatch-undefined-behavior" ${sanitizer_variable})
if(${${sanitizer_variable}})
- set(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fcatch-undefined-behavior")
- message(STATUS "${sanitizer} sanitizer supported using catch-undefined-behavior")
- else()
- message(FATAL_ERROR "${sanitizer} isn't a supported sanitizer")
+ set(${_sanitizer_flag} "-fcatch-undefined-behavior")
endif()
- else()
- message(FATAL_ERROR "${sanitizer} isn't a supported sanitizer")
endif()
endif()
-
unset(CMAKE_REQUIRED_FLAGS)
-endforeach()
+endmacro(test_sanitizer)
+
+set(SANITIZER_FLAGS "")
+if("${ENABLE_SANITIZERS}")
+ #
+ # This appears to indicate that ENABLE_SANITIZERS was set to a
+ # string value that is "one of the true constants", meaning
+ # "1, ON, YES, TRUE, Y, or a non-zero number".
+ #
+ # It does not appear to happen for other settings, including
+ # setting it to a list of one or more sanitizers.
+ #
+ # This setting means "enable all sanitizers that the compiler
+ # supports".
+ #
+ foreach(sanitizer "address" "undefined")
+ unset(SANITIZER_FLAG)
+ test_sanitizer(${sanitizer} SANITIZER_FLAG)
+ if(SANITIZER_FLAG)
+ message(STATUS "${sanitizer} sanitizer supported using ${SANITIZER_FLAG}")
+ set(SANITIZER_FLAGS "${SANITIZER_FLAGS} ${SANITIZER_FLAG}")
+ else()
+ message(STATUS "${sanitizer} isn't a supported sanitizer")
+ endif()
+ endforeach()
+ if("${SANITIZER_FLAGS}" STREQUAL "")
+ message(FATAL_ERROR "No supported sanitizers found")
+ endif()
+else()
+ #
+ # This appears to indicate that ENABLE_SANITIZERS was either:
+ #
+ # not set;
+ # set to a set to a string value that is not "one of the true
+ # constants", meaning "1, ON, YES, TRUE, Y, or a non-zero number".
+ #
+ # The latter includes setting it to "one of the false constants",
+ # meaning the string "is 0, OFF, NO, FALSE, N, IGNORE, NOTFOUND,
+ # the empty string, or ends in the suffix -NOTFOUND."
+ #
+ # It also includes setting it to a list of one or more sanitizers.
+ #
+ # We want to treat "not set" and "set to one of the false constants"
+ # as meaning "do not enable any sanitizers".
+ #
+ # We want to treat "set to a list of one or more sanitizers" as
+ # meaning "enable all the sanitizers in the list".
+ #
+ # This requires that we distinguish between those two cases.
+ #
+ if(ENABLE_SANITIZERS)
+ #
+ # This appears to indicate that ENABLE_SANITIZERS was set to
+ # a string value that is "not one of the false constants".
+ #
+ # We already know it's "not one of the true constants", so
+ # we treat it as a list of sanitizers.
+ #
+ foreach(sanitizer IN LISTS ENABLE_SANITIZERS)
+ unset(SANITIZER_FLAG)
+ test_sanitizer(${sanitizer} SANITIZER_FLAG)
+ if(SANITIZER_FLAG)
+ message(STATUS "${sanitizer} sanitizer supported using ${SANITIZER_FLAG}")
+ set(SANITIZER_FLAGS "${SANITIZER_FLAGS} ${SANITIZER_FLAG}")
+ else()
+ message(FATAL_ERROR "${sanitizer} isn't a supported sanitizer")
+ endif()
+ endforeach()
+ else()
+ #
+ # This appears to indicate that ENABLE_SANITIZERS was either:
+ #
+ # not set;
+ # set to a value that's "one of the false constants";
+ #
+ # so we don't enable any sanitizers.
+ #
+ message(STATUS "Not enabling sanitizers")
+ endif()
+endif()
if(NOT "${SANITIZER_FLAGS}" STREQUAL "")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O1 -g ${SANITIZER_FLAGS} -fno-omit-frame-pointer -fno-optimize-sibling-calls")
diff --git a/Makefile.in b/Makefile.in
index 736aebda..e5176427 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -149,6 +149,7 @@ HDR = $(PUBHDR) \
sf-pcap.h \
sf-pcapng.h \
sunatmpos.h \
+ thread-local.h \
varattrs.h
GENHDR = \
@@ -522,7 +523,7 @@ scanner.o: scanner.c grammar.h
#
# and this is an explicit target entry.
#
-# Therefore, instead of using $<, we explicitly put in $(srcdir)/libpcap.pc.in.
+# Therefore, instead of using $<, we explicitly put in $(srcdir)/grammar.y.in.
#
grammar.y: $(srcdir)/grammar.y.in ./config.status
@rm -f $@ $@.tmp
@@ -593,7 +594,7 @@ build-rpcapd: libpcap.a
#
# Test programs - not built by default, and not installed.
#
-testprogs: FORCE
+testprogs: FORCE libpcap.a
(cd testprogs; $(MAKE))
FORCE:
@@ -864,10 +865,10 @@ releasecheck: releasetar
touch .devel && \
echo "[$@] $$ ./configure --enable-remote --quiet --prefix=$$INSTALL_DIR" && \
./configure --enable-remote --quiet --prefix="$$INSTALL_DIR" && \
- echo '[$@] $$ make -s all testprogs' && \
- make -s all testprogs && \
- echo '[$@] $$ make -s install' && \
- make -s install && \
+ echo '[$@] $$ $(MAKE) -s all testprogs' && \
+ $(MAKE) -s all testprogs && \
+ echo '[$@] $$ $(MAKE) -s install' && \
+ $(MAKE) -s install && \
cd .. && \
rm -rf "$$TAG" && \
rm -rf "$$INSTALL_DIR" && \
@@ -882,10 +883,10 @@ releasecheck: releasetar
-DCMAKE_RULE_MESSAGES=OFF \
-DCMAKE_INSTALL_MESSAGE=NEVER \
.. && \
- echo '[$@] $$ make -s all testprogs' && \
- make -s all testprogs && \
- echo '[$@] $$ make -s install' && \
- make -s install && \
+ echo '[$@] $$ $(MAKE) -s all testprogs' && \
+ $(MAKE) -s all testprogs && \
+ echo '[$@] $$ $(MAKE) -s install' && \
+ $(MAKE) -s install && \
cd ../.. && \
rm -rf "$$TAG" && \
rm -rf "$$INSTALL_DIR" && \
diff --git a/aclocal.m4 b/aclocal.m4
index eacbe25b..adf74362 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -266,7 +266,7 @@ AC_DEFUN(AC_LBL_CHECK_COMPILER_OPT,
# https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us
#
# This may, as per those two messages, be fixed in autoconf 2.70,
- # but we only require 2.64 or newer for now.
+ # but we only require 2.69 or newer for now.
#
AC_COMPILE_IFELSE(
[AC_LANG_SOURCE([[int main(void) { return 0; }]])],
diff --git a/bpf_image.c b/bpf_image.c
index e48c76d5..febd07bb 100644
--- a/bpf_image.c
+++ b/bpf_image.c
@@ -44,6 +44,8 @@
#include "pcap-int.h"
+#include "thread-local.h"
+
#ifdef HAVE_OS_PROTO_H
#include "os-proto.h"
#endif
@@ -130,7 +132,7 @@ char *
bpf_image(const struct bpf_insn *p, int n)
{
const char *op;
- static char image[256];
+ static thread_local char image[256];
char operand_buf[64];
const char *operand;
diff --git a/build.sh b/build.sh
index 956cfe2f..d00bb500 100755
--- a/build.sh
+++ b/build.sh
@@ -54,11 +54,6 @@ clang-*/NetBSD-*)
# 'long' to 'suseconds_t' (aka 'int') [-Wshorten-64-to-32]
LIBPCAP_TAINTED=yes
;;
-clang-15.*/*)
- # grammar.c:1369:14: warning: variable 'pcap_nerrs' set but not used
- # [-Wunused-but-set-variable]
- LIBPCAP_TAINTED=yes
- ;;
clang-*/SunOS-5.11)
# (Solaris 11 and OpenIndiana)
# pcap-bpf.c:1044:18: warning: implicit conversion loses integer precision:
@@ -87,21 +82,16 @@ suncc-5.1[45]/SunOS-5.11)
# "./filtertest.c", line 281: warning: statement not reached
LIBPCAP_TAINTED=yes
;;
-*/Haiku-*)
- # (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]
+clang-*/Haiku-*)
+ # pcap-haiku.c:82:26: error: implicit conversion loses integer precision:
+ # 'ssize_t' (aka 'long') to 'int32_t' (aka 'int')
+ # [-Werror,-Wshorten-64-to-32]
+ # pcap-haiku.c:88:51: error: implicit conversion loses integer precision:
+ # 'ssize_t' (aka 'long') to 'u_int' (aka 'unsigned int')
+ # [-Werror,-Wshorten-64-to-32]
+ # pcap-haiku.c:98:15: error: implicit conversion loses integer precision:
+ # 'ssize_t' (aka 'long') to 'bpf_u_int32' (aka 'unsigned int')
+ # [-Werror,-Wshorten-64-to-32]
LIBPCAP_TAINTED=yes
;;
esac
diff --git a/build_common.sh b/build_common.sh
index b5fa66b6..3264d2e9 100644
--- a/build_common.sh
+++ b/build_common.sh
@@ -214,6 +214,7 @@ os_id() {
;;
Haiku)
# Meaningful version is the substring before the plus sign.
+ # "hrev56578" stands for "R1/beta4".
# "hrev55181" stands for "R1/beta3".
# "hrev54154" stands for "R1/beta2".
: "${os_id_version:=`uname -v`}"
@@ -248,6 +249,9 @@ print_so_deps() {
Darwin-*)
run_after_echo otool -L "${1:?}"
;;
+ Haiku-*)
+ run_after_echo objdump -p "${1:?}"
+ ;;
*)
run_after_echo ldd "${1:?}"
;;
diff --git a/config.guess b/config.guess
index a419d864..69188da7 100755
--- a/config.guess
+++ b/config.guess
@@ -1,10 +1,10 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-# Copyright 1992-2022 Free Software Foundation, Inc.
+# Copyright 1992-2023 Free Software Foundation, Inc.
# shellcheck disable=SC2006,SC2268 # see below for rationale
-timestamp='2022-08-01'
+timestamp='2023-01-01'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -60,7 +60,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright 1992-2022 Free Software Foundation, Inc.
+Copyright 1992-2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -966,6 +966,12 @@ EOF
GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC
;;
+ x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*)
+ GUESS="$UNAME_MACHINE-pc-managarm-mlibc"
+ ;;
+ *:[Mm]anagarm:*:*)
+ GUESS="$UNAME_MACHINE-unknown-managarm-mlibc"
+ ;;
*:Minix:*:*)
GUESS=$UNAME_MACHINE-unknown-minix
;;
diff --git a/config.sub b/config.sub
index fbaa37f2..de4259e4 100755
--- a/config.sub
+++ b/config.sub
@@ -1,10 +1,10 @@
#! /bin/sh
# Configuration validation subroutine script.
-# Copyright 1992-2022 Free Software Foundation, Inc.
+# Copyright 1992-2023 Free Software Foundation, Inc.
# shellcheck disable=SC2006,SC2268 # see below for rationale
-timestamp='2022-08-01'
+timestamp='2023-01-21'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -76,7 +76,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
-Copyright 1992-2022 Free Software Foundation, Inc.
+Copyright 1992-2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -145,7 +145,7 @@ case $1 in
nto-qnx* | linux-* | uclinux-uclibc* \
| uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
| netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
- | storm-chaos* | os2-emx* | rtmk-nova*)
+ | storm-chaos* | os2-emx* | rtmk-nova* | managarm-*)
basic_machine=$field1
basic_os=$maybe_os
;;
@@ -1075,7 +1075,7 @@ case $cpu-$vendor in
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
cpu=i586
;;
- pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)
+ pentiumpro-* | p6-* | 6x86-* | athlon-* | athlon_*-*)
cpu=i686
;;
pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
@@ -1341,6 +1341,10 @@ EOF
kernel=linux
os=`echo "$basic_os" | sed -e 's|linux|gnu|'`
;;
+ managarm*)
+ kernel=managarm
+ os=`echo "$basic_os" | sed -e 's|managarm|mlibc|'`
+ ;;
*)
kernel=
os=$basic_os
@@ -1754,7 +1758,7 @@ case $os in
| onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
| midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
| nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \
- | fiwix* )
+ | fiwix* | mlibc* )
;;
# This one is extra strict with allowed versions
sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
@@ -1762,6 +1766,9 @@ case $os in
;;
none)
;;
+ kernel* )
+ # Restricted further below
+ ;;
*)
echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2
exit 1
@@ -1772,16 +1779,26 @@ esac
# (given a valid OS), if there is a kernel.
case $kernel-$os in
linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \
- | linux-musl* | linux-relibc* | linux-uclibc* )
+ | linux-musl* | linux-relibc* | linux-uclibc* | linux-mlibc* )
;;
uclinux-uclibc* )
;;
- -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* )
+ managarm-mlibc* | managarm-kernel* )
+ ;;
+ -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* | -mlibc* )
# These are just libc implementations, not actual OSes, and thus
# require a kernel.
echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2
exit 1
;;
+ -kernel* )
+ echo "Invalid configuration \`$1': \`$os' needs explicit kernel." 1>&2
+ exit 1
+ ;;
+ *-kernel* )
+ echo "Invalid configuration \`$1': \`$kernel' does not support \`$os'." 1>&2
+ exit 1
+ ;;
kfreebsd*-gnu* | kopensolaris*-gnu*)
;;
vxworks-simlinux | vxworks-simwindows | vxworks-spe)
diff --git a/etherent.c b/etherent.c
index 69da9a54..e0e5023c 100644
--- a/etherent.c
+++ b/etherent.c
@@ -33,6 +33,8 @@
#include <pcap/namedb.h>
+#include "thread-local.h"
+
#ifdef HAVE_OS_PROTO_H
#include "os-proto.h"
#endif
@@ -87,7 +89,7 @@ pcap_next_etherent(FILE *fp)
u_char d;
char *bp;
size_t namesize;
- static struct pcap_etherent e;
+ static thread_local struct pcap_etherent e;
memset((char *)&e, 0, sizeof(e));
for (;;) {
diff --git a/gencode.c b/gencode.c
index 7b818ec4..aefa9fc9 100644
--- a/gencode.c
+++ b/gencode.c
@@ -4102,7 +4102,16 @@ gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr,
{
struct block *b0, *b1;
u_int offset;
- uint32_t *a, *m;
+ /*
+ * Code below needs to access four separate 32-bit parts of the 128-bit
+ * IPv6 address and mask. In some OSes this is as simple as using the
+ * s6_addr32 pseudo-member of struct in6_addr, which contains a union of
+ * 8-, 16- and 32-bit arrays. In other OSes this is not the case, as
+ * far as libpcap sees it. Hence copy the data before use to avoid
+ * potential unaligned memory access and the associated compiler
+ * warnings (whether genuine or not).
+ */
+ bpf_u_int32 a[4], m[4];
switch (dir) {
@@ -4156,8 +4165,8 @@ gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr,
/*NOTREACHED*/
}
/* this order is important */
- a = (uint32_t *)addr;
- m = (uint32_t *)mask;
+ memcpy(a, addr, sizeof(a));
+ memcpy(m, mask, sizeof(m));
b1 = gen_mcmp(cstate, OR_LINKPL, offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3]));
b0 = gen_mcmp(cstate, OR_LINKPL, offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2]));
gen_and(b0, b1);
@@ -6673,6 +6682,277 @@ gen_proto(compiler_state_t *cstate, bpf_u_int32 v, int proto, int dir)
/*NOTREACHED*/
}
+/*
+ * Convert a non-numeric name to a port number.
+ */
+static int
+nametoport(compiler_state_t *cstate, const char *name, int ipproto)
+{
+ struct addrinfo hints, *res, *ai;
+ int error;
+ struct sockaddr_in *in4;
+#ifdef INET6
+ struct sockaddr_in6 *in6;
+#endif
+ int port = -1;
+
+ /*
+ * We check for both TCP and UDP in case there are
+ * ambiguous entries.
+ */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = (ipproto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM;
+ hints.ai_protocol = ipproto;
+ error = getaddrinfo(NULL, name, &hints, &res);
+ if (error != 0) {
+ switch (error) {
+
+ case EAI_NONAME:
+ case EAI_SERVICE:
+ /*
+ * No such port. Just return -1.
+ */
+ break;
+
+#ifdef EAI_SYSTEM
+ case EAI_SYSTEM:
+ /*
+ * We don't use strerror() because it's not
+ * guaranteed to be thread-safe on all platforms
+ * (probably because it might use a non-thread-local
+ * buffer into which to format an error message
+ * if the error code isn't one for which it has
+ * a canned string; three cheers for C string
+ * handling).
+ */
+ bpf_set_error(cstate, "getaddrinfo(\"%s\" fails with system error: %d",
+ name, errno);
+ port = -2; /* a real error */
+ break;
+#endif
+
+ default:
+ /*
+ * This is a real error, not just "there's
+ * no such service name".
+ *
+ * We don't use gai_strerror() because it's not
+ * guaranteed to be thread-safe on all platforms
+ * (probably because it might use a non-thread-local
+ * buffer into which to format an error message
+ * if the error code isn't one for which it has
+ * a canned string; three cheers for C string
+ * handling).
+ */
+ bpf_set_error(cstate, "getaddrinfo(\"%s\") fails with error: %d",
+ name, error);
+ port = -2; /* a real error */
+ break;
+ }
+ } else {
+ /*
+ * OK, we found it. Did it find anything?
+ */
+ for (ai = res; ai != NULL; ai = ai->ai_next) {
+ /*
+ * Does it have an address?
+ */
+ if (ai->ai_addr != NULL) {
+ /*
+ * Yes. Get a port number; we're done.
+ */
+ if (ai->ai_addr->sa_family == AF_INET) {
+ in4 = (struct sockaddr_in *)ai->ai_addr;
+ port = ntohs(in4->sin_port);
+ break;
+ }
+#ifdef INET6
+ if (ai->ai_addr->sa_family == AF_INET6) {
+ in6 = (struct sockaddr_in6 *)ai->ai_addr;
+ port = ntohs(in6->sin6_port);
+ break;
+ }
+#endif
+ }
+ }
+ freeaddrinfo(res);
+ }
+ return port;
+}
+
+/*
+ * Convert a string to a port number.
+ */
+static bpf_u_int32
+stringtoport(compiler_state_t *cstate, const char *string, size_t string_size,
+ int *proto)
+{
+ stoulen_ret ret;
+ char *cpy;
+ bpf_u_int32 val;
+ int tcp_port = -1;
+ int udp_port = -1;
+
+ /*
+ * See if it's a number.
+ */
+ ret = stoulen(string, string_size, &val, cstate);
+ switch (ret) {
+
+ case STOULEN_OK:
+ /* Unknown port type - it's just a numbrer. */
+ *proto = PROTO_UNDEF;
+ break;
+
+ case STOULEN_NOT_OCTAL_NUMBER:
+ case STOULEN_NOT_HEX_NUMBER:
+ case STOULEN_NOT_DECIMAL_NUMBER:
+ /*
+ * Not a valid number; try looking it up as a port.
+ */
+ cpy = malloc(string_size + 1); /* +1 for terminating '\0' */
+ memcpy(cpy, string, string_size);
+ cpy[string_size] = '\0';
+ tcp_port = nametoport(cstate, cpy, IPPROTO_TCP);
+ if (tcp_port == -2) {
+ /*
+ * We got a hard error; the error string has
+ * already been set.
+ */
+ free(cpy);
+ longjmp(cstate->top_ctx, 1);
+ /*NOTREACHED*/
+ }
+ udp_port = nametoport(cstate, cpy, IPPROTO_UDP);
+ if (udp_port == -2) {
+ /*
+ * We got a hard error; the error string has
+ * already been set.
+ */
+ free(cpy);
+ longjmp(cstate->top_ctx, 1);
+ /*NOTREACHED*/
+ }
+
+ /*
+ * We need to check /etc/services for ambiguous entries.
+ * If we find an ambiguous entry, and it has the
+ * same port number, change the proto to PROTO_UNDEF
+ * so both TCP and UDP will be checked.
+ */
+ if (tcp_port >= 0) {
+ val = (bpf_u_int32)tcp_port;
+ *proto = IPPROTO_TCP;
+ if (udp_port >= 0) {
+ if (udp_port == tcp_port)
+ *proto = PROTO_UNDEF;
+#ifdef notdef
+ else
+ /* Can't handle ambiguous names that refer
+ to different port numbers. */
+ warning("ambiguous port %s in /etc/services",
+ cpy);
+#endif
+ }
+ free(cpy);
+ break;
+ }
+ if (udp_port >= 0) {
+ val = (bpf_u_int32)udp_port;
+ *proto = IPPROTO_UDP;
+ free(cpy);
+ break;
+ }
+#if defined(ultrix) || defined(__osf__)
+ /* Special hack in case NFS isn't in /etc/services */
+ if (strcmp(cpy, "nfs") == 0) {
+ val = 2049;
+ *proto = PROTO_UNDEF;
+ free(cpy);
+ break;
+ }
+#endif
+ bpf_set_error(cstate, "'%s' is not a valid port", cpy);
+ free(cpy);
+ longjmp(cstate->top_ctx, 1);
+ /*NOTREACHED*/
+
+ case STOULEN_ERROR:
+ /* Error already set. */
+ longjmp(cstate->top_ctx, 1);
+ /*NOTREACHED*/
+
+ default:
+ /* Should not happen */
+ bpf_set_error(cstate, "stoulen returned %d - this should not happen", ret);
+ longjmp(cstate->top_ctx, 1);
+ /*NOTREACHED*/
+ }
+ return (val);
+}
+
+/*
+ * Convert a string in the form PPP-PPP, which correspond to ports, to
+ * a starting and ending port in a port range.
+ */
+static void
+stringtoportrange(compiler_state_t *cstate, const char *string,
+ bpf_u_int32 *port1, bpf_u_int32 *port2, int *proto)
+{
+ char *hyphen_off;
+ const char *first, *second;
+ size_t first_size, second_size;
+ int save_proto;
+
+ if ((hyphen_off = strchr(string, '-')) == NULL)
+ bpf_error(cstate, "port range '%s' contains no hyphen", string);
+
+ /*
+ * Make sure there are no other hyphens.
+ *
+ * XXX - we support named ports, but there are some port names
+ * in /etc/services that include hyphens, so this would rule
+ * that out.
+ */
+ if (strchr(hyphen_off + 1, '-') != NULL)
+ bpf_error(cstate, "port range '%s' contains more than one hyphen",
+ string);
+
+ /*
+ * Get the length of the first port.
+ */
+ first = string;
+ first_size = hyphen_off - string;
+ if (first_size == 0) {
+ /* Range of "-port", which we don't support. */
+ bpf_error(cstate, "port range '%s' has no starting port", string);
+ }
+
+ /*
+ * Try to convert it to a port.
+ */
+ *port1 = stringtoport(cstate, first, first_size, proto);
+ save_proto = *proto;
+
+ /*
+ * Get the length of the second port.
+ */
+ second = hyphen_off + 1;
+ second_size = strlen(second);
+ if (second_size == 0) {
+ /* Range of "port-", which we don't support. */
+ bpf_error(cstate, "port range '%s' has no ending port", string);
+ }
+
+ /*
+ * Try to convert it to a port.
+ */
+ *port2 = stringtoport(cstate, second, second_size, proto);
+ if (*proto != save_proto)
+ *proto = PROTO_UNDEF;
+}
+
struct block *
gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
{
@@ -6690,7 +6970,7 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
#endif /*INET6*/
struct block *b, *tmp;
int port, real_proto;
- int port1, port2;
+ bpf_u_int32 port1, port2;
/*
* Catch errors reported by us and routines below us, and return NULL
@@ -6890,8 +7170,7 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
if (proto != Q_DEFAULT &&
proto != Q_UDP && proto != Q_TCP && proto != Q_SCTP)
bpf_error(cstate, "illegal qualifier of 'portrange'");
- if (pcap_nametoportrange(name, &port1, &port2, &real_proto) == 0)
- bpf_error(cstate, "unknown port in range '%s'", name);
+ stringtoportrange(cstate, name, &port1, &port2, &real_proto);
if (proto == Q_UDP) {
if (real_proto == IPPROTO_TCP)
bpf_error(cstate, "port in range '%s' is tcp", name);
@@ -6919,12 +7198,8 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
/* override PROTO_UNDEF */
real_proto = IPPROTO_SCTP;
}
- if (port1 < 0)
- bpf_error(cstate, "illegal port number %d < 0", port1);
if (port1 > 65535)
bpf_error(cstate, "illegal port number %d > 65535", port1);
- if (port2 < 0)
- bpf_error(cstate, "illegal port number %d < 0", port2);
if (port2 > 65535)
bpf_error(cstate, "illegal port number %d > 65535", port2);
@@ -7179,14 +7454,14 @@ gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q)
#ifdef INET6
struct block *
-gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2,
- bpf_u_int32 masklen, struct qual q)
+gen_mcode6(compiler_state_t *cstate, const char *s, bpf_u_int32 masklen,
+ struct qual q)
{
struct addrinfo *res;
struct in6_addr *addr;
struct in6_addr mask;
struct block *b;
- uint32_t *a, *m;
+ bpf_u_int32 a[4], m[4]; /* Same as in gen_hostop6(). */
/*
* Catch errors reported by us and routines below us, and return NULL
@@ -7195,15 +7470,12 @@ gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2,
if (setjmp(cstate->top_ctx))
return (NULL);
- if (s2)
- bpf_error(cstate, "no mask %s supported", s2);
-
- res = pcap_nametoaddrinfo(s1);
+ res = pcap_nametoaddrinfo(s);
if (!res)
- bpf_error(cstate, "invalid ip6 address %s", s1);
+ bpf_error(cstate, "invalid ip6 address %s", s);
cstate->ai = res;
if (res->ai_next)
- bpf_error(cstate, "%s resolved to multiple address", s1);
+ bpf_error(cstate, "%s resolved to multiple address", s);
addr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
if (masklen > sizeof(mask.s6_addr) * 8)
@@ -7215,11 +7487,11 @@ gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2,
(0xff << (8 - masklen % 8)) & 0xff;
}
- a = (uint32_t *)addr;
- m = (uint32_t *)&mask;
+ memcpy(a, addr, sizeof(a));
+ memcpy(m, &mask, sizeof(m));
if ((a[0] & ~m[0]) || (a[1] & ~m[1])
|| (a[2] & ~m[2]) || (a[3] & ~m[3])) {
- bpf_error(cstate, "non-network bits set in \"%s/%d\"", s1, masklen);
+ bpf_error(cstate, "non-network bits set in \"%s/%d\"", s, masklen);
}
switch (q.addr) {
diff --git a/gencode.h b/gencode.h
index 93ca5216..b8296ab2 100644
--- a/gencode.h
+++ b/gencode.h
@@ -327,8 +327,8 @@ struct block *gen_acode(compiler_state_t *, const char *, struct qual);
struct block *gen_mcode(compiler_state_t *, const char *, const char *,
bpf_u_int32, struct qual);
#ifdef INET6
-struct block *gen_mcode6(compiler_state_t *, const char *, const char *,
- bpf_u_int32, struct qual);
+struct block *gen_mcode6(compiler_state_t *, const char *, bpf_u_int32,
+ struct qual);
#endif
struct block *gen_ncode(compiler_state_t *, const char *, bpf_u_int32,
struct qual);
diff --git a/grammar.y.in b/grammar.y.in
index 2360d3c7..77f92afb 100644
--- a/grammar.y.in
+++ b/grammar.y.in
@@ -110,21 +110,31 @@ struct rtentry;
#include "os-proto.h"
#endif
-#ifdef YYBYACC
+/*
+ * Work around some bugs in Berkeley YACC prior to the 2017-07-09
+ * release.
+ *
+ * The 2005-05-05 release was the first one to define YYPATCH, so
+ * we treat any release that either 1) doesn't define YYPATCH or
+ * 2) defines it to a value < 20170709 as being buggy.
+ */
+#if defined(YYBYACC) && (!defined(YYPATCH) || YYPATCH < 20170709)
/*
* Both Berkeley YACC and Bison define yydebug (under whatever name
* it has) as a global, but Bison does so only if YYDEBUG is defined.
- * Berkeley YACC define it even if YYDEBUG isn't defined; declare it
- * here to suppress a warning.
+ * Berkeley YACC, prior to the 2017-07-09 release, defines it even if
+ * YYDEBUG isn't defined; declare it here to suppress a warning. The
+ * 2017-07-09 release fixes that.
*/
#if !defined(YYDEBUG)
extern int yydebug;
#endif
/*
- * In Berkeley YACC, yynerrs (under whatever name it has) is global,
- * even if it's building a reentrant parser. In Bison, it's local
- * in reentrant parsers.
+ * In Berkeley YACC, prior to the 2017-07-09 release, yynerrs (under
+ * whatever name it has) is global, even if it's building a reentrant
+ * parser. In Bison, and in the Berkeley YACC 2017-07-09 release and
+ * later, it's local in reentrant parsers.
*
* Declare it to squelch a warning.
*/
@@ -424,6 +434,14 @@ DIAG_OFF_BISON_BYACC
%%
prog: null expr
{
+ /*
+ * I'm not sure we have a reason to use yynerrs, but it's
+ * declared, and incremented, whether we need it or not,
+ * which means tha Clang 15 will give a "used but not
+ * set" warning. This should suppress the warning for
+ * yynerrs without suppressing it for other variables.
+ */
+ (void) yynerrs;
CHECK_INT_VAL(finish_parse(cstate, $2.b));
}
| null
@@ -446,25 +464,59 @@ id: nid
| paren pid ')' { $$ = $2; }
;
nid: ID { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_scode(cstate, $1, $$.q = $<blk>0.q))); }
- | HID '/' NUM { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_mcode(cstate, $1, NULL, $3,
- $$.q = $<blk>0.q))); }
- | HID NETMASK HID { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_mcode(cstate, $1, $3, 0,
- $$.q = $<blk>0.q))); }
+ | HID '/' NUM {
+ CHECK_PTR_VAL($1);
+ /* Check whether HID/NUM is being used when appropriate */
+ $$.q = $<blk>0.q;
+ if ($$.q.addr == Q_PORT) {
+ bpf_set_error(cstate, "'port' modifier applied to IP address and prefix length");
+ YYABORT;
+ } else if ($$.q.addr == Q_PORTRANGE) {
+ bpf_set_error(cstate, "'portrange' modifier applied to IP address and prefix length");
+ YYABORT;
+ } else if ($$.q.addr == Q_PROTO) {
+ bpf_set_error(cstate, "'proto' modifier applied to IP address and prefix length");
+ YYABORT;
+ } else if ($$.q.addr == Q_PROTOCHAIN) {
+ bpf_set_error(cstate, "'protochain' modifier applied to IP address and prefix length");
+ YYABORT;
+ }
+ CHECK_PTR_VAL(($$.b = gen_mcode(cstate, $1, NULL, $3, $$.q)));
+ }
+ | HID NETMASK HID {
+ CHECK_PTR_VAL($1);
+ /* Check whether HID maesk HID is being used when appropriate */
+ $$.q = $<blk>0.q;
+ if ($$.q.addr == Q_PORT) {
+ bpf_set_error(cstate, "'port' modifier applied to IP address and netmask");
+ YYABORT;
+ } else if ($$.q.addr == Q_PORTRANGE) {
+ bpf_set_error(cstate, "'portrange' modifier applied to IP address and netmask");
+ YYABORT;
+ } else if ($$.q.addr == Q_PROTO) {
+ bpf_set_error(cstate, "'proto' modifier applied to IP address and netmask");
+ YYABORT;
+ } else if ($$.q.addr == Q_PROTOCHAIN) {
+ bpf_set_error(cstate, "'protochain' modifier applied to IP address and netmask");
+ YYABORT;
+ }
+ CHECK_PTR_VAL(($$.b = gen_mcode(cstate, $1, $3, 0, $$.q)));
+ }
| HID {
CHECK_PTR_VAL($1);
- /* Decide how to parse HID based on proto */
+ /* Check whether HID is being used when appropriate */
$$.q = $<blk>0.q;
if ($$.q.addr == Q_PORT) {
- bpf_set_error(cstate, "'port' modifier applied to ip host");
+ bpf_set_error(cstate, "'port' modifier applied to IP address");
YYABORT;
} else if ($$.q.addr == Q_PORTRANGE) {
- bpf_set_error(cstate, "'portrange' modifier applied to ip host");
+ bpf_set_error(cstate, "'portrange' modifier applied to IP address");
YYABORT;
} else if ($$.q.addr == Q_PROTO) {
- bpf_set_error(cstate, "'proto' modifier applied to ip host");
+ bpf_set_error(cstate, "'proto' modifier applied to IP address");
YYABORT;
} else if ($$.q.addr == Q_PROTOCHAIN) {
- bpf_set_error(cstate, "'protochain' modifier applied to ip host");
+ bpf_set_error(cstate, "'protochain' modifier applied to IP address");
YYABORT;
}
CHECK_PTR_VAL(($$.b = gen_ncode(cstate, $1, 0, $$.q)));
@@ -472,10 +524,24 @@ nid: ID { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_scode(cstate, $1, $$.
| HID6 '/' NUM {
CHECK_PTR_VAL($1);
#ifdef INET6
- CHECK_PTR_VAL(($$.b = gen_mcode6(cstate, $1, NULL, $3,
- $$.q = $<blk>0.q)));
+ /* Check whether HID6/NUM is being used when appropriate */
+ $$.q = $<blk>0.q;
+ if ($$.q.addr == Q_PORT) {
+ bpf_set_error(cstate, "'port' modifier applied to IP address and prefix length");
+ YYABORT;
+ } else if ($$.q.addr == Q_PORTRANGE) {
+ bpf_set_error(cstate, "'portrange' modifier applied to IP address and prefix length");
+ YYABORT;
+ } else if ($$.q.addr == Q_PROTO) {
+ bpf_set_error(cstate, "'proto' modifier applied to IP address and prefix length ");
+ YYABORT;
+ } else if ($$.q.addr == Q_PROTOCHAIN) {
+ bpf_set_error(cstate, "'protochain' modifier applied to IP address and prefix length");
+ YYABORT;
+ }
+ CHECK_PTR_VAL(($$.b = gen_mcode6(cstate, $1, $3, $$.q)));
#else
- bpf_set_error(cstate, "'ip6addr/prefixlen' not supported "
+ bpf_set_error(cstate, "IPv6 addresses not supported "
"in this configuration");
YYABORT;
#endif /*INET6*/
@@ -483,10 +549,24 @@ nid: ID { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_scode(cstate, $1, $$.
| HID6 {
CHECK_PTR_VAL($1);
#ifdef INET6
- CHECK_PTR_VAL(($$.b = gen_mcode6(cstate, $1, 0, 128,
- $$.q = $<blk>0.q)));
+ /* Check whether HID6 is being used when appropriate */
+ $$.q = $<blk>0.q;
+ if ($$.q.addr == Q_PORT) {
+ bpf_set_error(cstate, "'port' modifier applied to IP address");
+ YYABORT;
+ } else if ($$.q.addr == Q_PORTRANGE) {
+ bpf_set_error(cstate, "'portrange' modifier applied to IP address");
+ YYABORT;
+ } else if ($$.q.addr == Q_PROTO) {
+ bpf_set_error(cstate, "'proto' modifier applied to 'ip6addr/prefixlen");
+ YYABORT;
+ } else if ($$.q.addr == Q_PROTOCHAIN) {
+ bpf_set_error(cstate, "'protochain' modifier applied to IP address");
+ YYABORT;
+ }
+ CHECK_PTR_VAL(($$.b = gen_mcode6(cstate, $1, 128, $$.q)));
#else
- bpf_set_error(cstate, "'ip6addr' not supported "
+ bpf_set_error(cstate, "IPv6 addresses not supported "
"in this configuration");
YYABORT;
#endif /*INET6*/
diff --git a/instrument-functions.c b/instrument-functions.c
index 350a1682..67bcbd3e 100644
--- a/instrument-functions.c
+++ b/instrument-functions.c
@@ -74,13 +74,14 @@ static void print_debug(void *this_fn, void *call_site, action_type action)
static long symcount;
static asection *text;
static bfd_vma vma;
- static char *instrument_type;
static int instrument_set;
static int instrument_off;
static int instrument_global;
- int i;
+ long i;
if (!instrument_set) {
+ static char *instrument_type;
+
/* Get the configuration environment variable INSTRUMENT value if any */
instrument_type = getenv("INSTRUMENT");
/* unset or set to an empty string ? */
diff --git a/msdos/makefile.dj b/msdos/makefile.dj
index 9e41064e..7c65cc06 100644
--- a/msdos/makefile.dj
+++ b/msdos/makefile.dj
@@ -9,7 +9,7 @@
# Note: you should do a "set LFN=y" before running this makefile.
#
-VPATH = missing msdos bpf/net
+VPATH = missing msdos
PREREQUISITES = scanner.c grammar.c tokdefs.h version.h msdos/pkt_stub.inc
@@ -22,7 +22,7 @@ CFLAGS += -DDEBUG -DNDIS_DEBUG -DHAVE_LIMITS_H -DHAVE_STRERROR -DHAVE_SNPRINTF -
CFLAGS += -Dyylval=pcap_lval # -DBDEBUG -DNDEBUG
-SOURCES = grammar.c scanner.c bpf/net/bpf_filter.c bpf_image.c bpf_dump.c \
+SOURCES = grammar.c scanner.c bpf_filter.c bpf_image.c bpf_dump.c \
etherent.c gencode.c nametoaddr.c pcap-common.c pcap-dos.c optimize.c \
savefile.c pcap.c sf-pcap.c sf-pcapng.c \
msdos/pktdrvr.c msdos/ndis2.c
diff --git a/msdos/makefile.wc b/msdos/makefile.wc
index 02460120..a0aa71fc 100644
--- a/msdos/makefile.wc
+++ b/msdos/makefile.wc
@@ -52,8 +52,8 @@ $(OBJDIR)\pktdrvr.obj: msdos\pkt_stub.inc msdos\pktdrvr.c &
pcap-dos.h pcap-int.h pcap.h msdos\pktdrvr.h
*$(CC) $(CFLAGS) msdos\pktdrvr.c -fo=$@
-$(OBJDIR)\bpf_filter.obj: bpf\net\bpf_filter.c
- *$(CC) $(CFLAGS) bpf\net\bpf_filter.c -fo=$@
+$(OBJDIR)\bpf_filter.obj: bpf_filter.c
+ *$(CC) $(CFLAGS) bpf_filter.c -fo=$@
$(OBJDIR)\ndis2.obj: msdos\ndis2.c
*$(CC) $(CFLAGS) msdos\ndis2.c -fo=$@
@@ -94,7 +94,7 @@ clean realclean vclean: .SYMBOLIC
#
# dependencies
#
-$(OBJDIR)\bpf_filter.obj: bpf\net\bpf_filter.c pcap-int.h pcap.h pcap-bpf.h
+$(OBJDIR)\bpf_filter.obj: bpf_filter.c pcap-int.h pcap.h pcap-bpf.h
$(OBJDIR)\bpf_imag.obj: bpf_imag.c pcap-int.h pcap.h pcap-bpf.h
diff --git a/nametoaddr.c b/nametoaddr.c
index a746cb6d..67d31343 100644
--- a/nametoaddr.c
+++ b/nametoaddr.c
@@ -135,6 +135,8 @@
#include <pcap/namedb.h>
#include "nametoaddr.h"
+#include "thread-local.h"
+
#ifdef HAVE_OS_PROTO_H
#include "os-proto.h"
#endif
@@ -465,40 +467,33 @@ pcap_nametoport(const char *name, int *port, int *proto)
int
pcap_nametoportrange(const char *name, int *port1, int *port2, int *proto)
{
- u_int p1, p2;
char *off, *cpy;
int save_proto;
- if (sscanf(name, "%d-%d", &p1, &p2) != 2) {
- if ((cpy = strdup(name)) == NULL)
- return 0;
+ if ((cpy = strdup(name)) == NULL)
+ return 0;
- if ((off = strchr(cpy, '-')) == NULL) {
- free(cpy);
- return 0;
- }
+ if ((off = strchr(cpy, '-')) == NULL) {
+ free(cpy);
+ return 0;
+ }
- *off = '\0';
+ *off = '\0';
- if (pcap_nametoport(cpy, port1, proto) == 0) {
- free(cpy);
- return 0;
- }
- save_proto = *proto;
+ if (pcap_nametoport(cpy, port1, proto) == 0) {
+ free(cpy);
+ return 0;
+ }
+ save_proto = *proto;
- if (pcap_nametoport(off + 1, port2, proto) == 0) {
- free(cpy);
- return 0;
- }
+ if (pcap_nametoport(off + 1, port2, proto) == 0) {
free(cpy);
+ return 0;
+ }
+ free(cpy);
- if (*proto != save_proto)
- *proto = PROTO_UNDEF;
- } else {
- *port1 = p1;
- *port2 = p2;
+ if (*proto != save_proto)
*proto = PROTO_UNDEF;
- }
return 1;
}
@@ -806,16 +801,18 @@ pcap_ether_aton(const char *s)
#ifndef HAVE_ETHER_HOSTTON
/*
* Roll our own.
- * XXX - not thread-safe, because pcap_next_etherent() isn't thread-
- * safe! Needs a mutex or a thread-safe pcap_next_etherent().
+ *
+ * This should be thread-safe, as we define the static variables
+ * we use to be thread-local, and as pcap_next_etherent() does so
+ * as well.
*/
u_char *
pcap_ether_hostton(const char *name)
{
register struct pcap_etherent *ep;
register u_char *ap;
- static FILE *fp = NULL;
- static int init = 0;
+ static thread_local FILE *fp = NULL;
+ static thread_local int init = 0;
if (!init) {
fp = fopen(PCAP_ETHERS_FILE, "r");
diff --git a/pcap-bpf.c b/pcap-bpf.c
index 92e73adf..f8d10833 100644
--- a/pcap-bpf.c
+++ b/pcap-bpf.c
@@ -1061,7 +1061,7 @@ static int
pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
{
struct pcap_bpf *pb = p->priv;
- int cc;
+ ssize_t cc;
int n = 0;
register u_char *bp, *ep;
u_char *datap;
@@ -1107,7 +1107,7 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
} else
#endif
{
- cc = (int)read(p->fd, p->buffer, p->bufsize);
+ cc = read(p->fd, p->buffer, p->bufsize);
}
if (cc < 0) {
/* Don't choke when we get ptraced */
diff --git a/pcap-config.1 b/pcap-config.1
index 66b65b11..8f0fdd62 100644
--- a/pcap-config.1
+++ b/pcap-config.1
@@ -18,7 +18,7 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP\-CONFIG 1 "18 February 2023"
+.TH PCAP\-CONFIG 1 "10 April 2023"
.SH NAME
pcap-config \- write libpcap compiler and linker flags to standard output
.SH SYNOPSIS
@@ -52,13 +52,9 @@ pcap-config \- write libpcap compiler and linker flags to standard output
.I pcap\-config
writes to the standard output various compiler and linker flags required to
build a user program with libpcap. By default, it writes flags appropriate
-for building with a dynamically\-linked version of libpcap; see the
-.B \-\-static
-and
-.B \-\-static\-pcap\-only
-options for building with a statically\-linked version. Depending on the
-manner of libpcap installation, some options or their combinations may
-produce empty output \- this is by design.
+for building with a dynamically\-linked version of libpcap; see below
+for static linking. Depending on the manner of libpcap installation, some
+options or their combinations may produce empty output \- this is by design.
.SH OPTIONS
.TP
@@ -121,6 +117,16 @@ libpcap.
exits with a non-zero status when invoked with an invalid command\-line
option, and with status 0 otherwise.
+.SH BACKWARD COMPATIBILITY
+.PP
+Before libpcap release 1.10.2
+.I pcap\-config
+did not treat invalid command\-line options as an error. The
+.B \-\-static\-pcap\-only
+flag became available in libpcap release 1.10.2. The
+.B \-\-static
+flag became available in libpcap release 1.1.0.
+
.SH SEE ALSO
.BR pkg\-config (1),
.BR pcap (3PCAP)
diff --git a/pcap-dpdk.c b/pcap-dpdk.c
index 025a6748..844db652 100644
--- a/pcap-dpdk.c
+++ b/pcap-dpdk.c
@@ -529,8 +529,8 @@ static void eth_addr_str(ETHER_ADDR_TYPE *addrp, char* mac_str, int len)
static uint16_t portid_by_device(char * device)
{
uint16_t ret = DPDK_PORTID_MAX;
- int len = strlen(device);
- int prefix_len = strlen(DPDK_PREFIX);
+ size_t len = strlen(device);
+ size_t prefix_len = strlen(DPDK_PREFIX);
unsigned long ret_ul = 0L;
char *pEnd;
if (len<=prefix_len || strncmp(device, DPDK_PREFIX, prefix_len)) // check prefix dpdk:
diff --git a/pcap-npf.c b/pcap-npf.c
index ed68fd86..736ecbf2 100644
--- a/pcap-npf.c
+++ b/pcap-npf.c
@@ -143,14 +143,56 @@ PacketGetMonitorMode(PCHAR AdapterName _U_)
#endif
/*
- * Sigh. PacketRequest() will have made a DeviceIoControl()
- * call to the NPF driver to perform the OID request, with a
- * BIOCQUERYOID ioctl. The kernel code should get back one
- * of NDIS_STATUS_INVALID_OID, NDIS_STATUS_NOT_SUPPORTED,
- * or NDIS_STATUS_NOT_RECOGNIZED if the OID request isn't
- * supported by the OS or the driver, but that doesn't seem
- * to make it to the caller of PacketRequest() in a
- * reliable fashion.
+ * If a driver returns an NTSTATUS value:
+ *
+ * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/87fba13e-bf06-450e-83b1-9241dc81e781
+ *
+ * with the "Customer" bit set, it will not be mapped to a Windows error
+ * value in userland, so it will be returned by GetLastError().
+ *
+ * Note that "driver" here includes the Npcap NPF driver, as various
+ * versions would take NT status values and set the "Customer" bit
+ * before returning the status code. The commit message for the
+ * change that started doing that is
+ *
+ * Returned a customer-defined NTSTATUS in OID requests to avoid
+ * NTSTATUS-to-Win32 Error code translation.
+ *
+ * but I don't know why the goal was to avoid that translation. For
+ * a while, I suspected that the NT status STATUS_NOT_SUPPORTED was
+ * getting mapped to ERROR_GEN_FAILURE, but, in the cases where
+ * attempts to set promiscuous mode on regular Ethernet devices were
+ * failing with ERROR_GEN_FAILURE, it turns out that the drivers for
+ * those devices were NetAdapterCx drivers, and Microsoft's NetAdapterCx
+ * mechanism wasn't providing the correct "bytes processed" value on
+ * attempts to set OIDs, and the Npcap NPF driver was checking for
+ * that and returning STATUS_UNSUCCESSFUL, which gets mapped to
+ * ERROR_GEN_FAILURE, so perhaps there's no need to avoid that
+ * translation.
+ *
+ * Attempting to set the hardware filter on a Microsoft Surface Pro's
+ * Mobile Broadband Adapter returns an error that appears to be
+ * NDIS_STATUS_NOT_SUPPORTED ORed with the "Customer" bit, so it's
+ * probably indicating that it doesn't support that. It was probably
+ * the NPF driver setting that bit.
+ */
+#define NT_STATUS_CUSTOMER_DEFINED 0x20000000
+
+/*
+ * PacketRequest() makes a DeviceIoControl() call to the NPF driver to
+ * perform the OID request, with a BIOCQUERYOID ioctl. The kernel code
+ * should get back one of NDIS_STATUS_INVALID_OID, NDIS_STATUS_NOT_SUPPORTED,
+ * or NDIS_STATUS_NOT_RECOGNIZED if the OID request isn't supported by
+ * the OS or the driver.
+ *
+ * Currently, that code may be returned by the Npcap NPF driver with the
+ * NT_STATUS_CUSTOMER_DEFINED bit. That prevents the return status from
+ * being mapped to a Windows error code; if the NPF driver were to stop
+ * ORing in the NT_STATUS_CUSTOMER_DEFINED bit, it's not obvious how those
+ * the NDIS_STATUS_ values that don't correspond to NTSTATUS values would
+ * be translated to Windows error values (NDIS_STATUS_NOT_SUPPORTED is
+ * the same as STATUS_NOT_SUPPORTED, which is an NTSTATUS value that is
+ * mapped to ERROR_NOT_SUPPORTED).
*/
#define NDIS_STATUS_INVALID_OID 0xc0010017
#define NDIS_STATUS_NOT_SUPPORTED 0xc00000bb /* STATUS_NOT_SUPPORTED */
@@ -984,38 +1026,6 @@ pcap_breakloop_npf(pcap_t *p)
SetEvent(PacketGetReadEvent(pw->adapter));
}
-/*
- * These are NTSTATUS values:
- *
- * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/87fba13e-bf06-450e-83b1-9241dc81e781
- *
- * with the "Customer" bit set. If a driver returns them, they are not
- * mapped to Windows error values in userland; they're returned by
- * GetLastError().
- *
- * Note that "driver" here includes the Npcap NPF driver, as various
- * versions would take NT status values and set the "Customer" bit
- * before returning the status code. The commit message for the
- * change that started doing that is
- *
- * Returned a customer-defined NTSTATUS in OID requests to avoid
- * NTSTATUS-to-Win32 Error code translation.
- *
- * but I don't know why the goal was to avoid that translation.
- *
- * Attempting to set the hardware filter on a Microsoft Surface Pro's
- * Mobile Broadband Adapter returns an error that appears to be
- * NDIS_STATUS_NOT_SUPPORTED ORed with the "Customer" bit, so it's
- * probably indicating that it doesn't support that.
- *
- * It is likely that there are other devices which throw spurious errors,
- * at which point this will need refactoring to efficiently check against
- * a list, but for now we can just check this one value. Perhaps the
- * right way to do this is compare against various NDIS errors with
- * the "customer" bit ORed in.
- */
-#define NT_STATUS_CUSTOMER_DEFINED 0x20000000
-
static int
pcap_activate_npf(pcap_t *p)
{
@@ -1297,7 +1307,12 @@ pcap_activate_npf(pcap_t *p)
/* Set promiscuous mode */
if (p->opt.promisc)
{
-
+ /*
+ * For future reference, in case we ever want to query
+ * whether an adapter supports promiscuous mode, that
+ * would be done on Windows by querying the value
+ * of the OID_GEN_SUPPORTED_PACKET_FILTERS OID.
+ */
if (PacketSetHwFilter(pw->adapter,NDIS_PACKET_TYPE_PROMISCUOUS) == FALSE)
{
DWORD errcode = GetLastError();
@@ -1341,8 +1356,16 @@ pcap_activate_npf(pcap_t *p)
* value, so that old incorrect programs that
* assume a non-zero return from pcap_activate()
* is an error don't break.)
+ *
+ * We check here for ERROR_NOT_SUPPORTED, which
+ * is what NDIS_STATUS_NOT_SUPPORTED (which is
+ * the same value as the NTSTATUS value
+ * STATUS_NOT_SUPPORTED) gets mapped to, as
+ * well as NDIS_STATUS_NOT_SUPPORTED with the
+ * "Customer" bit set.
*/
- if (errcode != (NDIS_STATUS_NOT_SUPPORTED|NT_STATUS_CUSTOMER_DEFINED))
+ if (errcode != ERROR_NOT_SUPPORTED &&
+ errcode != (NDIS_STATUS_NOT_SUPPORTED|NT_STATUS_CUSTOMER_DEFINED))
{
pcap_fmt_errmsg_for_win32_err(p->errbuf,
PCAP_ERRBUF_SIZE, errcode,
diff --git a/pcap.c b/pcap.c
index 44ce8a01..04aa7441 100644
--- a/pcap.c
+++ b/pcap.c
@@ -65,6 +65,8 @@ struct rtentry; /* declarations in <net/if.h> */
#include "diag-control.h"
+#include "thread-local.h"
+
#ifdef HAVE_OS_PROTO_H
#include "os-proto.h"
#endif
@@ -1616,7 +1618,19 @@ pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp,
ifr.ifr_addr.sa_family = AF_INET;
#endif
(void)pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+#if defined(__HAIKU__) && defined(__clang__)
+ /*
+ * In Haiku R1/beta4 <unistd.h> ioctl() is a macro that needs to take 4
+ * arguments to initialize its intermediate 2-member structure fully so
+ * that Clang does not generate a -Wmissing-field-initializers warning
+ * (which manifests only when it runs with -Werror). This workaround
+ * can be removed as soon as there is a Haiku release that fixes the
+ * problem. See also https://review.haiku-os.org/c/haiku/+/6369
+ */
+ if (ioctl(fd, SIOCGIFADDR, (char *)&ifr, sizeof(ifr)) < 0) {
+#else
if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
+#endif /* __HAIKU__ && __clang__ */
if (errno == EADDRNOTAVAIL) {
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"%s: no IPv4 address assigned", device);
@@ -1635,7 +1649,12 @@ pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp,
ifr.ifr_addr.sa_family = AF_INET;
#endif
(void)pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+#if defined(__HAIKU__) && defined(__clang__)
+ /* Same as above. */
+ if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr, sizeof(ifr)) < 0) {
+#else
if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) {
+#endif /* __HAIKU__ && __clang__ */
pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
errno, "SIOCGIFNETMASK: %s", device);
(void)close(fd);
@@ -3377,7 +3396,7 @@ pcap_datalink_val_to_description(int dlt)
const char *
pcap_datalink_val_to_description_or_dlt(int dlt)
{
- static char unkbuf[40];
+ static thread_local char unkbuf[40];
const char *description;
description = pcap_datalink_val_to_description(dlt);
@@ -3643,7 +3662,7 @@ pcap_setnonblock_fd(pcap_t *p, int nonblock)
const char *
pcap_statustostr(int errnum)
{
- static char ebuf[15+10+1];
+ static thread_local char ebuf[15+10+1];
switch (errnum) {
@@ -3704,7 +3723,7 @@ pcap_strerror(int errnum)
{
#ifdef HAVE_STRERROR
#ifdef _WIN32
- static char errbuf[PCAP_ERRBUF_SIZE];
+ static thread_local char errbuf[PCAP_ERRBUF_SIZE];
errno_t err = strerror_s(errbuf, PCAP_ERRBUF_SIZE, errnum);
if (err != 0) /* err = 0 if successful */
@@ -3716,7 +3735,7 @@ pcap_strerror(int errnum)
#else
extern int sys_nerr;
extern const char *const sys_errlist[];
- static char errbuf[PCAP_ERRBUF_SIZE];
+ static thread_local char errbuf[PCAP_ERRBUF_SIZE];
if ((unsigned int)errnum < sys_nerr)
return ((char *)sys_errlist[errnum]);
diff --git a/rpcapd/rpcapd-config.manfile.in b/rpcapd/rpcapd-config.manfile.in
index 267b48e5..dd0c91e1 100644
--- a/rpcapd/rpcapd-config.manfile.in
+++ b/rpcapd/rpcapd-config.manfile.in
@@ -22,11 +22,13 @@
rpcapd-config \- rpcapd configuration file format
.SH DESCRIPTION
An
-.B rpcapd
+.I rpcapd
configuration file allows parameters to be set for
.BR rpcapd (@MAN_ADMIN_COMMANDS@).
.LP
-A # introduces a comment that runs to the end of the line. Blank lines,
+A
+.B #
+introduces a comment that runs to the end of the line. Blank lines,
and lines with only a comment, are ignored. Leading and trailing white
space on a line are also ignored.
.LP
@@ -34,7 +36,9 @@ Lines that set a parameter are of the form
.IP
\fIparameter\fB=\fIvalue\fR
.LP
-Whitespace preceding or following the = is ignored.
+Whitespace preceding or following the
+.B =
+is ignored.
.LP
The
.IR parameter s
@@ -72,7 +76,7 @@ or
.BR NO .
.B YES
means that null authentication is permitted;
-.B No
+.B NO
means that it is not permitted.
.SH SEE ALSO
.BR rpcapd (@MAN_ADMIN_COMMANDS@)
diff --git a/rpcapd/rpcapd.manadmin.in b/rpcapd/rpcapd.manadmin.in
index 17dde4a3..250e8595 100644
--- a/rpcapd/rpcapd.manadmin.in
+++ b/rpcapd/rpcapd.manadmin.in
@@ -98,22 +98,22 @@ and filter part of libpcap to be run on a remote system.
Rpcapd can run in two modes: passive mode (default) and active mode.
.LP
In passive mode, the client (e.g., a network sniffer) connects to
-.BR rpcapd .
+.IR rpcapd .
The client then sends the appropriate commands to
-.B rpcapd
+.I rpcapd
to start the capture.
.LP
In active mode,
-.B rpcapd
+.I rpcapd
tries to establish a connection toward the client
(e.g., a network sniffer). The client then sends the appropriate commands
to rpcapd to start the capture.
.LP
Active mode is useful in case
-.B rpcapd
+.I rpcapd
is run behind a firewall and
cannot receive connections from the external world. In this case,
-.B rpcapd
+.I rpcapd
can be configured to establish the connection to a given host,
which has to be configured in order to wait for that connection. After
establishing the connection, the protocol continues its job in almost
@@ -122,18 +122,19 @@ the same way in both active and passive mode.
.LP
The user can create a configuration file in the same directory as the
executable, and put the configuration commands in there. In order for
-.B rpcapd
+.I rpcapd
to execute the commands, it needs to be restarted on Win32, i.e.
the configuration file is parsed only at the beginning. The UNIX
version of
-.B rpcapd
+.I rpcapd
will reread the configuration file upon receiving a
-HUP signal. In that case, all the existing connections remain in place,
+.B HUP
+signal. In that case, all the existing connections remain in place,
while the new connections will be created according to the new parameters.
.LP
In case a user does not want to create the configuration file manually,
they can launch
-.B rpcapd
+.I rpcapd
with the desired flags plus
.BR "-s filename" .
Rpcapd will parse all the parameters and save them into the specified
@@ -142,7 +143,7 @@ configuration file.
.LP
The remote daemon is installed automatically when installing WinPcap.
The installation process places the
-.B rpcapd
+.I rpcapd
executable file into the WinPcap folder.
This file can be executed either from the command line, or as a service.
For instance, the installation process updates the list of available
@@ -160,7 +161,7 @@ flag.
.SH Starting rpcapd on Win32
.LP
The
-.B rpcapd
+.I rpcapd
executable can be launched directly, i.e. it can run in the
foreground as well (not as a daemon/service). The procedure is quite
simple: you have to invoke the executable from the command line with all
@@ -171,7 +172,7 @@ start in the foreground.
.SH Installing rpcapd on Unix-like systems
TBD
.SH Starting rpcapd on Unix-like systems
-.B rpcapd
+.I rpcapd
needs sufficient privileges to perform packet capture, e.g.
run as root or be owned by root and have suid set. Most operating
systems provide more elegant solutions when run as user than the
@@ -203,8 +204,7 @@ and the
.B rpcapd.inetd.conf
entry has been added to
.BR inetd.conf (@MAN_FILE_FORMATS@),
-the rpcapd service can be enabled by telling
-.B inetd
+the rpcapd service can be enabled by telling inetd
to reread its configuration file.
.LP
If your system supports
@@ -213,8 +213,7 @@ and the
.B rpcapd.xinetd.conf
entry has been added to
.BR xinetd.conf (@MAN_FILE_FORMATS@),
-the rpcapd service can be enabled by telling
-.B xinetd
+the rpcapd service can be enabled by telling xinetd
to reread its configuration file.
.SH OPTIONS
.TP
@@ -223,14 +222,14 @@ Bind to the IP address specified by
.I address
(either numeric or literal).
By default,
-.B rpcapd
+.I rpcapd
binds to all local IPv4 and IPv6 addresses.
.TP
.BI \-p " port"
Bind to the port specified by
.IR port .
By default,
-.B rpcapd
+.I rpcapd
binds to port 2002.
.TP
.BI \-t " data_port"
@@ -238,13 +237,13 @@ Use the port specified by
.I data_port
as the port for data transfer.
By default,
-.B rpcapd
+.I rpcapd
uses a port chosen by the operating system.
.TP
.B \-4
Listen only on IPv4 addresses.
By default,
-.B rpcapd
+.I rpcapd
listens on both IPv4 and IPv6 addresses.
.TP
.BI \-l " host_list"
@@ -257,8 +256,9 @@ We suggest that you use host names rather than literal IP addresses
in order to avoid problems with different address families.
.TP
.B \-n
-Permit NULL authentication (usually used with
-.BR \-l ).
+Permit NULL authentication (usually used with the
+.B \-l
+flag).
.TP
.BI \-a " host" , "port"
Run in active mode, connecting to host
@@ -273,8 +273,8 @@ is omitted, the default port (2003) is used.
Run in active mode only; by default, if
.B \-a
is specified,
-.B rpcapd
-it accepts passive connections as well.
+.I rpcapd
+accepts passive connections as well.
.TP
.B \-d
Run in daemon mode (UNIX only) or as a service (Win32 only).
@@ -304,7 +304,7 @@ and ignore all flags specified on the command line.
Print this help screen.
.LP
If
-.B rpcapd
+.I rpcapd
was compiled with SSL support, the following options are also
available:
.TP
@@ -315,14 +315,12 @@ Require that SSL be used on connections.
With SSL enabled, XXX - I'm not sure how *fetching* the list of
compression mechanisms does anything to compression.
.TP
-.B \-S
-.I ssl_keyfile
+.BI \-S " ssl_keyfile"
With SSL enabled, use
.I ssl_keyfile
as the SSL key file.
.TP
-.B \-X
-.I ssl_certfile
+.BI \-X " ssl_certfile"
With SSL enabled, use
.I ssl_certfile
as the SSL certificate file.
diff --git a/scanner.l b/scanner.l
index 85fe395a..c20637b2 100644
--- a/scanner.l
+++ b/scanner.l
@@ -32,6 +32,26 @@
#include "grammar.h"
#include "diag-control.h"
+
+/*
+ * Convert string to 32-bit unsigned integer; the string starts at
+ * string and is string_len bytes long.
+ *
+ * On success, sets *val to the value and returns 1.
+ * On failure, sets the BPF error string and returns 0.
+ *
+ * Also used in gencode.c
+ */
+typedef enum {
+ STOULEN_OK,
+ STOULEN_NOT_HEX_NUMBER,
+ STOULEN_NOT_OCTAL_NUMBER,
+ STOULEN_NOT_DECIMAL_NUMBER,
+ STOULEN_ERROR
+} stoulen_ret;
+
+stoulen_ret stoulen(const char *string, size_t stringlen, bpf_u_int32 *val,
+ compiler_state_t *cstate);
}
/*
@@ -149,7 +169,7 @@ void pcap_set_column(int, yyscan_t);
#include "os-proto.h"
#endif
-static int stou(char *, YYSTYPE *, compiler_state_t *);
+static int stou(const char *, YYSTYPE *, compiler_state_t *);
/*
* Disable diagnostics in the code generated by Flex.
@@ -490,27 +510,20 @@ tcp-cwr { yylval->h = 0x80; return NUM; }
*/
DIAG_ON_FLEX
-/*
- * Convert string to 32-bit unsigned integer. Just like atoi(), but checks for
- * preceding 0x or 0 and uses hex or octal instead of decimal.
- *
- * On success, sets yylval->h to the value and returns NUM.
- * On failure, sets the BPF error string and returns LEX_ERROR, to force
- * the parse to stop.
- */
-static int
-stou(char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
+stoulen_ret
+stoulen(const char *string, size_t string_len, bpf_u_int32 *val,
+ compiler_state_t *cstate)
{
bpf_u_int32 n = 0;
unsigned int digit;
- char *s = yytext_arg;
+ const char *s = string;
/*
- * yytext_arg is guaranteed either to be a string of decimal digits
+ * string is guaranteed either to be a string of decimal digits
* or 0[xX] followed by a string of hex digits.
*/
- if (*s == '0') {
- if (s[1] == 'x' || s[1] == 'X') {
+ if (string_len >= 1 && *s == '0') {
+ if (string_len >= 2 && (s[1] == 'x' || s[1] == 'X')) {
/*
* Begins with 0x or 0X, so hex.
* Guaranteed to be all hex digits following the
@@ -518,13 +531,25 @@ stou(char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
* A-F.
*/
s += 2; /* skip the prefix */
- while ((digit = *s++) != '\0') {
+ string_len -= 2;
+ while (string_len != 0) {
+ digit = *s++;
+ string_len--;
if (digit >= '0' && digit <= '9')
digit = digit - '0';
else if (digit >= 'a' && digit <= 'f')
digit = digit - 'a' + 10;
- else
+ else if (digit >= 'A' && digit <= 'F')
digit = digit - 'A' + 10;
+ else {
+ /*
+ * Not a valid hex number.
+ * Don't treat this as an error,
+ * in case the caller wants to
+ * interpret it as something else.
+ */
+ return STOULEN_NOT_HEX_NUMBER;
+ }
/*
* Check for overflow.
@@ -536,10 +561,10 @@ stou(char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
* add 4 more; that won't fit
* in 32 bits.
*/
- bpf_set_error(yyextra_arg,
- "number %s overflows 32 bits",
- yytext_arg);
- return LEX_ERROR;
+ bpf_set_error(cstate,
+ "number %.*s overflows 32 bits",
+ (int)string_len, string);
+ return STOULEN_ERROR;
}
n = (n << 4) + digit;
}
@@ -551,14 +576,20 @@ stou(char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
* report an error.
*/
s += 1;
- while ((digit = *s++) != '\0') {
+ string_len -= 1;
+ while (string_len != 0) {
+ digit = *s++;
+ string_len--;
if (digit >= '0' && digit <= '7')
digit = digit - '0';
else {
- bpf_set_error(yyextra_arg,
- "number %s contains non-octal digit",
- yytext_arg);
- return LEX_ERROR;
+ /*
+ * Not a valid octal number.
+ * Don't treat this as an error,
+ * in case the caller wants to
+ * interpret it as something else.
+ */
+ return STOULEN_NOT_OCTAL_NUMBER;
}
if (n > 03777777777U) {
/*
@@ -567,10 +598,10 @@ stou(char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
* 3 more; that won't fit in
* 32 bits.
*/
- bpf_set_error(yyextra_arg,
- "number %s overflows 32 bits",
- yytext_arg);
- return LEX_ERROR;
+ bpf_set_error(cstate,
+ "number %.*s overflows 32 bits",
+ (int)string_len, string);
+ return STOULEN_ERROR;
}
n = (n << 3) + digit;
}
@@ -579,21 +610,83 @@ stou(char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
/*
* Decimal.
*/
- while ((digit = *s++) != '\0') {
- digit = digit - '0';
+ while (string_len != 0) {
+ digit = *s++;
+ string_len--;
+ if (digit >= '0' && digit <= '9')
+ digit = digit - '0';
+ else {
+ /*
+ * Not a valid decimal number.
+ * Don't treat this as an error,
+ * in case the caller wants to
+ * interpret it as something else.
+ */
+ return STOULEN_NOT_DECIMAL_NUMBER;
+ }
#define CUTOFF_DEC (0xFFFFFFFFU / 10U)
#define CUTLIM_DEC (0xFFFFFFFFU % 10U)
if (n > CUTOFF_DEC ||
(n == CUTOFF_DEC && digit > CUTLIM_DEC)) {
- bpf_set_error(yyextra_arg,
- "number %s overflows 32 bits",
- yytext_arg);
- return LEX_ERROR;
+ /*
+ * Adding that digit will result in a
+ * number that won't fit in 32 bits.
+ */
+ bpf_set_error(cstate,
+ "number %.*s overflows 32 bits",
+ (int)string_len, string);
+ return STOULEN_ERROR;
}
n = (n * 10) + digit;
}
}
- yylval_arg->h = n;
- return NUM;
+ *val = n;
+ return STOULEN_OK;
+}
+
+/*
+ * Convert string to 32-bit unsigned integer. Just like atoi(), but checks for
+ * preceding 0x or 0 and uses hex or octal instead of decimal.
+ *
+ * On success, sets yylval->h to the value and returns NUM.
+ * On failure, sets the BPF error string and returns LEX_ERROR, to force
+ * the parse to stop.
+ */
+static int
+stou(const char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
+{
+ stoulen_ret ret;
+
+ ret = stoulen(yytext_arg, strlen(yytext_arg), &yylval_arg->h,
+ yyextra_arg);
+ switch (ret) {
+
+ case STOULEN_OK:
+ return NUM;
+
+ case STOULEN_NOT_OCTAL_NUMBER:
+ bpf_set_error(yyextra_arg, "number %s contains non-octal digit",
+ yytext_arg);
+ return LEX_ERROR;
+
+ case STOULEN_NOT_HEX_NUMBER:
+ bpf_set_error(yyextra_arg, "number %s contains non-hex digit",
+ yytext_arg);
+ return LEX_ERROR;
+
+ case STOULEN_NOT_DECIMAL_NUMBER:
+ bpf_set_error(yyextra_arg, "number %s contains non-decimal digit",
+ yytext_arg);
+ return LEX_ERROR;
+
+ case STOULEN_ERROR:
+ /* Error already set. */
+ return LEX_ERROR;
+
+ default:
+ /* Should not happen */
+ bpf_set_error(yyextra_arg, "stoulen returned %d", ret);
+ return LEX_ERROR;
+ }
}
diff --git a/thread-local.h b/thread-local.h
new file mode 100644
index 00000000..61296e56
--- /dev/null
+++ b/thread-local.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1994, 1995, 1996
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef thread_local_h
+#define thread_local_h
+
+/*
+ * This defines thread_local to specify thread-local storage, if it
+ * is not already defined.
+ *
+ * C11, if __STDC_NO_THREADS__ is not defined to be 1, defines
+ * _Thread_local to indicate thread-local storage. (You can also
+ * include <threads.h> to so define it, but we don't use any of
+ * the other stuff there.)
+ *
+ * Otherwise, we define it ourselves, based on the compiler.
+ *
+ * This is taken from https://stackoverflow.com/a/18298965/16139739.
+ */
+#ifndef thread_local
+ #if __STDC_VERSION__ >= 201112 && !defined __STDC_NO_THREADS__
+ #define thread_local _Thread_local
+ #elif defined _WIN32 && ( \
+ defined _MSC_VER || \
+ defined __ICL || \
+ defined __DMC__ || \
+ defined __BORLANDC__ )
+ #define thread_local __declspec(thread)
+ /* note that ICC (linux) and Clang are covered by __GNUC__ */
+ #elif defined __GNUC__ || \
+ defined __SUNPRO_C || \
+ defined __xlC__
+ #define thread_local __thread
+ #else
+ #error "Cannot define thread_local"
+ #endif
+#endif
+
+#endif