aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2021-01-06 20:22:57 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-01-06 20:22:57 +0000
commitd452836f1bb93431e3acfcbcff1fb0737c85e369 (patch)
tree6258b7da515b2a7661114322d98216708d2134a9
parent8ac014d123247fcc8bbdd3e4129169a65efb0c39 (diff)
parent42cd90cfc1dd3fd2dac2d86723d3713105108194 (diff)
downloadlibpcap-d452836f1bb93431e3acfcbcff1fb0737c85e369.tar.gz
Merge "Upgrade libpcap to libpcap-1.10.0" am: c1cf421806 am: 56dae89b50 am: 42cd90cfc1
Original change: https://android-review.googlesource.com/c/platform/external/libpcap/+/1541006 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: I2c702c8ad27745cbd3d1b75a3f66e2a496158ede
-rw-r--r--.appveyor.yml95
-rw-r--r--.cirrus.yml25
-rw-r--r--.mailmap28
-rw-r--r--.travis.yml88
-rw-r--r--CHANGES122
-rw-r--r--CMakeLists.txt849
-rw-r--r--CREDITS72
-rw-r--r--INSTALL.md213
-rw-r--r--METADATA10
-rw-r--r--Makefile.in103
-rw-r--r--README.md42
-rw-r--r--VERSION2
-rw-r--r--Win32/Prj/wpcap.vcxproj.filters2
-rw-r--r--aclocal.m4419
-rw-r--r--atmuni31.h2
-rw-r--r--bpf_filter.c84
-rw-r--r--bpf_image.c156
-rw-r--r--charconv.c216
-rw-r--r--charconv.h44
-rw-r--r--cmake/Modules/FindAirPcap.cmake69
-rw-r--r--cmake/Modules/FindPacket.cmake19
-rw-r--r--cmake/Modules/Finddpdk.cmake123
-rw-r--r--cmakeconfig.h.in70
-rwxr-xr-xconfig.guess597
-rw-r--r--config.h.in75
-rwxr-xr-xconfig.sub1657
-rwxr-xr-xconfigure2155
-rw-r--r--configure.ac1007
-rw-r--r--diag-control.h138
-rw-r--r--dlpisubs.c24
-rw-r--r--doc/README.Win32.md199
-rw-r--r--doc/README.aix2
-rw-r--r--doc/README.capture-module353
-rw-r--r--doc/README.dag4
-rw-r--r--doc/README.hpux8
-rw-r--r--doc/README.linux.md80
-rw-r--r--doc/README.septel2
-rw-r--r--doc/README.sita11
-rw-r--r--etherent.c20
-rw-r--r--ethertype.h38
-rw-r--r--extract.h300
-rw-r--r--fad-getad.c3
-rw-r--r--fad-gifc.c10
-rw-r--r--fad-glifc.c3
-rw-r--r--fmtutils.c284
-rw-r--r--fmtutils.h2
-rw-r--r--ftmacros.h8
-rw-r--r--gencode.c793
-rw-r--r--gencode.h68
-rw-r--r--grammar.y.in (renamed from grammar.y)126
-rw-r--r--lbl/os-osf4.h4
-rw-r--r--lbl/os-osf5.h6
-rw-r--r--lbl/os-solaris2.h2
-rw-r--r--lbl/os-sunos4.h2
-rw-r--r--missing/getopt.c17
-rw-r--r--missing/snprintf.c631
-rw-r--r--missing/win_asprintf.c4
-rw-r--r--missing/win_snprintf.c43
-rwxr-xr-xmkdep32
-rw-r--r--msdos/readme.dos8
-rw-r--r--nametoaddr.c68
-rw-r--r--optimize.c667
-rw-r--r--org.tcpdump.chmod_bpf.plist2
-rw-r--r--pcap-airpcap.c1044
-rw-r--r--pcap-airpcap.h36
-rw-r--r--pcap-bpf.c655
-rw-r--r--pcap-bt-linux.c42
-rw-r--r--pcap-bt-monitor-linux.c27
-rw-r--r--pcap-common.c134
-rw-r--r--pcap-config.12
-rw-r--r--pcap-dag.c59
-rw-r--r--pcap-dbus.c28
-rw-r--r--pcap-dlpi.c70
-rw-r--r--pcap-dos.c24
-rw-r--r--pcap-dpdk.c1070
-rw-r--r--pcap-dpdk.h28
-rw-r--r--pcap-enet.c4
-rw-r--r--pcap-filter.manmisc.in272
-rw-r--r--pcap-haiku.cpp282
-rw-r--r--pcap-int.h139
-rw-r--r--pcap-libdlpi.c8
-rw-r--r--pcap-linktype.manmisc.in8
-rw-r--r--pcap-linux.c4848
-rw-r--r--pcap-netfilter-linux.c64
-rw-r--r--pcap-netmap.c7
-rw-r--r--pcap-new.c22
-rw-r--r--pcap-nit.c9
-rw-r--r--pcap-npf.c454
-rw-r--r--pcap-pf.c23
-rw-r--r--pcap-rdmasniff.c41
-rw-r--r--pcap-rpcap.c552
-rw-r--r--pcap-savefile.manfile.in8
-rw-r--r--pcap-septel.c36
-rw-r--r--pcap-sita.c59
-rw-r--r--pcap-sita.html28
-rw-r--r--pcap-snf.c44
-rw-r--r--pcap-snit.c7
-rw-r--r--pcap-snoop.c8
-rw-r--r--pcap-tc.c176
-rw-r--r--pcap-tstamp.manmisc.in61
-rw-r--r--pcap-types.h1
-rw-r--r--pcap-usb-linux.c127
-rw-r--r--pcap.3pcap.in110
-rw-r--r--pcap.c711
-rw-r--r--pcap/bpf.h34
-rw-r--r--pcap/compiler-tests.h2
-rw-r--r--pcap/dlt.h114
-rw-r--r--pcap/funcattrs.h76
-rw-r--r--pcap/namedb.h3
-rw-r--r--pcap/pcap-inttypes.h120
-rw-r--r--pcap/pcap.h311
-rw-r--r--pcap/socket.h9
-rw-r--r--pcap_activate.3pcap35
-rw-r--r--pcap_breakloop.3pcap32
-rw-r--r--pcap_can_set_rfmon.3pcap28
-rw-r--r--pcap_close.3pcap4
-rw-r--r--pcap_compile.3pcap.in22
-rw-r--r--pcap_create.3pcap8
-rw-r--r--pcap_datalink.3pcap.in15
-rw-r--r--pcap_datalink_name_to_val.3pcap8
-rw-r--r--pcap_datalink_val_to_name.3pcap22
-rw-r--r--pcap_dump.3pcap12
-rw-r--r--pcap_dump_close.3pcap6
-rw-r--r--pcap_dump_file.3pcap6
-rw-r--r--pcap_dump_flush.3pcap13
-rw-r--r--pcap_dump_ftell.3pcap16
-rw-r--r--pcap_dump_open.3pcap.in49
-rw-r--r--pcap_file.3pcap20
-rw-r--r--pcap_fileno.3pcap20
-rw-r--r--pcap_findalldevs.3pcap26
-rw-r--r--pcap_freecode.3pcap8
-rw-r--r--pcap_get_required_select_timeout.3pcap163
-rw-r--r--pcap_get_selectable_fd.3pcap77
-rw-r--r--pcap_get_tstamp_precision.3pcap.in12
-rw-r--r--pcap_geterr.3pcap6
-rw-r--r--pcap_init.3pcap99
-rw-r--r--pcap_inject.3pcap34
-rw-r--r--pcap_is_swapped.3pcap16
-rw-r--r--pcap_lib_version.3pcap4
-rw-r--r--pcap_list_datalinks.3pcap.in22
-rw-r--r--pcap_list_tstamp_types.3pcap.in19
-rw-r--r--pcap_lookupdev.3pcap33
-rw-r--r--pcap_lookupnet.3pcap10
-rw-r--r--pcap_loop.3pcap84
-rw-r--r--pcap_major_version.3pcap10
-rw-r--r--pcap_next_ex.3pcap54
-rw-r--r--pcap_offline_filter.3pcap8
-rw-r--r--pcap_open_dead.3pcap.in25
-rw-r--r--pcap_open_live.3pcap16
-rw-r--r--pcap_open_offline.3pcap.in29
-rw-r--r--pcap_set_buffer_size.3pcap12
-rw-r--r--pcap_set_datalink.3pcap15
-rw-r--r--pcap_set_immediate_mode.3pcap.in30
-rw-r--r--pcap_set_promisc.3pcap12
-rw-r--r--pcap_set_protocol_linux.3pcap20
-rw-r--r--pcap_set_rfmon.3pcap14
-rw-r--r--pcap_set_snaplen.3pcap12
-rw-r--r--pcap_set_timeout.3pcap13
-rw-r--r--pcap_set_tstamp_precision.3pcap.in20
-rw-r--r--pcap_set_tstamp_type.3pcap.in20
-rw-r--r--pcap_setdirection.3pcap16
-rw-r--r--pcap_setfilter.3pcap16
-rw-r--r--pcap_setnonblock.3pcap48
-rw-r--r--pcap_snapshot.3pcap14
-rw-r--r--pcap_stats.3pcap16
-rw-r--r--pcap_statustostr.3pcap4
-rw-r--r--pcap_strerror.3pcap4
-rw-r--r--pcap_tstamp_type_name_to_val.3pcap7
-rw-r--r--pcap_tstamp_type_val_to_name.3pcap7
-rw-r--r--portability.h46
-rw-r--r--rpcap-protocol.c6
-rw-r--r--rpcap-protocol.h35
-rw-r--r--rpcapd/CMakeLists.txt22
-rw-r--r--rpcapd/Makefile.in5
-rw-r--r--rpcapd/daemon.c691
-rw-r--r--rpcapd/daemon.h8
-rw-r--r--rpcapd/fileconf.c30
-rw-r--r--rpcapd/log.c2
-rw-r--r--rpcapd/org.tcpdump.rpcapd.plist2
-rw-r--r--rpcapd/rpcapd-config.manfile.in8
-rw-r--r--rpcapd/rpcapd.c117
-rw-r--r--rpcapd/rpcapd.manadmin.in88
-rw-r--r--rpcapd/win32-svc.c13
-rw-r--r--rpcapd/win32-svc.h2
-rw-r--r--savefile.c199
-rw-r--r--scanner.l244
-rw-r--r--sf-pcap.c99
-rw-r--r--sf-pcapng.c83
-rw-r--r--sockutils.c165
-rw-r--r--sockutils.h12
-rw-r--r--sslutils.c239
-rw-r--r--sslutils.h66
-rw-r--r--testprogs/.gitignore2
-rw-r--r--testprogs/BPF/1.txt2
-rw-r--r--testprogs/CMakeLists.txt8
-rw-r--r--testprogs/Makefile.in15
-rw-r--r--testprogs/can_set_rfmon_test.c1
-rw-r--r--testprogs/capturetest.c89
-rw-r--r--testprogs/filtertest.c39
-rw-r--r--testprogs/findalldevstest-perf.c100
-rw-r--r--testprogs/findalldevstest.c25
-rw-r--r--testprogs/fuzz/CMakeLists.txt43
-rw-r--r--testprogs/fuzz/fuzz_both.c101
-rw-r--r--testprogs/fuzz/fuzz_both.options2
-rw-r--r--testprogs/fuzz/fuzz_filter.c43
-rw-r--r--testprogs/fuzz/fuzz_filter.options2
-rw-r--r--testprogs/fuzz/fuzz_pcap.c80
-rw-r--r--testprogs/fuzz/fuzz_pcap.options2
-rw-r--r--testprogs/fuzz/fuzz_rclient.c56
-rw-r--r--testprogs/fuzz/fuzz_rserver.c56
-rw-r--r--testprogs/fuzz/onefile.c54
-rw-r--r--testprogs/opentest.c19
-rw-r--r--testprogs/reactivatetest.c1
-rw-r--r--testprogs/selpolltest.c64
-rw-r--r--testprogs/threadsignaltest.c58
-rw-r--r--testprogs/valgrindtest.c34
-rwxr-xr-xtestprogs/visopts.py35
-rw-r--r--testprogs/writecaptest.c556
218 files changed, 18975 insertions, 10368 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
index a644151c..15e1824e 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -9,21 +9,84 @@ install:
- cinst winflexbison
- win_flex --version
- win_bison --version
- - appveyor DownloadFile http://www.winpcap.org/install/bin/WpdPack_4_1_2.zip
+ - 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://nmap.org/npcap/dist/npcap-sdk-0.1.zip
- - 7z x .\npcap-sdk-0.1.zip -oc:\projects\libpcap\Win32
+ - appveyor DownloadFile https://nmap.org/npcap/dist/npcap-sdk-1.05.zip
+ - 7z x .\npcap-sdk-1.05.zip -oc:\projects\libpcap\Win32\npcap-sdk-1.05
+ - appveyor DownloadFile https://support.riverbed.com/bin/support/download?sid=l3vk3eu649usgu3rj60uncjqqu -FileName AirPcap_Devpack.zip
+ - 7z x .\AirPcap_Devpack.zip -oc:\projects\libpcap\Win32
environment:
matrix:
- - GENERATOR: "Visual Studio 12 2013"
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+ GENERATOR: "MinGW Makefiles"
SDK: WpdPack
- - GENERATOR: "Visual Studio 12 2013 Win64"
+ 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.05
+ 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
- - GENERATOR: "Visual Studio 12 2013"
- SDK: npcap-sdk-0.1
- - GENERATOR: "Visual Studio 12 2013 Win64"
- SDK: npcap-sdk-0.1
+ AIRPCAP: -DDISABLE_AIRPCAP=YES
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+ GENERATOR: "Visual Studio 14 2015 Win64"
+ SDK: WpdPack
+ AIRPCAP: -DDISABLE_AIRPCAP=YES
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+ GENERATOR: "Visual Studio 14 2015"
+ SDK: npcap-sdk-1.05
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+ GENERATOR: "Visual Studio 14 2015 Win64"
+ SDK: npcap-sdk-1.05
+ AIRPCAP: -DDISABLE_AIRPCAP=YES
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+ GENERATOR: "Visual Studio 15 2017"
+ SDK: WpdPack
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+ GENERATOR: "Visual Studio 15 2017 Win64"
+ SDK: WpdPack
+ AIRPCAP: -DDISABLE_AIRPCAP=YES
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+ GENERATOR: "Visual Studio 15 2017"
+ SDK: npcap-sdk-1.05
+ AIRPCAP: -DDISABLE_AIRPCAP=YES
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+ GENERATOR: "Visual Studio 15 2017 Win64"
+ SDK: npcap-sdk-1.05
+ AIRPCAP: -DDISABLE_AIRPCAP=YES
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+ GENERATOR: "Visual Studio 15 2017 Win64"
+ SDK: npcap-sdk-1.05
+ AIRPCAP: -DDISABLE_AIRPCAP=NO
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+ GENERATOR: "Visual Studio 16 2019"
+ PLATFORM: Win32
+ SDK: WpdPack
+ AIRPCAP: -DDISABLE_AIRPCAP=YES
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+ GENERATOR: "Visual Studio 16 2019"
+ PLATFORM: x64
+ SDK: WpdPack
+ AIRPCAP: -DDISABLE_AIRPCAP=YES
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+ GENERATOR: "Visual Studio 16 2019"
+ PLATFORM: Win32
+ SDK: npcap-sdk-1.05
+ AIRPCAP: -DDISABLE_AIRPCAP=YES
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+ GENERATOR: "Visual Studio 16 2019"
+ PLATFORM: x64
+ SDK: npcap-sdk-1.05
+ AIRPCAP: -DDISABLE_AIRPCAP=YES
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+ GENERATOR: "Visual Studio 16 2019"
+ PLATFORM: x64
+ SDK: npcap-sdk-1.05
+ AIRPCAP: -DDISABLE_AIRPCAP=NO
build_script:
#
@@ -32,5 +95,15 @@ build_script:
- type NUL >.devel
- md build
- cd build
- - cmake -DCMAKE_PREFIX_PATH=c:\projects\libpcap\Win32\%SDK% -G"%GENERATOR%" ..
- - msbuild /m /nologo /p:Configuration=Release pcap.sln
+ # Remove the default MinGW path
+ - if "%GENERATOR%"=="MinGW Makefiles" set PATH=%PATH:C:\MinGW\bin;=%
+ # Add the specified MinGW path
+ - if "%GENERATOR%"=="MinGW Makefiles" set PATH=%MINGW_ROOT%\mingw64\bin;%PATH%
+ # Remove the path to Git, so that we don't pick up its sh.exe, as
+ # that breaks MinGW builds - CMake checks for that and fails in the
+ # configuration stage
+ - if "%GENERATOR%"=="MinGW Makefiles" set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
+ - if NOT DEFINED PLATFORM cmake %AIRPCAP% -DPacket_ROOT=c:\projects\libpcap\Win32\%SDK% -G"%GENERATOR%" -DPacket_ROOT=c:\projects\libpcap\Win32\%SDK% -DPacket_ROOT=c:\projects\libpcap\Win32\%SDK% -G"%GENERATOR%" -DAirPcap_ROOT=c:\projects\libpcap\Win32\Airpcap_Devpack -G"%GENERATOR%" ..
+ - if DEFINED PLATFORM cmake %AIRPCAP% -DPacket_ROOT=c:\projects\libpcap\Win32\%SDK% -G"%GENERATOR%" -DPacket_ROOT=c:\projects\libpcap\Win32\%SDK% -DPacket_ROOT=c:\projects\libpcap\Win32\%SDK% -G"%GENERATOR%" -DAirPcap_ROOT=c:\projects\libpcap\Win32\Airpcap_Devpack -G"%GENERATOR%" -A %PLATFORM% ..
+ - if NOT "%GENERATOR%"=="MinGW Makefiles" msbuild /m /nologo /p:Configuration=Release pcap.sln
+ - if "%GENERATOR%"=="MinGW Makefiles" mingw32-make
diff --git a/.cirrus.yml b/.cirrus.yml
new file mode 100644
index 00000000..0f71d89f
--- /dev/null
+++ b/.cirrus.yml
@@ -0,0 +1,25 @@
+# The internal git client reads CIRRUS_CLONE_DEPTH.
+env:
+ CIRRUS_CLONE_DEPTH: 3
+ MAXJOBS: 2
+ IGNORE_OSVERSION: yes
+
+task:
+ freebsd_instance:
+ image_family: $IMAGE_FAMILY
+ env:
+ matrix:
+ - IMAGE_FAMILY: freebsd-11-4
+ - IMAGE_FAMILY: freebsd-12-2
+ - IMAGE_FAMILY: freebsd-13-0-snap
+ script:
+ - freebsd-version
+ - pkg install -qy autoconf
+ - touch .devel
+ - ./configure --enable-remote --prefix=/tmp
+ - make -s all
+ - make -s testprogs
+ - make install
+ - make releasetar
+ - testprogs/findalldevstest
+
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 00000000..b6547394
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,28 @@
+Assar Westerlund <assar@sics.se> assar <assar>
+Bill Fenner <fenner@gmail.com> fenner <fenner>
+Denis Ovsienko <denis@ovsienko.info> <infrastation@yandex.ru>
+Francois-Xavier Le Bail <devel.fx.lebail@orange.fr> fxlb <fx.lebail@yahoo.com>
+Francois-Xavier Le Bail <devel.fx.lebail@orange.fr> <fx.lebail@yahoo.com>
+Fulvio Risso <risso@polito.it> risso <risso>
+Gianluca Varenni <gianluca.varenni@gmail.com> gianluca <gianluca>
+Guy Harris <gharris@sonic.net> <gharris@localhost.localdomain>
+Guy Harris <gharris@sonic.net> <gharris@steve.local>
+Guy Harris <gharris@sonic.net> <gharris@ubu9-10.(none)>
+Guy Harris <gharris@sonic.net> <guy@alum.mit.edu>
+Guy Harris <gharris@sonic.net> Guy (Core OS) Harris <gharris@gharris.apple.com>
+Guy Harris <gharris@sonic.net> guy <guy>
+Hannes Gredler <hannes@gredler.at> hannes <hannes>
+Hannes Gredler <hannes@gredler.at> <hannes@juniper.net>
+Jun-ichiro itojun Hagino <itojun@iijlab.net> itojun <itojun>
+Ken Hornstein <kenh@cmf.nrl.navy.mil> kenh <kenh>
+Loris Degioanni <loris@netgroup-serv.polito.it> loris <loris>
+Michael Richardson <mcr@sandelman.ca> <mcr@credil.org>
+Michael Richardson <mcr@sandelman.ca> <mcr@finepoint.com>
+Michael Richardson <mcr@sandelman.ca> mcr <mcr>
+Michael Richardson <mcr@sandelman.ca> <mcr@sandelman.ottawa.on.ca>
+Michael Richardson <mcr@sandelman.ca> <mcr@tcpdump.org>
+Stephen Donnelly <stephen.donnelly@emulex.com> <sfd@nzhmlwks0033.(none)>
+Stephen Donnelly <stephen.donnelly@emulex.com> sfd <stephen.donnelly@emulex.com>
+Stephen Donnelly <stephen.donnelly@emulex.com> sfd <stephen.donnelly@endace.com>
+Stephen Donnelly <stephen.donnelly@emulex.com> <stephen.donnelly@endace.com>
+Torsten Landschoff <t.landschoff@gmx.net> torsten <torsten>
diff --git a/.travis.yml b/.travis.yml
index 086765fc..b840a66d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,14 +1,49 @@
-sudo: false
language: c
+#
+# Try building on these 4 architectures; all are 64-bit, and all but
+# "s390x", a/k/a z/Architecture, are little-endian.
+#
+arch:
+ - amd64
+ - ppc64le
+ - s390x
+ - arm64
+
os:
- linux
- osx
+dist: bionic
+
compiler:
- gcc
- clang
+#
+# Linux runs on all of the architectures listed above; macOS currently
+# runs only on 64-bit x86, although the Spaceshipologists are all in a
+# tizzy about the possibility of Arm-based Macs. Suppress the macOS
+# builds that don't work.
+#
+# In addition, with newer versions of macOS, Apple ships a "gcc" that's
+# just another front end to Clang, presumably for backwards
+# compatibility with build scripts etc. that expect the compiler to be
+# "gcc", so don't bother doing "gcc" builds on macOS.
+#
+jobs:
+ exclude:
+ - arch: ppc64le
+ os: osx
+ - arch: s390x
+ os: osx
+ - arch: arm64
+ os: osx
+ - compiler: gcc
+ os: osx
+
+cache: ccache
+
env:
global:
# encrypted COVERITY_SCAN_TOKEN from
@@ -16,10 +51,11 @@ env:
- secure: "SwNcek+I4lMVcnb5EGGmNm6ljWN6C/mnXzBr82a5rEQNKxAoJfdvvPpKIp0iEfg5j0PtYlcRHoIDyVZ/6QM/WEw0wrio9Z0cio9hkOS6kV8g2QouXfnoNtKJ5nNso7UD2GPJ9+M0GIR1GZ0Edvxr81sHlNAkpVKydYGBwCIMGyg="
# Coverity run condition (avoid matrix multiple runs), need customized
# build script. Need an update if new matrix cases.
- - coverity_scan_run_condition='"$TRAVIS_OS_NAME" = linux -a "$CC" = gcc -a "$REMOTE" = enable -a "$CMAKE" = no'
+ - coverity_scan_run_condition='"$TRAVIS_CPU_ARCH" = amd64 -a "$TRAVIS_OS_NAME" = linux -a "$CC" = gcc -a "$REMOTE" = enable -a "$CMAKE" = no'
# Coverity script test mode (if true no uploading, avoid reaching the quota)
# usual processing: false.
- coverity_scan_script_test_mode=false
+ - MAKEFLAGS='-j 2' # Travis CI VMs come with 2 cores
matrix:
- REMOTE=disable CMAKE=no
- ENABLE_REMOTE="" CMAKE=yes
@@ -49,8 +85,7 @@ addons:
branch_pattern: coverity_scan
apt:
packages:
- - libusb-1.0-0-dev
- - libdbus-glib-1-dev
+ - libdbus-1-dev
- libbluetooth-dev
- libnl-genl-3-dev
- libibverbs-dev
@@ -62,24 +97,39 @@ git:
before_install:
- uname -a
- date
+ - if [ "$TRAVIS_OS_NAME" = linux ]; then apt list --installed 'lib*-dev'; fi
install:
before_script:
script:
- - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then touch .devel configure; fi
- - if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$CMAKE" = no ]; then echo '$ ./configure [...]' && echo -n travis_fold:start:script.configure; fi
- - if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$CMAKE" = no ]; then ./configure --prefix=/tmp "--${REMOTE}-remote"; fi
- - if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$CMAKE" = yes ]; then mkdir build; fi
- - if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$CMAKE" = yes ]; then cd build; fi
- - if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$CMAKE" = yes ]; then cmake -DCMAKE_INSTALL_PREFIX=/tmp $ENABLE_REMOTE ..; fi
- - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then echo -n travis_fold:end:script.configure; fi
- - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -s all; fi
- - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -s testprogs; fi
- - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then echo '$ make install [...]' && echo -n travis_fold:start:script.make_install; fi
- - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then PATH=$PATH make install; fi
- - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then echo -n travis_fold:end:script.make_install; fi
- - if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$CMAKE" = no ]; then testprogs/findalldevstest; fi
- - if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$CMAKE" = yes ]; then run/findalldevstest; fi
- - if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$CMAKE" = no ]; then make releasetar; fi
+ - if [ "$COVERITY_SCAN_BRANCH" = 1 ]; then echo "Coverity build - nothing more to do"; exit 0; fi
+ - touch .devel configure
+ - if [ "$CMAKE" = no ]; then echo '$ ./configure [...]' && echo travis_fold:start:script.configure; fi
+ - if [ "$CMAKE" = no ]; then ./configure --prefix=/tmp "--${REMOTE}-remote"; fi
+ - if [ "$CMAKE" = no ]; then echo -n travis_fold:end:script.configure; fi
+ - if [ "$CMAKE" = yes ]; then mkdir build; fi
+ - if [ "$CMAKE" = yes ]; then cd build; fi
+ - if [ "$CMAKE" = yes ]; then echo travis_fold:start:script.cmake; fi
+ - if [ "$CMAKE" = yes ]; then cmake -DCMAKE_INSTALL_PREFIX=/tmp $ENABLE_REMOTE ..; fi
+ - if [ "$CMAKE" = yes ]; then echo -n travis_fold:end:script.cmake; fi
+ - make -s
+ - make -s testprogs
+ - echo '$ make install [...]' && echo travis_fold:start:script.make_install
+ - PATH=$PATH make install
+ - echo -n travis_fold:end:script.make_install
+ - if [ "$CMAKE" = no ]; then testprogs/findalldevstest; fi
+ - if [ "$CMAKE" = yes ]; then run/findalldevstest; fi
+ - if [ "$CMAKE" = no ]; then make releasetar; fi
+ - echo '$ cat Makefile [...]'; echo travis_fold:start:script.cat_makefile
+ - if [ "$CMAKE" = no ]; then cat Makefile | sed -n '1,/DO NOT DELETE THIS LINE -- mkdep uses it/p'; fi
+ - if [ "$CMAKE" = yes ]; then cat Makefile; fi
+ - echo -n travis_fold:end:script.cat_makefile
+ - echo '$ cat config.h'; echo travis_fold:start:script.cat_config_h
+ - cat config.h
+ - echo -n travis_fold:end:script.cat_config_h
+ - if [ "$CMAKE" = no ]; then echo '$ cat config.log'; echo travis_fold:start:script.cat_config_log; fi
+ - if [ "$CMAKE" = no ]; then cat config.log; fi
+ - if [ "$CMAKE" = no ]; then echo -n travis_fold:end:script.cat_config_log; fi
+ - if [ "$TRAVIS_OS_NAME" = osx ]; then sleep 10; fi
diff --git a/CHANGES b/CHANGES
index 89e739c4..4dd30f11 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,111 @@
+Tuesday, December 29, 2020
+ Summary for 1.10.0 libpcap release
+ Require, and assume, some level of C99 support in the C compiler
+ Require Visual Studio 2015 or later if using Visual Studio
+ Add support for capturing on DPDK devices
+ rpcap: support rpcap-over-TLS
+ Windows: report the system error for PacketSetHwFilter() failures
+ Label most APIs by the first release in which they're available
+ Add support for getting and setting packet time stamp types
+ with Npcap
+ Add pcap_init(), and add support for UTF-8 strings, including error
+ messages, on Windows
+ Improve man pages, including adding backward compatibility notes
+ Fix configure script issues, including with libnl on Linux
+ Fix CMake issues
+ Squelch complaints from Bison about "%define api.pure" being
+ deprecated
+ Fix some memory leaks, including in pcap_compile()
+ Linux: handle systems without AF_INET or AF_UNIX socket support
+ Catch invalid IPv4 addresses in filters
+ AIX: fix loading of BPF kernel extension
+ rpcapd: fix core dumps with invalid configuration file
+ Show special Linux BPF offsets symbolically in bpf_image() and
+ bpf_dump()
+ Add some overflow checks in the optimizer
+ Add pcap_datalink_val_to_description_or_dlt()
+ Windows: make the snapshot length work even if pcap_setfilter()
+ isn't called
+ Linux: get rid of Wireless Extensions for turning monitor mode on
+ Handle the pcap private data in a fashion that makes fewer
+ assumptions about memory layouts (might fix GitHub issue #940
+ on ARM)
+ Fix "unknown ether proto 'aarp'"
+ Fix some issues found by cppcheck.
+ Linux: proper memory sync for PACKET_MMAP (may prevent GitHub issue
+ #898)
+ Remove undocumented and rather old "ether proto" protocols
+ Fix some thread safety issues
+ Windows: add pcap_handle(), and deprecate pcap_fileno()
+ AirPcap: add AirPcap support in a module, rather than using
+ WinPcap/Npcap's support for it
+ Linux: drop support for libnl 1 and 2.
+ Linux: Require PF_PACKET support, and kernel 2.6.27 or later
+ Add DLT_LINUX_SLL2
+ Add a new filter "ifindex" for DLT_LINUX_SLL2 files and live
+ Linux captures
+ optimizer: add a hack to try to catch certain optimizer loops
+ (should prevent GitHub issue #112)
+ Probe CONFIGURATION descriptor of connected USB devices
+ macOS: cope with getting EPWROFF from SIOCGIFMEDIA
+ Linux: return error on interface going away, but not if it just went
+ down
+ Windows: fix compilation on Cygwin/MSYS
+ Linux: set socket protocol only after packet ring configured,
+ reducing bogus packet drop reports
+ pcap_findalldevs(): don't sort interfaces by unit number
+ Linux: get ifdrop stats from sysfs.
+ Fix various security issues reported by Charles Smith at Tangible
+ Security
+ Fix various security issues reported by Include Security
+ rpcapd: on UN*X, don't tell the client why authentication failed
+ Linux: when adjusting BPF programs, do not subtract the
+ SLL[2]_HDR_LEN if the location is negative (special metadata
+ offset)
+ Preserve references to metadata when adjusting the program;
+ see https://github.com/the-tcpdump-group/tcpdump/issues/480#issuecomment-486827278
+ Always return a list of supported time-stamp types, even if only
+ host time stamps are supported
+ Linux: with a timeout of zero, wait indefinitely
+ Linux: clean up support for some non-GNU libc C libraries
+ Increase the maximum snaplen for LINKTYPE_USBPCAP/DLT_USBPCAP
+ Fix handling of some ioctls that fail with "permission denied" even
+ when the ioctl isn't supported at all
+ Added support for ICMPv6 types 1-4 as tokens in filters
+ Windows: Report PCAP_ERROR_NO_SUCH_DEVICE for a non-existent device
+ Windows: return an appropriate error message for device removed or
+ device unusable due to a suspend/resume
+ BPF: treat both ENXIO (everybody but OpenBSD) and EIO (OpenBSD) as
+ meaning "the interface was removed"
+ BPF: report "the interface disappeared", not "the interface went
+ down", if the interface was removed during a capture
+ Linux, Windows: report a warning for unknown link-layer header types
+ Create the file in pcap_dump_open_append() if it doesn't exist
+ Linux, NPF: have pcap_breakloop() forcibly break out of a sleeping
+ capture loop
+ Report the DLT description in error messages
+ Linux: Add support for DSA data link types
+ Linux USB: use the snapshot length to set the buffer size, and set
+ the len field to reflect the length in the URB (GitHub issue
+ #808)
+ rpcapd: allow rpcapd to rebind more rapidly (GitHub issue #765)
+ Windows: clean up building DLL
+ Fix compilation of pcap-tc.c
+ Add Haiku pcap implementation
+ Windows: handle CRT mismatch for pcap_dump_fopen()
+ Windows: map NdisMediumWirelessWan to DLT_RAW
+ rpcap: add some new authentication libpcap error codes for
+ specific errors
+ rpcap: redo protocol version negotiation to avoid problems with old
+ servers (it still works with servers using the old negotiation,
+ as well as servers not supporting negotiation)
+ rpcap: error handling cleanups
+ rpcapd: fix some inetd issues
+ Don't assume ARM supports unaligned accesses
+ Remove (unused) SITA support here.
+ Correctly handle pcapng captures with more than one IDB with a
+ snspshot length greater than the supported maximum
+
Sunday, July 22, 2018
Summary for 1.9.1 libpcap release
Mention pcap_get_required_select_timeout() in the main pcap man page
@@ -93,7 +201,7 @@ Sunday, June 24, 2018, by mcr@sandelman.ca
Make VLAN filter handle both metadata and inline tags
D-Bus captures can now be up to 128MB in size
Added LORATAP DLT value
- Added DLT_VSOCK for http://qemu-project.org/Features/VirtioVsock
+ Added DLT_VSOCK for https://qemu-project.org/Features/VirtioVsock
probe_devices() fixes not to overrun buffer for name of device
Add linux-specific pcap_set_protocol_linux() to allow specifying a specific capture protocol.
RDMA sniffing support for pcap
@@ -275,7 +383,7 @@ Summary for 1.5.0 libpcap release
than the mcr repository
Checks added for malloc()/realloc()/etc. failures
Fixed build on Solaris 11
- Support filtering filtering E1 SS7 traffic on MTP2 layer Annex A
+ Support filtering E1 SS7 traffic on MTP2 layer Annex A
Use "ln -s" to link man pages by default
Add support for getting nanosecond-resolution time stamps when
capturing and reading capture files
@@ -336,7 +444,7 @@ Summary for 1.3.0 libpcap release
Friday December 9, 2011. guy@alum.mit.edu.
Summary for 1.2.1 libpcap release
Update README file.
- Fix typoes in README.linux file.
+ Fix typos in README.linux file.
Clean up some compiler warnings.
Fix Linux compile problems and tests for ethtool.h.
Treat Debian/kFreeBSD and GNU/Hurd as systems with GNU
@@ -369,7 +477,7 @@ Summary for 1.2 libpcap release
Noted real nature of LINKTYPE_ARCNET.
Add a link-layer type for DVB-CI.
Fix configure-script discovery of VLAN acceleration support.
- see http://netoptimizer.blogspot.com/2010/09/tcpdump-vs-vlan-tags.html
+ see https://netoptimizer.blogspot.com/2010/09/tcpdump-vs-vlan-tags.html
Linux, HP-UX, AIX, NetBSD and OpenBSD compilation/conflict fixes.
Protect against including AIX 5.x's <net/bpf.h> having been included.
Add DLT_DBUS, for raw D-Bus messages.
@@ -568,7 +676,7 @@ Tue. September 19, 2006. ken@xelerance.com. Summary for 0.9.5 libpcap release
beginning+link-layer
Add DLT/LINKTYPE for carrying FRF.16 Multi-link Frame Relay
Fix allocation of buffer for list of link-layer types
- Added a new DLT and LINKTYPE value for ARINC 653 Interpartition Communcation Messages
+ Added a new DLT and LINKTYPE value for ARINC 653 Interpartition Communication Messages
Fixed a typo in a DLT value: it should start with DLT_ and not LINKTYPE_
Redefined DLT_CAN20B and LINKTYPE_CAN20B as #190 (as this is the right value for CAN).
Added definition for DLT_A429 and LINKTYPE_A429 as #184.
@@ -682,7 +790,7 @@ Tuesday January 9, 2001. guy@alum.mit.edu. Summary for 0.6 release
Header files fixed to allow use in C++ programs.
- Removed dependancy on native headers for packet layout.
+ Removed dependency on native headers for packet layout.
Removed Linux specific headers that were shipped.
Security fixes: Strcpy replaced with strlcpy, sprintf replaced
@@ -820,7 +928,7 @@ v0.3 Sat Nov 30 20:56:27 PST 1996
v0.2.1 Sun Jul 14 03:02:26 PDT 1996
-- Fixes for HP-UX 10. Thanks in part to to Thomas Wolfram
+- Fixes for HP-UX 10. Thanks in part to Thomas Wolfram
(wolf@prz.tu-berlin.de) and Rick Jones (raj@hpisrdq.cup.hp.com)
- Added support for SINIX. Thanks to Andrej Borsenkow
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 55b93f14..50bf1713 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,11 @@
-cmake_minimum_required(VERSION 2.8.6)
+if(WIN32)
+ #
+ # We need 3.12 or later, so that we can set policy CMP0074; see
+ # below.
+ cmake_minimum_required(VERSION 3.12)
+else(WIN32)
+ cmake_minimum_required(VERSION 2.8.6)
+endif(WIN32)
#
# Apple doesn't build with an install_name starting with @rpath, and
@@ -9,44 +16,34 @@ if(POLICY CMP0042)
cmake_policy(SET CMP0042 OLD)
endif()
-set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules)
-
-project(pcap)
-
#
-# Try to enable as many C99 features as we can.
-# At minimum, we want C++/C99-style // comments.
+# Squelch noise about quoted strings in if() statements.
+# WE KNOW WHAT WE'RE DOING, WE'RE DOING EVERYTHING THE WAY THAT NEWER
+# VERSIONS OF CMAKE EXPECT BY DEFAULT, DON'T WASTE OUR TIME WITH NOISE.
#
-# Newer versions of compilers might default to supporting C99, but older
-# versions may require a special flag.
-#
-# Prior to CMake 3.1, setting CMAKE_C_STANDARD will not have any effect,
-# so, unless and until we require CMake 3.1 or later, we have to do it
-# ourselves on pre-3.1 CMake, so we just do it ourselves on all versions
-# of CMake.
-#
-# Note: with CMake 3.1 through 3.5, the only compilers for which CMake
-# handles CMAKE_C_STANDARD are GCC and Clang. 3.6 adds support only
-# for Intel C; 3.9 adds support for PGI C, Sun C, and IBM XL C, and
-# 3.10 adds support for Cray C and IAR C, but no version of CMake has
-# support for HP C. Therefore, even if we use CMAKE_C_STANDARD with
-# compilers for which CMake supports it, we may still have to do it
-# ourselves on other compilers.
+if(POLICY CMP0054)
+ cmake_policy(SET CMP0054 NEW)
+endif()
+
#
-# See the CMake documentation for the CMAKE_<LANG>_COMPILER_ID variables
-# for a list of compiler IDs.
+# We want find_file() and find_library() to honor {packagename}_ROOT,
+# as that appears to be the only way, with the Visual Studio 2019 IDE
+# and its CMake support, to tell CMake where to look for the Npcap
+# or WinPcap SDK.
#
-# We don't worry about MSVC; it doesn't have such a flag - either it
-# doesn't support the C99 features we need at all, or it supports them
-# regardless of the compiler flag.
+if(POLICY CMP0074)
+ cmake_policy(SET CMP0074 NEW)
+endif()
+
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules)
+
+project(pcap)
+
+include(CheckCCompilerFlag)
+
#
-# XXX - this just tests whether the option works and adds it if it does.
-# We don't test whether it's necessary in order to get the C99 features
-# that we use; if we ever have a user who tries to compile with a compiler
-# that can't be made to support those features, we can add a test to make
-# sure we actually *have* C99 support.
+# For checking if a compiler flag works and adding it if it does.
#
-include(CheckCCompilerFlag)
macro(check_and_add_compiler_option _option)
message(STATUS "Checking C compiler flag ${_option}")
string(REPLACE "=" "-" _temp_option_variable ${_option})
@@ -57,23 +54,103 @@ macro(check_and_add_compiler_option _option)
endif()
endmacro()
+#
+# If we're building with Visual Studio, we require Visual Studio 2015,
+# in order to get sufficient C99 compatibility. Check for that.
+#
+# If not, try the appropriate flag for the compiler to enable C99
+# features.
+#
set(C_ADDITIONAL_FLAGS "")
-if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR
- CMAKE_C_COMPILER_ID MATCHES "Clang")
- check_and_add_compiler_option("-std=gnu99")
-elseif(CMAKE_C_COMPILER_ID MATCHES "XL")
- #
- # We want support for extensions picked up for GNU C compatibility,
- # so we use -qlanglvl=extc99.
- #
- check_and_add_compiler_option("-qlanglvl=extc99")
-elseif(CMAKE_C_COMPILER_ID MATCHES "HP")
- check_and_add_compiler_option("-AC99")
-elseif(CMAKE_C_COMPILER_ID MATCHES "Sun")
- check_and_add_compiler_option("-xc99")
-elseif(CMAKE_C_COMPILER_ID MATCHES "Intel")
- check_and_add_compiler_option("-c99")
-endif()
+if(MSVC)
+ if(MSVC_VERSION LESS 1900)
+ message(FATAL_ERROR "Visual Studio 2015 or later is required")
+ endif()
+
+ #
+ # Treat source files as being in UTF-8 with MSVC if it's not using
+ # the Clang front end.
+ # We assume that UTF-8 source is OK with other compilers and with
+ # MSVC if it's using the Clang front end.
+ #
+ if(NOT ${CMAKE_C_COMPILER} MATCHES "clang*")
+ set(C_ADDITIONAL_FLAGS "${C_ADDITIONAL_FLAGS} /utf-8")
+ endif(NOT ${CMAKE_C_COMPILER} MATCHES "clang*")
+else(MSVC)
+ #
+ # For checking if a compiler flag works, failing if it doesn't,
+ # and adding it otherwise.
+ #
+ macro(require_and_add_compiler_option _option)
+ message(STATUS "Checking C compiler flag ${_option}")
+ string(REPLACE "=" "-" _temp_option_variable ${_option})
+ string(REGEX REPLACE "^-" "" _option_variable ${_temp_option_variable})
+ check_c_compiler_flag("${_option}" ${_option_variable})
+ if(${${_option_variable}})
+ set(C_ADDITIONAL_FLAGS "${C_ADDITIONAL_FLAGS} ${_option}")
+ else()
+ message(FATAL_ERROR "C99 support is required, but the compiler doesn't support a compiler flag to enable it")
+ endif()
+ endmacro()
+
+ #
+ # Try to enable as many C99 features as we can.
+ # At minimum, we want C++/C99-style // comments.
+ #
+ # Newer versions of compilers might default to supporting C99, but
+ # older versions may require a special flag.
+ #
+ # Prior to CMake 3.1, setting CMAKE_C_STANDARD will not have any effect,
+ # so, unless and until we require CMake 3.1 or later, we have to do it
+ # ourselves on pre-3.1 CMake, so we just do it ourselves on all versions
+ # of CMake.
+ #
+ # Note: with CMake 3.1 through 3.5, the only compilers for which CMake
+ # handles CMAKE_C_STANDARD are GCC and Clang. 3.6 adds support only
+ # for Intel C; 3.9 adds support for PGI C, Sun C, and IBM XL C, and
+ # 3.10 adds support for Cray C and IAR C, but no version of CMake has
+ # support for HP C. Therefore, even if we use CMAKE_C_STANDARD with
+ # compilers for which CMake supports it, we may still have to do it
+ # ourselves on other compilers.
+ #
+ # See the CMake documentation for the CMAKE_<LANG>_COMPILER_ID variables
+ # for a list of compiler IDs.
+ #
+ # XXX - this just tests whether the option works, fails if it doesn't,
+ # and adds it if it does. We don't test whether it's necessary in order
+ # to get the C99 features that we use, or whether, if it's used, it
+ # enables all the features that we require.
+ #
+ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR
+ CMAKE_C_COMPILER_ID MATCHES "Clang")
+ require_and_add_compiler_option("-std=gnu99")
+ elseif(CMAKE_C_COMPILER_ID MATCHES "XL")
+ #
+ # We want support for extensions picked up for GNU C compatibility,
+ # so we use -qlanglvl=extc99.
+ #
+ require_and_add_compiler_option("-qlanglvl=extc99")
+ elseif(CMAKE_C_COMPILER_ID MATCHES "HP")
+ require_and_add_compiler_option("-AC99")
+ elseif(CMAKE_C_COMPILER_ID MATCHES "Sun")
+ require_and_add_compiler_option("-xc99")
+ elseif(CMAKE_C_COMPILER_ID MATCHES "Intel")
+ require_and_add_compiler_option("-c99")
+ endif()
+endif(MSVC)
+
+#
+# If we're building with MinGW, we need to specify _WIN32_WINNT as
+# 0x0600 ("NT 6.0", a/k/a Vista/Windows Server 2008) in order to
+# get the full IPv6 API, including inet_ntop().
+#
+# NOTE: pcap does *NOT* work with msvcrt.dll; it must link with
+# a newer version of the C library, i.e. Visual Studio 2015 or
+# later, as it depends on C99 features introduced in VS 2015.
+#
+if(MINGW)
+ add_definitions(-D_WIN32_WINNT=0x0600)
+endif(MINGW)
#
# Build all runtimes in the top-level binary directory; that way,
@@ -107,9 +184,12 @@ if(WIN32)
endif(WIN32)
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
if(WIN32)
- set(PACKET_DLL_DIR "" CACHE PATH "Path to directory with include and lib subdirectories for packet.dll")
+ set(Packet_ROOT "" CACHE PATH "Path to directory with include and lib subdirectories for packet.dll")
+ set(AirPcap_ROOT "" CACHE PATH "Path to directory with include and lib subdirectories for airpcap.dll")
endif(WIN32)
+option(ENABLE_PROFILING "Enable code profiling" OFF)
+
# To pacify those who hate the protochain instruction
option(NO_PROTOCHAIN "Disable protochain instruction" OFF)
@@ -131,16 +211,19 @@ else()
endif(WIN32)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
- option(PCAP_SUPPORT_PACKET_RING "Enable Linux packet ring support" ON)
option(BUILD_WITH_LIBNL "Build with libnl" ON)
endif()
#
# Additional capture modules.
#
-option(DISABLE_USB "Disable USB sniffing support" OFF)
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ option(DISABLE_LINUX_USBMON "Disable Linux usbmon USB sniffing support" OFF)
+endif()
option(DISABLE_BLUETOOTH "Disable Bluetooth sniffing support" OFF)
option(DISABLE_NETMAP "Disable netmap support" OFF)
+option(DISABLE_DPDK "Disable DPDK support" OFF)
+
#
# We don't support D-Bus sniffing on macOS; see
#
@@ -231,15 +314,16 @@ if(WIN32)
cmake_push_check_state()
set(CMAKE_REQUIRED_LIBRARIES ${PACKET_LIBRARIES})
check_function_exists(PacketIsLoopbackAdapter HAVE_PACKET_IS_LOOPBACK_ADAPTER)
+ check_function_exists(PacketGetTimestampModes HAVE_PACKET_GET_TIMESTAMP_MODES)
cmake_pop_check_state()
endif(PACKET_FOUND)
message(STATUS "checking for Npcap's version.h")
check_symbol_exists(WINPCAP_PRODUCT_NAME "../../version.h" HAVE_VERSION_H)
if(HAVE_VERSION_H)
- message(STATUS "HAVE version.h")
+ message(STATUS "HAVE version.h")
else(HAVE_VERSION_H)
- message(STATUS "MISSING version.h")
+ message(STATUS "MISSING version.h")
endif(HAVE_VERSION_H)
endif(WIN32)
@@ -294,9 +378,7 @@ if(NOT WIN32)
check_include_file(sys/ioccom.h HAVE_SYS_IOCCOM_H)
check_include_file(sys/sockio.h HAVE_SYS_SOCKIO_H)
check_include_file(sys/select.h HAVE_SYS_SELECT_H)
-endif(NOT WIN32)
-check_include_file(limits.h HAVE_LIMITS_H)
-if(NOT WIN32)
+
check_include_file(netpacket/packet.h HAVE_NETPACKET_PACKET_H)
check_include_files("sys/types.h;sys/socket.h;net/if.h;net/pfvar.h" HAVE_NET_PFVAR_H)
if(HAVE_NET_PFVAR_H)
@@ -318,13 +400,6 @@ main(void)
HAVE_PF_NAT_THROUGH_PF_NORDR)
endif(HAVE_NET_PFVAR_H)
check_include_file(netinet/if_ether.h HAVE_NETINET_IF_ETHER_H)
- if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
- check_include_file(linux/sockios.h HAVE_LINUX_SOCKIOS_H)
- #
- # linux/if_bonding.h requires sys/socket.h.
- #
- check_include_files("sys/socket.h;linux/if_bonding.h" HAVE_LINUX_IF_BONDING_H)
- endif()
endif(NOT WIN32)
#
@@ -356,14 +431,28 @@ main(void)
endif(NOT HAVE_GNU_STRERROR_R)
else(HAVE_STRERROR_R)
#
- # We don't have strerror_r; do we have strerror_s?
+ # We don't have strerror_r; do we have _wcserror_s?
#
- check_function_exists(strerror_s HAVE_STRERROR_S)
+ check_function_exists(_wcserror_s HAVE__WCSERROR_S)
endif(HAVE_STRERROR_R)
+
+#
+# Make sure we have vsnprintf() and snprintf(); we require them.
+# We use check_symbol_exists(), as they aren't necessarily external
+# functions - in Visual Studio, for example, they're inline functions
+# calling a common external function.
+#
+check_symbol_exists(vsnprintf "stdio.h" HAVE_VSNPRINTF)
+if(NOT HAVE_VSNPRINTF)
+ message(FATAL_ERROR "vsnprintf() is required but wasn't found")
+endif(NOT HAVE_VSNPRINTF)
+check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF)
+if(NOT HAVE_SNPRINTF)
+ message(FATAL_ERROR "snprintf() is required but wasn't found")
+endif()
+
check_function_exists(strlcpy HAVE_STRLCPY)
check_function_exists(strlcat HAVE_STRLCAT)
-check_function_exists(snprintf HAVE_SNPRINTF)
-check_function_exists(vsnprintf HAVE_VSNPRINTF)
check_function_exists(asprintf HAVE_ASPRINTF)
check_function_exists(vasprintf HAVE_VASPRINTF)
check_function_exists(strtok_r HAVE_STRTOK_R)
@@ -433,10 +522,18 @@ else(WIN32)
#
set(PCAP_LINK_LIBRARIES socket nsl ${PCAP_LINK_LIBRARIES})
else(LIBSOCKET_HAS_GETADDRINFO)
- #
- # We didn't find it.
- #
- message(FATAL_ERROR "getaddrinfo is required, but wasn't found")
+ check_library_exists(network getaddrinfo "" LIBNETWORK_HAS_GETADDRINFO)
+ if(LIBNETWORK_HAS_GETADDRINFO)
+ #
+ # OK, we found it in libnetwork (Haiku).
+ #
+ set(PCAP_LINK_LIBRARIES network ${PCAP_LINK_LIBRARIES})
+ else(LIBNETWORK_HAS_GETADDRINFO)
+ #
+ # We didn't find it.
+ #
+ message(FATAL_ERROR "getaddrinfo is required, but wasn't found")
+ endif(LIBNETWORK_HAS_GETADDRINFO)
endif(LIBSOCKET_HAS_GETADDRINFO)
#
@@ -812,6 +909,125 @@ if(NOT WIN32)
endif(NOT CMAKE_USE_PTHREADS_INIT)
endif(NOT WIN32)
+if(ENABLE_PROFILING)
+ if(NOT MSVC)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg")
+ endif()
+endif()
+
+#
+# Based on
+#
+# https://github.com/commonmark/cmark/blob/master/FindAsan.cmake
+#
+# The MIT License (MIT)
+#
+# Copyright (c) 2013 Matthew Arsenault
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# Test if the each of the sanitizers in the ENABLE_SANITIZERS list are
+# supported by the compiler, and, if so, adds the appropriate flags to
+# CMAKE_C_FLAGS, CMAKE_CXX_FLAGS, and SANITIZER_FLAGS. If not, it fails.
+#
+# Do this last, in the hope that it will prevent configuration on Linux
+# from somehow deciding it doesn't need -lpthread when building rpcapd
+# (it does require it, but somehow, in some mysterious fashion that no
+# 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)
+ # 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})
+ if(${${sanitizer_variable}})
+ set(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fsanitize=${sanitizer}")
+ message(STATUS "${sanitizer} sanitizer supported using -fsanitizer=${sanitizer}")
+ else()
+ #
+ # Try the versions supported prior to Clang 3.2.
+ # If the sanitizer is "address", try -fsanitize-address.
+ # If it's "undefined", try -fcatch-undefined-behavior.
+ # Otherwise, give up.
+ #
+ set(sanitizer_variable "OLD_${sanitizer_variable}")
+ 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")
+ endif()
+ 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")
+ endif()
+ else()
+ message(FATAL_ERROR "${sanitizer} isn't a supported sanitizer")
+ endif()
+ endif()
+
+ unset(CMAKE_REQUIRED_FLAGS)
+endforeach()
+
+if(NOT "${SANITIZER_FLAGS}" STREQUAL "")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O1 -g ${SANITIZER_FLAGS} -fno-omit-frame-pointer -fno-optimize-sibling-calls")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O1 -g ${SANITIZER_FLAGS} -fno-omit-frame-pointer -fno-optimize-sibling-calls")
+endif()
+
+#
+# OpenSSL/libressl.
+#
+find_package(OpenSSL)
+if(OPENSSL_FOUND)
+ #
+ # We have OpenSSL.
+ #
+ include_directories(SYSTEM ${OPENSSL_INCLUDE_DIR})
+ set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${OPENSSL_LIBRARIES})
+ set(HAVE_OPENSSL YES)
+endif(OPENSSL_FOUND)
+
+#
+# Additional linker flags.
+#
+set(LINKER_FLAGS "${SANITIZER_FLAGS}")
+if(ENABLE_PROFILING)
+ if(MSVC)
+ set(LINKER_FLAGS " /PROFILE")
+ else()
+ set(LINKER_FLAGS " -pg")
+ endif()
+endif()
+
######################################
# Input files
######################################
@@ -834,52 +1050,16 @@ set(PROJECT_SOURCE_LIST_C
if(WIN32)
#
- # For now, we assume we don't have snprintf() or that it's not one
- # that behaves enough like C99's snprintf() for our purposes (i.e.,
- # it doesn't null-terminate the string if it truncates it to fit in
- # the buffer), so we have to provide our own (a wrapper around
- # _snprintf() that null-terminates the buffer).
+ # We add the character set conversion routines; they're Windows-only
+ # for now.
#
- # We also assume we don't have asprintf(), and provide an implementation
+ # We assume we don't have asprintf(), and provide an implementation
# that uses _vscprintf() to determine how big the string needs to be.
#
set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C}
- missing/win_snprintf.c missing/win_asprintf.c)
+ charconv.c missing/win_asprintf.c)
else()
- #
- # Either:
- #
- # we have snprintf() and vsnprintf(), and have asprintf() and
- # vasprintf();
- #
- # we have snprintf() and vsnprintf(), but don't have asprintf()
- # or vasprintf();
- #
- # we have neither snprintf() nor vsnprintf(), and don't have
- # asprintf() or vasprintf(), either.
- #
- # We assume that if we have asprintf() we have vasprintf(), as well
- # as snprintf() and vsnprintf(), and that if we have snprintf() we
- # have vsnprintf().
- #
- # For the first case, we don't need any replacement routines.
- # For the second case, we need replacement asprintf()/vasprintf()
- # routines.
- # For the third case, we need replacement snprintf()/vsnprintf() and
- # asprintf()/vasprintf() routines.
- #
- if(NOT HAVE_SNPRINTF)
- #
- # We assume we have none of them; missing/snprintf.c supplies
- # all of them.
- #
- set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} missing/snprintf.c)
- elif(NOT HAVE_ASPRINTF)
- #
- # We assume we have snprintf()/vsnprintf() but lack
- # asprintf()/vasprintf(); missing/asprintf.c supplies
- # the latter (using vsnprintf()).
- #
+ if(NOT HAVE_ASPRINTF)
set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} missing/asprintf.c)
endif()
if(NOT HAVE_STRLCAT)
@@ -985,6 +1165,7 @@ else()
check_include_file(linux/socket.h HAVE_LINUX_SOCKET_H)
check_include_file(net/raw.h HAVE_NET_RAW_H)
check_include_file(sys/dlpi.h HAVE_SYS_DLPI_H)
+ check_include_file(config/HaikuConfig.h HAVE_CONFIG_HAIKUCONFIG_H)
if(BPF_H_DEFINES_BIOCSETIF)
#
@@ -1028,6 +1209,11 @@ else()
# DLPI on pre-Solaris 11 SunOS 5, HP-UX, possibly others.
#
set(PCAP_TYPE dlpi)
+ elseif(HAVE_CONFIG_HAIKUCONFIG_H)
+ #
+ # Haiku.
+ #
+ set(PCAP_TYPE haiku)
else()
#
# Nothing we support.
@@ -1038,18 +1224,20 @@ else()
endif(WIN32)
message(STATUS "Packet capture mechanism type: ${PCAP_TYPE}")
+find_package(PkgConfig QUIET)
+
#
# Do capture-mechanism-dependent tests.
#
if(WIN32)
if(PCAP_TYPE STREQUAL "npf")
#
- # Link with packet.dll before WinSock2.
+ # Link with packet.dll before Winsock2.
#
set(PCAP_LINK_LIBRARIES ${PACKET_LIBRARIES} ${PCAP_LINK_LIBRARIES})
elseif(PCAP_TYPE STREQUAL "null")
else()
- message(ERROR "${PCAP_TYPE} is not a valid pcap type")
+ message(FATAL_ERROR "${PCAP_TYPE} is not a valid pcap type")
endif()
else(WIN32)
if(PCAP_TYPE STREQUAL "dlpi")
@@ -1109,70 +1297,34 @@ else(WIN32)
#
# Do we have libnl?
+ # We only want version 3. Version 2 was, apparently,
+ # short-lived, and version 1 is source and binary
+ # incompatible with version 3, and it appears that,
+ # these days, everybody's using version 3. We're
+ # not supporting older versions of the Linux kernel;
+ # let's drop support for older versions of libnl, too.
#
if(BUILD_WITH_LIBNL)
- #
- # Try libnl 3.x first.
- #
- cmake_push_check_state()
- set(CMAKE_REQUIRED_LIBRARIES nl-3)
- check_function_exists(nl_socket_alloc HAVE_LIBNL)
- cmake_pop_check_state()
- if(HAVE_LIBNL)
- #
- # Yes, we have libnl 3.x.
- #
- set(PCAP_LINK_LIBRARIES nl-genl-3 nl-3 ${PCAP_LINK_LIBRARIES})
- set(HAVE_LIBNL_3_x ON)
- set(HAVE_LIBNL_NLE ON)
- set(HAVE_LIBNL_SOCKETS ON)
- include_directories("/usr/include/libnl3")
+ pkg_check_modules(LIBNL libnl-3.0)
+ if(LIBNL_FOUND)
+ set(PCAP_LINK_LIBRARIES ${LIBNL_LIBRARIES} ${PCAP_LINK_LIBRARIES})
else()
- #
- # Try libnl 2.x.
- #
cmake_push_check_state()
- set(CMAKE_REQUIRED_LIBRARIES nl)
+ set(CMAKE_REQUIRED_LIBRARIES nl-3)
check_function_exists(nl_socket_alloc HAVE_LIBNL)
cmake_pop_check_state()
if(HAVE_LIBNL)
#
- # Yes, we have libnl 2.x.
- #
- set(PCAP_LINK_LIBRARIES nl-genl nl ${PCAP_LINK_LIBRARIES})
- set(HAVE_LIBNL_2_x ON)
- set(HAVE_LIBNL_NLE ON)
- set(HAVE_LIBNL_SOCKETS ON)
- else()
- #
- # No, we don't; do we have libnl 1.x?
+ # Yes, we have libnl 3.x.
#
- cmake_push_check_state()
- set(CMAKE_REQUIRED_LIBRARIES nl)
- check_function_exists(nl_handle_alloc HAVE_LIBNL)
- cmake_pop_check_state()
- if(HAVE_LIBNL)
- set(PCAP_LINK_LIBRARIES nl ${PCAP_LINK_LIBRARIES})
- endif()
+ set(PCAP_LINK_LIBRARIES nl-genl-3 nl-3 ${PCAP_LINK_LIBRARIES})
+ include_directories("/usr/include/libnl3")
endif()
endif()
+ else()
+ unset(HAVE_LIBNL CACHE) # check_function_exists stores results in cache
endif()
- check_include_file(linux/ethtool.h HAVE_LINUX_ETHTOOL_H)
-
- #
- # Checks to see if tpacket_stats is defined in linux/if_packet.h
- # If so then pcap-linux.c can use this to report proper statistics.
- #
- # XXX - there's no check_type() macro that's like check_type_size()
- # except that it only checks for the existence of the structure type,
- # so we use check_type_size() and ignore the size.
- #
- cmake_push_check_state()
- set(CMAKE_EXTRA_INCLUDE_FILES linux/if_packet.h)
- check_type_size("struct tpacket_stats" STRUCT_TPACKET_STATS)
- cmake_pop_check_state()
-
check_struct_has_member("struct tpacket_auxdata" tp_vlan_tci linux/if_packet.h HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI)
elseif(PCAP_TYPE STREQUAL "bpf")
#
@@ -1196,13 +1348,23 @@ else(WIN32)
check_type_size("struct BPF_TIMEVAL" STRUCT_BPF_TIMEVAL)
endif()
cmake_pop_check_state()
+ elseif(PCAP_TYPE STREQUAL "haiku")
+ #
+ # Check for some headers just in case.
+ #
+ check_include_files("net/if.h;net/if_dl.h;net/if_types.h" HAVE_NET_IF_TYPES_H)
+ set(PCAP_SRC pcap-${PCAP_TYPE}.cpp)
elseif(PCAP_TYPE STREQUAL "null")
else()
message(FATAL_ERROR "${PCAP_TYPE} is not a valid pcap type")
endif()
endif(WIN32)
-set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-${PCAP_TYPE}.c)
+if(NOT DEFINED PCAP_SRC)
+set(PCAP_SRC pcap-${PCAP_TYPE}.c)
+endif()
+
+set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} ${PCAP_SRC})
#
# Now figure out how we get a list of interfaces and addresses,
@@ -1308,11 +1470,13 @@ endif()
# Check for additional native sniffing capabilities.
#
-# Check for USB sniffing support on Linux.
-# On FreeBSD, it uses BPF, so we don't need to do anything special here.
-if(NOT DISABLE_USB)
- if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
- set(PCAP_SUPPORT_USB TRUE)
+#
+# Various Linux-specific mechanisms.
+#
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ # Check for usbmon USB sniffing support.
+ if(NOT DISABLE_LINUX_USBMON)
+ set(PCAP_SUPPORT_LINUX_USBMON TRUE)
set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-usb-linux.c)
set(LINUX_USB_MON_DEV /dev/usbmon)
#
@@ -1342,10 +1506,9 @@ if(NOT DISABLE_USB)
endif(HAVE_LINUX_COMPILER_H)
endif()
endif()
-endif()
-# Check for netfilter sniffing support.
-if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ #
+ # Check for netfilter sniffing support.
#
# Life's too short to deal with trying to get this to compile
# if you don't get the right types defined with
@@ -1401,6 +1564,48 @@ main(void)
endif(PCAP_SUPPORT_NETMAP)
endif()
+# Check for DPDK sniffing support
+if(NOT DISABLE_DPDK)
+ find_package(dpdk)
+ if(dpdk_FOUND)
+ #
+ # We include rte_bus.h, and older versions of DPDK didn't have
+ # it, so check for it.
+ #
+ # Also, we call rte_eth_dev_count_avail(), and older versions
+ # of DPDK didn't have it, so check for it.
+ #
+ cmake_push_check_state()
+ set(CMAKE_REQUIRED_INCLUDES ${dpdk_INCLUDE_DIRS})
+ check_include_file(rte_bus.h HAVE_RTE_BUS_H)
+ set(CMAKE_REQUIRED_LIBRARIES ${dpdk_LIBRARIES})
+ check_function_exists(rte_eth_dev_count_avail HAVE_RTE_ETH_DEV_COUNT_AVAIL)
+ cmake_pop_check_state()
+ if(HAVE_RTE_BUS_H AND HAVE_RTE_ETH_DEV_COUNT_AVAIL)
+ set(DPDK_C_FLAGS "-march=native")
+ set(DPDK_LIB dpdk rt m numa dl)
+ set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} ${DPDK_C_FLAGS})
+ include_directories(AFTER ${dpdk_INCLUDE_DIRS})
+ link_directories(AFTER ${dpdk_LIBRARIES})
+ set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${dpdk_LIBRARIES})
+ set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-dpdk.c)
+ set(PCAP_SUPPORT_DPDK TRUE)
+
+ #
+ # Check whether the rte_ether.h file defines
+ # struct ether_addr or struct rte_ether_addr.
+ #
+ # ("API compatibility? That's for losers!")
+ #
+ cmake_push_check_state()
+ set(CMAKE_REQUIRED_INCLUDES ${dpdk_INCLUDE_DIRS})
+ set(CMAKE_EXTRA_INCLUDE_FILES rte_ether.h)
+ check_type_size("struct rte_ether_addr" STRUCT_RTE_ETHER_ADDR)
+ cmake_pop_check_state()
+ endif()
+ endif()
+endif()
+
# Check for Bluetooth sniffing support
if(NOT DISABLE_BLUETOOTH)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
@@ -1439,9 +1644,11 @@ main(void)
endif(HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL)
endif(HAVE_BLUETOOTH_BLUETOOTH_H)
endif()
+else()
+ unset(PCAP_SUPPORT_BT_MONITOR CACHE)
endif()
-# Check for Bluetooth sniffing support
+# Check for D-Bus sniffing support
if(NOT DISABLE_DBUS)
#
# We don't support D-Bus sniffing on macOS; see
@@ -1451,7 +1658,6 @@ if(NOT DISABLE_DBUS)
if(APPLE)
message(FATAL_ERROR "Due to freedesktop.org bug 74029, D-Bus capture support is not available on macOS")
endif(APPLE)
- include(FindPkgConfig)
pkg_check_modules(DBUS dbus-1)
if(DBUS_FOUND)
set(PCAP_SUPPORT_DBUS TRUE)
@@ -1586,6 +1792,27 @@ if(NOT DISABLE_SNF)
endif()
endif()
+# Check for Riverbed AirPcap support.
+if(NOT DISABLE_AIRPCAP)
+ #
+ # Try to find the AirPcap header file and library.
+ #
+ find_package(AirPcap)
+
+ #
+ # Did we succeed?
+ #
+ if(AIRPCAP_FOUND)
+ #
+ # Yes.
+ #
+ include_directories(AFTER ${AIRPCAP_INCLUDE_DIRS})
+ set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-airpcap.c)
+ set(HAVE_AIRPCAP_API TRUE)
+ set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${AIRPCAP_LIBRARIES})
+ endif()
+endif()
+
# Check for Riverbed TurboCap support.
if(NOT DISABLE_TC)
#
@@ -1603,7 +1830,7 @@ if(NOT DISABLE_TC)
include_directories(AFTER ${TC_INCLUDE_DIRS})
set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-tc.c)
set(HAVE_TC_API TRUE)
- set(PCAP_LINK_LIBRARIES "${PCAP_LINK_LIBRARIES} ${TC_LIBRARIES} ${CMAKE_USE_PTHREADS_INIT} stdc++")
+ set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${TC_LIBRARIES} ${CMAKE_USE_PTHREADS_INIT} stdc++)
endif()
endif()
@@ -1629,7 +1856,7 @@ if(ENABLE_REMOTE)
check_struct_has_member("struct msghdr" msg_flags "ftmacros.h;sys/socket.h" HAVE_STRUCT_MSGHDR_MSG_FLAGS)
cmake_pop_check_state()
set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C}
- pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c)
+ pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c sslutils.c)
endif(ENABLE_REMOTE)
###################################################################
@@ -1698,6 +1925,20 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.devel OR EXISTS ${CMAKE_BINARY_DIR}/.deve
# structure members.
#
check_and_add_compiler_option(-wd4820)
+ #
+ # We do *not* care about every single place the compiler would
+ # have inserted Spectre mitigation if only we had told it to
+ # do so with /Qspectre. Maybe it's worth it, as that's in
+ # Bison-generated code that we don't control.
+ #
+ # XXX - add /Qspectre if that is really worth doing.
+ #
+ check_and_add_compiler_option(-wd5045)
+
+ #
+ # Treat all (remaining) warnings as errors.
+ #
+ check_and_add_compiler_option(-WX)
else()
#
# Other compilers, including MSVC with a Clang front end and
@@ -1705,21 +1946,23 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.devel OR EXISTS ${CMAKE_BINARY_DIR}/.deve
# they might support GCC-style -W options.
#
check_and_add_compiler_option(-Wall)
- check_and_add_compiler_option(-Wsign-compare)
- check_and_add_compiler_option(-Wmissing-prototypes)
- check_and_add_compiler_option(-Wstrict-prototypes)
- check_and_add_compiler_option(-Wshadow)
- check_and_add_compiler_option(-Wdeclaration-after-statement)
- check_and_add_compiler_option(-Wused-but-marked-unused)
- check_and_add_compiler_option(-Wdocumentation)
check_and_add_compiler_option(-Wcomma)
- check_and_add_compiler_option(-Wmissing-noreturn)
# Warns about safeguards added in case the enums are extended
# check_and_add_compiler_option(-Wcovered-switch-default)
- check_and_add_compiler_option(-Wmissing-variable-declarations)
- check_and_add_compiler_option(-Wunused-parameter)
+ check_and_add_compiler_option(-Wdocumentation)
check_and_add_compiler_option(-Wformat-nonliteral)
+ check_and_add_compiler_option(-Wmissing-noreturn)
+ check_and_add_compiler_option(-Wmissing-prototypes)
+ check_and_add_compiler_option(-Wmissing-variable-declarations)
+ check_and_add_compiler_option(-Wpointer-arith)
+ check_and_add_compiler_option(-Wpointer-sign)
+ check_and_add_compiler_option(-Wshadow)
+ check_and_add_compiler_option(-Wsign-compare)
+ check_and_add_compiler_option(-Wshorten-64-to-32)
+ check_and_add_compiler_option(-Wstrict-prototypes)
check_and_add_compiler_option(-Wunreachable-code)
+ check_and_add_compiler_option(-Wunused-parameter)
+ check_and_add_compiler_option(-Wused-but-marked-unused)
endif()
endif()
@@ -1816,6 +2059,27 @@ find_program(YACC_EXECUTABLE NAMES bison win_bison byacc yacc)
if(YACC_EXECUTABLE STREQUAL "YACC_EXECUTABLE-NOTFOUND")
message(FATAL_ERROR "Neither bison nor win_bison nor byacc nor yacc was found.")
endif()
+
+if(YACC_EXECUTABLE MATCHES "byacc" OR YACC_EXECUTABLE MATCHES "yacc")
+ #
+ # Berkeley YACC doesn't support "%define api.pure", so use
+ # "%pure-parser".
+ #
+ set(REENTRANT_PARSER "%pure-parser")
+else()
+ #
+ # Bison prior to 2.4(.1) doesn't support "%define api.pure", so use
+ # "%pure-parser".
+ #
+ execute_process(COMMAND ${YACC_EXECUTABLE} -V OUTPUT_VARIABLE bison_full_version)
+ string(REGEX MATCH "[1-9][0-9]*[.][1-9][0-9]*" bison_major_minor ${bison_full_version})
+ if (bison_major_minor VERSION_LESS "2.4")
+ set(REENTRANT_PARSER "%pure-parser")
+ else()
+ set(REENTRANT_PARSER "%define api.pure")
+ endif()
+endif()
+
message(STATUS "Parser generator: ${YACC_EXECUTABLE}")
#
@@ -1829,9 +2093,9 @@ if("${YACC_NAME}" STREQUAL "bison" OR "${YACC_NAME}" STREQUAL "win_bison")
endif()
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/grammar.c ${CMAKE_CURRENT_BINARY_DIR}/grammar.h
- SOURCE ${pcap_SOURCE_DIR}/grammar.y
- COMMAND ${YACC_EXECUTABLE} ${YACC_COMPATIBILITY_FLAG} -p pcap_ -o ${CMAKE_CURRENT_BINARY_DIR}/grammar.c -d ${pcap_SOURCE_DIR}/grammar.y
- DEPENDS ${pcap_SOURCE_DIR}/grammar.y
+ SOURCE ${pcap_BINARY_DIR}/grammar.y
+ COMMAND ${YACC_EXECUTABLE} ${YACC_COMPATIBILITY_FLAG} -p pcap_ -o ${CMAKE_CURRENT_BINARY_DIR}/grammar.c -d ${pcap_BINARY_DIR}/grammar.y
+ DEPENDS ${pcap_BINARY_DIR}/grammar.y
)
#
@@ -1939,6 +2203,11 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "SunOS" AND CMAKE_SYSTEM_VERSION MATCHES "5[.]
set(MAN_MISC_INFO 5)
set(MAN_DEVICES 7D)
endif()
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Haiku")
+ #
+ # Haiku needs _BSD_SOURCE for the _IO* macros because it doesn't use them.
+ #
+ add_definitions(-D_BSD_SOURCE)
endif()
source_group("Source Files" FILES ${PROJECT_SOURCE_LIST_C})
@@ -1969,7 +2238,7 @@ add_subdirectory(testprogs)
#
# See
#
-# http://public.kitware.com/pipermail/cmake/2013-August/055510.html
+# https://public.kitware.com/pipermail/cmake/2013-August/055510.html
#
add_custom_target(SerializeTarget
DEPENDS
@@ -2000,6 +2269,10 @@ if(BUILD_SHARED_LIBS)
#
set_target_properties(${LIBRARY_NAME} PROPERTIES
DEFINE_SYMBOL pcap_EXPORTS)
+ if(NOT "${LINKER_FLAGS}" STREQUAL "")
+ set_target_properties(${LIBRARY_NAME} PROPERTIES
+ LINK_FLAGS "${LINKER_FLAGS}")
+ endif()
endif(BUILD_SHARED_LIBS)
add_library(${LIBRARY_NAME}_static STATIC
@@ -2150,13 +2423,20 @@ if(APPLE AND "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "")
# for 32-bit x86 code and if and when Apple adds
# ARM-based Macs. (You're on your own for iOS etc.)
#
- # XXX - check whether we *can* build for i386 and, if not,
- # suggest that the user install the /usr/include headers if
- # they want to build fat.
+ # First, check whether we're building with OpenSSL.
+ # If so, don't bother trying to build fat.
#
- cmake_push_check_state()
- set(CMAKE_REQUIRED_FLAGS "-arch i386")
- check_c_source_compiles(
+ if(HAVE_OPENSSL)
+ set(X86_32_BIT_SUPPORTED NO)
+ set(OSX_LIBRARY_ARCHITECTURES "x86_64")
+ message(WARNING "We're assuming the OpenSSL libraries are 64-bit only, so we're not compiling for 32-bit x86")
+ else()
+ #
+ # Now, check whether we *can* build for i386.
+ #
+ cmake_push_check_state()
+ set(CMAKE_REQUIRED_FLAGS "-arch i386")
+ check_c_source_compiles(
"int
main(void)
{
@@ -2164,20 +2444,25 @@ main(void)
}
"
X86_32_BIT_SUPPORTED)
- cmake_pop_check_state()
- if(X86_32_BIT_SUPPORTED)
- set(OSX_LIBRARY_ARCHITECTURES "x86_64;i386")
- else()
- set(OSX_LIBRARY_ARCHITECTURES "x86_64")
- if(SYSTEM_VERSION_MAJOR LESS 18)
- #
- # Pre-Mojave; the command-line tools should be sufficient to
- # enable 32-bit x86 builds.
- #
- message(WARNING "Compiling for 32-bit x86 gives an error; try installing the command-line tools")
- else()
- message(WARNING "Compiling for 32-bit x86 gives an error; try installing the command-line tools and, after that, installing the /usr/include headers from the /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg package")
- endif()
+ cmake_pop_check_state()
+ if(X86_32_BIT_SUPPORTED)
+ set(OSX_LIBRARY_ARCHITECTURES "x86_64;i386")
+ else()
+ set(OSX_LIBRARY_ARCHITECTURES "x86_64")
+ #
+ # We can't build fat; suggest that the user install the
+ # /usr/include headers if they want to build fat.
+ #
+ if(SYSTEM_VERSION_MAJOR LESS 18)
+ #
+ # Pre-Mojave; the command-line tools should be sufficient to
+ # enable 32-bit x86 builds.
+ #
+ message(WARNING "Compiling for 32-bit x86 gives an error; try installing the command-line tools")
+ else()
+ message(WARNING "Compiling for 32-bit x86 gives an error; try installing the command-line tools and, after that, installing the /usr/include headers from the /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg package")
+ endif()
+ endif()
endif()
endif()
if(BUILD_SHARED_LIBS)
@@ -2195,6 +2480,12 @@ endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmakeconfig.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
######################################
+# Write out the grammar.y file
+######################################
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/grammar.y.in ${CMAKE_CURRENT_BINARY_DIR}/grammar.y @ONLY)
+
+######################################
# Install pcap library, include files, and man pages
######################################
@@ -2209,12 +2500,11 @@ set(LIBRARY_NAME_STATIC ${LIBRARY_NAME}_static)
function(install_manpage_symlink SOURCE TARGET MANDIR)
if(MINGW)
- find_program(LINK_EXECUTABLE ln)
- if(LINK_EXECUTABLE)
- set(LINK_COMMAND "\"${LINK_EXECUTABLE}\" \"-s\" \"${SOURCE}\" \"${TARGET}\"")
- else(LINK_EXECUTABLE)
- message(FATAL_ERROR "ln (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ln.html) not found.")
- endif(LINK_EXECUTABLE)
+ #
+ # If we haven't found an ln executable with MinGW, we don't try
+ # generating and installing the man pages, so if we get here,
+ # we've found that executable.
+ set(LINK_COMMAND "\"${LINK_EXECUTABLE}\" \"-s\" \"${SOURCE}\" \"${TARGET}\"")
else(MINGW)
set(LINK_COMMAND "\"${CMAKE_COMMAND}\" \"-E\" \"create_symlink\" \"${SOURCE}\" \"${TARGET}\"")
endif(MINGW)
@@ -2271,6 +2561,7 @@ set(MAN3PCAP_NOEXPAND
pcap_get_required_select_timeout.3pcap
pcap_get_selectable_fd.3pcap
pcap_geterr.3pcap
+ pcap_init.3pcap
pcap_inject.3pcap
pcap_is_swapped.3pcap
pcap_lib_version.3pcap
@@ -2312,19 +2603,19 @@ endif(NOT BUILD_SHARED_LIBS)
if(WIN32)
if(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
#
- # Install 64-bit code built with MSVC in the amd64 subdirectories,
+ # Install 64-bit code built with MSVC in the x64 subdirectories,
# as that's where it expects it to be.
#
install(TARGETS ${LIBRARY_NAME} ${LIBRARY_NAME_STATIC}
- RUNTIME DESTINATION bin/amd64
- LIBRARY DESTINATION lib/amd64
- ARCHIVE DESTINATION lib/amd64)
+ RUNTIME DESTINATION bin/x64
+ LIBRARY DESTINATION lib/x64
+ ARCHIVE DESTINATION lib/x64)
if(NOT MINGW)
install(FILES $<TARGET_FILE_DIR:${LIBRARY_NAME_STATIC}>/${LIBRARY_NAME_STATIC}.pdb
- DESTINATION bin/amd64 OPTIONAL)
+ DESTINATION bin/x64 OPTIONAL)
if(BUILD_SHARED_LIBS)
install(FILES $<TARGET_PDB_FILE:${LIBRARY_NAME}>
- DESTINATION bin/amd64 OPTIONAL)
+ DESTINATION bin/x64 OPTIONAL)
endif(BUILD_SHARED_LIBS)
endif(NOT MINGW)
else(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
@@ -2362,7 +2653,7 @@ if(NOT MSVC)
set(prefix ${CMAKE_INSTALL_PREFIX})
set(exec_prefix "\${prefix}")
set(includedir "\${prefix}/include")
- set(libdir "\${exec_prefix}/lib")
+ set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "OpenBSD" OR
@@ -2404,54 +2695,64 @@ if(NOT MSVC)
# For each section of the manual for which we have man pages
# that require macro expansion, do the expansion.
#
- set(MAN1 "")
- foreach(MANPAGE ${MAN1_NOEXPAND})
- set(MAN1 ${MAN1} ${CMAKE_CURRENT_SOURCE_DIR}/${MANPAGE})
- endforeach(MANPAGE)
- install(FILES ${MAN1} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
-
- set(MAN3PCAP "")
- foreach(MANPAGE ${MAN3PCAP_NOEXPAND})
- set(MAN3PCAP ${MAN3PCAP} ${CMAKE_CURRENT_SOURCE_DIR}/${MANPAGE})
- endforeach(MANPAGE)
- foreach(TEMPLATE_MANPAGE ${MAN3PCAP_EXPAND})
- string(REPLACE ".in" "" MANPAGE ${TEMPLATE_MANPAGE})
- configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY)
- set(MAN3PCAP ${MAN3PCAP} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE})
- endforeach(TEMPLATE_MANPAGE)
- install(FILES ${MAN3PCAP} DESTINATION ${CMAKE_INSTALL_MANDIR}/man3)
- install_manpage_symlink(pcap_datalink_val_to_name.3pcap pcap_datalink_val_to_description.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
- install_manpage_symlink(pcap_dump_open.3pcap pcap_dump_fopen.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
- install_manpage_symlink(pcap_findalldevs.3pcap pcap_freealldevs.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
- install_manpage_symlink(pcap_geterr.3pcap pcap_perror.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
- install_manpage_symlink(pcap_inject.3pcap pcap_sendpacket.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
- install_manpage_symlink(pcap_list_datalinks.3pcap pcap_free_datalinks.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
- install_manpage_symlink(pcap_list_tstamp_types.3pcap pcap_free_tstamp_types.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
- install_manpage_symlink(pcap_loop.3pcap pcap_dispatch.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
- install_manpage_symlink(pcap_major_version.3pcap pcap_minor_version.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
- install_manpage_symlink(pcap_next_ex.3pcap pcap_next.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
- install_manpage_symlink(pcap_open_dead.3pcap pcap_open_dead_with_tstamp_precision.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
- install_manpage_symlink(pcap_open_offline.3pcap pcap_open_offline_with_tstamp_precision.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
- install_manpage_symlink(pcap_open_offline.3pcap pcap_fopen_offline.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
- install_manpage_symlink(pcap_open_offline.3pcap pcap_fopen_offline_with_tstamp_precision.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
- install_manpage_symlink(pcap_tstamp_type_val_to_name.3pcap pcap_tstamp_type_val_to_description.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
- install_manpage_symlink(pcap_setnonblock.3pcap pcap_getnonblock.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
-
- set(MANFILE "")
- foreach(TEMPLATE_MANPAGE ${MANFILE_EXPAND})
- string(REPLACE ".manfile.in" ".${MAN_FILE_FORMATS}" MANPAGE ${TEMPLATE_MANPAGE})
- configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY)
- set(MANFILE ${MANFILE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE})
- endforeach(TEMPLATE_MANPAGE)
- install(FILES ${MANFILE} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_FILE_FORMATS})
-
- set(MANMISC "")
- foreach(TEMPLATE_MANPAGE ${MANMISC_EXPAND})
- string(REPLACE ".manmisc.in" ".${MAN_MISC_INFO}" MANPAGE ${TEMPLATE_MANPAGE})
- configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY)
- set(MANMISC ${MANMISC} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE})
- endforeach(TEMPLATE_MANPAGE)
- install(FILES ${MANMISC} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_MISC_INFO})
+ # If this is MinGW, maybe we have a UN*X-style ln command and
+ # maybe we don't. (No, we do *NOT* require MSYS!) If we don't
+ # have it, don't do the man pages.
+ #
+ if(MINGW)
+ find_program(LINK_EXECUTABLE ln)
+ endif(MINGW)
+ if(UNIX OR (MINGW AND LINK_EXECUTABLE))
+ set(MAN1 "")
+ foreach(MANPAGE ${MAN1_NOEXPAND})
+ set(MAN1 ${MAN1} ${CMAKE_CURRENT_SOURCE_DIR}/${MANPAGE})
+ endforeach(MANPAGE)
+ install(FILES ${MAN1} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
+
+ set(MAN3PCAP "")
+ foreach(MANPAGE ${MAN3PCAP_NOEXPAND})
+ set(MAN3PCAP ${MAN3PCAP} ${CMAKE_CURRENT_SOURCE_DIR}/${MANPAGE})
+ endforeach(MANPAGE)
+ foreach(TEMPLATE_MANPAGE ${MAN3PCAP_EXPAND})
+ string(REPLACE ".in" "" MANPAGE ${TEMPLATE_MANPAGE})
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY)
+ set(MAN3PCAP ${MAN3PCAP} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE})
+ endforeach(TEMPLATE_MANPAGE)
+ install(FILES ${MAN3PCAP} DESTINATION ${CMAKE_INSTALL_MANDIR}/man3)
+ install_manpage_symlink(pcap_datalink_val_to_name.3pcap pcap_datalink_val_to_description.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+ install_manpage_symlink(pcap_datalink_val_to_name.3pcap pcap_datalink_val_to_description_or_dlt.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+ install_manpage_symlink(pcap_dump_open.3pcap pcap_dump_fopen.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+ install_manpage_symlink(pcap_findalldevs.3pcap pcap_freealldevs.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+ install_manpage_symlink(pcap_geterr.3pcap pcap_perror.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+ install_manpage_symlink(pcap_inject.3pcap pcap_sendpacket.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+ install_manpage_symlink(pcap_list_datalinks.3pcap pcap_free_datalinks.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+ install_manpage_symlink(pcap_list_tstamp_types.3pcap pcap_free_tstamp_types.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+ install_manpage_symlink(pcap_loop.3pcap pcap_dispatch.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+ install_manpage_symlink(pcap_major_version.3pcap pcap_minor_version.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+ install_manpage_symlink(pcap_next_ex.3pcap pcap_next.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+ install_manpage_symlink(pcap_open_dead.3pcap pcap_open_dead_with_tstamp_precision.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+ install_manpage_symlink(pcap_open_offline.3pcap pcap_open_offline_with_tstamp_precision.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+ install_manpage_symlink(pcap_open_offline.3pcap pcap_fopen_offline.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+ install_manpage_symlink(pcap_open_offline.3pcap pcap_fopen_offline_with_tstamp_precision.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+ install_manpage_symlink(pcap_tstamp_type_val_to_name.3pcap pcap_tstamp_type_val_to_description.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+ install_manpage_symlink(pcap_setnonblock.3pcap pcap_getnonblock.3pcap ${CMAKE_INSTALL_MANDIR}/man3)
+
+ set(MANFILE "")
+ foreach(TEMPLATE_MANPAGE ${MANFILE_EXPAND})
+ string(REPLACE ".manfile.in" ".${MAN_FILE_FORMATS}" MANPAGE ${TEMPLATE_MANPAGE})
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY)
+ set(MANFILE ${MANFILE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE})
+ endforeach(TEMPLATE_MANPAGE)
+ install(FILES ${MANFILE} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_FILE_FORMATS})
+
+ set(MANMISC "")
+ foreach(TEMPLATE_MANPAGE ${MANMISC_EXPAND})
+ string(REPLACE ".manmisc.in" ".${MAN_MISC_INFO}" MANPAGE ${TEMPLATE_MANPAGE})
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY)
+ set(MANMISC ${MANMISC} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE})
+ endforeach(TEMPLATE_MANPAGE)
+ install(FILES ${MANMISC} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_MISC_INFO})
+ endif(UNIX OR (MINGW AND LINK_EXECUTABLE))
endif(NOT MSVC)
# uninstall target
diff --git a/CREDITS b/CREDITS
index f7abc1f3..d01e8322 100644
--- a/CREDITS
+++ b/CREDITS
@@ -3,29 +3,42 @@ This file lists people who have contributed to libpcap.
The current maintainers (in alphabetical order):
Denis Ovsienko <denis at ovsienko dot info>
Francois-Xavier Le Bail <devel dot fx dot lebail at orange dot fr>
- Guy Harris <guy at alum dot mit dot edu>
+ Guy Harris <gharris at sonic dot net>
Michael Richardson <mcr at sandelman dot ottawa dot on dot ca>
Additional people who have contributed patches (in alphabetical order):
+ Adrian Budau <adbudau at bitdefender dot com>
Akos Vandra <axos88 at gmail dot com>
Alan Bawden <Alan at LCS dot MIT dot EDU>
Albert Chin <china at thewrittenword dot com>
+ Alexander Galanin <al at galanin dot nnov dot ru>
Alexander 'Leo' Bergolth <Leo dot Bergolth at wu-wien dot ac dot at>
Alexey Kuznetsov <kuznet at ms2 dot inr dot ac dot ru>
+ Alex Smith <44322503+MadAlexUK at users dot noreply dot github dot com>
+ Alfredo Alvarez Fernandez <alfredoalvarezernandez at gmail dot com>
Ali Abdulkadir <autostart dot ini at gmail dot com>
Alon Bar-Lev <alonbl at sourceforge dot net>
+ Anders Broman <anders dot broman at ericsson dot com>
Andres Perera <andres dot p at zoho dot com>
Andrew Brown <atatat at atatdot dot net>
<andy-1 at sourceforge dot net>
Ani Sinha <ani at aristanetworks dot com>
+ Anthony Kirby <Anthony dot Kirby at nominet dot uk>
Antti Kantee <pooka at netbsd dot org>
Arien Vijn <arienvijn at sourceforge dot net>
Arkadiusz Miskiewicz <misiek at pld dot org dot pl>
Armando L. Caro Jr. <acaro at mail dot eecis dot udel dot edu>
Assar Westerlund <assar at sics dot se>
+ Atzm Watanabe <atzm at atzm dot org>
+ Baptiste Peugnez <baptiste dot peugnez at cea dot fr>
+ Baruch Siach <baruch at tkos dot co dot il>
Bill Parker <wp02855 at gmail dot com>
+ blazeable <blazeable at blazeable dot eu>
+ bleader <bleader at ratonland dot org>
Brent Cook <brent at boundary dot com>
Brian Ginsbach <ginsbach at cray dot com>
+ B. Scott Michel <scooter dot phd at gmail dot com>
+ Cedric Cellier <rixed at happyleptic dot org>
Charles M. Hannum <mycroft at netbsd dot org>
Chris G. Demetriou <cgd at netbsd dot org>
Chris Lightfoot <cwrl at users dot sourceforge dot net>
@@ -34,15 +47,22 @@ Additional people who have contributed patches (in alphabetical order):
Christian Bell <csbell at myri dot com>
Christian Peron <csjp at freebsd dot org>
Christian Svensson <blue at cmd dot nu>
+ Christopher K Lee <christopher dot lee at cspi dot com>
+ Daniel Borkmann <dborkman at redhat dot com>
Daniele Orlandi <daniele at orlandi dot com>
+ Daniel Lublin <daniel at lublin dot se>
+ Daniel Miller <dmiller at nmap dot org>
+ Dario Lombardo <lomato at gmail dot com>
Darren Lim <darren dot lim at endace dot com>
Darren Reed <darrenr at sun dot com>
+ Dave Barach <dave at barachs dot net>
David Clark <david dot clark at datasoft dot com>
David Kaelbling <drk at sgi dot com>
David Ward <david dot ward at ll dot mit dot edu>
David Young <dyoung at ojctech dot com>
Dean Gaudet <dean at arctic dot org>
dhruv <rsrivat at sourceforge dot net>
+ Dmytro Ovdiienko <dmitriy dot ovdienko at gmail dot com>
Don Ebright <Don dot Ebright at compuware dot com>
Dug Song <dugsong at monkey dot org>
Dustin Spicuzza <dustin at virtualroadside dot com>
@@ -50,8 +70,12 @@ Additional people who have contributed patches (in alphabetical order):
Edward Sheldrake <ejs1920 at sourceforge dot net>
Eric Anderson <anderse at hpl dot hp dot com>
Erik de Castro Lopo <erik dot de dot castro dot lopo at sensorynetworks dot com>
+ Fedor Sakharov <fedor dot sakharov at gmail dot com>
+ Felix Janda <felix dot janda at posteo dot de>
Felix Obenhuber <felix at obenhuber dot de>
Florent Drouin <Florent dot Drouin at alcatel-lucent dot fr>
+ Florian Fainelli <f dot fainelli at gmail dot com>
+ François Revol <revol at free dot fr>
Franz Schaefer <schaefer at mond dot at>
frederich <frederich at sourceforge dot net>
Fulko Hew <fulko dot hew at gmail dot com>
@@ -59,6 +83,7 @@ Additional people who have contributed patches (in alphabetical order):
Gabor Tatarka <gabor dot tatarka at ericsson dot com>
Garrett Cooper <yaberauneya at sourceforge dot net>
George Neville-Neil <gnn at freebsd dot org>
+ Gerald Combs <gerald at zing dot org>
Gerard Garcia <nouboh at gmail dot com>
Gianluca Varenni <gianluca dot varenni at gmail dot com>
Gilbert Hoyek <gil_hoyek at hotmail dot com>
@@ -71,47 +96,64 @@ Additional people who have contributed patches (in alphabetical order):
Gustavo Zacarias <gustavo at zacarias dot com dot ar>
Hagen Paul Pfeifer <hagen at jauu dot net>
Henri Doreau <hdoreau at sourceforge dot net>
+ Hiroaki KAWAI <kawai at stratosphere dot co dot jp>
Hyung Sik Yoon <hsyn at kr dot ibm dot com>
Igor Khristophorov <igor at atdot dot org>
+ Jakub Sitnicki <jsitnicki at gmail dot com>
Jakub Zawadzki <darkjames at darkjames dot pl>
+ James Ko <jck at exegin dot com>
Jan-Philip Velders <jpv at veldersjes dot net>
Jason R. Thorpe <thorpej at netbsd dot org>
Javier Achirica <achirica at ttd dot net>
Jean-Louis Charton <Jean-Louis dot CHARTON at oikialog dot com>
Jean Tourrilhes <jt at hpl dot hp dot com>
Jefferson Ogata <jogata at nodc dot noaa dot gov>
+ Jerome Duval <jerome dot duval at gmail dot com>
Jesper Dangaard Brouer <hawk at comx dot dk>
Jesper Peterson <jesper at endace dot com>
Jesse Gross <jesse at nicira dot com>
+ JHA <jon dot anderson at oracle dot com>
+ jingyu yang <jingleyang at users dot noreply dot github dot com>
Jiri Slaby <jirislaby at gmail dot com>
+ João Valverde <joao dot valverde at tecnico dot ulisboa dot pt>
Joerg Mayer <jmayer at loplof dot de>
John Bankier <jbankier at rainfinity dot com>
Jon Lindgren <jonl at yubyub dot net>
Jon Smirl <jonsmirl at gmail dot com>
Jorge Boncompte [DTI2] <jorge at dti2 dot net>
+ jromanr <jromanr at hotmail dot com>
Juergen Schoenwaelder <schoenw at ibr dot cs dot tu-bs dot de>
Julien Moutinho <julm at savines dot alpes dot fr dot eu dot org>
Jung-uk Kim <jkim at FreeBSD dot org>
Kazushi Sugyo <sugyo at pb dot jp dot nec dot com>
+ Kevin Boulain <kevin dot boulain at securactive dot net>
Klaus Klein <kleink at netbsd dot org>
Koryn Grant <koryn at endace dot com>
Kris Katterjohn <katterjohn at gmail dot com>
Krzysztof Halasa <khc at pm dot waw dot pl>
Lennert Buytenhek <buytenh at wantstofly dot org>
+ lixiaoyan <lixiaoyan at google dot com>
Lorenzo Cavallaro <sullivan at sikurezza dot org>
Loris Degioanni <loris at netgroup-serv dot polito dot it>
Love Hörnquist-Åstrand <lha at stacken dot kth dot se>
Luis MartinGarcia <luis dot mgarc at gmail dot com>
+ lxy <391861737 at qq dot com>
Maciej W. Rozycki <macro at ds2 dot pg dot gda dot pl>
Mansour Behabadi <mansour at oxplot dot com>
Marcus Felipe Pereira <marcus at task dot com dot br>
+ Mario J. Rugiero <mrugiero at gmail dot com>
Mark C. Brown <mbrown at hp dot com>
Mark Johnston <markjdb at gmail dot com>
+ Mark Marshall <mark dot marshall at omicronenergy dot com>
Mark Pizzolato <List-tcpdump-workers at subscriptions dot pizzolato dot net>
Markus Mayer <markus_mayer at sourceforge dot net>
Martin Husemann <martin at netbsd dot org>
Márton Németh <nm127 at freemail dot hu>
+ Matt Eaton <agnosticdev at gmail dot com>
Matthew Luckie <mjl at luckie dot org dot nz>
+ Matthias Hannig <matthias at hannig dot cc>
+ Matwey V. Kornilov <matwey dot kornilov at gmail dot com>
+ maxice8 <thinkabit dot ukim at gmail dot com>
Max Laier <max at love2party dot net>
Michal Kubecek <mkubecek at suse dot cz>
Michal Labedzki <michal dot labedzki at tieto dot com>
@@ -119,25 +161,36 @@ Additional people who have contributed patches (in alphabetical order):
Mike Frysinger <vapier at gmail dot com>
Mike Kershaw <dragorn at kismetwireless dot net>
Mike Wiacek <mike at iroot dot net>
+ Milosz Kaniewski <milosz dot kaniewski at gmail dot com>
Miroslav Lichvar <mlichvar at redhat dot com>
Monroe Williams <monroe at pobox dot com>
+ Myricom Help <myri at users dot noreply dot github dot com>
+ Nan Xiao <nan at chinadtrace dot org>
+ Nick Kelsey <nickk at silicondust dot com>
Nicolas Dade <ndade at nsd dot dyndns dot org>
Niko Delarich <niko dot delarich at gmail dot com>
N. Leiten <nleiten at sourceforge dot net>
+ nnposter <nnposter at users dot noreply dot github dot com>
<nvercamm at sourceforge dot net>
Octavian Cerna <tavy at ylabs dot com>
Olaf Kirch <okir at caldera dot de>
Ollie Wild <aaw at users dot sourceforge dot net>
+ Ondřej Hošek <ondra dot hosek at gmail dot com>
Onno van der Linden <onno at simplex dot nl>
+ Orgad Shaneh <orgad dot shaneh at audiocodes dot com>
+ Ørjan Malde <red at foxi dot me>
Paolo Abeni <pabeni at redhat dot com>
Patrick Marie <mycroft at virgaria dot org>
Patrick McHardy <kaber at trash not net>
Paul Mundt <lethal at linux-sh dot org>
Pavel Kankovsky <kan at dcit dot cz>
+ Pawel Brzezinski <pawel dot brzezinski at harman dot com>
Pawel Pokrywka <publicpp at gmail dot com>
Peter Fales <peter at fales-lorenz dot net>
Peter Jeremy <peter dot jeremy at alcatel dot com dot au>
Peter Volkov <pva at gentoo dot org>
+ Petr Vorel <pvorel at suse dot cz>
+ Philippe Antoine <contact at catenacyber dot fr>
Phil Wood <cpw at lanl dot gov>
Rafal Maszkowski <rzm at icm dot edu dot pl>
<rcb-isis at users dot sourceforge dot net>
@@ -145,9 +198,9 @@ Additional people who have contributed patches (in alphabetical order):
Rick Jones <raj at cup dot hp dot com>
Robert Edmonds <stu-42 at sourceforge dot net>
Roberto Mariani <jelot-tcpdump at jelot dot it>
- Rongxi Li <rongxi dot li at chaitin dot com>
Roland Dreier <roland at purestorage dot com>
Romain Francoise <rfrancoise at debian dot org>
+ Rongxi Li <rongxi dot li at chaitin dot com>
Sagun Shakya <sagun dot shakya at sun dot com>
Scott Barron <sb125499 at ohiou dot edu>
Scott Gifford <sgifford at tir dot com>
@@ -156,22 +209,37 @@ Additional people who have contributed patches (in alphabetical order):
Sebastien Roy <Sebastien dot Roy at Sun dot COM>
Sepherosa Ziehau <sepherosa at gmail dot com>
Shaun Clowes <delius at progsoc dot uts dot edu dot au>
+ solofox <wensg100 at sina dot com>
Solomon Peachy <pizza at shaftnet dot org>
Stefan Hudson <hudson at mbay dot net>
Stephen Donnelly <stephen at endace dot com>
+ Steve Karg <skarg at users dot sourceforge dot net>
+ stubbfel <stubbfel at gmail dot com>
Takashi Yamamoto <yamt at mwd dot biglobe dot ne dot jp>
Tanaka Shin-ya <zstanaka at archer dot livedoor dot com>
+ Thomas Habets <habets at google dot com>
+ Thomas Petazzoni <thomas dot petazzoni at free-electrons dot com>
Tobias Poschwatta <posch at sourceforge dot net>
+ Tomasz Moń <desowin at gmail dot com>
+ Tommy Beadle <tbeadle at arbor dot net>
Tony Li <tli at procket dot com>
Torsten Landschoff <torsten at debian dot org>
+ Tymoteusz Blazejczyk <tymoteusz dot blazejczyk at intel dot com>
Uns Lider <unslider at miranda dot org>
Uwe Girlich <Uwe dot Girlich at philosys dot de>
+ Vitaly Lavrov <vel21ripn at gmail dot com>
+ Vivien Didelot <vivien dot didelot at gmail dot com>
+ Vladimir Gladkov <vovkos at gmail dot com>
+ Vladimir Marek <vlmarek at volny dot cz>
+ Walter Schell <walterschell at users dot noreply dot github dot com>
Wesley Shields <wxs at FreeBSD dot org>
Xianjie Zhang <xzhang at cup dot hp dot com>
Xin Li <delphij at FreeBSD dot org>
Xue Jiang Qing <xuejianqing at star-net dot cn>
+ Yang Luo <hsluoyz at qq dot com>
Yen Yen Lim
Yoann Vandoorselaere <yoann at prelude-ids dot org>
+ Yogesh Prasad <yogesh dot prasad at rockwellcollins dot com>
Yvan Vanhullebus <vanhu at sourceforge dot net>
The original LBL crew:
diff --git a/INSTALL.md b/INSTALL.md
index 3a303fe0..ba8b8f92 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -41,8 +41,8 @@ You will need either Bison, Berkeley YACC, or a version of YACC
compatible with them (if any exist), to build libpcap. The configure
script will abort if there isn't any such program. If you don't have
any such program, the current version of Bison can be found at
-http://ftp.gnu.org/gnu/bison/ and the current version of Berkeley YACC
-can be found at http://invisible-island.net/byacc/.
+https://ftp.gnu.org/gnu/bison/ and the current version of Berkeley YACC
+can be found at https://invisible-island.net/byacc/.
Sometimes the stock C compiler does not interact well with Flex and
Bison. The list of problems includes undefined references for alloca.
@@ -188,7 +188,7 @@ If you use SINIX, you should be able to build libpcap from this
release. It is known to compile and run on SINIX-Y/N 5.42 with the C-DS
V1.0 or V1.1 compiler. But note that in some releases of SINIX, yacc
emits incorrect code; if grammar.y fails to compile, change every
-occurence of:
+occurrence of:
#ifdef YYDEBUG
@@ -206,7 +206,7 @@ it appears that completely new code would need to be written to capture
network traffic. SCO do not appear to provide tcpdump binaries for
OpenServer 5 or OpenServer 6 as part of SCO Skunkware:
- http://www.sco.com/skunkware/
+ http://www.sco.com/skunkware/
If you use UnixWare, you might be able to build libpcap from this
release, or you might not. We do not have a machine running UnixWare,
@@ -221,7 +221,7 @@ a Sun4, your version of Bison is broken. In any case version 1.16 or
higher is recommended (1.14 is known to cause problems 1.16 is known to
work). Either pick up a current version from:
- http://ftp.gnu.org/gnu/bison/
+ https://ftp.gnu.org/gnu/bison/
or hack around it by inserting the lines:
@@ -248,105 +248,104 @@ config and boot the new kernel.
FILES
-----
-CHANGES - description of differences between releases
-ChmodBPF/* - macOS startup item to set ownership and permissions
- on /dev/bpf*
-CMakeLists.txt - CMake file
-CONTRIBUTING - guidelines for contributing
-CREDITS - people that have helped libpcap along
-INSTALL.md - this file
-LICENSE - the license under which tcpdump is distributed
-Makefile.in - compilation rules (input to the configure script)
-README.md - description of distribution
-doc/README.aix - notes on using libpcap on AIX
-doc/README.dag - notes on using libpcap to capture on Endace DAG devices
-doc/README.hpux - notes on using libpcap on HP-UX
-doc/README.linux.md - notes on using libpcap on Linux
-doc/README.macos - notes on using libpcap on macOS
-doc/README.septel - notes on using libpcap to capture on Intel/Septel devices
-doc/README.sita - notes on using libpcap to capture on SITA devices
-doc/README.tru64 - notes on using libpcap on Digital/Tru64 UNIX
-doc/README.Win32 - notes on using libpcap on Win32 systems (with Npcap)
-VERSION - version of this release
-acconfig.h - support for post-2.13 autoconf
-aclocal.m4 - autoconf macros
-arcnet.h - ARCNET definitions
-atmuni31.h - ATM Q.2931 definitions
-bpf_dump.c - BPF program printing routines
-bpf_filter.c - BPF filtering routines
-bpf_image.c - BPF disassembly routine
-config.guess - autoconf support
-config.h.in - autoconf input
-config.sub - autoconf support
-configure - configure script (run this first)
-configure.ac - configure script source
-dlpisubs.c - DLPI-related functions for pcap-dlpi.c and pcap-libdlpi.c
-dlpisubs.h - DLPI-related function declarations
-etherent.c - /etc/ethers support routines
-ethertype.h - Ethernet protocol types and names definitions
-fad-getad.c - pcap_findalldevs() for systems with getifaddrs()
-fad-gifc.c - pcap_findalldevs() for systems with only SIOCGIFLIST
-fad-glifc.c - pcap_findalldevs() for systems with SIOCGLIFCONF
-filtertest.c - test program for BPF compiler
-findalldevstest.c - test program for pcap_findalldevs()
-gencode.c - BPF code generation routines
-gencode.h - BPF code generation definitions
-grammar.y - filter string grammar
-ieee80211.h - 802.11 definitions
-install-sh - BSD style install script
-lbl/os-*.h - OS-dependent defines and prototypes
-llc.h - 802.2 LLC SAP definitions
-missing/* - replacements for missing library functions
-mkdep - construct Makefile dependency list
-msdos/* - drivers for MS-DOS capture support
-nametoaddr.c - hostname to address routines
-nlpid.h - OSI network layer protocol identifier definitions
-net - symlink to bpf/net
-optimize.c - BPF optimization routines
-pcap/bluetooth.h - public definition of DLT_BLUETOOTH_HCI_H4_WITH_PHDR header
-pcap/bpf.h - BPF definitions
-pcap/namedb.h - public libpcap name database definitions
-pcap/pcap.h - public libpcap definitions
-pcap/sll.h - public definition of DLT_LINUX_SLL header
-pcap/usb.h - public definition of DLT_USB header
-pcap-bpf.c - BSD Packet Filter support
-pcap-bpf.h - header for backwards compatibility
-pcap-bt-linux.c - Bluetooth capture support for Linux
-pcap-bt-linux.h - Bluetooth capture support for Linux
-pcap-dag.c - Endace DAG device capture support
-pcap-dag.h - Endace DAG device capture support
-pcap-dlpi.c - Data Link Provider Interface support
-pcap-dos.c - MS-DOS capture support
-pcap-dos.h - headers for MS-DOS capture support
-pcap-enet.c - enet support
-pcap-int.h - internal libpcap definitions
-pcap-libdlpi.c - Data Link Provider Interface support for systems with libdlpi
-pcap-linux.c - Linux packet socket support
-pcap-namedb.h - header for backwards compatibility
-pcap-nit.c - SunOS Network Interface Tap support
-pcap-nit.h - SunOS Network Interface Tap definitions
-pcap-npf.c - WinPcap capture support
-pcap-null.c - dummy monitor support (allows offline use of libpcap)
-pcap-pf.c - Ultrix and Digital/Tru64 UNIX Packet Filter support
-pcap-pf.h - Ultrix and Digital/Tru64 UNIX Packet Filter definitions
-pcap-septel.c - Intel/Septel device capture support
-pcap-septel.h - Intel/Septel device capture support
-pcap-sita.c - SITA device capture support
-pcap-sita.h - SITA device capture support
-pcap-sita.html - SITA device capture documentation
-pcap-stdinc.h - includes and #defines for compiling on Win32 systems
-pcap-snit.c - SunOS 4.x STREAMS-based Network Interface Tap support
-pcap-snoop.c - IRIX Snoop network monitoring support
-pcap-usb-linux.c - USB capture support for Linux
-pcap-usb-linux.h - USB capture support for Linux
-pcap.3pcap - manual entry for the library
-pcap.c - pcap utility routines
-pcap.h - header for backwards compatibility
-pcap_*.3pcap - manual entries for library functions
-pcap-filter.4 - manual entry for filter syntax
-pcap-linktype.4 - manual entry for link-layer header types
-ppp.h - Point to Point Protocol definitions
-savefile.c - offline support
-scanner.l - filter string scanner
-sunatmpos.h - definitions for SunATM capturing
-Win32 - headers and routines for building on Win32 systems
+ CHANGES - description of differences between releases
+ ChmodBPF/* - macOS startup item to set ownership and permissions on /dev/bpf*
+ CMakeLists.txt - CMake file
+ CONTRIBUTING.md - guidelines for contributing
+ CREDITS - people that have helped libpcap along
+ INSTALL.md - this file
+ LICENSE - the license under which tcpdump is distributed
+ Makefile.in - compilation rules (input to the configure script)
+ README.md - description of distribution
+ doc/README.aix - notes on using libpcap on AIX
+ doc/README.dag - notes on using libpcap to capture on Endace DAG devices
+ doc/README.hpux - notes on using libpcap on HP-UX
+ doc/README.linux.md - notes on using libpcap on Linux
+ doc/README.macos - notes on using libpcap on macOS
+ doc/README.septel - notes on using libpcap to capture on Intel/Septel devices
+ doc/README.sita - notes on using libpcap to capture on SITA devices
+ doc/README.tru64 - notes on using libpcap on Digital/Tru64 UNIX
+ doc/README.Win32.md - notes on using libpcap on Win32 systems (with Npcap)
+ VERSION - version of this release
+ acconfig.h - support for post-2.13 autoconf
+ aclocal.m4 - autoconf macros
+ arcnet.h - ARCNET definitions
+ atmuni31.h - ATM Q.2931 definitions
+ bpf_dump.c - BPF program printing routines
+ bpf_filter.c - BPF filtering routines
+ bpf_image.c - BPF disassembly routine
+ config.guess - autoconf support
+ config.h.in - autoconf input
+ config.sub - autoconf support
+ configure - configure script (run this first)
+ configure.ac - configure script source
+ dlpisubs.c - DLPI-related functions for pcap-dlpi.c and pcap-libdlpi.c
+ dlpisubs.h - DLPI-related function declarations
+ etherent.c - /etc/ethers support routines
+ ethertype.h - Ethernet protocol types and names definitions
+ fad-getad.c - pcap_findalldevs() for systems with getifaddrs()
+ fad-gifc.c - pcap_findalldevs() for systems with only SIOCGIFLIST
+ fad-glifc.c - pcap_findalldevs() for systems with SIOCGLIFCONF
+ filtertest.c - test program for BPF compiler
+ findalldevstest.c - test program for pcap_findalldevs()
+ gencode.c - BPF code generation routines
+ gencode.h - BPF code generation definitions
+ grammar.y - filter string grammar
+ ieee80211.h - 802.11 definitions
+ install-sh - BSD style install script
+ lbl/os-*.h - OS-dependent defines and prototypes
+ llc.h - 802.2 LLC SAP definitions
+ missing/* - replacements for missing library functions
+ mkdep - construct Makefile dependency list
+ msdos/* - drivers for MS-DOS capture support
+ nametoaddr.c - hostname to address routines
+ nlpid.h - OSI network layer protocol identifier definitions
+ net - symlink to bpf/net
+ optimize.c - BPF optimization routines
+ pcap/bluetooth.h - public definition of DLT_BLUETOOTH_HCI_H4_WITH_PHDR header
+ pcap/bpf.h - BPF definitions
+ pcap/namedb.h - public libpcap name database definitions
+ pcap/pcap.h - public libpcap definitions
+ pcap/sll.h - public definitions of DLT_LINUX_SLL and DLT_LINUX_SLL2 headers
+ pcap/usb.h - public definition of DLT_USB header
+ pcap-bpf.c - BSD Packet Filter support
+ pcap-bpf.h - header for backwards compatibility
+ pcap-bt-linux.c - Bluetooth capture support for Linux
+ pcap-bt-linux.h - Bluetooth capture support for Linux
+ pcap-dag.c - Endace DAG device capture support
+ pcap-dag.h - Endace DAG device capture support
+ pcap-dlpi.c - Data Link Provider Interface support
+ pcap-dos.c - MS-DOS capture support
+ pcap-dos.h - headers for MS-DOS capture support
+ pcap-enet.c - enet support
+ pcap-int.h - internal libpcap definitions
+ pcap-libdlpi.c - Data Link Provider Interface support for systems with libdlpi
+ pcap-linux.c - Linux packet socket support
+ pcap-namedb.h - header for backwards compatibility
+ pcap-nit.c - SunOS Network Interface Tap support
+ pcap-nit.h - SunOS Network Interface Tap definitions
+ pcap-npf.c - Npcap capture support
+ pcap-null.c - dummy monitor support (allows offline use of libpcap)
+ pcap-pf.c - Ultrix and Digital/Tru64 UNIX Packet Filter support
+ pcap-pf.h - Ultrix and Digital/Tru64 UNIX Packet Filter definitions
+ pcap-septel.c - Intel/Septel device capture support
+ pcap-septel.h - Intel/Septel device capture support
+ pcap-sita.c - SITA device capture support
+ pcap-sita.h - SITA device capture support
+ pcap-sita.html - SITA device capture documentation
+ pcap-stdinc.h - includes and #defines for compiling on Win32 systems
+ pcap-snit.c - SunOS 4.x STREAMS-based Network Interface Tap support
+ pcap-snoop.c - IRIX Snoop network monitoring support
+ pcap-usb-linux.c - USB capture support for Linux
+ pcap-usb-linux.h - USB capture support for Linux
+ pcap.3pcap - manual entry for the library
+ pcap.c - pcap utility routines
+ pcap.h - header for backwards compatibility
+ pcap_*.3pcap - manual entries for library functions
+ pcap-filter.4 - manual entry for filter syntax
+ pcap-linktype.4 - manual entry for link-layer header types
+ ppp.h - Point to Point Protocol definitions
+ savefile.c - offline support
+ scanner.l - filter string scanner
+ sunatmpos.h - definitions for SunATM capturing
+ Win32 - headers and routines for building on Win32 systems
diff --git a/METADATA b/METADATA
index e62c7cb6..2f80bb86 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://github.com/the-tcpdump-group/libpcap/archive/libpcap-1.9.1.tar.gz"
+ value: "https://github.com/the-tcpdump-group/libpcap/archive/libpcap-1.10.0.tar.gz"
}
- version: "libpcap-1.9.1"
+ version: "libpcap-1.10.0"
license_type: RESTRICTED
last_upgrade_date {
- year: 2020
- month: 4
- day: 24
+ year: 2021
+ month: 1
+ day: 5
}
}
diff --git a/Makefile.in b/Makefile.in
index 5a6b165d..d8b8507b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -38,6 +38,7 @@ mandir = @mandir@
# VPATH
srcdir = @srcdir@
+top_srcdir = @top_srcdir@
VPATH = @srcdir@
#
@@ -70,6 +71,7 @@ EXTRA_NETWORK_LIBS=@EXTRA_NETWORK_LIBS@
# Standard CFLAGS for building members of a shared library
FULL_CFLAGS = $(CCOPT) @V_LIB_CCOPT_FAT@ $(SHLIB_CCOPT) $(INCLS) $(DEFS) $(CFLAGS)
+CXXFLAGS = $(CCOPT) @V_LIB_CCOPT_FAT@ $(SHLIB_CCOPT) $(INCLS) $(DEFS) $(CFLAGS)
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -86,21 +88,29 @@ YACC = @YACC@
@rm -f $@
$(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c
-PSRC = pcap-@V_PCAP@.c @USB_SRC@ @BT_SRC@ @BT_MONITOR_SRC@ @NETFILTER_SRC@ @DBUS_SRC@ @NETMAP_SRC@ @RDMA_SRC@
-FSRC = @V_FINDALLDEVS@
-SSRC = @SSRC@
-CSRC = pcap.c gencode.c optimize.c nametoaddr.c etherent.c \
- fmtutils.c \
- savefile.c sf-pcap.c sf-pcapng.c pcap-common.c \
- bpf_image.c bpf_filter.c bpf_dump.c
-GENSRC = scanner.c grammar.c
+PLATFORM_C_SRC = @PLATFORM_C_SRC@
+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 \
+ savefile.c sf-pcap.c sf-pcapng.c pcap-common.c \
+ bpf_image.c bpf_filter.c bpf_dump.c
+GENERATED_C_SRC = scanner.c grammar.c
LIBOBJS = @LIBOBJS@
-SRC = $(PSRC) $(FSRC) $(CSRC) $(SSRC) $(GENSRC)
+SRC = $(PLATFORM_C_SRC) $(PLATFORM_CXX_SRC) \
+ $(MODULE_C_SRC) $(REMOTE_C_SRC) $(COMMON_C_SRC) \
+ $(GENERATED_C_SRC)
# We would like to say "OBJ = $(SRC:.c=.o)" but Ultrix's make cannot
-# hack the extra indirection
-OBJ = $(PSRC:.c=.o) $(FSRC:.c=.o) $(CSRC:.c=.o) $(SSRC:.c=.o) $(GENSRC:.c=.o) $(LIBOBJS)
+# hack the extra indirection, and we have to handle PLATFORM_CXX_SRC
+# differently from the defines for C source
+OBJ = $(PLATFORM_C_SRC:.c=.o) $(PLATFORM_CXX_SRC:.cpp=.o) \
+ $(MODULE_C_SRC:.c=.o) $(REMOTE_C_SRC:.c=.o) $(COMMON_C_SRC:.c=.o) \
+ $(GENERATED_C_SRC:.c=.o) \
+ $(LIBOBJS)
+
PUBHDR = \
pcap.h \
pcap-bpf.h \
@@ -154,7 +164,7 @@ TAGFILES = \
$(SRC) $(HDR)
CLEANFILES = $(OBJ) libpcap.a libpcap.so.`cat $(srcdir)/VERSION` \
- $(PROG)-`cat $(srcdir)/VERSION`.tar.gz $(GENSRC) $(GENHDR) \
+ $(PROG)-`cat $(srcdir)/VERSION`.tar.gz $(GENERATED_C_SRC) $(GENHDR) \
lex.yy.c pcap-config libpcap.pc
MAN1 = pcap-config.1
@@ -193,6 +203,7 @@ MAN3PCAP_NOEXPAND = \
pcap_get_required_select_timeout.3pcap \
pcap_get_selectable_fd.3pcap \
pcap_geterr.3pcap \
+ pcap_init.3pcap \
pcap_inject.3pcap \
pcap_is_swapped.3pcap \
pcap_lib_version.3pcap \
@@ -246,10 +257,13 @@ EXTRA_DIST = \
TODO \
VERSION \
aclocal.m4 \
+ charconv.c \
+ charconv.h \
chmod_bpf \
cmake_uninstall.cmake.in \
cmakeconfig.h.in \
cmake/Modules/FindDAG.cmake \
+ cmake/Modules/Finddpdk.cmake \
cmake/Modules/FindFseeko.cmake \
cmake/Modules/FindLFS.cmake \
cmake/Modules/FindPacket.cmake \
@@ -266,7 +280,7 @@ EXTRA_DIST = \
fad-getad.c \
fad-gifc.c \
fad-glifc.c \
- grammar.y \
+ grammar.y.in \
install-sh \
lbl/os-aix4.h \
lbl/os-aix7.h \
@@ -280,12 +294,10 @@ EXTRA_DIST = \
missing/asprintf.c \
missing/getopt.c \
missing/getopt.h \
- missing/snprintf.c \
missing/strlcat.c \
missing/strlcpy.c \
missing/strtok_r.c \
missing/win_asprintf.c \
- missing/win_snprintf.c \
mkdep \
msdos/bin2c.c \
msdos/makefile \
@@ -298,6 +310,8 @@ EXTRA_DIST = \
msdos/readme.dos \
nomkdep \
org.tcpdump.chmod_bpf.plist \
+ pcap-airpcap.c \
+ pcap-airpcap.h \
pcap-bpf.c \
pcap-bt-linux.c \
pcap-bt-linux.h \
@@ -312,7 +326,10 @@ EXTRA_DIST = \
pcap-dlpi.c \
pcap-dos.c \
pcap-dos.h \
+ pcap-dpdk.c \
+ pcap-dpdk.h \
pcap-enet.c \
+ pcap-haiku.cpp \
pcap-int.h \
pcap-libdlpi.c \
pcap-linux.c \
@@ -367,6 +384,8 @@ EXTRA_DIST = \
rpcapd/win32-svc.h \
sockutils.c \
sockutils.h \
+ sslutils.c \
+ sslutils.h \
scanner.l \
testprogs/CMakeLists.txt \
testprogs/Makefile.in \
@@ -374,12 +393,23 @@ EXTRA_DIST = \
testprogs/capturetest.c \
testprogs/filtertest.c \
testprogs/findalldevstest.c \
+ testprogs/findalldevstest-perf.c \
+ testprogs/fuzz/CMakeLists.txt \
+ testprogs/fuzz/fuzz_both.c \
+ testprogs/fuzz/fuzz_both.options \
+ testprogs/fuzz/fuzz_filter.c \
+ testprogs/fuzz/fuzz_filter.options \
+ testprogs/fuzz/fuzz_pcap.c \
+ testprogs/fuzz/fuzz_pcap.options \
+ testprogs/fuzz/onefile.c \
testprogs/opentest.c \
testprogs/reactivatetest.c \
testprogs/selpolltest.c \
testprogs/threadsignaltest.c \
testprogs/unix.h \
testprogs/valgrindtest.c \
+ testprogs/visopts.py \
+ testprogs/writecaptest.c \
tests/shb-option-too-long.pcapng \
Win32/Prj/wpcap.sln \
Win32/Prj/wpcap.vcxproj \
@@ -480,7 +510,26 @@ scanner.h: scanner.c
scanner.o: scanner.c grammar.h
$(CC) $(FULL_CFLAGS) -c scanner.c
-grammar.c: $(srcdir)/grammar.y
+#
+# Generate the grammar.y file.
+#
+# Some Makes, e.g. AIX Make and Solaris Make, can't handle "--file=$@.tmp:$<";
+# for example, the Solaris 9 make man page says
+#
+# Because make assigns $< and $* as it would for implicit rules
+# (according to the suffixes list and the directory contents),
+# they may be unreliable when used within explicit target entries.
+#
+# and this is an explicit target entry.
+#
+# Therefore, instead of using $<, we explicitly put in $(srcdir)/libpcap.pc.in.
+#
+grammar.y: $(srcdir)/grammar.y.in ./config.status
+ @rm -f $@ $@.tmp
+ ./config.status --file=$@.tmp:$(srcdir)/grammar.y.in
+ mv $@.tmp $@
+
+grammar.c: grammar.y
$(YACC) -p pcap_ -o grammar.c -d $<
grammar.h: grammar.c
## Recover from the removal of $@
@@ -528,7 +577,6 @@ libpcap.pc: $(srcdir)/libpcap.pc.in ./config.status
@rm -f $@ $@.tmp
./config.status --file=$@.tmp:$(srcdir)/libpcap.pc.in
mv $@.tmp $@
- chmod a+x $@
#
# Generate the pcap-config script. See above.
@@ -695,6 +743,7 @@ uninstall: uninstall-shared uninstall-rpcapd
for i in $(MAN3PCAP); do \
rm -f $(DESTDIR)$(mandir)/man3/$$i; done
rm -f $(DESTDIR)$(mandir)/man3/pcap_datalink_val_to_description.3pcap
+ rm -f $(DESTDIR)$(mandir)/man3/pcap_datalink_val_to_description_or_dlt.3pcap
rm -f $(DESTDIR)$(mandir)/man3/pcap_dump_fopen.3pcap
rm -f $(DESTDIR)$(mandir)/man3/pcap_freealldevs.3pcap
rm -f $(DESTDIR)$(mandir)/man3/pcap_perror.3pcap
@@ -745,7 +794,7 @@ clean:
cd testprogs; $(MAKE) clean
distclean: clean
- rm -f Makefile config.cache config.log config.status \
+ rm -f Makefile grammar.y config.cache config.log config.status \
config.h gnuc.h net os-proto.h libpcap.pc \
pcap-config stamp-h stamp-h.in
rm -f $(MAN3PCAP_EXPAND:.in=) $(MANFILE:.in=) $(MANMISC:.in=)
@@ -760,15 +809,23 @@ tags: $(TAGFILES)
ctags -wtd $(TAGFILES)
releasetar:
- @cwd=`pwd` ; dir=`basename $$cwd` ; name=$(PROG)-`cat VERSION` ; \
+ @autoreconf -f; \
+ name=$(PROG)-`cat VERSION` ; \
mkdir $$name; \
- tar -c --exclude='*~' -f - $(CSRC) $(HDR) $(MAN1) $(MAN3PCAP_EXPAND) \
- $(MAN3PCAP_NOEXPAND) $(MANFILE) $(MANMISC) $(EXTRA_DIST) | \
+ tar -c --exclude='*~' -f - $(COMMON_C_SRC) $(HDR) $(MAN1) \
+ $(MAN3PCAP_EXPAND) $(MAN3PCAP_NOEXPAND) $(MANFILE) \
+ $(MANMISC) $(EXTRA_DIST) | \
(cd $$name; tar xf -); \
tar -c -z -f $$name.tar.gz $$name; \
rm -rf $$name
-depend: $(GENSRC) $(GENHDR)
- $(MKDEP) -c "$(CC)" -m "$(DEPENDENCY_CFLAG)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC)
+rc1 rc2 rc3 rc4 rc5:
+ @VER=`cat $(srcdir)/VERSION`; \
+ sed -i "s/$$VER/$${VER}$@/" VERSION ; \
+ make releasetar; \
+ git checkout VERSION
+
+depend: $(GENERATED_C_SRC) $(GENHDR)
+ $(MKDEP) -c "$(CC)" -m "$(DEPENDENCY_CFLAG)" -s "$(srcdir)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC)
cd rpcapd; $(MAKE) depend
cd testprogs; $(MAKE) depend
diff --git a/README.md b/README.md
index 78cc3c4b..1e3a245b 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,30 @@
+LIBPCAP 1.x.y
+=============
+
+[![Build Status](https://travis-ci.org/the-tcpdump-group/tcpdump.svg?branch=master)](https://travis-ci.org/the-tcpdump-group/libpcap)
+
+[![Build Status](https://ci.appveyor.com/api/projects/status/github/the-tcpdump-group/tcpdump?branch=master&svg=true)](https://ci.appveyor.com/project/guyharris/libpcap)
+
+Now maintained by "The Tcpdump Group"
+
+ https://www.tcpdump.org
+
+formerly from Lawrence Berkeley National Laboratory
+ Network Research Group <libpcap@ee.lbl.gov>
+ ftp://ftp.ee.lbl.gov/old/libpcap-0.4a7.tar.Z
+
To report a security issue please send an e-mail to security@tcpdump.org.
To report bugs and other problems, contribute patches, request a
feature, provide generic feedback etc please see the file
-[CONTRIBUTING](CONTRIBUTING.md) in the libpcap source tree root.
+[CONTRIBUTING.md](CONTRIBUTING.md) in the libpcap source tree root.
The directory doc/ has README files about specific operating systems and
options.
-LIBPCAP 1.x.y
-Now maintained by "The Tcpdump Group"
-https://www.tcpdump.org
-
Anonymous Git is available via:
- https://github.com/the-tcpdump-group/libpcap.git
-formerly from Lawrence Berkeley National Laboratory
- Network Research Group <libpcap@ee.lbl.gov>
- ftp://ftp.ee.lbl.gov/old/libpcap-0.4a7.tar.Z
+ https://github.com/the-tcpdump-group/libpcap.git
This directory contains source code for libpcap, a system-independent
interface for user-level packet capture. libpcap provides a portable
@@ -39,19 +47,15 @@ Winter Usenix paper ``The BSD Packet Filter: A New Architecture for
User-level Packet Capture''. A compressed PostScript version can be
found at
- ftp://ftp.ee.lbl.gov/papers/bpf-usenix93.ps.Z
-
-or
-
- https://www.tcpdump.org/papers/bpf-usenix93.ps.Z
+ https://www.tcpdump.org/papers/bpf-usenix93.ps.Z
and a gzipped version can be found at
- https://www.tcpdump.org/papers/bpf-usenix93.ps.gz
+ https://www.tcpdump.org/papers/bpf-usenix93.ps.gz
A PDF version can be found at
- https://www.tcpdump.org/papers/bpf-usenix93.pdf
+ https://www.tcpdump.org/papers/bpf-usenix93.pdf
Although most packet capture interfaces support in-kernel filtering,
libpcap utilizes in-kernel filtering only for the BPF interface.
@@ -68,7 +72,7 @@ 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 in:
- https://www.tcpdump.org/other/bpfext42.tar.Z
+ https://www.tcpdump.org/other/bpfext42.tar.Z
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
@@ -87,7 +91,3 @@ that.
We've been maintaining binary compatibility between libpcap releases for
quite a while; there's no reason to tie a binary linked with libpcap to
a particular release of libpcap.
-
-Current versions can be found at https://www.tcpdump.org.
-
- - The TCPdump group
diff --git a/VERSION b/VERSION
index 9ab8337f..81c871de 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.9.1
+1.10.0
diff --git a/Win32/Prj/wpcap.vcxproj.filters b/Win32/Prj/wpcap.vcxproj.filters
index 6e06ccbc..879bb059 100644
--- a/Win32/Prj/wpcap.vcxproj.filters
+++ b/Win32/Prj/wpcap.vcxproj.filters
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project ToolsVersion="4.0" xmlns="https://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="..\..\bpf_dump.c">
<Filter>Source Files</Filter>
diff --git a/aclocal.m4 b/aclocal.m4
index aa91e846..786423bf 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -271,7 +271,7 @@ dnl with the flag in question, and the "treat warnings as errors" flag
dnl set, and don't add the flag to the first argument if the compile
dnl fails; this is for warning options cause problems that can't be
dnl worked around. If a third argument is supplied, a fourth argument
-dnl should also be supplied; it's a message desribing what the test
+dnl should also be supplied; it's a message describing what the test
dnl program is checking.
dnl
AC_DEFUN(AC_LBL_CHECK_COMPILER_OPT,
@@ -425,14 +425,14 @@ AC_DEFUN(AC_LBL_CHECK_DEPENDENCY_GENERATION_OPT,
if AC_RUN_LOG([eval "$CC $ac_lbl_dependency_flag conftest.c >/dev/null 2>&1"]); then
AC_MSG_RESULT([yes, with $ac_lbl_dependency_flag])
DEPENDENCY_CFLAG="$ac_lbl_dependency_flag"
- MKDEP='${srcdir}/mkdep'
+ MKDEP='${top_srcdir}/mkdep'
else
AC_MSG_RESULT([no])
#
# We can't run mkdep, so have "make depend" do
# nothing.
#
- MKDEP='${srcdir}/nomkdep'
+ MKDEP='${top_srcdir}/nomkdep'
fi
rm -rf conftest*
else
@@ -441,7 +441,7 @@ AC_DEFUN(AC_LBL_CHECK_DEPENDENCY_GENERATION_OPT,
# We can't run mkdep, so have "make depend" do
# nothing.
#
- MKDEP='${srcdir}/nomkdep'
+ MKDEP='${top_srcdir}/nomkdep'
fi
AC_SUBST(DEPENDENCY_CFLAG)
AC_SUBST(MKDEP)
@@ -484,8 +484,8 @@ AC_DEFUN(AC_LBL_SHLIBS_INIT,
aix*)
;;
- freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*|midipix*)
- #
+ freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*|haiku*|midipix*)
+ #
# Platforms where the linker is the GNU linker
# or accepts command-line arguments like
# those the GNU linker accepts.
@@ -514,7 +514,7 @@ AC_DEFUN(AC_LBL_SHLIBS_INIT,
hpux*)
V_SHLIB_CCOPT="$V_SHLIB_CCOPT -fpic"
- #
+ #
# XXX - this assumes GCC is using the HP linker,
# rather than the GNU linker, and that the "+h"
# option is used on all HP-UX platforms, both .sl
@@ -522,7 +522,7 @@ AC_DEFUN(AC_LBL_SHLIBS_INIT,
#
V_SONAME_OPT="-Wl,+h,"
#
- # By default, directories specifed with -L
+ # By default, directories specified with -L
# are added to the run-time search path, so
# we don't add them in pcap-config.
#
@@ -583,14 +583,14 @@ AC_DEFUN(AC_LBL_SHLIBS_INIT,
V_SHLIB_OPT="-b"
V_SONAME_OPT="+h "
#
- # By default, directories specifed with -L
+ # By default, directories specified with -L
# are added to the run-time search path, so
# we don't add them in pcap-config.
#
;;
osf*)
- #
+ #
# Presumed to be DEC OSF/1, Digital UNIX, or
# Tru64 UNIX.
#
@@ -753,106 +753,6 @@ AC_DEFUN(AC_LBL_HAVE_RUN_PATH,
])
dnl
-dnl Checks to see if unaligned memory accesses fail
-dnl
-dnl usage:
-dnl
-dnl AC_LBL_UNALIGNED_ACCESS
-dnl
-dnl results:
-dnl
-dnl LBL_ALIGN (DEFINED)
-dnl
-AC_DEFUN(AC_LBL_UNALIGNED_ACCESS,
- [AC_MSG_CHECKING(if unaligned accesses fail)
- AC_CACHE_VAL(ac_cv_lbl_unaligned_fail,
- [case "$host_cpu" in
-
- #
- # These are CPU types where:
- #
- # the CPU faults on an unaligned access, but at least some
- # OSes that support that CPU catch the fault and simulate
- # the unaligned access (e.g., Alpha/{Digital,Tru64} UNIX) -
- # the simulation is slow, so we don't want to use it;
- #
- # the CPU, I infer (from the old
- #
- # XXX: should also check that they don't do weird things (like on arm)
- #
- # comment) doesn't fault on unaligned accesses, but doesn't
- # do a normal unaligned fetch, either (e.g., presumably, ARM);
- #
- # for whatever reason, the test program doesn't work
- # (this has been claimed to be the case for several of those
- # CPUs - I don't know what the problem is; the problem
- # was reported as "the test program dumps core" for SuperH,
- # but that's what the test program is *supposed* to do -
- # it dumps core before it writes anything, so the test
- # for an empty output file should find an empty output
- # file and conclude that unaligned accesses don't work).
- #
- # This run-time test won't work if you're cross-compiling, so
- # in order to support cross-compiling for a particular CPU,
- # we have to wire in the list of CPU types anyway, as far as
- # I know, so perhaps we should just have a set of CPUs on
- # which we know it doesn't work, a set of CPUs on which we
- # know it does work, and have the script just fail on other
- # cpu types and update it when such a failure occurs.
- #
- alpha*|arm*|bfin*|hp*|mips*|sh*|sparc*|ia64|nv1)
- ac_cv_lbl_unaligned_fail=yes
- ;;
-
- *)
- cat >conftest.c <<EOF
-# include <sys/types.h>
-# include <sys/wait.h>
-# include <stdio.h>
- unsigned char a[[5]] = { 1, 2, 3, 4, 5 };
- main() {
- unsigned int i;
- pid_t pid;
- int status;
- /* avoid "core dumped" message */
- pid = fork();
- if (pid < 0)
- exit(2);
- if (pid > 0) {
- /* parent */
- pid = waitpid(pid, &status, 0);
- if (pid < 0)
- exit(3);
- exit(!WIFEXITED(status));
- }
- /* child */
- i = *(unsigned int *)&a[[1]];
- printf("%d\n", i);
- exit(0);
- }
-EOF
- ${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS \
- conftest.c $LIBS >/dev/null 2>&1
- if test ! -x conftest ; then
- dnl failed to compile for some reason
- ac_cv_lbl_unaligned_fail=yes
- else
- ./conftest >conftest.out
- if test ! -s conftest.out ; then
- ac_cv_lbl_unaligned_fail=yes
- else
- ac_cv_lbl_unaligned_fail=no
- fi
- fi
- rm -f -r conftest* core core.conftest
- ;;
- esac])
- AC_MSG_RESULT($ac_cv_lbl_unaligned_fail)
- if test $ac_cv_lbl_unaligned_fail = yes ; then
- AC_DEFINE(LBL_ALIGN,1,[if unaligned access fails])
- fi])
-
-dnl
dnl If the file .devel exists:
dnl Add some warning flags if the compiler supports them
dnl If an os prototype include exists, symlink os-proto.h to it
@@ -881,12 +781,13 @@ AC_DEFUN(AC_LBL_DEVEL,
AC_LBL_CHECK_COMPILER_OPT($1, -W)
AC_LBL_CHECK_COMPILER_OPT($1, -Wall)
AC_LBL_CHECK_COMPILER_OPT($1, -Wcomma)
- AC_LBL_CHECK_COMPILER_OPT($1, -Wdeclaration-after-statement)
AC_LBL_CHECK_COMPILER_OPT($1, -Wdocumentation)
AC_LBL_CHECK_COMPILER_OPT($1, -Wformat-nonliteral)
AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-noreturn)
AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-prototypes)
AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-variable-declarations)
+ AC_LBL_CHECK_COMPILER_OPT($1, -Wpointer-arith)
+ AC_LBL_CHECK_COMPILER_OPT($1, -Wpointer-sign)
AC_LBL_CHECK_COMPILER_OPT($1, -Wshadow)
AC_LBL_CHECK_COMPILER_OPT($1, -Wsign-compare)
AC_LBL_CHECK_COMPILER_OPT($1, -Wstrict-prototypes)
@@ -930,6 +831,7 @@ testme(unsigned short a)
}
],
[generates warnings from ntohs()])
+ AC_LBL_CHECK_COMPILER_OPT($1, -Wshorten-64-to-32)
fi
AC_LBL_CHECK_DEPENDENCY_GENERATION_OPT()
#
@@ -1056,10 +958,19 @@ AC_DEFUN(AC_LBL_LIBRARY_NET, [
LIBS="-lsocket -lnsl $LIBS"
],
[
- #
- # We didn't find it.
- #
- AC_MSG_ERROR([getaddrinfo is required, but wasn't found])
+ AC_CHECK_LIB(network, getaddrinfo,
+ [
+ #
+ # OK, we found it in libnetwork on Haiku.
+ #
+ LIBS="-lnetwork $LIBS"
+ ],
+ [
+ #
+ # We didn't find it.
+ #
+ AC_MSG_ERROR([getaddrinfo is required, but wasn't found])
+ ])
], -lnsl)
#
@@ -1077,3 +988,281 @@ AC_DEFUN(AC_LBL_LIBRARY_NET, [
# DLPI needs putmsg under HPUX so test for -lstr while we're at it
AC_SEARCH_LIBS(putmsg, str)
])
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+dnl serial 11 (pkg-config-0.29)
+dnl
+dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful, but
+dnl WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+dnl 02111-1307, USA.
+dnl
+dnl As a special exception to the GNU General Public License, if you
+dnl distribute this file as part of a program that contains a
+dnl configuration script generated by Autoconf, you may include it under
+dnl the same distribution terms that you use for the rest of that
+dnl program.
+
+dnl PKG_PREREQ(MIN-VERSION)
+dnl -----------------------
+dnl Since: 0.29
+dnl
+dnl Verify that the version of the pkg-config macros are at least
+dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
+dnl installed version of pkg-config, this checks the developer's version
+dnl of pkg.m4 when generating configure.
+dnl
+dnl To ensure that this macro is defined, also add:
+dnl m4_ifndef([PKG_PREREQ],
+dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
+dnl
+dnl See the "Since" comment for each macro you use to see what version
+dnl of the macros you require.
+m4_defun([PKG_PREREQ],
+[m4_define([PKG_MACROS_VERSION], [0.29])
+m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
+ [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
+])dnl PKG_PREREQ
+
+dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
+dnl ----------------------------------
+dnl Since: 0.16
+dnl
+dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
+dnl first found in the path. Checks that the version of pkg-config found
+dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
+dnl used since that's the first version where most current features of
+dnl pkg-config existed.
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
+m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
+AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
+AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=m4_default([$1], [0.9.0])
+ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+fi[]dnl
+])dnl PKG_PROG_PKG_CONFIG
+
+dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl -------------------------------------------------------------------
+dnl Since: 0.18
+dnl
+dnl Check to see whether a particular set of modules exists. Similar to
+dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
+dnl
+dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+dnl only at the first occurrence in configure.ac, so if the first place
+dnl it's called might be skipped (such as if it is within an "if", you
+dnl have to call PKG_CHECK_EXISTS manually
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+ m4_default([$2], [:])
+m4_ifvaln([$3], [else
+ $3])dnl
+fi])
+
+dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+dnl ---------------------------------------------
+dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
+dnl pkg_failed based on the result.
+m4_define([_PKG_CONFIG],
+[if test -n "$$1"; then
+ pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+ PKG_CHECK_EXISTS([$3],
+ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes ],
+ [pkg_failed=yes])
+ else
+ pkg_failed=untried
+fi[]dnl
+])dnl _PKG_CONFIG
+
+dnl _PKG_SHORT_ERRORS_SUPPORTED
+dnl ---------------------------
+dnl Internal check to see if pkg-config supports short errors.
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi[]dnl
+])dnl _PKG_SHORT_ERRORS_SUPPORTED
+
+
+dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+dnl [ACTION-IF-NOT-FOUND])
+dnl --------------------------------------------------------------
+dnl Since: 0.4.0
+dnl
+dnl Note that if there is a possibility the first call to
+dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
+dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+ AC_MSG_RESULT([no])
+ _PKG_SHORT_ERRORS_SUPPORTED
+ if test $_pkg_short_errors_supported = yes; then
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
+ else
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+ m4_default([$4], [AC_MSG_ERROR(
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT])[]dnl
+ ])
+elif test $pkg_failed = untried; then
+ AC_MSG_RESULT([no])
+ m4_default([$4], [AC_MSG_FAILURE(
+[The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <https://pkg-config.freedesktop.org/>.])[]dnl
+ ])
+else
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+ AC_MSG_RESULT([yes])
+ $3
+fi[]dnl
+])dnl PKG_CHECK_MODULES
+
+
+dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+dnl [ACTION-IF-NOT-FOUND])
+dnl ---------------------------------------------------------------------
+dnl Since: 0.29
+dnl
+dnl Checks for existence of MODULES and gathers its build flags with
+dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
+dnl and VARIABLE-PREFIX_LIBS from --libs.
+dnl
+dnl Note that if there is a possibility the first call to
+dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
+dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
+dnl configure.ac.
+AC_DEFUN([PKG_CHECK_MODULES_STATIC],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+_save_PKG_CONFIG=$PKG_CONFIG
+PKG_CONFIG="$PKG_CONFIG --static"
+PKG_CHECK_MODULES($@)
+PKG_CONFIG=$_save_PKG_CONFIG[]dnl
+])dnl PKG_CHECK_MODULES_STATIC
+
+
+dnl PKG_INSTALLDIR([DIRECTORY])
+dnl -------------------------
+dnl Since: 0.27
+dnl
+dnl Substitutes the variable pkgconfigdir as the location where a module
+dnl should install pkg-config .pc files. By default the directory is
+dnl $libdir/pkgconfig, but the default can be changed by passing
+dnl DIRECTORY. The user can override through the --with-pkgconfigdir
+dnl parameter.
+AC_DEFUN([PKG_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+ [pkg-config installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([pkgconfigdir],
+ [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
+ [with_pkgconfigdir=]pkg_default)
+AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+])dnl PKG_INSTALLDIR
+
+
+dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
+dnl --------------------------------
+dnl Since: 0.27
+dnl
+dnl Substitutes the variable noarch_pkgconfigdir as the location where a
+dnl module should install arch-independent pkg-config .pc files. By
+dnl default the directory is $datadir/pkgconfig, but the default can be
+dnl changed by passing DIRECTORY. The user can override through the
+dnl --with-noarch-pkgconfigdir parameter.
+AC_DEFUN([PKG_NOARCH_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+ [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([noarch-pkgconfigdir],
+ [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
+ [with_noarch_pkgconfigdir=]pkg_default)
+AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+])dnl PKG_NOARCH_INSTALLDIR
+
+
+dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
+dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl -------------------------------------------
+dnl Since: 0.28
+dnl
+dnl Retrieves the value of the pkg-config variable for the given module.
+AC_DEFUN([PKG_CHECK_VAR],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
+
+_PKG_CONFIG([$1], [variable="][$3]["], [$2])
+AS_VAR_COPY([$1], [pkg_cv_][$1])
+
+AS_VAR_IF([$1], [""], [$5], [$4])dnl
+])dnl PKG_CHECK_VAR
+
diff --git a/atmuni31.h b/atmuni31.h
index 0f854300..7d4f270b 100644
--- a/atmuni31.h
+++ b/atmuni31.h
@@ -76,7 +76,7 @@
#define PROTO_POS 0 /* offset of protocol discriminator */
#define CALL_REF_POS 2 /* offset of call reference value */
#define MSG_TYPE_POS 5 /* offset of message type */
-#define MSG_LEN_POS 7 /* offset of mesage length */
+#define MSG_LEN_POS 7 /* offset of message length */
#define IE_BEGIN_POS 9 /* offset of first information element */
/* format of signalling messages */
diff --git a/bpf_filter.c b/bpf_filter.c
index 33872ff4..22d25587 100644
--- a/bpf_filter.c
+++ b/bpf_filter.c
@@ -44,6 +44,11 @@
#include <pcap/pcap-inttypes.h>
#include "pcap-types.h"
+#include "extract.h"
+#include "diag-control.h"
+
+#define EXTRACT_SHORT EXTRACT_BE_U_2
+#define EXTRACT_LONG EXTRACT_BE_U_4
#ifndef _WIN32
#include <sys/param.h>
@@ -55,42 +60,6 @@
#include <stdlib.h>
-#define int32 bpf_int32
-#define u_int32 bpf_u_int32
-
-#ifndef LBL_ALIGN
-/*
- * XXX - IA-64? If not, this probably won't work on Win64 IA-64
- * systems, unless LBL_ALIGN is defined elsewhere for them.
- * XXX - SuperH? If not, this probably won't work on WinCE SuperH
- * systems, unless LBL_ALIGN is defined elsewhere for them.
- */
-#if defined(sparc) || defined(__sparc__) || defined(mips) || \
- defined(ibm032) || defined(__alpha) || defined(__hpux) || \
- defined(__arm__)
-#define LBL_ALIGN
-#endif
-#endif
-
-#ifndef LBL_ALIGN
-#ifndef _WIN32
-#include <netinet/in.h>
-#endif
-
-#define EXTRACT_SHORT(p) ((u_short)ntohs(*(u_short *)p))
-#define EXTRACT_LONG(p) (ntohl(*(u_int32 *)p))
-#else
-#define EXTRACT_SHORT(p)\
- ((u_short)\
- ((u_short)*((u_char *)p+0)<<8|\
- (u_short)*((u_char *)p+1)<<0))
-#define EXTRACT_LONG(p)\
- ((u_int32)*((u_char *)p+0)<<24|\
- (u_int32)*((u_char *)p+1)<<16|\
- (u_int32)*((u_char *)p+2)<<8|\
- (u_int32)*((u_char *)p+3)<<0)
-#endif
-
#ifdef __linux__
#include <linux/types.h>
#include <linux/if_packet.h>
@@ -115,13 +84,19 @@ enum {
*
* Thanks to Ani Sinha <ani@arista.com> for providing initial implementation
*/
+#if defined(SKF_AD_VLAN_TAG_PRESENT)
u_int
-bpf_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p,
+pcap_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p,
u_int wirelen, u_int buflen, const struct bpf_aux_data *aux_data)
+#else
+u_int
+pcap_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p,
+ u_int wirelen, u_int buflen, const struct bpf_aux_data *aux_data _U_)
+#endif
{
- register u_int32 A, X;
+ register uint32_t A, X;
register bpf_u_int32 k;
- u_int32 mem[BPF_MEMWORDS];
+ uint32_t mem[BPF_MEMWORDS];
if (pc == 0)
/*
@@ -160,6 +135,13 @@ bpf_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p,
continue;
case BPF_LD|BPF_B|BPF_ABS:
+ /*
+ * Yes, we know, this switch doesn't do
+ * anything unless we're building for
+ * a Linux kernel with removed VLAN
+ * tags available as meta-data.
+ */
+DIAG_OFF_DEFAULT_ONLY_SWITCH
switch (pc->k) {
#if defined(SKF_AD_VLAN_TAG_PRESENT)
@@ -183,6 +165,7 @@ bpf_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p,
A = p[k];
break;
}
+DIAG_ON_DEFAULT_ONLY_SWITCH
continue;
case BPF_LD|BPF_W|BPF_LEN:
@@ -405,13 +388,12 @@ bpf_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p,
}
u_int
-bpf_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen,
+pcap_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen,
u_int buflen)
{
- return bpf_filter_with_aux_data(pc, p, wirelen, buflen, NULL);
+ return pcap_filter_with_aux_data(pc, p, wirelen, buflen, NULL);
}
-
/*
* Return true if the 'fcode' is a valid filter program.
* The constraints are that each jump be forward and to a valid
@@ -424,7 +406,7 @@ bpf_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen,
* Otherwise, a bogus program could easily crash the system.
*/
int
-bpf_validate(const struct bpf_insn *f, int len)
+pcap_validate_filter(const struct bpf_insn *f, int len)
{
u_int i, from;
const struct bpf_insn *p;
@@ -546,3 +528,19 @@ bpf_validate(const struct bpf_insn *f, int len)
}
return BPF_CLASS(f[len - 1].code) == BPF_RET;
}
+
+/*
+ * Exported because older versions of libpcap exported them.
+ */
+u_int
+bpf_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen,
+ u_int buflen)
+{
+ return pcap_filter(pc, p, wirelen, buflen);
+}
+
+int
+bpf_validate(const struct bpf_insn *f, int len)
+{
+ return pcap_validate_filter(f, len);
+}
diff --git a/bpf_image.c b/bpf_image.c
index ab41d1ef..e48c76d5 100644
--- a/bpf_image.c
+++ b/bpf_image.c
@@ -28,12 +28,104 @@
#include <stdio.h>
#include <string.h>
+#ifdef __linux__
+#include <linux/types.h>
+#include <linux/if_packet.h>
+#include <linux/filter.h>
+
+/*
+ * We want our versions of these #defines, not Linux's version.
+ * (The two should be the same; if not, we have a problem; all BPF
+ * implementations *should* be source-compatible supersets of ours.)
+ */
+#undef BPF_STMT
+#undef BPF_JUMP
+#endif
+
#include "pcap-int.h"
#ifdef HAVE_OS_PROTO_H
#include "os-proto.h"
#endif
+#ifdef SKF_AD_OFF
+/*
+ * Symbolic names for offsets that refer to the special Linux BPF locations.
+ */
+static const char *offsets[SKF_AD_MAX] = {
+#ifdef SKF_AD_PROTOCOL
+ [SKF_AD_PROTOCOL] = "proto",
+#endif
+#ifdef SKF_AD_PKTTYPE
+ [SKF_AD_PKTTYPE] = "type",
+#endif
+#ifdef SKF_AD_IFINDEX
+ [SKF_AD_IFINDEX] = "ifidx",
+#endif
+#ifdef SKF_AD_NLATTR
+ [SKF_AD_NLATTR] = "nla",
+#endif
+#ifdef SKF_AD_NLATTR_NEST
+ [SKF_AD_NLATTR_NEST] = "nlan",
+#endif
+#ifdef SKF_AD_MARK
+ [SKF_AD_MARK] = "mark",
+#endif
+#ifdef SKF_AD_QUEUE
+ [SKF_AD_QUEUE] = "queue",
+#endif
+#ifdef SKF_AD_HATYPE
+ [SKF_AD_HATYPE] = "hatype",
+#endif
+#ifdef SKF_AD_RXHASH
+ [SKF_AD_RXHASH] = "rxhash",
+#endif
+#ifdef SKF_AD_CPU
+ [SKF_AD_CPU] = "cpu",
+#endif
+#ifdef SKF_AD_ALU_XOR_X
+ [SKF_AD_ALU_XOR_X] = "xor_x",
+#endif
+#ifdef SKF_AD_VLAN_TAG
+ [SKF_AD_VLAN_TAG] = "vlan_tci",
+#endif
+#ifdef SKF_AD_VLAN_TAG_PRESENT
+ [SKF_AD_VLAN_TAG_PRESENT] = "vlanp",
+#endif
+#ifdef SKF_AD_PAY_OFFSET
+ [SKF_AD_PAY_OFFSET] = "poff",
+#endif
+#ifdef SKF_AD_RANDOM
+ [SKF_AD_RANDOM] = "random",
+#endif
+#ifdef SKF_AD_VLAN_TPID
+ [SKF_AD_VLAN_TPID] = "vlan_tpid"
+#endif
+};
+#endif
+
+static void
+bpf_print_abs_load_operand(char *buf, size_t bufsize, const struct bpf_insn *p)
+{
+#ifdef SKF_AD_OFF
+ const char *sym;
+
+ /*
+ * It's an absolute load.
+ * Is the offset a special Linux offset that we know about?
+ */
+ if (p->k >= (bpf_u_int32)SKF_AD_OFF &&
+ p->k < (bpf_u_int32)(SKF_AD_OFF + SKF_AD_MAX) &&
+ (sym = offsets[p->k - (bpf_u_int32)SKF_AD_OFF]) != NULL) {
+ /*
+ * Yes. Print the offset symbolically.
+ */
+ (void)snprintf(buf, bufsize, "[%s]", sym);
+ } else
+#endif
+ (void)snprintf(buf, bufsize, "[%d]", p->k);
+}
+
char *
bpf_image(const struct bpf_insn *p, int n)
{
@@ -46,13 +138,13 @@ bpf_image(const struct bpf_insn *p, int n)
default:
op = "unimp";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "0x%x", p->code);
+ (void)snprintf(operand_buf, sizeof operand_buf, "0x%x", p->code);
operand = operand_buf;
break;
case BPF_RET|BPF_K:
op = "ret";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
operand = operand_buf;
break;
@@ -63,19 +155,19 @@ bpf_image(const struct bpf_insn *p, int n)
case BPF_LD|BPF_W|BPF_ABS:
op = "ld";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "[%d]", p->k);
+ bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p);
operand = operand_buf;
break;
case BPF_LD|BPF_H|BPF_ABS:
op = "ldh";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "[%d]", p->k);
+ bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p);
operand = operand_buf;
break;
case BPF_LD|BPF_B|BPF_ABS:
op = "ldb";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "[%d]", p->k);
+ bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p);
operand = operand_buf;
break;
@@ -86,91 +178,91 @@ bpf_image(const struct bpf_insn *p, int n)
case BPF_LD|BPF_W|BPF_IND:
op = "ld";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
operand = operand_buf;
break;
case BPF_LD|BPF_H|BPF_IND:
op = "ldh";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
operand = operand_buf;
break;
case BPF_LD|BPF_B|BPF_IND:
op = "ldb";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
operand = operand_buf;
break;
case BPF_LD|BPF_IMM:
op = "ld";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
operand = operand_buf;
break;
case BPF_LDX|BPF_IMM:
op = "ldx";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
operand = operand_buf;
break;
case BPF_LDX|BPF_MSH|BPF_B:
op = "ldxb";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "4*([%d]&0xf)", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "4*([%d]&0xf)", p->k);
operand = operand_buf;
break;
case BPF_LD|BPF_MEM:
op = "ld";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
operand = operand_buf;
break;
case BPF_LDX|BPF_MEM:
op = "ldx";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
operand = operand_buf;
break;
case BPF_ST:
op = "st";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
operand = operand_buf;
break;
case BPF_STX:
op = "stx";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
operand = operand_buf;
break;
case BPF_JMP|BPF_JA:
op = "ja";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "%d", n + 1 + p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "%d", n + 1 + p->k);
operand = operand_buf;
break;
case BPF_JMP|BPF_JGT|BPF_K:
op = "jgt";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
operand = operand_buf;
break;
case BPF_JMP|BPF_JGE|BPF_K:
op = "jge";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
operand = operand_buf;
break;
case BPF_JMP|BPF_JEQ|BPF_K:
op = "jeq";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
operand = operand_buf;
break;
case BPF_JMP|BPF_JSET|BPF_K:
op = "jset";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
operand = operand_buf;
break;
@@ -246,61 +338,61 @@ bpf_image(const struct bpf_insn *p, int n)
case BPF_ALU|BPF_ADD|BPF_K:
op = "add";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
operand = operand_buf;
break;
case BPF_ALU|BPF_SUB|BPF_K:
op = "sub";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
operand = operand_buf;
break;
case BPF_ALU|BPF_MUL|BPF_K:
op = "mul";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
operand = operand_buf;
break;
case BPF_ALU|BPF_DIV|BPF_K:
op = "div";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
operand = operand_buf;
break;
case BPF_ALU|BPF_MOD|BPF_K:
op = "mod";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
operand = operand_buf;
break;
case BPF_ALU|BPF_AND|BPF_K:
op = "and";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
operand = operand_buf;
break;
case BPF_ALU|BPF_OR|BPF_K:
op = "or";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
operand = operand_buf;
break;
case BPF_ALU|BPF_XOR|BPF_K:
op = "xor";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
operand = operand_buf;
break;
case BPF_ALU|BPF_LSH|BPF_K:
op = "lsh";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
operand = operand_buf;
break;
case BPF_ALU|BPF_RSH|BPF_K:
op = "rsh";
- (void)pcap_snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
+ (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
operand = operand_buf;
break;
@@ -320,11 +412,11 @@ bpf_image(const struct bpf_insn *p, int n)
break;
}
if (BPF_CLASS(p->code) == BPF_JMP && BPF_OP(p->code) != BPF_JA) {
- (void)pcap_snprintf(image, sizeof image,
+ (void)snprintf(image, sizeof image,
"(%03d) %-8s %-16s jt %d\tjf %d",
n, op, operand, n + 1 + p->jt, n + 1 + p->jf);
} else {
- (void)pcap_snprintf(image, sizeof image,
+ (void)snprintf(image, sizeof image,
"(%03d) %-8s %s",
n, op, operand);
}
diff --git a/charconv.c b/charconv.c
new file mode 100644
index 00000000..4ede5720
--- /dev/null
+++ b/charconv.c
@@ -0,0 +1,216 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef _WIN32
+#include <stdio.h>
+
+#include <pcap/pcap.h> /* Needed for PCAP_ERRBUF_SIZE */
+
+#include "charconv.h"
+
+wchar_t *
+cp_to_utf_16le(UINT codepage, const char *cp_string, DWORD flags)
+{
+ int utf16le_len;
+ wchar_t *utf16le_string;
+
+ /*
+ * Map from the specified code page to UTF-16LE.
+ * First, find out how big a buffer we'll need.
+ */
+ utf16le_len = MultiByteToWideChar(codepage, flags, cp_string, -1,
+ NULL, 0);
+ if (utf16le_len == 0) {
+ /*
+ * Error. Fail with EINVAL.
+ */
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /*
+ * Now attempt to allocate a buffer for that.
+ */
+ utf16le_string = malloc(utf16le_len * sizeof (wchar_t));
+ if (utf16le_string == NULL) {
+ /*
+ * Not enough memory; assume errno has been
+ * set, and fail.
+ */
+ return (NULL);
+ }
+
+ /*
+ * Now convert.
+ */
+ utf16le_len = MultiByteToWideChar(codepage, flags, cp_string, -1,
+ utf16le_string, utf16le_len);
+ if (utf16le_len == 0) {
+ /*
+ * Error. Fail with EINVAL.
+ * XXX - should this ever happen, given that
+ * we already ran the string through
+ * MultiByteToWideChar() to find out how big
+ * a buffer we needed?
+ */
+ free(utf16le_string);
+ errno = EINVAL;
+ return (NULL);
+ }
+ return (utf16le_string);
+}
+
+char *
+utf_16le_to_cp(UINT codepage, const wchar_t *utf16le_string)
+{
+ int cp_len;
+ char *cp_string;
+
+ /*
+ * Map from UTF-16LE to the specified code page.
+ * First, find out how big a buffer we'll need.
+ * We convert composite characters to precomposed characters,
+ * as that's what Windows expects.
+ */
+ cp_len = WideCharToMultiByte(codepage, WC_COMPOSITECHECK,
+ utf16le_string, -1, NULL, 0, NULL, NULL);
+ if (cp_len == 0) {
+ /*
+ * Error. Fail with EINVAL.
+ */
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /*
+ * Now attempt to allocate a buffer for that.
+ */
+ cp_string = malloc(cp_len * sizeof (char));
+ if (cp_string == NULL) {
+ /*
+ * Not enough memory; assume errno has been
+ * set, and fail.
+ */
+ return (NULL);
+ }
+
+ /*
+ * Now convert.
+ */
+ cp_len = WideCharToMultiByte(codepage, WC_COMPOSITECHECK,
+ utf16le_string, -1, cp_string, cp_len, NULL, NULL);
+ if (cp_len == 0) {
+ /*
+ * Error. Fail with EINVAL.
+ * XXX - should this ever happen, given that
+ * we already ran the string through
+ * WideCharToMultiByte() to find out how big
+ * a buffer we needed?
+ */
+ free(cp_string);
+ errno = EINVAL;
+ return (NULL);
+ }
+ return (cp_string);
+}
+
+/*
+ * Convert an error message string from UTF-8 to the local code page, as
+ * best we can.
+ *
+ * The buffer is assumed to be PCAP_ERRBUF_SIZE bytes long; we truncate
+ * if it doesn't fit.
+ */
+void
+utf_8_to_acp_truncated(char *errbuf)
+{
+ wchar_t *utf_16_errbuf;
+ int retval;
+ DWORD err;
+
+ /*
+ * Do this by converting to UTF-16LE and then to the local
+ * code page. That means we get to use Microsoft's
+ * conversion routines, rather than having to understand
+ * all the code pages ourselves, *and* that this routine
+ * can convert in place.
+ */
+
+ /*
+ * Map from UTF-8 to UTF-16LE.
+ * First, find out how big a buffer we'll need.
+ * Convert any invalid characters to REPLACEMENT CHARACTER.
+ */
+ utf_16_errbuf = cp_to_utf_16le(CP_UTF8, errbuf, 0);
+ if (utf_16_errbuf == NULL) {
+ /*
+ * Error. Give up.
+ */
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Can't convert error string to the local code page");
+ return;
+ }
+
+ /*
+ * Now, convert that to the local code page.
+ * Use the current thread's code page. For unconvertable
+ * characters, let it pick the "best fit" character.
+ *
+ * XXX - we'd like some way to do what utf_16le_to_utf_8_truncated()
+ * does if the buffer isn't big enough, but we don't want to have
+ * to handle all local code pages ourselves; doing so requires
+ * knowledge of all those code pages, including knowledge of how
+ * characters are formed in thoe code pages so that we can avoid
+ * cutting a multi-byte character into pieces.
+ *
+ * Converting to an un-truncated string using Windows APIs, and
+ * then copying to the buffer, still requires knowledge of how
+ * characters are formed in the target code page.
+ */
+ retval = WideCharToMultiByte(CP_THREAD_ACP, 0, utf_16_errbuf, -1,
+ errbuf, PCAP_ERRBUF_SIZE, NULL, NULL);
+ if (retval == 0) {
+ err = GetLastError();
+ free(utf_16_errbuf);
+ if (err == ERROR_INSUFFICIENT_BUFFER)
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "The error string, in the local code page, didn't fit in the buffer");
+ else
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Can't convert error string to the local code page");
+ return;
+ }
+ free(utf_16_errbuf);
+}
+#endif
diff --git a/charconv.h b/charconv.h
new file mode 100644
index 00000000..a37d424b
--- /dev/null
+++ b/charconv.h
@@ -0,0 +1,44 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef charonv_h
+#define charonv_h
+
+#ifdef _WIN32
+extern wchar_t *cp_to_utf_16le(UINT codepage, const char *cp_string, DWORD flags);
+extern char *utf_16le_to_cp(UINT codepage, const wchar_t *utf16le_string);
+extern void utf_8_to_acp_truncated(char *);
+#endif
+
+#endif
diff --git a/cmake/Modules/FindAirPcap.cmake b/cmake/Modules/FindAirPcap.cmake
new file mode 100644
index 00000000..8198f70f
--- /dev/null
+++ b/cmake/Modules/FindAirPcap.cmake
@@ -0,0 +1,69 @@
+#
+# FindAirPcap
+# ==========
+#
+# Find the AirPcap library and include files.
+#
+# This module defines the following variables:
+#
+# AIRPCAP_INCLUDE_DIR - absolute path to the directory containing airpcap.h.
+#
+# AIRPCAP_LIBRARY - relative or absolute path to the AirPcap library to
+# link with. An absolute path is will be used if the
+# AirPcap library is not located in the compiler's
+# default search path.
+
+# AIRPCAP_FOUND - TRUE if the AirPcap library *and* header are found.
+#
+# Hints and Backward Compatibility
+# ================================
+#
+# To tell this module where to look, a user may set the environment variable
+# AirPcap_ROOT to point cmake to the *root* of a directory with include and
+# lib subdirectories for airpcap.dll (e.g Airpcap_Devpack).
+# Alternatively, AirPcap_ROOT may also be set from the CMake command
+# line or GUI (e.g cmake -DAirPcap_ROOT=C:\path\to\airpcap_sdk [...])
+#
+
+# The 64-bit airpcap.lib is located under /x64
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ #
+ # For the WinPcap and Npcap SDKs, the Lib subdirectory of the top-level
+ # directory contains 32-bit libraries; the 64-bit libraries are in the
+ # Lib/x64 directory.
+ #
+ # The only way to *FORCE* CMake to look in the Lib/x64 directory
+ # without searching in the Lib directory first appears to be to set
+ # CMAKE_LIBRARY_ARCHITECTURE to "x64".
+ #
+ # In newer versions of CMake, CMAKE_LIBRARY_ARCHITECTURE is set according to
+ # the language, e.g., CMAKE_<LANG>_LIBRARY_ARCHITECTURE. So, set the new
+ # variable, CMAKE_C_LIBRARY_ARCHITECTURE, so that CMAKE_LIBRARY_ARCHITECTURE
+ # inherits the correct value.
+ #
+ set(CMAKE_C_LIBRARY_ARCHITECTURE "x64")
+ set(CMAKE_LIBRARY_ARCHITECTURE "x64")
+endif()
+
+# Find the header
+find_path(AIRPCAP_INCLUDE_DIR airpcap.h
+ PATH_SUFFIXES include
+)
+
+# Find the library
+find_library(AIRPCAP_LIBRARY
+ NAMES airpcap
+)
+
+# Set AIRPCAP_FOUND to TRUE if AIRPCAP_INCLUDE_DIR and AIRPCAP_LIBRARY are TRUE.
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(AIRPCAP
+ DEFAULT_MSG
+ AIRPCAP_INCLUDE_DIR
+ AIRPCAP_LIBRARY
+)
+
+mark_as_advanced(AIRPCAP_INCLUDE_DIR AIRPCAP_LIBRARY)
+
+set(AIRPCAP_INCLUDE_DIRS ${AIRPCAP_INCLUDE_DIR})
+set(AIRPCAP_LIBRARIES ${AIRPCAP_LIBRARY})
diff --git a/cmake/Modules/FindPacket.cmake b/cmake/Modules/FindPacket.cmake
index f114875b..900c8e3f 100644
--- a/cmake/Modules/FindPacket.cmake
+++ b/cmake/Modules/FindPacket.cmake
@@ -33,8 +33,7 @@
# PACKET_LIBRARY - relative or absolute path to the Packet library to
# link with. An absolute path is will be used if the
# Packet library is not located in the compiler's
-# default search path. See e.g. PACKET_DLL_DIR
-# variable below.
+# default search path.
# PACKET_FOUND - TRUE if the Packet library *and* header are found.
#
@@ -42,10 +41,10 @@
# ================================
#
# To tell this module where to look, a user may set the environment variable
-# PACKET_DLL_DIR to point cmake to the *root* of a directory with include and
-# lib subdirectories for packet.dll (e.g WpdPack/npcap-sdk).
-# Alternatively, PACKET_DLL_DIR may also be set from cmake command line or GUI
-# (e.g cmake -DPACKET_DLL_DIR=/path/to/packet [...])
+# Packet_ROOT to point cmake to the *root* of a directory with include and
+# lib subdirectories for packet.dll (e.g WpdPack or npcap-sdk).
+# Alternatively, Packet_ROOT may also be set from cmake command line or GUI
+# (e.g cmake -DPacket_ROOT=C:\path\to\packet [...])
#
# The 64-bit Packet.lib is located under /x64
@@ -59,19 +58,23 @@ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
# without searching in the Lib directory first appears to be to set
# CMAKE_LIBRARY_ARCHITECTURE to "x64".
#
+ # In newer versions of CMake, CMAKE_LIBRARY_ARCHITECTURE is set according to
+ # the language, e.g., CMAKE_<LANG>_LIBRARY_ARCHITECTURE. So, set the new
+ # variable, CMAKE_C_LIBRARY_ARCHITECTURE, so that CMAKE_LIBRARY_ARCHITECTURE
+ # inherits the correct value.
+ #
+ set(CMAKE_C_LIBRARY_ARCHITECTURE "x64")
set(CMAKE_LIBRARY_ARCHITECTURE "x64")
endif()
# Find the header
find_path(PACKET_INCLUDE_DIR Packet32.h
- HINTS "${PACKET_DLL_DIR}" ENV PACKET_DLL_DIR
PATH_SUFFIXES include Include
)
# Find the library
find_library(PACKET_LIBRARY
NAMES Packet packet
- HINTS "${PACKET_DLL_DIR}" ENV PACKET_DLL_DIR
)
# Set PACKET_FOUND to TRUE if PACKET_INCLUDE_DIR and PACKET_LIBRARY are TRUE.
diff --git a/cmake/Modules/Finddpdk.cmake b/cmake/Modules/Finddpdk.cmake
new file mode 100644
index 00000000..50eafd90
--- /dev/null
+++ b/cmake/Modules/Finddpdk.cmake
@@ -0,0 +1,123 @@
+# Try to find dpdk
+#
+# Once done, this will define
+#
+# dpdk_FOUND
+# dpdk_INCLUDE_DIRS
+# dpdk_LIBRARIES
+
+if(PKG_CONFIG_FOUND)
+ pkg_check_modules(dpdk QUIET libdpdk)
+endif()
+message(STATUS "Executing Finddpdk")
+if(NOT dpdk_INCLUDE_DIRS)
+ message(STATUS "Executing find_path")
+ find_path(dpdk_config_INCLUDE_DIR rte_config.h
+ HINTS
+ ENV DPDK_DIR
+ PATH_SUFFIXES
+ dpdk
+ include
+)
+ find_path(dpdk_common_INCLUDE_DIR rte_common.h
+ HINTS
+ ENC DPDK_DIR
+ PATH_SUFFIXES
+ dpdk
+ include
+)
+ set(dpdk_INCLUDE_DIRS "${dpdk_config_INCLUDE_DIR}")
+ if(NOT dpdk_config_INCLUDE_DIR EQUAL dpdk_common_INCLUDE_DIR)
+ list(APPEND dpdk_INCLUDE_DIRS "${dpdk_common_INCLUDE_DIR}")
+ endif()
+
+ set(components
+ bus_pci
+ cmdline
+ eal
+ ethdev
+ hash
+ kvargs
+ mbuf
+ mempool
+ mempool_ring
+ mempool_stack
+ pci
+ pmd_af_packet
+ pmd_bond
+ pmd_i40e
+ pmd_ixgbe
+ pmd_mlx5
+ pmd_ring
+ pmd_vmxnet3_uio
+ ring)
+
+ set(dpdk_LIBRARIES)
+
+ foreach(c ${components})
+ find_library(DPDK_rte_${c}_LIBRARY rte_${c}
+ HINTS
+ ENV DPDK_DIR
+ ${dpdk_LIBRARY_DIRS}
+ PATH_SUFFIXES lib)
+ if(DPDK_rte_${c}_LIBRARY)
+ set(dpdk_lib dpdk::${c})
+ if (NOT TARGET ${dpdk_lib})
+ add_library(${dpdk_lib} UNKNOWN IMPORTED)
+ set_target_properties(${dpdk_lib} PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${dpdk_INCLUDE_DIRS}"
+ IMPORTED_LOCATION "${DPDK_rte_${c}_LIBRARY}")
+ if(c STREQUAL pmd_mlx5)
+ find_package(verbs QUIET)
+ if(verbs_FOUND)
+ target_link_libraries(${dpdk_lib} INTERFACE IBVerbs::verbs)
+ endif()
+ endif()
+ endif()
+ list(APPEND dpdk_LIBRARIES ${dpdk_lib})
+ endif()
+ endforeach()
+
+ #
+ # Where the heck did this list come from? libdpdk on Ubuntu 20.04,
+ # for example, doesn't even *have* -ldpdk; that's why we go with
+ # pkg-config, in the hopes that it provides a correct set of flags
+ # for this tangled mess.
+ #
+ list(APPEND dpdk_LIBRARIES dpdk rt m numo dl)
+endif()
+
+mark_as_advanced(dpdk_INCLUDE_DIRS ${dpdk_LIBRARIES})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(dpdk DEFAULT_MSG
+ dpdk_INCLUDE_DIRS
+ dpdk_LIBRARIES)
+
+if(dpdk_FOUND)
+ if(NOT TARGET dpdk::cflags)
+ if(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64")
+ set(rte_cflags "-march=core2")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm|ARM")
+ set(rte_cflags "-march=armv7-a")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64")
+ set(rte_cflags "-march=armv8-a+crc")
+ endif()
+ add_library(dpdk::cflags INTERFACE IMPORTED)
+ if (rte_cflags)
+ set_target_properties(dpdk::cflags PROPERTIES
+ INTERFACE_COMPILE_OPTIONS "${rte_cflags}")
+ endif()
+ endif()
+
+ if(NOT TARGET dpdk::dpdk)
+ add_library(dpdk::dpdk INTERFACE IMPORTED)
+ find_package(Threads QUIET)
+ list(APPEND dpdk_LIBRARIES
+ Threads::Threads
+ dpdk::cflags)
+ set_target_properties(dpdk::dpdk PROPERTIES
+ INTERFACE_LINK_LIBRARIES "${dpdk_LIBRARIES}"
+ INTERFACE_INCLUDE_DIRECTORIES "${dpdk_INCLUDE_DIRS}")
+ endif()
+endif()
diff --git a/cmakeconfig.h.in b/cmakeconfig.h.in
index 1639925e..192209cb 100644
--- a/cmakeconfig.h.in
+++ b/cmakeconfig.h.in
@@ -15,9 +15,15 @@
/* define if we have the AIX getprotobyname_r() */
#cmakedefine HAVE_AIX_GETPROTOBYNAME_R 1
+/* define if you have the AirPcap API */
+#cmakedefine HAVE_AIRPCAP_API 1
+
/* Define to 1 if you have the `asprintf' function. */
#cmakedefine HAVE_ASPRINTF 1
+/* Define to 1 if you have the <config/HaikuConfig.h> header file. */
+#cmakedefine HAVE_CONFIG_HAIKUCONFIG_H 1
+
/* define if you have the DAG API */
#cmakedefine HAVE_DAG_API 1
@@ -69,45 +75,21 @@
/* if libnl exists */
#cmakedefine HAVE_LIBNL 1
-/* if libnl exists and is version 2.x */
-#cmakedefine HAVE_LIBNL_2_x 1
-
-/* if libnl exists and is version 3.x */
-#cmakedefine HAVE_LIBNL_3_x 1
-
-/* libnl has NLE_FAILURE */
-#cmakedefine HAVE_LIBNL_NLE 1
-
-/* libnl has new-style socket api */
-#cmakedefine HAVE_LIBNL_SOCKETS 1
-
-/* Define to 1 if you have the <limits.h> header file. */
-#cmakedefine HAVE_LIMITS_H 1
-
/* Define to 1 if you have the <linux/compiler.h> header file. */
#cmakedefine HAVE_LINUX_COMPILER_H 1
-/* Define to 1 if you have the <linux/ethtool.h> header file. */
-#cmakedefine HAVE_LINUX_ETHTOOL_H 1
-
/* define if we have the Linux getnetbyname_r() */
#cmakedefine HAVE_LINUX_GETNETBYNAME_R 1
/* define if we have the Linux getprotobyname_r() */
#cmakedefine HAVE_LINUX_GETPROTOBYNAME_R 1
-/* Define to 1 if you have the <linux/if_bonding.h> header file. */
-#cmakedefine HAVE_LINUX_IF_BONDING_H 1
-
/* Define to 1 if you have the <linux/net_tstamp.h> header file. */
#cmakedefine HAVE_LINUX_NET_TSTAMP_H 1
/* Define to 1 if you have the <linux/socket.h> header file. */
#cmakedefine HAVE_LINUX_SOCKET_H 1
-/* Define to 1 if you have the <linux/sockios.h> header file. */
-#cmakedefine HAVE_LINUX_SOCKIOS_H 1
-
/* Define to 1 if you have the <linux/usbdevice_fs.h> header file. */
#cmakedefine HAVE_LINUX_USBDEVICE_FS_H 1
@@ -141,6 +123,9 @@
/* Define to 1 if you have the <net/raw.h> header file. */
#cmakedefine HAVE_NET_RAW_H 1
+/* Use OpenSSL */
+#cmakedefine HAVE_OPENSSL 1
+
/* if there's an os_proto.h for this platform, to use additional prototypes */
#cmakedefine HAVE_OS_PROTO_H 1
@@ -186,9 +171,6 @@
/* Define to 1 if you have the `strerror' function. */
#cmakedefine HAVE_STRERROR 1
-/* Define to 1 if you have the `strerror_s' function. */
-#cmakedefine HAVE_STRERROR_S 1
-
/* Define to 1 if you have the <strings.h> header file. */
#cmakedefine HAVE_STRINGS_H 1
@@ -216,6 +198,9 @@
/* Define to 1 if `msg_flags' is a member of `struct msghdr'. */
#cmakedefine HAVE_STRUCT_MSGHDR_MSG_FLAGS 1
+/* Define to 1 if the system has the type `struct rte_ether_addr'. */
+#cmakedefine HAVE_STRUCT_RTE_ETHER_ADDR 1
+
/* Define to 1 if `hci_channel' is a member of `struct sockaddr_hci'. */
#cmakedefine HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL 1
@@ -228,9 +213,6 @@
/* Define to 1 if `tp_vlan_tci' is a member of `struct tpacket_auxdata'. */
#cmakedefine HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI 1
-/* Define to 1 if the system has the type `struct tpacket_stats'. */
-#cmakedefine HAVE_STRUCT_TPACKET_STATS 1
-
/* Define to 1 if `bRequestType' is a member of `struct
usbdevfs_ctrltransfer'. */
#cmakedefine HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE 1
@@ -272,7 +254,13 @@
#cmakedefine HAVE_VSNPRINTF 1
/* Define to 1 if you have the `vsyslog' function. */
-#undef HAVE_VSYSLOG
+#cmakedefine HAVE_VSYSLOG 1
+
+/* Define to 1 if you have the `_wcserror_s' function. */
+#cmakedefine HAVE__WCSERROR_S 1
+
+/* Define to 1 if you have the `PacketGetTimestampModes' function. */
+#cmakedefine HAVE_PACKET_GET_TIMESTAMP_MODES 1
/* Define to 1 if you have the `PacketIsLoopbackAdapter' function. */
#cmakedefine HAVE_PACKET_IS_LOOPBACK_ADAPTER 1
@@ -280,9 +268,6 @@
/* IPv6 */
#cmakedefine INET6 1
-/* if unaligned access fails */
-#cmakedefine LBL_ALIGN 1
-
/* path for device for USB sniffing */
#cmakedefine LINUX_USB_MON_DEV "@LINUX_USB_MON_DEV@"
@@ -301,7 +286,7 @@
/* Define to the address where bug reports for this package should be sent. */
#cmakedefine PACKAGE_BUGREPORT 1
-/* Define to the DLL-preferred version string of of this package. */
+/* Define to the DLL-preferred version string of this package. */
#cmakedefine PACKAGE_VERSION_DLL @PACKAGE_VERSION_DLL@
/* Define to the full name of this package. */
@@ -328,24 +313,21 @@
/* support D-Bus sniffing */
#cmakedefine PCAP_SUPPORT_DBUS 1
+/* target host supports DPDK */
+#cmakedefine PCAP_SUPPORT_DPDK 1
+
+/* target host supports Linux usbmon for USB sniffing */
+#cmakedefine PCAP_SUPPORT_LINUX_USBMON 1
+
/* target host supports netfilter sniffing */
#cmakedefine PCAP_SUPPORT_NETFILTER 1
/* target host supports netmap */
#cmakedefine PCAP_SUPPORT_NETMAP 1
-/* use packet ring capture support on Linux if available */
-#cmakedefine PCAP_SUPPORT_PACKET_RING 1
-
/* target host supports RDMA sniffing */
#cmakedefine PCAP_SUPPORT_RDMASNIFF 1
-/* target host supports USB sniffing */
-#cmakedefine PCAP_SUPPORT_USB 1
-
-/* include ACN support */
-#cmakedefine SITA 1
-
/* Define to 1 if you have the ANSI C header files. */
#cmakedefine STDC_HEADERS 1
diff --git a/config.guess b/config.guess
index 2b79f6d8..7f748177 100755
--- a/config.guess
+++ b/config.guess
@@ -1,8 +1,8 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-# Copyright 1992-2018 Free Software Foundation, Inc.
+# Copyright 1992-2020 Free Software Foundation, Inc.
-timestamp='2018-07-06'
+timestamp='2020-12-22'
# 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
@@ -27,12 +27,12 @@ timestamp='2018-07-06'
# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
#
# You can get the latest version of this script from:
-# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
#
# Please send patches to <config-patches@gnu.org>.
-me=`echo "$0" | sed -e 's,.*/,,'`
+me=$(echo "$0" | sed -e 's,.*/,,')
usage="\
Usage: $0 [OPTION]
@@ -50,7 +50,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright 1992-2018 Free Software Foundation, Inc.
+Copyright 1992-2020 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."
@@ -84,8 +84,6 @@ if test $# != 0; then
exit 1
fi
-trap 'exit 1' 1 2 15
-
# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
# compiler to aid in system detection is discouraged as it requires
# temporary files to be created and, as you can see below, it is a
@@ -96,66 +94,82 @@ trap 'exit 1' 1 2 15
# Portable tmp directory creation inspired by the Autoconf team.
-set_cc_for_build='
-trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
-trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
-: ${TMPDIR=/tmp} ;
- { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
- { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp 2>/dev/null) ; } ||
- { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
- { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
-dummy=$tmp/dummy ;
-tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
-case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
- ,,) echo "int x;" > "$dummy.c" ;
- for c in cc gcc c89 c99 ; do
- if ($c -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
- CC_FOR_BUILD="$c"; break ;
- fi ;
- done ;
- if test x"$CC_FOR_BUILD" = x ; then
- CC_FOR_BUILD=no_compiler_found ;
- fi
- ;;
- ,,*) CC_FOR_BUILD=$CC ;;
- ,*,*) CC_FOR_BUILD=$HOST_CC ;;
-esac ; set_cc_for_build= ;'
+tmp=
+# shellcheck disable=SC2172
+trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15
+
+set_cc_for_build() {
+ # prevent multiple calls if $tmp is already set
+ test "$tmp" && return 0
+ : "${TMPDIR=/tmp}"
+ # shellcheck disable=SC2039
+ { tmp=$( (umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null) && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; }
+ dummy=$tmp/dummy
+ case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
+ ,,) echo "int x;" > "$dummy.c"
+ for driver in cc gcc c89 c99 ; do
+ if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$driver"
+ break
+ fi
+ done
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+ esac
+}
# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
# (ghazi@noc.rutgers.edu 1994-08-24)
-if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+if test -f /.attbin/uname ; then
PATH=$PATH:/.attbin ; export PATH
fi
-UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
-UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
-UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
-UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+UNAME_MACHINE=$( (uname -m) 2>/dev/null) || UNAME_MACHINE=unknown
+UNAME_RELEASE=$( (uname -r) 2>/dev/null) || UNAME_RELEASE=unknown
+UNAME_SYSTEM=$( (uname -s) 2>/dev/null) || UNAME_SYSTEM=unknown
+UNAME_VERSION=$( (uname -v) 2>/dev/null) || UNAME_VERSION=unknown
case "$UNAME_SYSTEM" in
Linux|GNU|GNU/*)
- # If the system lacks a compiler, then just pick glibc.
- # We could probably try harder.
- LIBC=gnu
+ LIBC=unknown
- eval "$set_cc_for_build"
+ set_cc_for_build
cat <<-EOF > "$dummy.c"
#include <features.h>
#if defined(__UCLIBC__)
LIBC=uclibc
#elif defined(__dietlibc__)
LIBC=dietlibc
- #else
+ #elif defined(__GLIBC__)
LIBC=gnu
+ #else
+ #include <stdarg.h>
+ /* First heuristic to detect musl libc. */
+ #ifdef __DEFINED_va_list
+ LIBC=musl
+ #endif
#endif
EOF
- eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`"
+ eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g')"
- # If ldd exists, use it to detect musl libc.
- if command -v ldd >/dev/null && \
- ldd --version 2>&1 | grep -q ^musl
- then
- LIBC=musl
+ # Second heuristic to detect musl libc.
+ if [ "$LIBC" = unknown ] &&
+ command -v ldd >/dev/null &&
+ ldd --version 2>&1 | grep -q ^musl; then
+ LIBC=musl
+ fi
+
+ # If the system lacks a compiler, then just pick glibc.
+ # We could probably try harder.
+ if [ "$LIBC" = unknown ]; then
+ LIBC=gnu
fi
;;
esac
@@ -175,19 +189,20 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
# Note: NetBSD doesn't particularly care about the vendor
# portion of the name. We always set it to "unknown".
sysctl="sysctl -n hw.machine_arch"
- UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+ UNAME_MACHINE_ARCH=$( (uname -p 2>/dev/null || \
"/sbin/$sysctl" 2>/dev/null || \
"/usr/sbin/$sysctl" 2>/dev/null || \
- echo unknown)`
+ echo unknown))
case "$UNAME_MACHINE_ARCH" in
+ aarch64eb) machine=aarch64_be-unknown ;;
armeb) machine=armeb-unknown ;;
arm*) machine=arm-unknown ;;
sh3el) machine=shl-unknown ;;
sh3eb) machine=sh-unknown ;;
sh5el) machine=sh5le-unknown ;;
earmv*)
- arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
- endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'`
+ arch=$(echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,')
+ endian=$(echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p')
machine="${arch}${endian}"-unknown
;;
*) machine="$UNAME_MACHINE_ARCH"-unknown ;;
@@ -199,7 +214,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
os=netbsdelf
;;
arm*|i386|m68k|ns32k|sh3*|sparc|vax)
- eval "$set_cc_for_build"
+ set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ELF__
then
@@ -218,7 +233,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
case "$UNAME_MACHINE_ARCH" in
earm*)
expr='s/^earmv[0-9]/-eabi/;s/eb$//'
- abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"`
+ abi=$(echo "$UNAME_MACHINE_ARCH" | sed -e "$expr")
;;
esac
# The OS release
@@ -231,7 +246,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
release='-gnu'
;;
*)
- release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2`
+ release=$(echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2)
;;
esac
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
@@ -240,15 +255,15 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
echo "$machine-${os}${release}${abi-}"
exit ;;
*:Bitrig:*:*)
- UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+ UNAME_MACHINE_ARCH=$(arch | sed 's/Bitrig.//')
echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE"
exit ;;
*:OpenBSD:*:*)
- UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ UNAME_MACHINE_ARCH=$(arch | sed 's/OpenBSD.//')
echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE"
exit ;;
*:LibertyBSD:*:*)
- UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+ UNAME_MACHINE_ARCH=$(arch | sed 's/^.*BSD\.//')
echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE"
exit ;;
*:MidnightBSD:*:*)
@@ -260,6 +275,9 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
*:SolidBSD:*:*)
echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE"
exit ;;
+ *:OS108:*:*)
+ echo "$UNAME_MACHINE"-unknown-os108_"$UNAME_RELEASE"
+ exit ;;
macppc:MirBSD:*:*)
echo powerpc-unknown-mirbsd"$UNAME_RELEASE"
exit ;;
@@ -269,26 +287,29 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
*:Sortix:*:*)
echo "$UNAME_MACHINE"-unknown-sortix
exit ;;
+ *:Twizzler:*:*)
+ echo "$UNAME_MACHINE"-unknown-twizzler
+ exit ;;
*:Redox:*:*)
echo "$UNAME_MACHINE"-unknown-redox
exit ;;
mips:OSF1:*.*)
- echo mips-dec-osf1
- exit ;;
+ echo mips-dec-osf1
+ exit ;;
alpha:OSF1:*:*)
case $UNAME_RELEASE in
*4.0)
- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $3}')
;;
*5.*)
- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $4}')
;;
esac
# According to Compaq, /usr/sbin/psrinfo has been available on
# OSF/1 and Tru64 systems produced since 1995. I hope that
# covers most systems running today. This code pipes the CPU
# types through head -n 1, so we only detect the type of CPU 0.
- ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ ALPHA_CPU_TYPE=$(/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1)
case "$ALPHA_CPU_TYPE" in
"EV4 (21064)")
UNAME_MACHINE=alpha ;;
@@ -326,7 +347,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
# A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
- echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`"
+ echo "$UNAME_MACHINE"-dec-osf"$(echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)"
# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
exitcode=$?
trap '' 0
@@ -360,7 +381,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
exit ;;
Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
- if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ if test "$( (/bin/universe) 2>/dev/null)" = att ; then
echo pyramid-pyramid-sysv3
else
echo pyramid-pyramid-bsd
@@ -373,28 +394,28 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
echo sparc-icl-nx6
exit ;;
DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
- case `/usr/bin/uname -p` in
+ case $(/usr/bin/uname -p) in
sparc) echo sparc-icl-nx7; exit ;;
esac ;;
s390x:SunOS:*:*)
- echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
+ echo "$UNAME_MACHINE"-ibm-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')"
exit ;;
sun4H:SunOS:5.*:*)
- echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ echo sparc-hal-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
exit ;;
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
- echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
+ echo sparc-sun-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')"
exit ;;
i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
echo i386-pc-auroraux"$UNAME_RELEASE"
exit ;;
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
- eval "$set_cc_for_build"
+ set_cc_for_build
SUN_ARCH=i386
# If there is a compiler, see if it is configured for 64-bit objects.
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
# This test works for both compilers.
- if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+ if test "$CC_FOR_BUILD" != no_compiler_found; then
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
@@ -402,30 +423,30 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
SUN_ARCH=x86_64
fi
fi
- echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ echo "$SUN_ARCH"-pc-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
exit ;;
sun4*:SunOS:6*:*)
# According to config.sub, this is the proper way to canonicalize
# SunOS6. Hard to guess exactly what SunOS6 will be like, but
# it's likely to be more like Solaris than SunOS4.
- echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ echo sparc-sun-solaris3"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
exit ;;
sun4*:SunOS:*:*)
- case "`/usr/bin/arch -k`" in
+ case "$(/usr/bin/arch -k)" in
Series*|S4*)
- UNAME_RELEASE=`uname -v`
+ UNAME_RELEASE=$(uname -v)
;;
esac
# Japanese Language versions have a version number like `4.1.3-JL'.
- echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`"
+ echo sparc-sun-sunos"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/')"
exit ;;
sun3*:SunOS:*:*)
echo m68k-sun-sunos"$UNAME_RELEASE"
exit ;;
sun*:*:4.2BSD:*)
- UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ UNAME_RELEASE=$( (sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null)
test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3
- case "`/bin/arch`" in
+ case "$(/bin/arch)" in
sun3)
echo m68k-sun-sunos"$UNAME_RELEASE"
;;
@@ -482,7 +503,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
echo clipper-intergraph-clix"$UNAME_RELEASE"
exit ;;
mips:*:*:UMIPS | mips:*:*:RISCos)
- eval "$set_cc_for_build"
+ set_cc_for_build
sed 's/^ //' << EOF > "$dummy.c"
#ifdef __cplusplus
#include <stdio.h> /* for printf() prototype */
@@ -505,8 +526,8 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
}
EOF
$CC_FOR_BUILD -o "$dummy" "$dummy.c" &&
- dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` &&
- SYSTEM_NAME=`"$dummy" "$dummyarg"` &&
+ dummyarg=$(echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p') &&
+ SYSTEM_NAME=$("$dummy" "$dummyarg") &&
{ echo "$SYSTEM_NAME"; exit; }
echo mips-mips-riscos"$UNAME_RELEASE"
exit ;;
@@ -533,11 +554,11 @@ EOF
exit ;;
AViiON:dgux:*:*)
# DG/UX returns AViiON for all architectures
- UNAME_PROCESSOR=`/usr/bin/uname -p`
- if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ]
+ UNAME_PROCESSOR=$(/usr/bin/uname -p)
+ if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110
then
- if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \
- [ "$TARGET_BINARY_INTERFACE"x = x ]
+ if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \
+ test "$TARGET_BINARY_INTERFACE"x = x
then
echo m88k-dg-dgux"$UNAME_RELEASE"
else
@@ -561,17 +582,17 @@ EOF
echo m68k-tektronix-bsd
exit ;;
*:IRIX*:*:*)
- echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`"
+ echo mips-sgi-irix"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/g')"
exit ;;
????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
- exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ exit ;; # Note that: echo "'$(uname -s)'" gives 'AIX '
i*86:AIX:*:*)
echo i386-ibm-aix
exit ;;
ia64:AIX:*:*)
- if [ -x /usr/bin/oslevel ] ; then
- IBM_REV=`/usr/bin/oslevel`
+ if test -x /usr/bin/oslevel ; then
+ IBM_REV=$(/usr/bin/oslevel)
else
IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
fi
@@ -579,7 +600,7 @@ EOF
exit ;;
*:AIX:2:3)
if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
- eval "$set_cc_for_build"
+ set_cc_for_build
sed 's/^ //' << EOF > "$dummy.c"
#include <sys/systemcfg.h>
@@ -591,7 +612,7 @@ EOF
exit(0);
}
EOF
- if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"`
+ if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy")
then
echo "$SYSTEM_NAME"
else
@@ -604,15 +625,15 @@ EOF
fi
exit ;;
*:AIX:*:[4567])
- IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ IBM_CPU_ID=$(/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }')
if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then
IBM_ARCH=rs6000
else
IBM_ARCH=powerpc
fi
- if [ -x /usr/bin/lslpp ] ; then
- IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
- awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
+ if test -x /usr/bin/lslpp ; then
+ IBM_REV=$(/usr/bin/lslpp -Lqc bos.rte.libc |
+ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/)
else
IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
fi
@@ -640,14 +661,14 @@ EOF
echo m68k-hp-bsd4.4
exit ;;
9000/[34678]??:HP-UX:*:*)
- HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
+ HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//')
case "$UNAME_MACHINE" in
9000/31?) HP_ARCH=m68000 ;;
9000/[34]??) HP_ARCH=m68k ;;
9000/[678][0-9][0-9])
- if [ -x /usr/bin/getconf ]; then
- sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
- sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ if test -x /usr/bin/getconf; then
+ sc_cpu_version=$(/usr/bin/getconf SC_CPU_VERSION 2>/dev/null)
+ sc_kernel_bits=$(/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null)
case "$sc_cpu_version" in
523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
@@ -659,8 +680,8 @@ EOF
esac ;;
esac
fi
- if [ "$HP_ARCH" = "" ]; then
- eval "$set_cc_for_build"
+ if test "$HP_ARCH" = ""; then
+ set_cc_for_build
sed 's/^ //' << EOF > "$dummy.c"
#define _HPUX_SOURCE
@@ -694,13 +715,13 @@ EOF
exit (0);
}
EOF
- (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"`
+ (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=$("$dummy")
test -z "$HP_ARCH" && HP_ARCH=hppa
fi ;;
esac
- if [ "$HP_ARCH" = hppa2.0w ]
+ if test "$HP_ARCH" = hppa2.0w
then
- eval "$set_cc_for_build"
+ set_cc_for_build
# hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
# 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
@@ -722,11 +743,11 @@ EOF
echo "$HP_ARCH"-hp-hpux"$HPUX_REV"
exit ;;
ia64:HP-UX:*:*)
- HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
+ HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//')
echo ia64-hp-hpux"$HPUX_REV"
exit ;;
3050*:HI-UX:*:*)
- eval "$set_cc_for_build"
+ set_cc_for_build
sed 's/^ //' << EOF > "$dummy.c"
#include <unistd.h>
int
@@ -752,7 +773,7 @@ EOF
exit (0);
}
EOF
- $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` &&
+ $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy") &&
{ echo "$SYSTEM_NAME"; exit; }
echo unknown-hitachi-hiuxwe2
exit ;;
@@ -772,7 +793,7 @@ EOF
echo hppa1.0-hp-osf
exit ;;
i*86:OSF1:*:*)
- if [ -x /usr/sbin/sysversion ] ; then
+ if test -x /usr/sbin/sysversion ; then
echo "$UNAME_MACHINE"-unknown-osf1mk
else
echo "$UNAME_MACHINE"-unknown-osf1
@@ -821,14 +842,14 @@ EOF
echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
exit ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
- FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
- FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
- FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'`
+ FUJITSU_PROC=$(uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)
+ FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///')
+ FUJITSU_REL=$(echo "$UNAME_RELEASE" | sed -e 's/ /_/')
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
5000:UNIX_System_V:4.*:*)
- FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
- FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
+ FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///')
+ FUJITSU_REL=$(echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/')
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
@@ -840,15 +861,26 @@ EOF
*:BSD/OS:*:*)
echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE"
exit ;;
+ arm:FreeBSD:*:*)
+ UNAME_PROCESSOR=$(uname -p)
+ set_cc_for_build
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabi
+ else
+ echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabihf
+ fi
+ exit ;;
*:FreeBSD:*:*)
- UNAME_PROCESSOR=`/usr/bin/uname -p`
+ UNAME_PROCESSOR=$(/usr/bin/uname -p)
case "$UNAME_PROCESSOR" in
amd64)
UNAME_PROCESSOR=x86_64 ;;
i386)
UNAME_PROCESSOR=i586 ;;
esac
- echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
+ echo "$UNAME_PROCESSOR"-unknown-freebsd"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')"
exit ;;
i*:CYGWIN*:*)
echo "$UNAME_MACHINE"-pc-cygwin
@@ -881,18 +913,18 @@ EOF
echo "$UNAME_MACHINE"-pc-uwin
exit ;;
amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
- echo x86_64-unknown-cygwin
+ echo x86_64-pc-cygwin
exit ;;
prep*:SunOS:5.*:*)
- echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ echo powerpcle-unknown-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
exit ;;
*:GNU:*:*)
# the GNU system
- echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`"
+ echo "$(echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,')-unknown-$LIBC$(echo "$UNAME_RELEASE"|sed -e 's,/.*$,,')"
exit ;;
*:GNU/*:*:*)
# other systems with GNU libc and userland
- echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC"
+ echo "$UNAME_MACHINE-unknown-$(echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]")$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')-$LIBC"
exit ;;
*:Minix:*:*)
echo "$UNAME_MACHINE"-unknown-minix
@@ -905,7 +937,7 @@ EOF
echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
alpha:Linux:*:*)
- case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ case $(sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null) in
EV5) UNAME_MACHINE=alphaev5 ;;
EV56) UNAME_MACHINE=alphaev56 ;;
PCA56) UNAME_MACHINE=alphapca56 ;;
@@ -922,7 +954,7 @@ EOF
echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
arm*:Linux:*:*)
- eval "$set_cc_for_build"
+ set_cc_for_build
if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_EABI__
then
@@ -964,6 +996,9 @@ EOF
k1om:Linux:*:*)
echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
+ loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
m32r*:Linux:*:*)
echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
@@ -971,23 +1006,51 @@ EOF
echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
mips:Linux:*:* | mips64:Linux:*:*)
- eval "$set_cc_for_build"
+ set_cc_for_build
+ IS_GLIBC=0
+ test x"${LIBC}" = xgnu && IS_GLIBC=1
sed 's/^ //' << EOF > "$dummy.c"
#undef CPU
- #undef ${UNAME_MACHINE}
- #undef ${UNAME_MACHINE}el
+ #undef mips
+ #undef mipsel
+ #undef mips64
+ #undef mips64el
+ #if ${IS_GLIBC} && defined(_ABI64)
+ LIBCABI=gnuabi64
+ #else
+ #if ${IS_GLIBC} && defined(_ABIN32)
+ LIBCABI=gnuabin32
+ #else
+ LIBCABI=${LIBC}
+ #endif
+ #endif
+
+ #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6
+ CPU=mipsisa64r6
+ #else
+ #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6
+ CPU=mipsisa32r6
+ #else
+ #if defined(__mips64)
+ CPU=mips64
+ #else
+ CPU=mips
+ #endif
+ #endif
+ #endif
+
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
- CPU=${UNAME_MACHINE}el
+ MIPS_ENDIAN=el
#else
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
- CPU=${UNAME_MACHINE}
+ MIPS_ENDIAN=
#else
- CPU=
+ MIPS_ENDIAN=
#endif
#endif
EOF
- eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU'`"
- test "x$CPU" != x && { echo "$CPU-unknown-linux-$LIBC"; exit; }
+ eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI')"
+ test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; }
;;
mips64el:Linux:*:*)
echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
@@ -1006,7 +1069,7 @@ EOF
exit ;;
parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level
- case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ case $(grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2) in
PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;;
PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;;
*) echo hppa-unknown-linux-"$LIBC" ;;
@@ -1046,7 +1109,17 @@ EOF
echo "$UNAME_MACHINE"-dec-linux-"$LIBC"
exit ;;
x86_64:Linux:*:*)
- echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
+ set_cc_for_build
+ LIBCABI=$LIBC
+ if test "$CC_FOR_BUILD" != no_compiler_found; then
+ if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_X32 >/dev/null
+ then
+ LIBCABI="$LIBC"x32
+ fi
+ fi
+ echo "$UNAME_MACHINE"-pc-linux-"$LIBCABI"
exit ;;
xtensa*:Linux:*:*)
echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
@@ -1086,7 +1159,7 @@ EOF
echo "$UNAME_MACHINE"-pc-msdosdjgpp
exit ;;
i*86:*:4.*:*)
- UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'`
+ UNAME_REL=$(echo "$UNAME_RELEASE" | sed 's/\/MP$//')
if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL"
else
@@ -1095,19 +1168,19 @@ EOF
exit ;;
i*86:*:5:[678]*)
# UnixWare 7.x, OpenUNIX and OpenServer 6.
- case `/bin/uname -X | grep "^Machine"` in
+ case $(/bin/uname -X | grep "^Machine") in
*486*) UNAME_MACHINE=i486 ;;
*Pentium) UNAME_MACHINE=i586 ;;
*Pent*|*Celeron) UNAME_MACHINE=i686 ;;
esac
- echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}{$UNAME_VERSION}"
+ echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}"
exit ;;
i*86:*:3.2:*)
if test -f /usr/options/cb.name; then
- UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ UNAME_REL=$(sed -n 's/.*Version //p' </usr/options/cb.name)
echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL"
elif /bin/uname -X 2>/dev/null >/dev/null ; then
- UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ UNAME_REL=$( (/bin/uname -X|grep Release|sed -e 's/.*= //'))
(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
&& UNAME_MACHINE=i586
@@ -1157,7 +1230,7 @@ EOF
3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
OS_REL=''
test -r /etc/.relid \
- && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid)
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
@@ -1168,7 +1241,7 @@ EOF
NCR*:*:4.2:* | MPRAS*:*:4.2:*)
OS_REL='.3'
test -r /etc/.relid \
- && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid)
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
@@ -1201,7 +1274,7 @@ EOF
exit ;;
*:SINIX-*:*:*)
if uname -p 2>/dev/null >/dev/null ; then
- UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ UNAME_MACHINE=$( (uname -p) 2>/dev/null)
echo "$UNAME_MACHINE"-sni-sysv4
else
echo ns32k-sni-sysv
@@ -1235,7 +1308,7 @@ EOF
echo mips-sony-newsos6
exit ;;
R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
- if [ -d /usr/nec ]; then
+ if test -d /usr/nec; then
echo mips-nec-sysv"$UNAME_RELEASE"
else
echo mips-unknown-sysv"$UNAME_RELEASE"
@@ -1283,44 +1356,48 @@ EOF
*:Rhapsody:*:*)
echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE"
exit ;;
+ arm64:Darwin:*:*)
+ echo aarch64-apple-darwin"$UNAME_RELEASE"
+ exit ;;
*:Darwin:*:*)
- UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
- eval "$set_cc_for_build"
- if test "$UNAME_PROCESSOR" = unknown ; then
- UNAME_PROCESSOR=powerpc
+ UNAME_PROCESSOR=$(uname -p)
+ case $UNAME_PROCESSOR in
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ if command -v xcode-select > /dev/null 2> /dev/null && \
+ ! xcode-select --print-path > /dev/null 2> /dev/null ; then
+ # Avoid executing cc if there is no toolchain installed as
+ # cc will be a stub that puts up a graphical alert
+ # prompting the user to install developer tools.
+ CC_FOR_BUILD=no_compiler_found
+ else
+ set_cc_for_build
fi
- if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then
- if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
- if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
- grep IS_64BIT_ARCH >/dev/null
- then
- case $UNAME_PROCESSOR in
- i386) UNAME_PROCESSOR=x86_64 ;;
- powerpc) UNAME_PROCESSOR=powerpc64 ;;
- esac
- fi
- # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
- if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
- grep IS_PPC >/dev/null
- then
- UNAME_PROCESSOR=powerpc
- fi
+ if test "$CC_FOR_BUILD" != no_compiler_found; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ case $UNAME_PROCESSOR in
+ i386) UNAME_PROCESSOR=x86_64 ;;
+ powerpc) UNAME_PROCESSOR=powerpc64 ;;
+ esac
+ fi
+ # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
+ if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_PPC >/dev/null
+ then
+ UNAME_PROCESSOR=powerpc
fi
elif test "$UNAME_PROCESSOR" = i386 ; then
- # Avoid executing cc on OS X 10.9, as it ships with a stub
- # that puts up a graphical alert prompting to install
- # developer tools. Any system running Mac OS X 10.7 or
- # later (Darwin 11 and later) is required to have a 64-bit
- # processor. This is not true of the ARM version of Darwin
- # that Apple uses in portable devices.
- UNAME_PROCESSOR=x86_64
+ # uname -m returns i386 or x86_64
+ UNAME_PROCESSOR=$UNAME_MACHINE
fi
echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE"
exit ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
- UNAME_PROCESSOR=`uname -p`
+ UNAME_PROCESSOR=$(uname -p)
if test "$UNAME_PROCESSOR" = x86; then
UNAME_PROCESSOR=i386
UNAME_MACHINE=pc
@@ -1358,6 +1435,7 @@ EOF
# "uname -m" is not consistent, so use $cputype instead. 386
# is converted to i386 for consistency with other x86
# operating systems.
+ # shellcheck disable=SC2154
if test "$cputype" = 386; then
UNAME_MACHINE=i386
else
@@ -1387,10 +1465,10 @@ EOF
echo mips-sei-seiux"$UNAME_RELEASE"
exit ;;
*:DragonFly:*:*)
- echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
+ echo "$UNAME_MACHINE"-unknown-dragonfly"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')"
exit ;;
*:*VMS:*:*)
- UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ UNAME_MACHINE=$( (uname -p) 2>/dev/null)
case "$UNAME_MACHINE" in
A*) echo alpha-dec-vms ; exit ;;
I*) echo ia64-dec-vms ; exit ;;
@@ -1400,7 +1478,7 @@ EOF
echo i386-pc-xenix
exit ;;
i*86:skyos:*:*)
- echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`"
+ echo "$UNAME_MACHINE"-pc-skyos"$(echo "$UNAME_RELEASE" | sed -e 's/ .*$//')"
exit ;;
i*86:rdos:*:*)
echo "$UNAME_MACHINE"-pc-rdos
@@ -1414,8 +1492,148 @@ EOF
amd64:Isilon\ OneFS:*:*)
echo x86_64-unknown-onefs
exit ;;
+ *:Unleashed:*:*)
+ echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE"
+ exit ;;
esac
+# No uname command or uname output not recognized.
+set_cc_for_build
+cat > "$dummy.c" <<EOF
+#ifdef _SEQUENT_
+#include <sys/types.h>
+#include <sys/utsname.h>
+#endif
+#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
+#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
+#include <signal.h>
+#if defined(_SIZE_T_) || defined(SIGLOST)
+#include <sys/utsname.h>
+#endif
+#endif
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=$( (hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null);
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+#include <sys/param.h>
+#if defined (BSD)
+#if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+#else
+#if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#else
+ printf ("vax-dec-bsd\n"); exit (0);
+#endif
+#endif
+#else
+ printf ("vax-dec-bsd\n"); exit (0);
+#endif
+#else
+#if defined(_SIZE_T_) || defined(SIGLOST)
+ struct utsname un;
+ uname (&un);
+ printf ("vax-dec-ultrix%s\n", un.release); exit (0);
+#else
+ printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+#endif
+#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
+#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
+#if defined(_SIZE_T_) || defined(SIGLOST)
+ struct utsname *un;
+ uname (&un);
+ printf ("mips-dec-ultrix%s\n", un.release); exit (0);
+#else
+ printf ("mips-dec-ultrix\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=$($dummy) &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; }
+
echo "$0: unable to guess system type" >&2
case "$UNAME_MACHINE:$UNAME_SYSTEM" in
@@ -1435,9 +1653,15 @@ This script (version $timestamp), has failed to recognize the
operating system you are using. If your script is old, overwrite *all*
copies of config.guess and config.sub with the latest versions from:
- https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+ https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
and
- https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+ https://git.savannah.gnu.org/cgit/config.git/plain/config.sub
+EOF
+
+year=$(echo $timestamp | sed 's,-.*,,')
+# shellcheck disable=SC2003
+if test "$(expr "$(date +%Y)" - "$year")" -lt 3 ; then
+ cat >&2 <<EOF
If $0 has already been updated, send the following data and any
information you think might be pertinent to config-patches@gnu.org to
@@ -1445,26 +1669,27 @@ provide the necessary information to handle your system.
config.guess timestamp = $timestamp
-uname -m = `(uname -m) 2>/dev/null || echo unknown`
-uname -r = `(uname -r) 2>/dev/null || echo unknown`
-uname -s = `(uname -s) 2>/dev/null || echo unknown`
-uname -v = `(uname -v) 2>/dev/null || echo unknown`
+uname -m = $( (uname -m) 2>/dev/null || echo unknown)
+uname -r = $( (uname -r) 2>/dev/null || echo unknown)
+uname -s = $( (uname -s) 2>/dev/null || echo unknown)
+uname -v = $( (uname -v) 2>/dev/null || echo unknown)
-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
-/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+/usr/bin/uname -p = $( (/usr/bin/uname -p) 2>/dev/null)
+/bin/uname -X = $( (/bin/uname -X) 2>/dev/null)
-hostinfo = `(hostinfo) 2>/dev/null`
-/bin/universe = `(/bin/universe) 2>/dev/null`
-/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
-/bin/arch = `(/bin/arch) 2>/dev/null`
-/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+hostinfo = $( (hostinfo) 2>/dev/null)
+/bin/universe = $( (/bin/universe) 2>/dev/null)
+/usr/bin/arch -k = $( (/usr/bin/arch -k) 2>/dev/null)
+/bin/arch = $( (/bin/arch) 2>/dev/null)
+/usr/bin/oslevel = $( (/usr/bin/oslevel) 2>/dev/null)
+/usr/convex/getsysinfo = $( (/usr/convex/getsysinfo) 2>/dev/null)
UNAME_MACHINE = "$UNAME_MACHINE"
UNAME_RELEASE = "$UNAME_RELEASE"
UNAME_SYSTEM = "$UNAME_SYSTEM"
UNAME_VERSION = "$UNAME_VERSION"
EOF
+fi
exit 1
diff --git a/config.h.in b/config.h.in
index 94db7bbc..00618aec 100644
--- a/config.h.in
+++ b/config.h.in
@@ -18,6 +18,9 @@
/* Define to 1 if you have the `asprintf' function. */
#undef HAVE_ASPRINTF
+/* Define to 1 if you have the <config/HaikuConfig.h> header file. */
+#undef HAVE_CONFIG_HAIKUCONFIG_H
+
/* Define to 1 if you have the <dagapi.h> header file. */
#undef HAVE_DAGAPI_H
@@ -78,45 +81,21 @@
/* if libnl exists */
#undef HAVE_LIBNL
-/* if libnl exists and is version 2.x */
-#undef HAVE_LIBNL_2_x
-
-/* if libnl exists and is version 3.x */
-#undef HAVE_LIBNL_3_x
-
-/* libnl has NLE_FAILURE */
-#undef HAVE_LIBNL_NLE
-
-/* libnl has new-style socket api */
-#undef HAVE_LIBNL_SOCKETS
-
-/* Define to 1 if you have the <limits.h> header file. */
-#undef HAVE_LIMITS_H
-
/* Define to 1 if you have the <linux/compiler.h> header file. */
#undef HAVE_LINUX_COMPILER_H
-/* Define to 1 if you have the <linux/ethtool.h> header file. */
-#undef HAVE_LINUX_ETHTOOL_H
-
/* define if we have the Linux getnetbyname_r() */
#undef HAVE_LINUX_GETNETBYNAME_R
/* define if we have the Linux getprotobyname_r() */
#undef HAVE_LINUX_GETPROTOBYNAME_R
-/* Define to 1 if you have the <linux/if_bonding.h> header file. */
-#undef HAVE_LINUX_IF_BONDING_H
-
/* Define to 1 if you have the <linux/net_tstamp.h> header file. */
#undef HAVE_LINUX_NET_TSTAMP_H
/* Define to 1 if you have the <linux/socket.h> header file. */
#undef HAVE_LINUX_SOCKET_H
-/* Define to 1 if you have the <linux/sockios.h> header file. */
-#undef HAVE_LINUX_SOCKIOS_H
-
/* Define to 1 if you have the <linux/usbdevice_fs.h> header file. */
#undef HAVE_LINUX_USBDEVICE_FS_H
@@ -135,9 +114,18 @@
/* Define to 1 if you have the <net/enet.h> header file. */
#undef HAVE_NET_ENET_H
+/* Define to 1 if you have the <net/if_dl.h> header file. */
+#undef HAVE_NET_IF_DL_H
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#undef HAVE_NET_IF_H
+
/* Define to 1 if you have the <net/if_media.h> header file. */
#undef HAVE_NET_IF_MEDIA_H
+/* Define to 1 if you have the <net/if_types.h> header file. */
+#undef HAVE_NET_IF_TYPES_H
+
/* Define to 1 if you have the <net/nit.h> header file. */
#undef HAVE_NET_NIT_H
@@ -150,6 +138,9 @@
/* Define to 1 if you have the <net/raw.h> header file. */
#undef HAVE_NET_RAW_H
+/* Use OpenSSL */
+#undef HAVE_OPENSSL
+
/* if there's an os_proto.h for this platform, to use additional prototypes */
#undef HAVE_OS_PROTO_H
@@ -165,9 +156,6 @@
/* define if you have the Myricom SNF API */
#undef HAVE_SNF_API
-/* Define to 1 if you have the `snprintf' function. */
-#undef HAVE_SNPRINTF
-
/* Define to 1 if the system has the type `socklen_t'. */
#undef HAVE_SOCKLEN_T
@@ -189,9 +177,6 @@
/* Define to 1 if you have the `strerror' function. */
#undef HAVE_STRERROR
-/* Define to 1 if you have the `strerror_s' function. */
-#undef HAVE_STRERROR_S
-
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
@@ -219,6 +204,9 @@
/* Define to 1 if `msg_flags' is a member of `struct msghdr'. */
#undef HAVE_STRUCT_MSGHDR_MSG_FLAGS
+/* Define to 1 if the system has the type `struct rte_ether_addr'. */
+#undef HAVE_STRUCT_RTE_ETHER_ADDR
+
/* Define to 1 if `hci_channel' is a member of `struct sockaddr_hci'. */
#undef HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL
@@ -231,9 +219,6 @@
/* Define to 1 if `tp_vlan_tci' is a member of `struct tpacket_auxdata'. */
#undef HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI
-/* Define to 1 if the system has the type `struct tpacket_stats'. */
-#undef HAVE_STRUCT_TPACKET_STATS
-
/* Define to 1 if `bRequestType' is a member of `struct
usbdevfs_ctrltransfer'. */
#undef HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE
@@ -271,18 +256,15 @@
/* Define to 1 if you have the `vasprintf' function. */
#undef HAVE_VASPRINTF
-/* Define to 1 if you have the `vsnprintf' function. */
-#undef HAVE_VSNPRINTF
-
/* Define to 1 if you have the `vsyslog' function. */
#undef HAVE_VSYSLOG
+/* Define to 1 if you have the `_wcserror_s' function. */
+#undef HAVE__WCSERROR_S
+
/* IPv6 */
#undef INET6
-/* if unaligned access fails */
-#undef LBL_ALIGN
-
/* path for device for USB sniffing */
#undef LINUX_USB_MON_DEV
@@ -325,24 +307,21 @@
/* support D-Bus sniffing */
#undef PCAP_SUPPORT_DBUS
+/* target host supports DPDK */
+#undef PCAP_SUPPORT_DPDK
+
+/* target host supports Linux usbmon for USB sniffing */
+#undef PCAP_SUPPORT_LINUX_USBMON
+
/* target host supports netfilter sniffing */
#undef PCAP_SUPPORT_NETFILTER
/* target host supports netmap */
#undef PCAP_SUPPORT_NETMAP
-/* use packet ring capture support on Linux if available */
-#undef PCAP_SUPPORT_PACKET_RING
-
/* target host supports RDMA sniffing */
#undef PCAP_SUPPORT_RDMASNIFF
-/* target host supports USB sniffing */
-#undef PCAP_SUPPORT_USB
-
-/* include ACN support */
-#undef SITA
-
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
diff --git a/config.sub b/config.sub
index c95acc68..90bb8aed 100755
--- a/config.sub
+++ b/config.sub
@@ -1,8 +1,8 @@
#! /bin/sh
# Configuration validation subroutine script.
-# Copyright 1992-2018 Free Software Foundation, Inc.
+# Copyright 1992-2020 Free Software Foundation, Inc.
-timestamp='2018-07-03'
+timestamp='2020-12-22'
# 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
@@ -33,7 +33,7 @@ timestamp='2018-07-03'
# Otherwise, we print the canonical config type on stdout and succeed.
# You can get the latest version of this script from:
-# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub
# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
@@ -50,7 +50,7 @@ timestamp='2018-07-03'
# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# It is wrong to echo any other type of specification.
-me=`echo "$0" | sed -e 's,.*/,,'`
+me=$(echo "$0" | sed -e 's,.*/,,')
usage="\
Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
@@ -67,7 +67,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
-Copyright 1992-2018 Free Software Foundation, Inc.
+Copyright 1992-2020 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."
@@ -89,7 +89,7 @@ while test $# -gt 0 ; do
- ) # Use stdin as input.
break ;;
-* )
- echo "$me: invalid option $1$help"
+ echo "$me: invalid option $1$help" >&2
exit 1 ;;
*local*)
@@ -111,7 +111,8 @@ case $# in
esac
# Split fields of configuration type
-IFS="-" read -r field1 field2 field3 field4 <<EOF
+# shellcheck disable=SC2162
+IFS="-" read field1 field2 field3 field4 <<EOF
$1
EOF
@@ -123,55 +124,64 @@ case $1 in
;;
*-*-*-*)
basic_machine=$field1-$field2
- os=$field3-$field4
+ basic_os=$field3-$field4
;;
*-*-*)
# Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two
# parts
maybe_os=$field2-$field3
case $maybe_os in
- nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc \
- | linux-newlib* | linux-musl* | linux-uclibc* | uclinux-uclibc* \
+ 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*)
basic_machine=$field1
- os=$maybe_os
+ basic_os=$maybe_os
;;
android-linux)
basic_machine=$field1-unknown
- os=linux-android
+ basic_os=linux-android
;;
*)
basic_machine=$field1-$field2
- os=$field3
+ basic_os=$field3
;;
esac
;;
*-*)
- # Second component is usually, but not always the OS
- case $field2 in
- # Prevent following clause from handling this valid os
- sun*os*)
- basic_machine=$field1
- os=$field2
- ;;
- # Manufacturers
- dec* | mips* | sequent* | encore* | pc532* | sgi* | sony* \
- | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
- | unicom* | ibm* | next | hp | isi* | apollo | altos* \
- | convergent* | ncr* | news | 32* | 3600* | 3100* | hitachi* \
- | c[123]* | convex* | sun | crds | omron* | dg | ultra | tti* \
- | harris | dolphin | highlevel | gould | cbm | ns | masscomp \
- | apple | axis | knuth | cray | microblaze* \
- | sim | cisco | oki | wec | wrs | winbond)
- basic_machine=$field1-$field2
- os=
- ;;
- *)
- basic_machine=$field1
- os=$field2
- ;;
+ # A lone config we happen to match not fitting any pattern
+ case $field1-$field2 in
+ decstation-3100)
+ basic_machine=mips-dec
+ basic_os=
+ ;;
+ *-*)
+ # Second component is usually, but not always the OS
+ case $field2 in
+ # Prevent following clause from handling this valid os
+ sun*os*)
+ basic_machine=$field1
+ basic_os=$field2
+ ;;
+ # Manufacturers
+ dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
+ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
+ | unicom* | ibm* | next | hp | isi* | apollo | altos* \
+ | convergent* | ncr* | news | 32* | 3600* | 3100* \
+ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \
+ | ultra | tti* | harris | dolphin | highlevel | gould \
+ | cbm | ns | masscomp | apple | axis | knuth | cray \
+ | microblaze* | sim | cisco \
+ | oki | wec | wrs | winbond)
+ basic_machine=$field1-$field2
+ basic_os=
+ ;;
+ *)
+ basic_machine=$field1
+ basic_os=$field2
+ ;;
+ esac
+ ;;
esac
;;
*)
@@ -180,1105 +190,1089 @@ case $1 in
case $field1 in
386bsd)
basic_machine=i386-pc
- os=bsd
+ basic_os=bsd
;;
a29khif)
basic_machine=a29k-amd
- os=udi
+ basic_os=udi
;;
adobe68k)
basic_machine=m68010-adobe
- os=scout
+ basic_os=scout
+ ;;
+ alliant)
+ basic_machine=fx80-alliant
+ basic_os=
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ basic_os=
;;
am29k)
basic_machine=a29k-none
- os=bsd
+ basic_os=bsd
;;
amdahl)
basic_machine=580-amdahl
- os=sysv
+ basic_os=sysv
+ ;;
+ amiga)
+ basic_machine=m68k-unknown
+ basic_os=
;;
amigaos | amigados)
basic_machine=m68k-unknown
- os=amigaos
+ basic_os=amigaos
;;
amigaunix | amix)
basic_machine=m68k-unknown
- os=sysv4
+ basic_os=sysv4
;;
apollo68)
basic_machine=m68k-apollo
- os=sysv
+ basic_os=sysv
;;
apollo68bsd)
basic_machine=m68k-apollo
- os=bsd
+ basic_os=bsd
;;
aros)
basic_machine=i386-pc
- os=aros
+ basic_os=aros
;;
aux)
basic_machine=m68k-apple
- os=aux
+ basic_os=aux
;;
balance)
basic_machine=ns32k-sequent
- os=dynix
+ basic_os=dynix
;;
blackfin)
basic_machine=bfin-unknown
- os=linux
+ basic_os=linux
;;
cegcc)
basic_machine=arm-unknown
- os=cegcc
+ basic_os=cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ basic_os=bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ basic_os=bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ basic_os=bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ basic_os=bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ basic_os=bsd
;;
cray)
basic_machine=j90-cray
- os=unicos
+ basic_os=unicos
;;
- craynv)
- basic_machine=craynv-cray
- os=unicosmp
+ crds | unos)
+ basic_machine=m68k-crds
+ basic_os=
+ ;;
+ da30)
+ basic_machine=m68k-da30
+ basic_os=
+ ;;
+ decstation | pmax | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ basic_os=
;;
delta88)
basic_machine=m88k-motorola
- os=sysv3
+ basic_os=sysv3
;;
dicos)
basic_machine=i686-pc
- os=dicos
+ basic_os=dicos
;;
djgpp)
basic_machine=i586-pc
- os=msdosdjgpp
+ basic_os=msdosdjgpp
;;
ebmon29k)
basic_machine=a29k-amd
- os=ebmon
+ basic_os=ebmon
;;
es1800 | OSE68k | ose68k | ose | OSE)
basic_machine=m68k-ericsson
- os=ose
+ basic_os=ose
;;
gmicro)
basic_machine=tron-gmicro
- os=sysv
+ basic_os=sysv
;;
go32)
basic_machine=i386-pc
- os=go32
+ basic_os=go32
;;
h8300hms)
basic_machine=h8300-hitachi
- os=hms
+ basic_os=hms
;;
h8300xray)
basic_machine=h8300-hitachi
- os=xray
+ basic_os=xray
;;
h8500hms)
basic_machine=h8500-hitachi
- os=hms
+ basic_os=hms
;;
harris)
basic_machine=m88k-harris
- os=sysv3
+ basic_os=sysv3
;;
- hp300bsd)
+ hp300 | hp300hpux)
basic_machine=m68k-hp
- os=bsd
+ basic_os=hpux
;;
- hp300hpux)
+ hp300bsd)
basic_machine=m68k-hp
- os=hpux
+ basic_os=bsd
;;
hppaosf)
basic_machine=hppa1.1-hp
- os=osf
+ basic_os=osf
;;
hppro)
basic_machine=hppa1.1-hp
- os=proelf
+ basic_os=proelf
;;
i386mach)
basic_machine=i386-mach
- os=mach
- ;;
- vsta)
- basic_machine=i386-unknown
- os=vsta
+ basic_os=mach
;;
isi68 | isi)
basic_machine=m68k-isi
- os=sysv
+ basic_os=sysv
;;
m68knommu)
basic_machine=m68k-unknown
- os=linux
+ basic_os=linux
;;
magnum | m3230)
basic_machine=mips-mips
- os=sysv
+ basic_os=sysv
;;
merlin)
basic_machine=ns32k-utek
- os=sysv
+ basic_os=sysv
;;
mingw64)
basic_machine=x86_64-pc
- os=mingw64
+ basic_os=mingw64
;;
mingw32)
basic_machine=i686-pc
- os=mingw32
+ basic_os=mingw32
;;
mingw32ce)
basic_machine=arm-unknown
- os=mingw32ce
+ basic_os=mingw32ce
;;
monitor)
basic_machine=m68k-rom68k
- os=coff
+ basic_os=coff
;;
morphos)
basic_machine=powerpc-unknown
- os=morphos
+ basic_os=morphos
;;
moxiebox)
basic_machine=moxie-unknown
- os=moxiebox
+ basic_os=moxiebox
;;
msdos)
basic_machine=i386-pc
- os=msdos
+ basic_os=msdos
;;
msys)
basic_machine=i686-pc
- os=msys
+ basic_os=msys
;;
mvs)
basic_machine=i370-ibm
- os=mvs
+ basic_os=mvs
;;
nacl)
basic_machine=le32-unknown
- os=nacl
+ basic_os=nacl
;;
ncr3000)
basic_machine=i486-ncr
- os=sysv4
+ basic_os=sysv4
;;
netbsd386)
- basic_machine=i386-unknown
- os=netbsd
+ basic_machine=i386-pc
+ basic_os=netbsd
;;
netwinder)
basic_machine=armv4l-rebel
- os=linux
+ basic_os=linux
;;
news | news700 | news800 | news900)
basic_machine=m68k-sony
- os=newsos
+ basic_os=newsos
;;
news1000)
basic_machine=m68030-sony
- os=newsos
+ basic_os=newsos
;;
necv70)
basic_machine=v70-nec
- os=sysv
+ basic_os=sysv
;;
nh3000)
basic_machine=m68k-harris
- os=cxux
+ basic_os=cxux
;;
nh[45]000)
basic_machine=m88k-harris
- os=cxux
+ basic_os=cxux
;;
nindy960)
basic_machine=i960-intel
- os=nindy
+ basic_os=nindy
;;
mon960)
basic_machine=i960-intel
- os=mon960
+ basic_os=mon960
;;
nonstopux)
basic_machine=mips-compaq
- os=nonstopux
+ basic_os=nonstopux
;;
os400)
basic_machine=powerpc-ibm
- os=os400
+ basic_os=os400
;;
OSE68000 | ose68000)
basic_machine=m68000-ericsson
- os=ose
+ basic_os=ose
;;
os68k)
basic_machine=m68k-none
- os=os68k
+ basic_os=os68k
;;
paragon)
basic_machine=i860-intel
- os=osf
+ basic_os=osf
;;
parisc)
basic_machine=hppa-unknown
- os=linux
+ basic_os=linux
+ ;;
+ psp)
+ basic_machine=mipsallegrexel-sony
+ basic_os=psp
;;
pw32)
basic_machine=i586-unknown
- os=pw32
+ basic_os=pw32
;;
rdos | rdos64)
basic_machine=x86_64-pc
- os=rdos
+ basic_os=rdos
;;
rdos32)
basic_machine=i386-pc
- os=rdos
+ basic_os=rdos
;;
rom68k)
basic_machine=m68k-rom68k
- os=coff
+ basic_os=coff
;;
sa29200)
basic_machine=a29k-amd
- os=udi
+ basic_os=udi
;;
sei)
basic_machine=mips-sei
- os=seiux
+ basic_os=seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ basic_os=
;;
sps7)
basic_machine=m68k-bull
- os=sysv2
+ basic_os=sysv2
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ basic_os=
;;
stratus)
basic_machine=i860-stratus
- os=sysv4
+ basic_os=sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ basic_os=
;;
sun2os3)
basic_machine=m68000-sun
- os=sunos3
+ basic_os=sunos3
;;
sun2os4)
basic_machine=m68000-sun
- os=sunos4
+ basic_os=sunos4
+ ;;
+ sun3)
+ basic_machine=m68k-sun
+ basic_os=
;;
sun3os3)
basic_machine=m68k-sun
- os=sunos3
+ basic_os=sunos3
;;
sun3os4)
basic_machine=m68k-sun
- os=sunos4
+ basic_os=sunos4
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ basic_os=
;;
sun4os3)
basic_machine=sparc-sun
- os=sunos3
+ basic_os=sunos3
;;
sun4os4)
basic_machine=sparc-sun
- os=sunos4
+ basic_os=sunos4
;;
sun4sol2)
basic_machine=sparc-sun
- os=solaris2
+ basic_os=solaris2
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ basic_os=
;;
sv1)
basic_machine=sv1-cray
- os=unicos
+ basic_os=unicos
;;
symmetry)
basic_machine=i386-sequent
- os=dynix
+ basic_os=dynix
;;
t3e)
basic_machine=alphaev5-cray
- os=unicos
+ basic_os=unicos
;;
t90)
basic_machine=t90-cray
- os=unicos
+ basic_os=unicos
;;
toad1)
basic_machine=pdp10-xkl
- os=tops20
+ basic_os=tops20
;;
tpf)
basic_machine=s390x-ibm
- os=tpf
+ basic_os=tpf
;;
udi29k)
basic_machine=a29k-amd
- os=udi
+ basic_os=udi
;;
ultra3)
basic_machine=a29k-nyu
- os=sym1
+ basic_os=sym1
;;
v810 | necv810)
basic_machine=v810-nec
- os=none
+ basic_os=none
;;
vaxv)
basic_machine=vax-dec
- os=sysv
+ basic_os=sysv
;;
vms)
basic_machine=vax-dec
- os=vms
+ basic_os=vms
+ ;;
+ vsta)
+ basic_machine=i386-pc
+ basic_os=vsta
;;
vxworks960)
basic_machine=i960-wrs
- os=vxworks
+ basic_os=vxworks
;;
vxworks68)
basic_machine=m68k-wrs
- os=vxworks
+ basic_os=vxworks
;;
vxworks29k)
basic_machine=a29k-wrs
- os=vxworks
+ basic_os=vxworks
;;
xbox)
basic_machine=i686-pc
- os=mingw32
+ basic_os=mingw32
;;
ymp)
basic_machine=ymp-cray
- os=unicos
+ basic_os=unicos
;;
*)
basic_machine=$1
- os=
+ basic_os=
;;
esac
;;
esac
-# Decode aliases for certain CPU-COMPANY combinations.
+# Decode 1-component or ad-hoc basic machines
case $basic_machine in
- # Recognize the basic CPU types without company name.
- # Some are omitted here because they have special meanings below.
- 1750a | 580 \
- | a29k \
- | aarch64 | aarch64_be \
- | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
- | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
- | am33_2.0 \
- | arc | arceb \
- | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv6m | armv[78][arm] \
- | avr | avr32 \
- | ba \
- | be32 | be64 \
- | bfin \
- | c4x | c8051 | clipper | csky \
- | d10v | d30v | dlx | dsp16xx \
- | e2k | epiphany \
- | fido | fr30 | frv | ft32 \
- | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
- | hexagon \
- | i370 | i860 | i960 | ia16 | ia64 \
- | ip2k | iq2000 \
- | k1om \
- | le32 | le64 \
- | lm32 \
- | m32c | m32r | m32rle | m68000 | m68k | m88k \
- | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
- | mips | mipsbe | mipseb | mipsel | mipsle \
- | mips16 \
- | mips64 | mips64el \
- | mips64octeon | mips64octeonel \
- | mips64orion | mips64orionel \
- | mips64r5900 | mips64r5900el \
- | mips64vr | mips64vrel \
- | mips64vr4100 | mips64vr4100el \
- | mips64vr4300 | mips64vr4300el \
- | mips64vr5000 | mips64vr5000el \
- | mips64vr5900 | mips64vr5900el \
- | mipsisa32 | mipsisa32el \
- | mipsisa32r2 | mipsisa32r2el \
- | mipsisa32r6 | mipsisa32r6el \
- | mipsisa64 | mipsisa64el \
- | mipsisa64r2 | mipsisa64r2el \
- | mipsisa64r6 | mipsisa64r6el \
- | mipsisa64sb1 | mipsisa64sb1el \
- | mipsisa64sr71k | mipsisa64sr71kel \
- | mipsr5900 | mipsr5900el \
- | mipstx39 | mipstx39el \
- | mn10200 | mn10300 \
- | moxie \
- | mt \
- | msp430 \
- | nds32 | nds32le | nds32be \
- | nfp \
- | nios | nios2 | nios2eb | nios2el \
- | ns16k | ns32k \
- | open8 | or1k | or1knd | or32 \
- | pdp10 | pj | pjl \
- | powerpc | powerpc64 | powerpc64le | powerpcle \
- | pru \
- | pyramid \
- | riscv | riscv32 | riscv64 \
- | rl78 | rx \
- | score \
- | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
- | sh64 | sh64le \
- | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
- | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
- | spu \
- | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
- | ubicom32 \
- | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
- | visium \
- | wasm32 \
- | x86 | xc16x | xstormy16 | xtensa \
- | z8k | z80)
- basic_machine=$basic_machine-unknown
- ;;
- c54x)
- basic_machine=tic54x-unknown
- ;;
- c55x)
- basic_machine=tic55x-unknown
- ;;
- c6x)
- basic_machine=tic6x-unknown
- ;;
- leon|leon[3-9])
- basic_machine=sparc-$basic_machine
- ;;
- m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
- basic_machine=$basic_machine-unknown
- os=${os:-none}
- ;;
- m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65)
+ # Here we handle the default manufacturer of certain CPU types. It is in
+ # some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ cpu=hppa1.1
+ vendor=winbond
;;
- m9s12z | m68hcs12z | hcs12z | s12z)
- basic_machine=s12z-unknown
- os=${os:-none}
+ op50n)
+ cpu=hppa1.1
+ vendor=oki
;;
- ms1)
- basic_machine=mt-unknown
+ op60c)
+ cpu=hppa1.1
+ vendor=oki
;;
- strongarm | thumb | xscale)
- basic_machine=arm-unknown
+ ibm*)
+ cpu=i370
+ vendor=ibm
;;
- xgate)
- basic_machine=$basic_machine-unknown
- os=${os:-none}
+ orion105)
+ cpu=clipper
+ vendor=highlevel
;;
- xscaleeb)
- basic_machine=armeb-unknown
+ mac | mpw | mac-mpw)
+ cpu=m68k
+ vendor=apple
;;
-
- xscaleel)
- basic_machine=armel-unknown
+ pmac | pmac-mpw)
+ cpu=powerpc
+ vendor=apple
;;
- # We use `pc' rather than `unknown'
- # because (1) that's what they normally are, and
- # (2) the word "unknown" tends to confuse beginning users.
- i*86 | x86_64)
- basic_machine=$basic_machine-pc
- ;;
- # Recognize the basic CPU types with company name.
- 580-* \
- | a29k-* \
- | aarch64-* | aarch64_be-* \
- | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
- | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
- | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
- | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
- | avr-* | avr32-* \
- | ba-* \
- | be32-* | be64-* \
- | bfin-* | bs2000-* \
- | c[123]* | c30-* | [cjt]90-* | c4x-* \
- | c8051-* | clipper-* | craynv-* | csky-* | cydra-* \
- | d10v-* | d30v-* | dlx-* \
- | e2k-* | elxsi-* \
- | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
- | h8300-* | h8500-* \
- | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
- | hexagon-* \
- | i*86-* | i860-* | i960-* | ia16-* | ia64-* \
- | ip2k-* | iq2000-* \
- | k1om-* \
- | le32-* | le64-* \
- | lm32-* \
- | m32c-* | m32r-* | m32rle-* \
- | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
- | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
- | microblaze-* | microblazeel-* \
- | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
- | mips16-* \
- | mips64-* | mips64el-* \
- | mips64octeon-* | mips64octeonel-* \
- | mips64orion-* | mips64orionel-* \
- | mips64r5900-* | mips64r5900el-* \
- | mips64vr-* | mips64vrel-* \
- | mips64vr4100-* | mips64vr4100el-* \
- | mips64vr4300-* | mips64vr4300el-* \
- | mips64vr5000-* | mips64vr5000el-* \
- | mips64vr5900-* | mips64vr5900el-* \
- | mipsisa32-* | mipsisa32el-* \
- | mipsisa32r2-* | mipsisa32r2el-* \
- | mipsisa32r6-* | mipsisa32r6el-* \
- | mipsisa64-* | mipsisa64el-* \
- | mipsisa64r2-* | mipsisa64r2el-* \
- | mipsisa64r6-* | mipsisa64r6el-* \
- | mipsisa64sb1-* | mipsisa64sb1el-* \
- | mipsisa64sr71k-* | mipsisa64sr71kel-* \
- | mipsr5900-* | mipsr5900el-* \
- | mipstx39-* | mipstx39el-* \
- | mmix-* \
- | mt-* \
- | msp430-* \
- | nds32-* | nds32le-* | nds32be-* \
- | nfp-* \
- | nios-* | nios2-* | nios2eb-* | nios2el-* \
- | none-* | np1-* | ns16k-* | ns32k-* \
- | open8-* \
- | or1k*-* \
- | orion-* \
- | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
- | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
- | pru-* \
- | pyramid-* \
- | riscv-* | riscv32-* | riscv64-* \
- | rl78-* | romp-* | rs6000-* | rx-* \
- | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
- | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
- | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
- | sparclite-* \
- | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
- | tahoe-* \
- | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
- | tile*-* \
- | tron-* \
- | ubicom32-* \
- | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
- | vax-* \
- | visium-* \
- | wasm32-* \
- | we32k-* \
- | x86-* | x86_64-* | xc16x-* | xps100-* \
- | xstormy16-* | xtensa*-* \
- | ymp-* \
- | z8k-* | z80-*)
- ;;
- # Recognize the basic CPU types without company name, with glob match.
- xtensa*)
- basic_machine=$basic_machine-unknown
- ;;
# Recognize the various machine names and aliases which stand
# for a CPU type and a company and sometimes even an OS.
3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
- basic_machine=m68000-att
+ cpu=m68000
+ vendor=att
;;
3b*)
- basic_machine=we32k-att
- ;;
- abacus)
- basic_machine=abacus-unknown
- ;;
- alliant | fx80)
- basic_machine=fx80-alliant
- ;;
- altos | altos3068)
- basic_machine=m68k-altos
- ;;
- amd64)
- basic_machine=x86_64-pc
- ;;
- amd64-*)
- basic_machine=x86_64-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- ;;
- amiga | amiga-*)
- basic_machine=m68k-unknown
- ;;
- asmjs)
- basic_machine=asmjs-unknown
- ;;
- blackfin-*)
- basic_machine=bfin-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- os=linux
+ cpu=we32k
+ vendor=att
;;
bluegene*)
- basic_machine=powerpc-ibm
- os=cnk
- ;;
- c54x-*)
- basic_machine=tic54x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- ;;
- c55x-*)
- basic_machine=tic55x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- ;;
- c6x-*)
- basic_machine=tic6x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- ;;
- c90)
- basic_machine=c90-cray
- os=${os:-unicos}
- ;;
- convex-c1)
- basic_machine=c1-convex
- os=bsd
- ;;
- convex-c2)
- basic_machine=c2-convex
- os=bsd
- ;;
- convex-c32)
- basic_machine=c32-convex
- os=bsd
- ;;
- convex-c34)
- basic_machine=c34-convex
- os=bsd
- ;;
- convex-c38)
- basic_machine=c38-convex
- os=bsd
- ;;
- cr16 | cr16-*)
- basic_machine=cr16-unknown
- os=${os:-elf}
- ;;
- crds | unos)
- basic_machine=m68k-crds
- ;;
- crisv32 | crisv32-* | etraxfs*)
- basic_machine=crisv32-axis
- ;;
- cris | cris-* | etrax*)
- basic_machine=cris-axis
- ;;
- crx)
- basic_machine=crx-unknown
- os=${os:-elf}
- ;;
- da30 | da30-*)
- basic_machine=m68k-da30
- ;;
- decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
- basic_machine=mips-dec
+ cpu=powerpc
+ vendor=ibm
+ basic_os=cnk
;;
decsystem10* | dec10*)
- basic_machine=pdp10-dec
- os=tops10
+ cpu=pdp10
+ vendor=dec
+ basic_os=tops10
;;
decsystem20* | dec20*)
- basic_machine=pdp10-dec
- os=tops20
+ cpu=pdp10
+ vendor=dec
+ basic_os=tops20
;;
delta | 3300 | motorola-3300 | motorola-delta \
| 3300-motorola | delta-motorola)
- basic_machine=m68k-motorola
- ;;
- dpx20 | dpx20-*)
- basic_machine=rs6000-bull
- os=${os:-bosx}
+ cpu=m68k
+ vendor=motorola
;;
dpx2*)
- basic_machine=m68k-bull
- os=sysv3
- ;;
- e500v[12])
- basic_machine=powerpc-unknown
- os=$os"spe"
- ;;
- e500v[12]-*)
- basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- os=$os"spe"
+ cpu=m68k
+ vendor=bull
+ basic_os=sysv3
;;
encore | umax | mmax)
- basic_machine=ns32k-encore
+ cpu=ns32k
+ vendor=encore
;;
elxsi)
- basic_machine=elxsi-elxsi
- os=${os:-bsd}
+ cpu=elxsi
+ vendor=elxsi
+ basic_os=${basic_os:-bsd}
;;
fx2800)
- basic_machine=i860-alliant
+ cpu=i860
+ vendor=alliant
;;
genix)
- basic_machine=ns32k-ns
+ cpu=ns32k
+ vendor=ns
;;
h3050r* | hiux*)
- basic_machine=hppa1.1-hitachi
- os=hiuxwe2
- ;;
- hp300-*)
- basic_machine=m68k-hp
+ cpu=hppa1.1
+ vendor=hitachi
+ basic_os=hiuxwe2
;;
hp3k9[0-9][0-9] | hp9[0-9][0-9])
- basic_machine=hppa1.0-hp
+ cpu=hppa1.0
+ vendor=hp
;;
hp9k2[0-9][0-9] | hp9k31[0-9])
- basic_machine=m68000-hp
+ cpu=m68000
+ vendor=hp
;;
hp9k3[2-9][0-9])
- basic_machine=m68k-hp
+ cpu=m68k
+ vendor=hp
;;
hp9k6[0-9][0-9] | hp6[0-9][0-9])
- basic_machine=hppa1.0-hp
+ cpu=hppa1.0
+ vendor=hp
;;
hp9k7[0-79][0-9] | hp7[0-79][0-9])
- basic_machine=hppa1.1-hp
+ cpu=hppa1.1
+ vendor=hp
;;
hp9k78[0-9] | hp78[0-9])
# FIXME: really hppa2.0-hp
- basic_machine=hppa1.1-hp
+ cpu=hppa1.1
+ vendor=hp
;;
hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
# FIXME: really hppa2.0-hp
- basic_machine=hppa1.1-hp
+ cpu=hppa1.1
+ vendor=hp
;;
hp9k8[0-9][13679] | hp8[0-9][13679])
- basic_machine=hppa1.1-hp
+ cpu=hppa1.1
+ vendor=hp
;;
hp9k8[0-9][0-9] | hp8[0-9][0-9])
- basic_machine=hppa1.0-hp
- ;;
- i370-ibm* | ibm*)
- basic_machine=i370-ibm
+ cpu=hppa1.0
+ vendor=hp
;;
i*86v32)
- basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
- os=sysv32
+ cpu=$(echo "$1" | sed -e 's/86.*/86/')
+ vendor=pc
+ basic_os=sysv32
;;
i*86v4*)
- basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
- os=sysv4
+ cpu=$(echo "$1" | sed -e 's/86.*/86/')
+ vendor=pc
+ basic_os=sysv4
;;
i*86v)
- basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
- os=sysv
+ cpu=$(echo "$1" | sed -e 's/86.*/86/')
+ vendor=pc
+ basic_os=sysv
;;
i*86sol2)
- basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
- os=solaris2
+ cpu=$(echo "$1" | sed -e 's/86.*/86/')
+ vendor=pc
+ basic_os=solaris2
;;
j90 | j90-cray)
- basic_machine=j90-cray
- os=${os:-unicos}
+ cpu=j90
+ vendor=cray
+ basic_os=${basic_os:-unicos}
;;
iris | iris4d)
- basic_machine=mips-sgi
- case $os in
+ cpu=mips
+ vendor=sgi
+ case $basic_os in
irix*)
;;
*)
- os=irix4
+ basic_os=irix4
;;
esac
;;
- leon-*|leon[3-9]-*)
- basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'`
- ;;
- m68knommu-*)
- basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- os=linux
- ;;
- microblaze*)
- basic_machine=microblaze-xilinx
- ;;
miniframe)
- basic_machine=m68000-convergent
+ cpu=m68000
+ vendor=convergent
;;
*mint | mint[0-9]* | *MiNT | *MiNT[0-9]*)
- basic_machine=m68k-atari
- os=mint
- ;;
- mips3*-*)
- basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`
- ;;
- mips3*)
- basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`-unknown
- ;;
- ms1-*)
- basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'`
+ cpu=m68k
+ vendor=atari
+ basic_os=mint
;;
news-3600 | risc-news)
- basic_machine=mips-sony
- os=newsos
+ cpu=mips
+ vendor=sony
+ basic_os=newsos
;;
next | m*-next)
- basic_machine=m68k-next
- case $os in
- nextstep* )
+ cpu=m68k
+ vendor=next
+ case $basic_os in
+ openstep*)
+ ;;
+ nextstep*)
;;
ns2*)
- os=nextstep2
+ basic_os=nextstep2
;;
*)
- os=nextstep3
+ basic_os=nextstep3
;;
esac
;;
np1)
- basic_machine=np1-gould
+ cpu=np1
+ vendor=gould
;;
- neo-tandem)
- basic_machine=neo-tandem
+ op50n-* | op60c-*)
+ cpu=hppa1.1
+ vendor=oki
+ basic_os=proelf
;;
- nse-tandem)
- basic_machine=nse-tandem
+ pa-hitachi)
+ cpu=hppa1.1
+ vendor=hitachi
+ basic_os=hiuxwe2
;;
- nsr-tandem)
- basic_machine=nsr-tandem
+ pbd)
+ cpu=sparc
+ vendor=tti
;;
- nsv-tandem)
- basic_machine=nsv-tandem
+ pbb)
+ cpu=m68k
+ vendor=tti
;;
- nsx-tandem)
- basic_machine=nsx-tandem
+ pc532)
+ cpu=ns32k
+ vendor=pc532
;;
- op50n-* | op60c-*)
- basic_machine=hppa1.1-oki
- os=proelf
+ pn)
+ cpu=pn
+ vendor=gould
;;
- openrisc | openrisc-*)
- basic_machine=or32-unknown
+ power)
+ cpu=power
+ vendor=ibm
;;
- pa-hitachi)
- basic_machine=hppa1.1-hitachi
- os=hiuxwe2
+ ps2)
+ cpu=i386
+ vendor=ibm
;;
- parisc-*)
- basic_machine=hppa-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- os=linux
+ rm[46]00)
+ cpu=mips
+ vendor=siemens
;;
- pbd)
- basic_machine=sparc-tti
+ rtpc | rtpc-*)
+ cpu=romp
+ vendor=ibm
;;
- pbb)
- basic_machine=m68k-tti
+ sde)
+ cpu=mipsisa32
+ vendor=sde
+ basic_os=${basic_os:-elf}
;;
- pc532 | pc532-*)
- basic_machine=ns32k-pc532
+ simso-wrs)
+ cpu=sparclite
+ vendor=wrs
+ basic_os=vxworks
;;
- pc98)
- basic_machine=i386-pc
+ tower | tower-32)
+ cpu=m68k
+ vendor=ncr
;;
- pc98-*)
- basic_machine=i386-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ vpp*|vx|vx-*)
+ cpu=f301
+ vendor=fujitsu
;;
- pentium | p5 | k5 | k6 | nexgen | viac3)
- basic_machine=i586-pc
+ w65)
+ cpu=w65
+ vendor=wdc
;;
- pentiumpro | p6 | 6x86 | athlon | athlon_*)
- basic_machine=i686-pc
+ w89k-*)
+ cpu=hppa1.1
+ vendor=winbond
+ basic_os=proelf
;;
- pentiumii | pentium2 | pentiumiii | pentium3)
- basic_machine=i686-pc
+ none)
+ cpu=none
+ vendor=none
;;
- pentium4)
- basic_machine=i786-pc
+ leon|leon[3-9])
+ cpu=sparc
+ vendor=$basic_machine
;;
- pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
- basic_machine=i586-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ leon-*|leon[3-9]-*)
+ cpu=sparc
+ vendor=$(echo "$basic_machine" | sed 's/-.*//')
;;
- pentiumpro-* | p6-* | 6x86-* | athlon-*)
- basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+
+ *-*)
+ # shellcheck disable=SC2162
+ IFS="-" read cpu vendor <<EOF
+$basic_machine
+EOF
;;
- pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
- basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ cpu=$basic_machine
+ vendor=pc
;;
- pentium4-*)
- basic_machine=i786-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ # These rules are duplicated from below for sake of the special case above;
+ # i.e. things that normalized to x86 arches should also default to "pc"
+ pc98)
+ cpu=i386
+ vendor=pc
;;
- pn)
- basic_machine=pn-gould
+ x64 | amd64)
+ cpu=x86_64
+ vendor=pc
;;
- power) basic_machine=power-ibm
+ # Recognize the basic CPU types without company name.
+ *)
+ cpu=$basic_machine
+ vendor=unknown
;;
- ppc | ppcbe) basic_machine=powerpc-unknown
+esac
+
+unset -v basic_machine
+
+# Decode basic machines in the full and proper CPU-Company form.
+case $cpu-$vendor in
+ # Here we handle the default manufacturer of certain CPU types in canonical form. It is in
+ # some cases the only manufacturer, in others, it is the most popular.
+ craynv-unknown)
+ vendor=cray
+ basic_os=${basic_os:-unicosmp}
;;
- ppc-* | ppcbe-*)
- basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ c90-unknown | c90-cray)
+ vendor=cray
+ basic_os=${Basic_os:-unicos}
;;
- ppcle | powerpclittle)
- basic_machine=powerpcle-unknown
+ fx80-unknown)
+ vendor=alliant
;;
- ppcle-* | powerpclittle-*)
- basic_machine=powerpcle-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ romp-unknown)
+ vendor=ibm
;;
- ppc64) basic_machine=powerpc64-unknown
+ mmix-unknown)
+ vendor=knuth
;;
- ppc64-*) basic_machine=powerpc64-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ microblaze-unknown | microblazeel-unknown)
+ vendor=xilinx
;;
- ppc64le | powerpc64little)
- basic_machine=powerpc64le-unknown
+ rs6000-unknown)
+ vendor=ibm
;;
- ppc64le-* | powerpc64little-*)
- basic_machine=powerpc64le-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ vax-unknown)
+ vendor=dec
;;
- ps2)
- basic_machine=i386-ibm
+ pdp11-unknown)
+ vendor=dec
;;
- rm[46]00)
- basic_machine=mips-siemens
+ we32k-unknown)
+ vendor=att
;;
- rtpc | rtpc-*)
- basic_machine=romp-ibm
+ cydra-unknown)
+ vendor=cydrome
;;
- s390 | s390-*)
- basic_machine=s390-ibm
+ i370-ibm*)
+ vendor=ibm
;;
- s390x | s390x-*)
- basic_machine=s390x-ibm
+ orion-unknown)
+ vendor=highlevel
;;
- sb1)
- basic_machine=mipsisa64sb1-unknown
+ xps-unknown | xps100-unknown)
+ cpu=xps100
+ vendor=honeywell
;;
- sb1el)
- basic_machine=mipsisa64sb1el-unknown
+
+ # Here we normalize CPU types with a missing or matching vendor
+ dpx20-unknown | dpx20-bull)
+ cpu=rs6000
+ vendor=bull
+ basic_os=${basic_os:-bosx}
;;
- sde)
- basic_machine=mipsisa32-sde
- os=${os:-elf}
+
+ # Here we normalize CPU types irrespective of the vendor
+ amd64-*)
+ cpu=x86_64
;;
- sequent)
- basic_machine=i386-sequent
+ blackfin-*)
+ cpu=bfin
+ basic_os=linux
;;
- sh5el)
- basic_machine=sh5le-unknown
+ c54x-*)
+ cpu=tic54x
;;
- simso-wrs)
- basic_machine=sparclite-wrs
- os=vxworks
+ c55x-*)
+ cpu=tic55x
;;
- spur)
- basic_machine=spur-unknown
+ c6x-*)
+ cpu=tic6x
;;
- st2000)
- basic_machine=m68k-tandem
+ e500v[12]-*)
+ cpu=powerpc
+ basic_os=${basic_os}"spe"
;;
- strongarm-* | thumb-*)
- basic_machine=arm-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ mips3*-*)
+ cpu=mips64
;;
- sun2)
- basic_machine=m68000-sun
+ ms1-*)
+ cpu=mt
;;
- sun3 | sun3-*)
- basic_machine=m68k-sun
+ m68knommu-*)
+ cpu=m68k
+ basic_os=linux
;;
- sun4)
- basic_machine=sparc-sun
+ m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*)
+ cpu=s12z
;;
- sun386 | sun386i | roadrunner)
- basic_machine=i386-sun
+ openrisc-*)
+ cpu=or32
;;
- tile*)
- basic_machine=$basic_machine-unknown
- os=linux-gnu
+ parisc-*)
+ cpu=hppa
+ basic_os=linux
;;
- tx39)
- basic_machine=mipstx39-unknown
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ cpu=i586
;;
- tx39el)
- basic_machine=mipstx39el-unknown
+ pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)
+ cpu=i686
;;
- tower | tower-32)
- basic_machine=m68k-ncr
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ cpu=i686
;;
- vpp*|vx|vx-*)
- basic_machine=f301-fujitsu
+ pentium4-*)
+ cpu=i786
;;
- w65*)
- basic_machine=w65-wdc
- os=none
+ pc98-*)
+ cpu=i386
;;
- w89k-*)
- basic_machine=hppa1.1-winbond
- os=proelf
+ ppc-* | ppcbe-*)
+ cpu=powerpc
;;
- x64)
- basic_machine=x86_64-pc
+ ppcle-* | powerpclittle-*)
+ cpu=powerpcle
;;
- xps | xps100)
- basic_machine=xps100-honeywell
+ ppc64-*)
+ cpu=powerpc64
;;
- xscale-* | xscalee[bl]-*)
- basic_machine=`echo "$basic_machine" | sed 's/^xscale/arm/'`
+ ppc64le-* | powerpc64little-*)
+ cpu=powerpc64le
;;
- none)
- basic_machine=none-none
- os=${os:-none}
+ sb1-*)
+ cpu=mipsisa64sb1
;;
-
-# Here we handle the default manufacturer of certain CPU types. It is in
-# some cases the only manufacturer, in others, it is the most popular.
- w89k)
- basic_machine=hppa1.1-winbond
+ sb1el-*)
+ cpu=mipsisa64sb1el
;;
- op50n)
- basic_machine=hppa1.1-oki
+ sh5e[lb]-*)
+ cpu=$(echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/')
;;
- op60c)
- basic_machine=hppa1.1-oki
+ spur-*)
+ cpu=spur
;;
- romp)
- basic_machine=romp-ibm
+ strongarm-* | thumb-*)
+ cpu=arm
;;
- mmix)
- basic_machine=mmix-knuth
+ tx39-*)
+ cpu=mipstx39
;;
- rs6000)
- basic_machine=rs6000-ibm
+ tx39el-*)
+ cpu=mipstx39el
;;
- vax)
- basic_machine=vax-dec
+ x64-*)
+ cpu=x86_64
;;
- pdp11)
- basic_machine=pdp11-dec
+ xscale-* | xscalee[bl]-*)
+ cpu=$(echo "$cpu" | sed 's/^xscale/arm/')
;;
- we32k)
- basic_machine=we32k-att
+ arm64-*)
+ cpu=aarch64
;;
- sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
- basic_machine=sh-unknown
+
+ # Recognize the canonical CPU Types that limit and/or modify the
+ # company names they are paired with.
+ cr16-*)
+ basic_os=${basic_os:-elf}
;;
- cydra)
- basic_machine=cydra-cydrome
+ crisv32-* | etraxfs*-*)
+ cpu=crisv32
+ vendor=axis
;;
- orion)
- basic_machine=orion-highlevel
+ cris-* | etrax*-*)
+ cpu=cris
+ vendor=axis
;;
- orion105)
- basic_machine=clipper-highlevel
+ crx-*)
+ basic_os=${basic_os:-elf}
;;
- mac | mpw | mac-mpw)
- basic_machine=m68k-apple
+ neo-tandem)
+ cpu=neo
+ vendor=tandem
;;
- pmac | pmac-mpw)
- basic_machine=powerpc-apple
+ nse-tandem)
+ cpu=nse
+ vendor=tandem
+ ;;
+ nsr-tandem)
+ cpu=nsr
+ vendor=tandem
;;
- *-unknown)
- # Make sure to match an already-canonicalized machine name.
+ nsv-tandem)
+ cpu=nsv
+ vendor=tandem
+ ;;
+ nsx-tandem)
+ cpu=nsx
+ vendor=tandem
;;
+ mipsallegrexel-sony)
+ cpu=mipsallegrexel
+ vendor=sony
+ ;;
+ tile*-*)
+ basic_os=${basic_os:-linux-gnu}
+ ;;
+
*)
- echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2
- exit 1
+ # Recognize the canonical CPU types that are allowed with any
+ # company name.
+ case $cpu in
+ 1750a | 580 \
+ | a29k \
+ | aarch64 | aarch64_be \
+ | abacus \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \
+ | alphapca5[67] | alpha64pca5[67] \
+ | am33_2.0 \
+ | amdgcn \
+ | arc | arceb \
+ | arm | arm[lb]e | arme[lb] | armv* \
+ | avr | avr32 \
+ | asmjs \
+ | ba \
+ | be32 | be64 \
+ | bfin | bpf | bs2000 \
+ | c[123]* | c30 | [cjt]90 | c4x \
+ | c8051 | clipper | craynv | csky | cydra \
+ | d10v | d30v | dlx | dsp16xx \
+ | e2k | elxsi | epiphany \
+ | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \
+ | h8300 | h8500 \
+ | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | hexagon \
+ | i370 | i*86 | i860 | i960 | ia16 | ia64 \
+ | ip2k | iq2000 \
+ | k1om \
+ | le32 | le64 \
+ | lm32 \
+ | loongarch32 | loongarch64 | loongarchx32 \
+ | m32c | m32r | m32rle \
+ | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \
+ | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \
+ | m88110 | m88k | maxq | mb | mcore | mep | metag \
+ | microblaze | microblazeel \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64eb | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa32r6 | mipsisa32r6el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64r6 | mipsisa64r6el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipsr5900 | mipsr5900el \
+ | mipstx39 | mipstx39el \
+ | mmix \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nds32 | nds32le | nds32be \
+ | nfp \
+ | nios | nios2 | nios2eb | nios2el \
+ | none | np1 | ns16k | ns32k | nvptx \
+ | open8 \
+ | or1k* \
+ | or32 \
+ | orion \
+ | picochip \
+ | pdp10 | pdp11 | pj | pjl | pn | power \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \
+ | pru \
+ | pyramid \
+ | riscv | riscv32 | riscv64 \
+ | rl78 | romp | rs6000 | rx \
+ | s390 | s390x \
+ | score \
+ | sh | shl \
+ | sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \
+ | sh[1234]e[lb] | sh[12345][lb]e | sh[23]ele | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \
+ | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \
+ | spu \
+ | tahoe \
+ | thumbv7* \
+ | tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \
+ | tron \
+ | ubicom32 \
+ | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \
+ | vax \
+ | visium \
+ | w65 \
+ | wasm32 | wasm64 \
+ | we32k \
+ | x86 | x86_64 | xc16x | xgate | xps100 \
+ | xstormy16 | xtensa* \
+ | ymp \
+ | z8k | z80)
+ ;;
+
+ *)
+ echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2
+ exit 1
+ ;;
+ esac
;;
esac
# Here we canonicalize certain aliases for manufacturers.
-case $basic_machine in
- *-digital*)
- basic_machine=`echo "$basic_machine" | sed 's/digital.*/dec/'`
+case $vendor in
+ digital*)
+ vendor=dec
;;
- *-commodore*)
- basic_machine=`echo "$basic_machine" | sed 's/commodore.*/cbm/'`
+ commodore*)
+ vendor=cbm
;;
*)
;;
@@ -1286,8 +1280,47 @@ esac
# Decode manufacturer-specific aliases for certain operating systems.
-if [ x$os != x ]
+if test x$basic_os != x
then
+
+# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just
+# set os.
+case $basic_os in
+ gnu/linux*)
+ kernel=linux
+ os=$(echo $basic_os | sed -e 's|gnu/linux|gnu|')
+ ;;
+ os2-emx)
+ kernel=os2
+ os=$(echo $basic_os | sed -e 's|os2-emx|emx|')
+ ;;
+ nto-qnx*)
+ kernel=nto
+ os=$(echo $basic_os | sed -e 's|nto-qnx|qnx|')
+ ;;
+ *-*)
+ # shellcheck disable=SC2162
+ IFS="-" read kernel os <<EOF
+$basic_os
+EOF
+ ;;
+ # Default OS when just kernel was specified
+ nto*)
+ kernel=nto
+ os=$(echo $basic_os | sed -e 's|nto|qnx|')
+ ;;
+ linux*)
+ kernel=linux
+ os=$(echo $basic_os | sed -e 's|linux|gnu|')
+ ;;
+ *)
+ kernel=
+ os=$basic_os
+ ;;
+esac
+
+# Now, normalize the OS (knowing we just have one component, it's not a kernel,
+# etc.)
case $os in
# First match some system type aliases that might get confused
# with valid system types.
@@ -1299,7 +1332,7 @@ case $os in
os=cnk
;;
solaris1 | solaris1.*)
- os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ os=$(echo $os | sed -e 's|solaris1|sunos4|')
;;
solaris)
os=solaris2
@@ -1307,9 +1340,6 @@ case $os in
unixware*)
os=sysv4.2uw
;;
- gnu/linux*)
- os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
- ;;
# es1800 is here to avoid being matched by es* (a different OS)
es1800*)
os=ose
@@ -1331,12 +1361,9 @@ case $os in
os=sco3.2v4
;;
sco3.2.[4-9]*)
- os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ os=$(echo $os | sed -e 's/sco3.2./sco3.2v/')
;;
- sco3.2v[4-9]* | sco5v6*)
- # Don't forget version if it is 3.2v4 or newer.
- ;;
- scout)
+ sco*v* | scout)
# Don't match below
;;
sco*)
@@ -1345,78 +1372,26 @@ case $os in
psos*)
os=psos
;;
- # Now accept the basic system types.
- # The portable systems comes first.
- # Each alternative MUST end in a * to match a version number.
- # sysv* is not here because it comes later, after sysvr4.
- gnu* | bsd* | mach* | minix* | genix* | ultrix* | irix* \
- | *vms* | esix* | aix* | cnk* | sunos | sunos[34]*\
- | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
- | sym* | kopensolaris* | plan9* \
- | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
- | aos* | aros* | cloudabi* | sortix* \
- | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
- | clix* | riscos* | uniplus* | iris* | rtu* | xenix* \
- | knetbsd* | mirbsd* | netbsd* \
- | bitrig* | openbsd* | solidbsd* | libertybsd* \
- | ekkobsd* | kfreebsd* | freebsd* | riscix* | lynxos* \
- | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
- | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
- | udi* | eabi* | lites* | ieee* | go32* | aux* | hcos* \
- | chorusrdb* | cegcc* | glidix* \
- | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
- | midipix* | mingw32* | mingw64* | linux-gnu* | linux-android* \
- | linux-newlib* | linux-musl* | linux-uclibc* \
- | uxpv* | beos* | mpeix* | udk* | moxiebox* \
- | interix* | uwin* | mks* | rhapsody* | darwin* \
- | openstep* | oskit* | conix* | pw32* | nonstopux* \
- | storm-chaos* | tops10* | tenex* | tops20* | its* \
- | os2* | vos* | palmos* | uclinux* | nucleus* \
- | morphos* | superux* | rtmk* | windiss* \
- | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \
- | skyos* | haiku* | rdos* | toppers* | drops* | es* \
- | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
- | midnightbsd*)
- # Remember, each alternative MUST END IN *, to match a version number.
- ;;
qnx*)
- case $basic_machine in
- x86-* | i*86-*)
- ;;
- *)
- os=nto-$os
- ;;
- esac
+ os=qnx
;;
hiux*)
os=hiuxwe2
;;
- nto-qnx*)
- ;;
- nto*)
- os=`echo $os | sed -e 's|nto|nto-qnx|'`
- ;;
- sim | xray | os68k* | v88r* \
- | windows* | osx | abug | netware* | os9* \
- | macos* | mpw* | magic* | mmixware* | mon960* | lnews*)
- ;;
- linux-dietlibc)
- os=linux-dietlibc
- ;;
- linux*)
- os=`echo $os | sed -e 's|linux|linux-gnu|'`
- ;;
lynx*178)
os=lynxos178
;;
lynx*5)
os=lynxos5
;;
+ lynxos*)
+ # don't get caught up in next wildcard
+ ;;
lynx*)
os=lynxos
;;
- mac*)
- os=`echo "$os" | sed -e 's|mac|macos|'`
+ mac[0-9]*)
+ os=$(echo "$os" | sed -e 's|mac|macos|')
;;
opened*)
os=openedition
@@ -1425,10 +1400,10 @@ case $os in
os=os400
;;
sunos5*)
- os=`echo "$os" | sed -e 's|sunos5|solaris2|'`
+ os=$(echo "$os" | sed -e 's|sunos5|solaris2|')
;;
sunos6*)
- os=`echo "$os" | sed -e 's|sunos6|solaris3|'`
+ os=$(echo "$os" | sed -e 's|sunos6|solaris3|')
;;
wince*)
os=wince
@@ -1460,12 +1435,9 @@ case $os in
ns2)
os=nextstep2
;;
- nsk*)
- os=nsk
- ;;
# Preserve the version number of sinix5.
sinix5.*)
- os=`echo $os | sed -e 's|sinix|sysv|'`
+ os=$(echo $os | sed -e 's|sinix|sysv|')
;;
sinix*)
os=sysv4
@@ -1488,18 +1460,12 @@ case $os in
sysvr4)
os=sysv4
;;
- # This must come after sysvr4.
- sysv*)
- ;;
ose*)
os=ose
;;
*mint | mint[0-9]* | *MiNT | MiNT[0-9]*)
os=mint
;;
- zvmoe)
- os=zvmoe
- ;;
dicos*)
os=dicos
;;
@@ -1507,7 +1473,7 @@ case $os in
# Until real need of OS specific support for
# particular features comes up, bare metal
# configurations are quite functional.
- case $basic_machine in
+ case $cpu in
arm*)
os=eabi
;;
@@ -1516,19 +1482,11 @@ case $os in
;;
esac
;;
- nacl*)
- ;;
- ios)
- ;;
- none)
- ;;
- *-eabi)
- ;;
*)
- echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2
- exit 1
+ # No normalization, but not necessarily accepted, that comes below.
;;
esac
+
else
# Here we handle the default operating systems that come with various machines.
@@ -1541,7 +1499,8 @@ else
# will signal an error saying that MANUFACTURER isn't an operating
# system, and we'll never get to this point.
-case $basic_machine in
+kernel=
+case $cpu-$vendor in
score-*)
os=elf
;;
@@ -1552,7 +1511,8 @@ case $basic_machine in
os=riscix1.2
;;
arm*-rebel)
- os=linux
+ kernel=linux
+ os=gnu
;;
arm*-semi)
os=aout
@@ -1718,86 +1678,173 @@ case $basic_machine in
os=none
;;
esac
+
fi
+# Now, validate our (potentially fixed-up) OS.
+case $os in
+ # Sometimes we do "kernel-abi", so those need to count as OSes.
+ musl* | newlib* | uclibc*)
+ ;;
+ # Likewise for "kernel-libc"
+ eabi | eabihf | gnueabi | gnueabihf)
+ ;;
+ # Now accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST end in a * to match a version number.
+ gnu* | android* | bsd* | mach* | minix* | genix* | ultrix* | irix* \
+ | *vms* | esix* | aix* | cnk* | sunos | sunos[34]* \
+ | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
+ | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \
+ | hiux* | abug | nacl* | netware* | windows* \
+ | os9* | macos* | osx* | ios* \
+ | mpw* | magic* | mmixware* | mon960* | lnews* \
+ | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
+ | aos* | aros* | cloudabi* | sortix* | twizzler* \
+ | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
+ | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \
+ | mirbsd* | netbsd* | dicos* | openedition* | ose* \
+ | bitrig* | openbsd* | solidbsd* | libertybsd* | os108* \
+ | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \
+ | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
+ | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
+ | udi* | lites* | ieee* | go32* | aux* | hcos* \
+ | chorusrdb* | cegcc* | glidix* \
+ | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
+ | midipix* | mingw32* | mingw64* | mint* \
+ | uxpv* | beos* | mpeix* | udk* | moxiebox* \
+ | interix* | uwin* | mks* | rhapsody* | darwin* \
+ | openstep* | oskit* | conix* | pw32* | nonstopux* \
+ | storm-chaos* | tops10* | tenex* | tops20* | its* \
+ | os2* | vos* | palmos* | uclinux* | nucleus* | morphos* \
+ | scout* | superux* | sysv* | rtmk* | tpf* | windiss* \
+ | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \
+ | skyos* | haiku* | rdos* | toppers* | drops* | es* \
+ | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
+ | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
+ | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*)
+ ;;
+ # This one is extra strict with allowed versions
+ sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ ;;
+ none)
+ ;;
+ *)
+ echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# As a final step for OS-related things, validate the OS-kernel combination
+# (given a valid OS), if there is a kernel.
+case $kernel-$os in
+ linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* )
+ ;;
+ uclinux-uclibc* )
+ ;;
+ -dietlibc* | -newlib* | -musl* | -uclibc* )
+ # 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
+ ;;
+ kfreebsd*-gnu* | kopensolaris*-gnu*)
+ ;;
+ nto-qnx*)
+ ;;
+ os2-emx)
+ ;;
+ *-eabi* | *-gnueabi*)
+ ;;
+ -*)
+ # Blank kernel with real OS is always fine.
+ ;;
+ *-*)
+ echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2
+ exit 1
+ ;;
+esac
+
# Here we handle the case where we know the os, and the CPU type, but not the
# manufacturer. We pick the logical manufacturer.
-vendor=unknown
-case $basic_machine in
- *-unknown)
- case $os in
- riscix*)
+case $vendor in
+ unknown)
+ case $cpu-$os in
+ *-riscix*)
vendor=acorn
;;
- sunos*)
+ *-sunos*)
vendor=sun
;;
- cnk*|-aix*)
+ *-cnk* | *-aix*)
vendor=ibm
;;
- beos*)
+ *-beos*)
vendor=be
;;
- hpux*)
+ *-hpux*)
vendor=hp
;;
- mpeix*)
+ *-mpeix*)
vendor=hp
;;
- hiux*)
+ *-hiux*)
vendor=hitachi
;;
- unos*)
+ *-unos*)
vendor=crds
;;
- dgux*)
+ *-dgux*)
vendor=dg
;;
- luna*)
+ *-luna*)
vendor=omron
;;
- genix*)
+ *-genix*)
vendor=ns
;;
- clix*)
+ *-clix*)
vendor=intergraph
;;
- mvs* | opened*)
+ *-mvs* | *-opened*)
+ vendor=ibm
+ ;;
+ *-os400*)
vendor=ibm
;;
- os400*)
+ s390-* | s390x-*)
vendor=ibm
;;
- ptx*)
+ *-ptx*)
vendor=sequent
;;
- tpf*)
+ *-tpf*)
vendor=ibm
;;
- vxsim* | vxworks* | windiss*)
+ *-vxsim* | *-vxworks* | *-windiss*)
vendor=wrs
;;
- aux*)
+ *-aux*)
vendor=apple
;;
- hms*)
+ *-hms*)
vendor=hitachi
;;
- mpw* | macos*)
+ *-mpw* | *-macos*)
vendor=apple
;;
- *mint | mint[0-9]* | *MiNT | MiNT[0-9]*)
+ *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*)
vendor=atari
;;
- vos*)
+ *-vos*)
vendor=stratus
;;
esac
- basic_machine=`echo "$basic_machine" | sed "s/unknown/$vendor/"`
;;
esac
-echo "$basic_machine-$os"
+echo "$cpu-$vendor-${kernel:+$kernel-}$os"
exit
# Local variables:
diff --git a/configure b/configure
index fa15fc73..fd572193 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for pcap 1.9.1.
+# Generated by GNU Autoconf 2.69 for pcap 1.10.0.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -577,8 +577,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='pcap'
PACKAGE_TARNAME='pcap'
-PACKAGE_VERSION='1.9.1'
-PACKAGE_STRING='pcap 1.9.1'
+PACKAGE_VERSION='1.10.0'
+PACKAGE_STRING='pcap 1.10.0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -623,20 +623,13 @@ ac_subst_vars='LTLIBOBJS
INSTALL_DATA
INSTALL_SCRIPT
INSTALL_PROGRAM
-RDMA_SRC
PCAP_SUPPORT_RDMASNIFF
-DBUS_SRC
PCAP_SUPPORT_DBUS
-PKGCONFIG
-BT_MONITOR_SRC
-BT_SRC
PCAP_SUPPORT_BT
-NETMAP_SRC
+PCAP_SUPPORT_DPDK
PCAP_SUPPORT_NETMAP
-NETFILTER_SRC
PCAP_SUPPORT_NETFILTER
-USB_SRC
-PCAP_SUPPORT_USB
+PCAP_SUPPORT_LINUX_USBMON
EXTRA_NETWORK_LIBS
RPCAPD_LIBS
INSTALL_RPCAPD
@@ -647,7 +640,10 @@ MAN_MISC_INFO
MAN_FILE_FORMATS
MAN_DEVICES
DYEXT
-SSRC
+REMOTE_C_SRC
+MODULE_C_SRC
+PLATFORM_CXX_SRC
+PLATFORM_C_SRC
ADDLARCHIVEOBJS
ADDLOBJS
V_YACC
@@ -656,10 +652,8 @@ V_SONAME_OPT
V_SHLIB_OPT
V_SHLIB_CMD
V_SHLIB_CCOPT
-V_PCAP
V_LEX
V_INCLS
-V_FINDALLDEVS
V_DEFS
V_PROG_LDFLAGS_FAT
V_PROG_CCOPT_FAT
@@ -671,17 +665,21 @@ DEPENDENCY_CFLAG
LN_S
AR
RANLIB
+REENTRANT_PARSER
YFLAGS
YACC
LEXLIB
LEX_OUTPUT_ROOT
LEX
-PCAP_SUPPORT_PACKET_RING
+PKGCONFIG
VALGRINDTEST_SRC
LIBOBJS
EGREP
GREP
CPP
+ac_ct_CXX
+CXXFLAGS
+CXX
OBJEXT
EXEEXT
ac_ct_CC
@@ -747,10 +745,8 @@ enable_option_checking
with_gcc
enable_largefile
enable_protochain
-with_sita
with_pcap
with_libnl
-enable_packet_ring
enable_ipv6
with_dag
with_dag_includes
@@ -767,6 +763,7 @@ enable_universal
enable_shared
enable_usb
enable_netmap
+with_dpdk
enable_bluetooth
enable_dbus
enable_rdma
@@ -779,6 +776,9 @@ CFLAGS
LDFLAGS
LIBS
CPPFLAGS
+CXX
+CXXFLAGS
+CCC
CPP
YACC
YFLAGS'
@@ -1332,7 +1332,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures pcap 1.9.1 to adapt to many kinds of systems.
+\`configure' configures pcap 1.10.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1399,7 +1399,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of pcap 1.9.1:";;
+ short | recursive ) echo "Configuration of pcap 1.10.0:";;
esac
cat <<\_ACEOF
@@ -1409,7 +1409,6 @@ Optional Features:
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--disable-largefile omit support for large files
--disable-protochain disable \"protochain\" insn
- --enable-packet-ring enable packet ring support on Linux [default=yes]
--enable-ipv6 build IPv6-capable version [default=yes]
--enable-remote enable remote packet capture [default=no]
--disable-remote disable remote packet capture
@@ -1418,8 +1417,8 @@ Optional Features:
--disable-universal don't build universal on macOS
--enable-shared build shared libraries [default=yes, if support
available]
- --enable-usb enable USB capture support [default=yes, if support
- available]
+ --enable-usb enable Linux usbmon USB capture support
+ [default=yes, if support available]
--enable-netmap enable netmap support [default=yes, if support
available]
--enable-bluetooth enable Bluetooth support [default=yes, if support
@@ -1433,7 +1432,6 @@ Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--without-gcc don't use gcc
- --with-sita include SITA support
--with-pcap=TYPE use packet capture TYPE
--without-libnl disable libnl support [default=yes, on Linux, if
present]
@@ -1454,6 +1452,8 @@ Optional Packages:
--with-turbocap[=DIR] include Riverbed TurboCap support (located in
directory DIR, if supplied). [default=yes, if
present]
+ --with-dpdk[=DIR] include DPDK support (located in directory DIR, if
+ supplied). [default=yes, if present]
Some influential environment variables:
CC C compiler command
@@ -1463,6 +1463,8 @@ 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>
+ CXX C++ compiler command
+ CXXFLAGS C++ compiler flags
CPP C preprocessor
YACC The `Yet Another Compiler Compiler' implementation to use.
Defaults to the first program found out of: `bison -y', `byacc',
@@ -1537,7 +1539,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-pcap configure 1.9.1
+pcap configure 1.10.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1589,6 +1591,44 @@ fi
} # ac_fn_c_try_compile
+# ac_fn_cxx_try_compile LINENO
+# ----------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+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_compile") 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; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; 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_cxx_try_compile
+
# ac_fn_c_try_link LINENO
# -----------------------
# Try to link conftest.$ac_ext, and return whether this succeeded.
@@ -2059,7 +2099,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by pcap $as_me 1.9.1, which was
+It was created by pcap $as_me 1.10.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -2624,8 +2664,9 @@ fi
fi
#
-# Try to enable as many C99 features as we can.
-# At minimum, we want C++/C99-style // comments.
+# We require C99 or later.
+# Try to get it, which may involve adding compiler flags;
+# if that fails, give up.
#
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
@@ -3594,11 +3635,275 @@ fi
if test "$ac_cv_prog_cc_c99" = "no"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: The C compiler does not support C99; there may be compiler errors" >&5
-$as_echo "$as_me: WARNING: The C compiler does not support C99; there may be compiler errors" >&2;}
+ as_fn_error $? "The C compiler does not support C99" "$LINENO" 5
+fi
+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'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -z "$CXX"; then
+ if test -n "$CCC"; then
+ CXX=$CCC
+ else
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CXX"; then
+ ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
+$as_echo "$CXX" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CXX" && break
+ done
+fi
+if test -z "$CXX"; then
+ ac_ct_CXX=$CXX
+ for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CXX"; then
+ ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CXX="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
+$as_echo "$ac_ct_CXX" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
fi
+ test -n "$ac_ct_CXX" && break
+done
+
+ if test "x$ac_ct_CXX" = x; then
+ CXX="g++"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CXX=$ac_ct_CXX
+ fi
+fi
+
+ fi
+fi
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+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_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
+$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
+if ${ac_cv_cxx_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
+$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GXX=yes
+else
+ GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
+$as_echo_n "checking whether $CXX accepts -g... " >&6; }
+if ${ac_cv_prog_cxx_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+ ac_cxx_werror_flag=yes
+ ac_cv_prog_cxx_g=no
+ CXXFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_prog_cxx_g=yes
+else
+ CXXFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+else
+ ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+ CXXFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_prog_cxx_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
+$as_echo "$ac_cv_prog_cxx_g" >&6; }
+if test "$ac_test_CXXFLAGS" = set; then
+ CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+ if test "$GXX" = yes; then
+ CXXFLAGS="-g -O2"
+ else
+ CXXFLAGS="-g"
+ fi
+else
+ if test "$GXX" = yes; then
+ CXXFLAGS="-O2"
+ else
+ CXXFLAGS=
+ fi
+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
+
+ ;;
+esac
+
+
+
@@ -4018,8 +4323,8 @@ $as_echo "#define const /**/" >>confdefs.h
aix*)
;;
- freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*|midipix*)
- #
+ freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*|haiku*|midipix*)
+ #
# Platforms where the linker is the GNU linker
# or accepts command-line arguments like
# those the GNU linker accepts.
@@ -4048,7 +4353,7 @@ $as_echo "#define const /**/" >>confdefs.h
hpux*)
V_SHLIB_CCOPT="$V_SHLIB_CCOPT -fpic"
- #
+ #
# XXX - this assumes GCC is using the HP linker,
# rather than the GNU linker, and that the "+h"
# option is used on all HP-UX platforms, both .sl
@@ -4056,7 +4361,7 @@ $as_echo "#define const /**/" >>confdefs.h
#
V_SONAME_OPT="-Wl,+h,"
#
- # By default, directories specifed with -L
+ # By default, directories specified with -L
# are added to the run-time search path, so
# we don't add them in pcap-config.
#
@@ -4117,14 +4422,14 @@ $as_echo "#define const /**/" >>confdefs.h
V_SHLIB_OPT="-b"
V_SONAME_OPT="+h "
#
- # By default, directories specifed with -L
+ # By default, directories specified with -L
# are added to the run-time search path, so
# we don't add them in pcap-config.
#
;;
osf*)
- #
+ #
# Presumed to be DEC OSF/1, Digital UNIX, or
# Tru64 UNIX.
#
@@ -4876,7 +5181,7 @@ fi
done
-for ac_header in sys/ioccom.h sys/sockio.h limits.h
+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"
@@ -4952,24 +5257,11 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
case "$host_os" in
-linux*|uclinux*)
- for ac_header in linux/sockios.h linux/if_bonding.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" "
-#include <sys/socket.h>
-#include <linux/if.h>
-
-"
-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
-
+haiku*)
+ #
+ # Haiku needs _BSD_SOURCE for the _IO* macros because it doesn't use them.
+ #
+ CFLAGS="$CFLAGS -D_BSD_SOURCE"
;;
esac
@@ -5079,14 +5371,14 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
else
#
- # We don't have strerror_r; do we have strerror_s?
+ # We don't have strerror_r; do we have _wcserror_s?
#
- for ac_func in strerror_s
+ for ac_func in _wcserror_s
do :
- ac_fn_c_check_func "$LINENO" "strerror_s" "ac_cv_func_strerror_s"
-if test "x$ac_cv_func_strerror_s" = xyes; then :
+ ac_fn_c_check_func "$LINENO" "_wcserror_s" "ac_cv_func__wcserror_s"
+if test "x$ac_cv_func__wcserror_s" = xyes; then :
cat >>confdefs.h <<_ACEOF
-#define HAVE_STRERROR_S 1
+#define HAVE__WCSERROR_S 1
_ACEOF
fi
@@ -5112,41 +5404,22 @@ done
#
-# Either:
-#
-# we have snprintf() and vsnprintf(), and have asprintf() and
-# vasprintf();
+# Make sure we have vsnprintf() and snprintf(); we require them.
#
-# we have snprintf() and vsnprintf(), but don't have asprintf()
-# or vasprintf();
-#
-# we have neither snprintf() nor vsnprintf(), and don't have
-# asprintf() or vasprintf(), either.
-#
-# We assume that if we have asprintf() we have vasprintf(), as well
-# as snprintf() and vsnprintf(), and that if we have snprintf() we
-# have vsnprintf().
-#
-# For the first case, we don't need any replacement routines.
-# For the second case, we need replacement asprintf()/vasprintf()
-# routines.
-# For the third case, we need replacement snprintf()/vsnprintf() and
-# asprintf()/vasprintf() routines.
-#
-needsnprintf=no
-for ac_func in vsnprintf snprintf
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf"
+if test "x$ac_cv_func_vsnprintf" = xyes; then :
else
- needsnprintf=yes
+ as_fn_error $? "vsnprintf() is required but wasn't found" "$LINENO" 5
fi
-done
+
+ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf"
+if test "x$ac_cv_func_snprintf" = xyes; then :
+
+else
+ as_fn_error $? "snprintf() is required but wasn't found" "$LINENO" 5
+fi
+
needasprintf=no
for ac_func in vasprintf asprintf
@@ -5163,23 +5436,7 @@ else
fi
done
-if test $needsnprintf = yes; then
- #
- # We assume we have none of them; missing/snprintf.c supplies
- # all of them.
- #
- case " $LIBOBJS " in
- *" snprintf.$ac_objext "* ) ;;
- *) LIBOBJS="$LIBOBJS snprintf.$ac_objext"
- ;;
-esac
-
-elif test $needasprintf = yes; then
- #
- # We assume we have snprintf()/vsnprintf() but lack
- # asprintf()/vasprintf(); missing/asprintf.c supplies
- # the latter (using vsnprintf()).
- #
+if test $needasprintf = yes; then
case " $LIBOBJS " in
*" asprintf.$ac_objext "* ) ;;
*) LIBOBJS="$LIBOBJS asprintf.$ac_objext"
@@ -5355,10 +5612,58 @@ if test "x$ac_cv_lib_socket_getaddrinfo" = xyes; then :
else
- #
- # We didn't find it.
- #
- as_fn_error $? "getaddrinfo is required, but wasn't found" "$LINENO" 5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo in -lnetwork" >&5
+$as_echo_n "checking for getaddrinfo in -lnetwork... " >&6; }
+if ${ac_cv_lib_network_getaddrinfo+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnetwork $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* 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
+char getaddrinfo ();
+int
+main ()
+{
+return getaddrinfo ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_network_getaddrinfo=yes
+else
+ ac_cv_lib_network_getaddrinfo=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_getaddrinfo" >&5
+$as_echo "$ac_cv_lib_network_getaddrinfo" >&6; }
+if test "x$ac_cv_lib_network_getaddrinfo" = xyes; then :
+
+ #
+ # OK, we found it in libnetwork on Haiku.
+ #
+ LIBS="-lnetwork $LIBS"
+
+else
+
+ #
+ # We didn't find it.
+ #
+ as_fn_error $? "getaddrinfo is required, but wasn't found" "$LINENO" 5
+
+fi
+
fi
@@ -6101,25 +6406,6 @@ $as_echo "${enable_protochain}" >&6; }
#
VALGRINDTEST_SRC=
-#
-# SITA support is mutually exclusive with native capture support;
-# "--with-sita" selects SITA support.
-#
-
-# Check whether --with-sita was given.
-if test "${with_sita+set}" = set; then :
- withval=$with_sita;
- if test ! "x$withval" = "xno" ; then
-
-$as_echo "#define SITA 1" >>confdefs.h
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: Enabling SITA ACN support" >&5
-$as_echo "$as_me: Enabling SITA ACN support" >&6;}
- V_PCAP=sita
- fi
-
-else
-
# Check whether --with-pcap was given.
if test "${with_pcap+set}" = set; then :
@@ -6254,6 +6540,18 @@ fi
done
+ for ac_header in config/HaikuConfig.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "config/HaikuConfig.h" "ac_cv_header_config_HaikuConfig_h" "$ac_includes_default"
+if test "x$ac_cv_header_config_HaikuConfig_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_CONFIG_HAIKUCONFIG_H 1
+_ACEOF
+
+fi
+
+done
+
if test "$ac_cv_lbl_bpf_h_defines_biocsetif" = yes; then
#
@@ -6279,11 +6577,6 @@ done
# No prizes for guessing this one.
#
V_PCAP=linux
-
- #
- # XXX - this won't work with older kernels that have
- # SOCK_PACKET sockets but not PF_PACKET sockets.
- #
VALGRINDTEST_SRC=valgrindtest.c
elif test "$ac_cv_header_net_pfilt_h" = yes; then
#
@@ -6315,6 +6608,11 @@ done
# DLPI on pre-Solaris 11 SunOS 5, HP-UX, possibly others.
#
V_PCAP=dlpi
+ elif test "$ac_cv_header_config_HaikuConfig_h" = yes; then
+ #
+ # Haiku.
+ #
+ V_PCAP=haiku
else
#
# Nothing we support.
@@ -6333,16 +6631,53 @@ $as_echo "$V_PCAP" >&6; }
#
-# Do capture-mechanism-dependent tests.
+# Do we have pkg-config?
+#
+# Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_PKGCONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$PKGCONFIG"; then
+ ac_cv_prog_PKGCONFIG="$PKGCONFIG" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_PKGCONFIG="pkg-config"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_prog_PKGCONFIG" && ac_cv_prog_PKGCONFIG="no"
+fi
+fi
+PKGCONFIG=$ac_cv_prog_PKGCONFIG
+if test -n "$PKGCONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5
+$as_echo "$PKGCONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+#
+# Handle each capture type.
#
case "$V_PCAP" in
dlpi)
#
- # Needed for common functions used by pcap-[dlpi,libdlpi].c
- #
- SSRC="dlpisubs.c"
-
- #
# Checks for some header files.
#
for ac_header in sys/bufmod.h sys/dlpi_ext.h
@@ -6370,7 +6705,7 @@ done
# Also, due to the bug above applications that link to libpcap with
# libdlpi will have to add "-L/lib" option to "configure".
#
- saved_ldflags=$LDFLAGS
+ save_LDFLAGS="$LDFLAGS"
LDFLAGS="$LIBS -L/lib"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlpi_walk in -ldlpi" >&5
$as_echo_n "checking for dlpi_walk in -ldlpi... " >&6; }
@@ -6413,14 +6748,28 @@ if test "x$ac_cv_lib_dlpi_dlpi_walk" = xyes; then :
LIBS="-ldlpi $LIBS"
V_PCAP=libdlpi
+ #
+ # Capture module plus common code needed for
+ # common functions used by pcap-[dlpi,libdlpi].c
+ #
+ PLATFORM_C_SRC="pcap-libdlpi.c dlpisubs.c"
+
$as_echo "#define HAVE_LIBDLPI 1" >>confdefs.h
else
- V_PCAP=dlpi
+
+ V_PCAP=dlpi
+
+ #
+ # Capture module plus common code needed for
+ # common functions used by pcap-[dlpi,libdlpi].c
+ #
+ PLATFORM_C_SRC="pcap-dlpi.c dlpisubs.c"
+
fi
- LDFLAGS=$saved_ldflags
+ LDFLAGS="$save_LDFLAGS"
#
# Checks whether <sys/dlpi.h> is usable, to catch weird SCO
@@ -6482,8 +6831,44 @@ fi
;;
+enet)
+ #
+ # Capture module
+ #
+ PLATFORM_C_SRC="pcap-enet.c"
+ ;;
+
+haiku)
+ #
+ # Capture module
+ #
+ PLATFORM_CXX_SRC="pcap-haiku.cpp"
+
+ #
+ # Just for the sake of it.
+ #
+ for ac_header in net/if.h net/if_dl.h net/if_types.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+ ;;
+
linux)
#
+ # Capture module
+ #
+ PLATFORM_C_SRC="pcap-linux.c"
+
+ #
# Do we have the wireless extensions?
#
for ac_header in linux/wireless.h
@@ -6506,6 +6891,12 @@ done
#
# Do we have libnl?
+ # We only want version 3. Version 2 was, apparently,
+ # short-lived, and version 1 is source and binary
+ # incompatible with version 3, and it appears that,
+ # these days, everybody's using version 3. We're
+ # not supporting older versions of the Linux kernel;
+ # let's drop support for older versions of libnl, too.
#
# Check whether --with-libnl was given.
@@ -6517,27 +6908,51 @@ fi
if test x$with_libnl != xno ; then
- have_any_nl="no"
+ if test "x$PKGCONFIG" != "xno"; then
+ #
+ # We have pkg-config; see if we have libnl-genl-3.0
+ # as a package.
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libnl-genl-3.0 with pkg-config" >&5
+$as_echo_n "checking for libnl-genl-3.0 with pkg-config... " >&6; }
+ if "$PKGCONFIG" libnl-genl-3.0; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5
+$as_echo "found" >&6; }
+ pkg_config_found_libnl=yes
+ libnl_genl_cflags=`"$PKGCONFIG" --cflags libnl-genl-3.0`
+ V_INCLS="$V_INCLS ${libnl_genl_cflags}"
+ libnl_genl_libs=`"$PKGCONFIG" --libs libnl-genl-3.0`
+ LIBS="${libnl_genl_libs} $LIBS"
+
+$as_echo "#define HAVE_LIBNL 1" >>confdefs.h
+
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+ fi
+ fi
- incdir=-I/usr/include/libnl3
- libnldir=
- case "$with_libnl" in
+ if test x$pkg_config_found_libnl != xyes; then
+ #
+ # OK, either we don't have pkg-config or there
+ # wasn't a .pc file for it; Check for it directly.
+ #
+ case "$with_libnl" in
- yes|if_available)
- ;;
+ yes|if_available)
+ incdir=-I/usr/include/libnl3
+ libnldir=
+ ;;
- *)
- if test -d $withval; then
- libnldir=-L${withval}/lib/.libs
- incdir=-I${withval}/include
- fi
- ;;
- esac
+ *)
+ if test -d $withval; then
+ libnldir=-L${withval}/lib
+ incdir=-I${withval}/include
+ fi
+ ;;
+ esac
- #
- # Try libnl 3.x first.
- #
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_socket_alloc in -lnl-3" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_socket_alloc in -lnl-3" >&5
$as_echo_n "checking for nl_socket_alloc in -lnl-3... " >&6; }
if ${ac_cv_lib_nl_3_nl_socket_alloc+:} false; then :
$as_echo_n "(cached) " >&6
@@ -6575,195 +6990,31 @@ fi
$as_echo "$ac_cv_lib_nl_3_nl_socket_alloc" >&6; }
if test "x$ac_cv_lib_nl_3_nl_socket_alloc" = xyes; then :
- #
- # Yes, we have libnl 3.x.
- #
- LIBS="${libnldir} -lnl-genl-3 -lnl-3 $LIBS"
-
-$as_echo "#define HAVE_LIBNL 1" >>confdefs.h
-
-
-$as_echo "#define HAVE_LIBNL_3_x 1" >>confdefs.h
-
-
-$as_echo "#define HAVE_LIBNL_NLE 1" >>confdefs.h
-
-
-$as_echo "#define HAVE_LIBNL_SOCKETS 1" >>confdefs.h
-
- V_INCLS="$V_INCLS ${incdir}"
- have_any_nl="yes"
-
-fi
-
-
- if test x$have_any_nl = xno ; then
- #
- # Try libnl 2.x
- #
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_socket_alloc in -lnl" >&5
-$as_echo_n "checking for nl_socket_alloc in -lnl... " >&6; }
-if ${ac_cv_lib_nl_nl_socket_alloc+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lnl $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* 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
-char nl_socket_alloc ();
-int
-main ()
-{
-return nl_socket_alloc ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_nl_nl_socket_alloc=yes
-else
- ac_cv_lib_nl_nl_socket_alloc=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nl_nl_socket_alloc" >&5
-$as_echo "$ac_cv_lib_nl_nl_socket_alloc" >&6; }
-if test "x$ac_cv_lib_nl_nl_socket_alloc" = xyes; then :
-
#
- # Yes, we have libnl 2.x.
+ # Yes, we have libnl 3.x.
#
- LIBS="${libnldir} -lnl-genl -lnl $LIBS"
+ LIBS="${libnldir} -lnl-genl-3 -lnl-3 $LIBS"
$as_echo "#define HAVE_LIBNL 1" >>confdefs.h
+ V_INCLS="$V_INCLS ${incdir}"
-$as_echo "#define HAVE_LIBNL_2_x 1" >>confdefs.h
-
-
-$as_echo "#define HAVE_LIBNL_NLE 1" >>confdefs.h
-
-
-$as_echo "#define HAVE_LIBNL_SOCKETS 1" >>confdefs.h
-
- have_any_nl="yes"
-
-fi
-
- fi
-
- if test x$have_any_nl = xno ; then
- #
- # No, we don't; do we have libnl 1.x?
- #
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_handle_alloc in -lnl" >&5
-$as_echo_n "checking for nl_handle_alloc in -lnl... " >&6; }
-if ${ac_cv_lib_nl_nl_handle_alloc+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lnl $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* 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
-char nl_handle_alloc ();
-int
-main ()
-{
-return nl_handle_alloc ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_nl_nl_handle_alloc=yes
else
- ac_cv_lib_nl_nl_handle_alloc=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nl_nl_handle_alloc" >&5
-$as_echo "$ac_cv_lib_nl_nl_handle_alloc" >&6; }
-if test "x$ac_cv_lib_nl_nl_handle_alloc" = xyes; then :
#
- # Yes.
+ # No, we don't have libnl at all.
+ # Fail if the user explicitly requested
+ # it.
#
- LIBS="${libnldir} -lnl $LIBS"
-
-$as_echo "#define HAVE_LIBNL 1" >>confdefs.h
-
- have_any_nl="yes"
+ if test x$with_libnl = xyes ; then
+ as_fn_error $? "libnl support requested but libnl not found" "$LINENO" 5
+ fi
fi
fi
-
- if test x$have_any_nl = xno ; then
- #
- # No, we don't have libnl at all.
- #
- if test x$with_libnl = xyes ; then
- as_fn_error $? "libnl support requested but libnl not found" "$LINENO" 5
- fi
- fi
fi
- for ac_header in linux/ethtool.h
-do :
- ac_fn_c_check_header_compile "$LINENO" "linux/ethtool.h" "ac_cv_header_linux_ethtool_h" "
-$ac_includes_default
-#include <linux/types.h>
-
-"
-if test "x$ac_cv_header_linux_ethtool_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LINUX_ETHTOOL_H 1
-_ACEOF
-
-fi
-
-done
-
-
- #
- # Check to see if struct tpacket_stats is defined in
- # <linux/if_packet.h>. If so, then pcap-linux.c can use this
- # to report proper statistics.
- #
- # -Scott Barron
- #
- ac_fn_c_check_type "$LINENO" "struct tpacket_stats" "ac_cv_type_struct_tpacket_stats" "
- #include <linux/if_packet.h>
-
-"
-if test "x$ac_cv_type_struct_tpacket_stats" = xyes; then :
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_TPACKET_STATS 1
-_ACEOF
-
-
-fi
-
-
#
# Check to see if the tpacket_auxdata struct has a tp_vlan_tci member.
#
@@ -6790,6 +7041,11 @@ fi
bpf)
#
+ # Capture module
+ #
+ PLATFORM_C_SRC="pcap-bpf.c"
+
+ #
# Check whether we have the *BSD-style ioctls.
#
for ac_header in net/if_media.h
@@ -6828,12 +7084,44 @@ fi
;;
+pf)
+ #
+ # Capture module
+ #
+ PLATFORM_C_SRC="pcap-pf.c"
+ ;;
+
+snit)
+ #
+ # Capture module
+ #
+ PLATFORM_C_SRC="pcap-snit.c"
+ ;;
+
+snoop)
+ #
+ # Capture module
+ #
+ PLATFORM_C_SRC="pcap-snoop.c"
+ ;;
+
dag)
#
# --with-pcap=dag is the only way to get here, and it means
# "DAG support but nothing else"
#
V_DEFS="$V_DEFS -DDAG_ONLY"
+ PLATFORM_C_SRC="pcap-dag.c"
+ xxx_only=yes
+ ;;
+
+dpdk)
+ #
+ # --with-pcap=dpdk is the only way to get here, and it means
+ # "DPDK support but nothing else"
+ #
+ V_DEFS="$V_DEFS -DDPDK_ONLY"
+ PLATFORM_C_SRC="pcap-dpdk.c"
xxx_only=yes
;;
@@ -6843,6 +7131,7 @@ septel)
# "Septel support but nothing else"
#
V_DEFS="$V_DEFS -DSEPTEL_ONLY"
+ PLATFORM_C_SRC="pcap-septel.c"
xxx_only=yes
;;
@@ -6852,10 +7141,15 @@ snf)
# "SNF support but nothing else"
#
V_DEFS="$V_DEFS -DSNF_ONLY"
+ PLATFORM_C_SRC="pcap-snf.c"
xxx_only=yes
;;
null)
+ #
+ # Capture module
+ #
+ PLATFORM_C_SRC="pcap-null.c"
;;
*)
@@ -6879,7 +7173,7 @@ if test "x$ac_cv_header_ifaddrs_h" = xyes; then :
# We have the header, so we use "getifaddrs()" to
# get the list of interfaces.
#
- V_FINDALLDEVS=fad-getad.c
+ PLATFORM_C_SRC="$PLATFORM_C_SRC fad-getad.c"
else
@@ -6948,18 +7242,15 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_have_siocglifconf" >&5
$as_echo "$ac_cv_lbl_have_siocglifconf" >&6; }
if test $ac_cv_lbl_have_siocglifconf = yes ; then
- V_FINDALLDEVS=fad-glifc.c
+ PLATFORM_C_SRC="$PLATFORM_C_SRC fad-glifc.c"
else
- V_FINDALLDEVS=fad-gifc.c
+ PLATFORM_C_SRC="$PLATFORM_C_SRC fad-gifc.c"
fi
fi
fi
-fi
-
-
case "$host_os" in
linux*)
for ac_header in linux/net_tstamp.h
@@ -6981,21 +7272,6 @@ $as_echo "$as_me: no hardware timestamp support implemented for $host_os" >&6;}
;;
esac
-# Check whether --enable-packet-ring was given.
-if test "${enable_packet_ring+set}" = set; then :
- enableval=$enable_packet_ring;
-else
- enable_packet_ring=yes
-fi
-
-
-if test "x$enable_packet_ring" != "xno" ; then
-
-$as_echo "#define PCAP_SUPPORT_PACKET_RING 1" >>confdefs.h
-
-
-fi
-
#
# Check for socklen_t.
#
@@ -7105,10 +7381,17 @@ if test "$want_dag" != no; then
if test -z "$dag_lib_dir"; then
dag_lib_dir="$dag_root/lib"
+ #
+ # Handle multiarch systems.
+ #
+ if test -d "$dag_lib_dir/$host"
+ then
+ dag_lib_dir="$dag_lib_dir/$host"
+ fi
fi
- V_INCLS="$V_INCLS -I$dag_include_dir"
-
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -I$dag_include_dir"
for ac_header in dagapi.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "dagapi.h" "ac_cv_header_dagapi_h" "$ac_includes_default"
@@ -7124,14 +7407,16 @@ done
if test "$ac_cv_header_dagapi_h" = yes; then
+ V_INCLS="$V_INCLS -I$dag_include_dir"
+
if test $V_PCAP != dag ; then
- SSRC="$SSRC pcap-dag.c"
+ MODULE_C_SRC="$MODULE_C_SRC pcap-dag.c"
fi
# Check for various DAG API functions.
# Don't need to save and restore LIBS to prevent -ldag being
# included if there's a found-action (arg 3).
- saved_ldflags=$LDFLAGS
+ save_LDFLAGS="$LDFLAGS"
LDFLAGS="-L$dag_lib_dir"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dag_attach_stream in -ldag" >&5
$as_echo_n "checking for dag_attach_stream in -ldag... " >&6; }
@@ -7309,7 +7594,7 @@ $as_echo "#define HAVE_DAG_GET_STREAM_ERF_TYPES 1" >>confdefs.h
fi
- LDFLAGS=$saved_ldflags
+ LDFLAGS="$save_LDFLAGS"
#
# We assume that if we have libdag we have libdagconf,
@@ -7388,10 +7673,11 @@ $as_echo "#define HAVE_DAG_API 1" >>confdefs.h
fi
if test "$want_dag" = yes; then
- # User wanted DAG support but we couldn't find it.
+ # User wanted DAG support but we couldn't find it.
as_fn_error $? "DAG support requested with --with-dag, but the DAG headers weren't found at $dag_include_dir: make sure the DAG support is installed, specify a different path or paths if necessary, or don't request DAG support" "$LINENO" 5
fi
fi
+ CFLAGS="$save_CFLAGS"
fi
@@ -7457,7 +7743,7 @@ $as_echo "yes ($septel_include_dir)" >&6; }
ADDLARCHIVEOBJS="$ADDLARCHIVEOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o"
if test "$V_PCAP" != septel ; then
- SSRC="$SSRC pcap-septel.c"
+ MODULE_C_SRC="$MODULE_C_SRC pcap-septel.c"
fi
@@ -7474,7 +7760,7 @@ $as_echo "no" >&6; }
fi
if test "$want_septel" = yes; then
- # User wanted Septel support but we couldn't find it.
+ # User wanted Septel support but we couldn't find it.
as_fn_error $? "Septel support requested with --with-septel, but the Septel headers weren't found at $septel_include_dir: make sure the Septel support is installed, specify a different path or paths if necessary, or don't request Septel support" "$LINENO" 5
fi
fi
@@ -7558,11 +7844,18 @@ $as_echo_n "checking whether we have Myricom Sniffer API... " >&6; }
if test -z "$snf_lib_dir"; then
snf_lib_dir="$snf_root/lib"
+ #
+ # Handle multiarch systems.
+ #
+ if test -d "$snf_lib_dir/$host"
+ then
+ snf_lib_dir="$snf_lib_dir/$host"
+ fi
fi
if test -f "$snf_include_dir/snf.h"; then
# We found a header; make sure we can link with the library
- saved_ldflags=$LDFLAGS
+ save_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS -L$snf_lib_dir"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for snf_init in -lsnf" >&5
$as_echo_n "checking for snf_init in -lsnf... " >&6; }
@@ -7604,7 +7897,7 @@ if test "x$ac_cv_lib_snf_snf_init" = xyes; then :
ac_cv_lbl_snf_api="yes"
fi
- LDFLAGS="$saved_ldflags"
+ LDFLAGS="$save_LDFLAGS"
if test "$ac_cv_lbl_snf_api" = no; then
as_fn_error $? "SNF API cannot correctly be linked; check config.log" "$LINENO" 5
fi
@@ -7619,7 +7912,7 @@ $as_echo "yes ($snf_root)" >&6; }
LDFLAGS="$LDFLAGS -L$snf_lib_dir"
if test "$V_PCAP" != snf ; then
- SSRC="$SSRC pcap-snf.c"
+ MODULE_C_SRC="$MODULE_C_SRC pcap-snf.c"
fi
@@ -7717,7 +8010,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
- SSRC="$SSRC pcap-tc.c"
+ MODULE_C_SRC="$MODULE_C_SRC pcap-tc.c"
V_INCLS="$V_INCLS $TURBOCAP_CFLAGS"
LIBS="$LIBS $TURBOCAP_LIBS -lTcApi -lpthread -lstdc++"
@@ -7729,7 +8022,7 @@ $as_echo "#define HAVE_TC_API 1" >>confdefs.h
$as_echo "no" >&6; }
if test "$want_turbocap" = yes; then
- # User wanted Turbo support but we couldn't find it.
+ # User wanted Turbo support but we couldn't find it.
as_fn_error $? "TurboCap support requested with --with-turbocap, but the TurboCap headers weren't found: make sure the TurboCap support is installed or don't request TurboCap support" "$LINENO" 5
fi
fi
@@ -7869,10 +8162,142 @@ _ACEOF
fi
+ #
+ # Optionally, we may want to support SSL.
+ # Check for OpenSSL/libressl.
+ #
+ # First, try looking for it as a regular system library.
+ # Make sure we can find SSL_library_init() using the
+ # standard headers, just in case we're running a version
+ # of macOS that ships with the OpenSSL library but not
+ # the OpenSSL headers, and have also installed another
+ # version of OpenSSL with headers.
+ #
+ save_LIBS="$LIBS"
+ LIBS="-lssl -lcrypto"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we have a system OpenSSL/libressl that we can use" >&5
+$as_echo_n "checking whether we have a system OpenSSL/libressl that we can use... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <openssl/ssl.h>
+
+int
+main ()
+{
+
+SSL_library_init();
+return 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ HAVE_OPENSSL=yes
+ OPENSSL_LIBS="-lssl -lcrypto"
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$save_LIBS"
+
+ #
+ # If we didn't find it, check for it with pkg-config.
+ #
+ if test "x$HAVE_OPENSSL" != "xyes"; then
+ if test "x$PKGCONFIG" != "xno"; then
+ #
+ # We have pkg-config; see if we have OpenSSL/
+ # libressl installed as a package.
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL/libressl with pkg-config" >&5
+$as_echo_n "checking for OpenSSL/libressl with pkg-config... " >&6; }
+ if "$PKGCONFIG" openssl; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5
+$as_echo "found" >&6; }
+ HAVE_OPENSSL=yes
+ OPENSSL_CFLAGS=`"$PKGCONFIG" --cflags openssl`
+ OPENSSL_LIBS=`"$PKGCONFIG" --libs openssl`
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+ fi
+ fi
+ fi
+
+ #
+ # If we didn't find it, check for it under /usr/local/opt/openssl;
+ # that's where Homebrew puts it on macOS. Feel free to add other
+ # -L directories as necessary; the "system library" check should
+ # also handle "add-on library under /usr/local", so that shouldn't
+ # be necessary here.
+ #
+ if test "x$HAVE_OPENSSL" != "xyes"; then
+ save_CFLAGS="$CFLAGS"
+ save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS -L/usr/local/opt/openssl/include"
+ LIBS="$LIBS -L/usr/local/opt/openssl/lib -lssl -lcrypto"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we have OpenSSL/libressl in /usr/local/opt that we can use" >&5
+$as_echo_n "checking whether we have OpenSSL/libressl in /usr/local/opt that we can use... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <openssl/ssl.h>
+
+int
+main ()
+{
+
+SSL_library_init();
+return 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ HAVE_OPENSSL=yes
+ OPENSSL_CFLAGS="-I/usr/local/opt/openssl/include"
+ OPENSSL_LIBS="-L/usr/local/opt/openssl/lib -lssl -lcrypto"
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$save_CFLAGS"
+ LIBS="$save_LIBS"
+ fi
+
+ #
+ # OK, did we find it?
+ #
+ if test "x$HAVE_OPENSSL" = "xyes"; then
+
+$as_echo "#define HAVE_OPENSSL 1" >>confdefs.h
+
+ CFLAGS="$CFLAGS $OPENSSL_CFLAGS"
+ LIBS="$LIBS $OPENSSL_LIBS"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: OpenSSL not found" >&5
+$as_echo "$as_me: OpenSSL not found" >&6;}
+ fi
+
$as_echo "#define ENABLE_REMOTE /**/" >>confdefs.h
- SSRC="$SSRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c"
+ REMOTE_C_SRC="$REMOTE_C_SRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c sslutils.c"
BUILD_RPCAPD=build-rpcapd
INSTALL_RPCAPD=install-rpcapd
;;
@@ -8146,28 +8571,59 @@ done
test -n "$YACC" || YACC="yacc"
-#
-# Make sure it supports the -p flag and supports processing our
-# grammar.y.
-#
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for capable yacc/bison" >&5
-$as_echo_n "checking for capable yacc/bison... " >&6; }
+case "$YACC" in
+
+*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.
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for capable yacc" >&5
+$as_echo_n "checking for capable yacc... " >&6; }
if ${tcpdump_cv_capable_yacc+:} false; then :
$as_echo_n "(cached) " >&6
else
- if $YACC -p pcap_ -o /dev/null $srcdir/grammar.y >/dev/null 2>&1; then
- tcpdump_cv_capable_yacc=yes
- else
- tcpdump_cv_capable_yacc=insufficient
- fi
+ if $YACC -V >/dev/null 2>&1; then
+ tcpdump_cv_capable_yacc=yes
+ else
+ tcpdump_cv_capable_yacc=insufficient
+ fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcpdump_cv_capable_yacc" >&5
$as_echo "$tcpdump_cv_capable_yacc" >&6; }
-if test $tcpdump_cv_capable_yacc = insufficient ; then
- as_fn_error $? "$YACC is insufficient to compile libpcap.
+ if test $tcpdump_cv_capable_yacc = insufficient ; then
+ as_fn_error $? "$YACC 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." "$LINENO" 5
-fi
+ fi
+
+ #
+ # Berkeley YACC doesn't support "%define api.pure", so use
+ # "%pure-parser".
+ #
+ REENTRANT_PARSER="%pure-parser"
+ ;;
+
+*)
+ #
+ # Bison prior to 2.4(.1) doesn't support "%define api.pure", so use
+ # "%pure-parser".
+ #
+ bison_major_version=`$YACC -V | sed -n 's/.* \([1-9][0-9]*\)\.[1-9][0-9.]*/\1/p'`
+ bison_minor_version=`$YACC -V | sed -n 's/.* [1-9][0-9]*\.\([1-9][0-9]*\).*/\1/p'`
+ if test "$bison_major_version" -lt 2 -o \
+ \( "$bison_major_version" -eq 2 -a "$bison_major_version" -lt 4 \)
+ then
+ REENTRANT_PARSER="%pure-parser"
+ else
+ REENTRANT_PARSER="%define api.pure"
+ fi
+ ;;
+esac
+
#
# Do various checks for various OSes and versions of those OSes.
@@ -8363,12 +8819,24 @@ return 0;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
- V_LIB_CCOPT_FAT="-arch x86_64 -arch i386"
- V_LIB_LDFLAGS_FAT="-arch x86_64 -arch i386"
+ V_LIB_CCOPT_FAT="-arch x86_64"
+ V_LIB_LDFLAGS_FAT="-arch x86_64"
+
+ #
+ # OpenSSL installation on macOS seems
+ # to install only the libs for 64-bit
+ # x86 - at least that's what Brew does:
+ # only configure 32-bit builds if we
+ # don't have OpenSSL.
+ #
+ if test "$HAVE_OPENSSL" != yes; then
+ V_LIB_CCOPT_FAT="$V_LIB_CCOPT_FAT -arch i386"
+ V_LIB_LDFLAGS_FAT="$V_LIB_LDFLAGS_FAT -arch i386"
+ fi
else
@@ -8400,7 +8868,8 @@ $as_echo "$as_me: WARNING: Compiling for 32-bit x86 gives an error; try installi
esac
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
CFLAGS="$save_CFLAGS"
;;
esac
@@ -8473,7 +8942,7 @@ irix*)
MAN_MISC_INFO=5
;;
-linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*|midipix*)
+linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*|haiku*|midipix*)
DYEXT="so"
#
@@ -9064,20 +9533,20 @@ fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wdeclaration-after-statement option" >&5
-$as_echo_n "checking whether the compiler supports the -Wdeclaration-after-statement option... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wdocumentation option" >&5
+$as_echo_n "checking whether the compiler supports the -Wdocumentation option... " >&6; }
save_CFLAGS="$CFLAGS"
- if expr "x-Wdeclaration-after-statement" : "x-W.*" >/dev/null
+ if expr "x-Wdocumentation" : "x-W.*" >/dev/null
then
- CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wdeclaration-after-statement"
- elif expr "x-Wdeclaration-after-statement" : "x-f.*" >/dev/null
+ CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wdocumentation"
+ elif expr "x-Wdocumentation" : "x-f.*" >/dev/null
then
- CFLAGS="$CFLAGS -Werror -Wdeclaration-after-statement"
- elif expr "x-Wdeclaration-after-statement" : "x-m.*" >/dev/null
+ CFLAGS="$CFLAGS -Werror -Wdocumentation"
+ elif expr "x-Wdocumentation" : "x-m.*" >/dev/null
then
- CFLAGS="$CFLAGS -Werror -Wdeclaration-after-statement"
+ CFLAGS="$CFLAGS -Werror -Wdocumentation"
else
- CFLAGS="$CFLAGS -Wdeclaration-after-statement"
+ CFLAGS="$CFLAGS -Wdocumentation"
fi
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -9104,8 +9573,8 @@ $as_echo "yes" >&6; }
if test "x" != "x"
then
CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wdeclaration-after-statement " >&5
-$as_echo_n "checking whether -Wdeclaration-after-statement ... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wdocumentation " >&5
+$as_echo_n "checking whether -Wdocumentation ... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -9133,7 +9602,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CFLAGS="$save_CFLAGS"
if test x"$can_add_to_cflags" = "xyes"
then
- V_CCOPT="$V_CCOPT -Wdeclaration-after-statement"
+ V_CCOPT="$V_CCOPT -Wdocumentation"
fi
else
@@ -9146,20 +9615,20 @@ fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wdocumentation option" >&5
-$as_echo_n "checking whether the compiler supports the -Wdocumentation option... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wformat-nonliteral option" >&5
+$as_echo_n "checking whether the compiler supports the -Wformat-nonliteral option... " >&6; }
save_CFLAGS="$CFLAGS"
- if expr "x-Wdocumentation" : "x-W.*" >/dev/null
+ if expr "x-Wformat-nonliteral" : "x-W.*" >/dev/null
then
- CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wdocumentation"
- elif expr "x-Wdocumentation" : "x-f.*" >/dev/null
+ CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wformat-nonliteral"
+ elif expr "x-Wformat-nonliteral" : "x-f.*" >/dev/null
then
- CFLAGS="$CFLAGS -Werror -Wdocumentation"
- elif expr "x-Wdocumentation" : "x-m.*" >/dev/null
+ CFLAGS="$CFLAGS -Werror -Wformat-nonliteral"
+ elif expr "x-Wformat-nonliteral" : "x-m.*" >/dev/null
then
- CFLAGS="$CFLAGS -Werror -Wdocumentation"
+ CFLAGS="$CFLAGS -Werror -Wformat-nonliteral"
else
- CFLAGS="$CFLAGS -Wdocumentation"
+ CFLAGS="$CFLAGS -Wformat-nonliteral"
fi
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -9186,8 +9655,8 @@ $as_echo "yes" >&6; }
if test "x" != "x"
then
CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wdocumentation " >&5
-$as_echo_n "checking whether -Wdocumentation ... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wformat-nonliteral " >&5
+$as_echo_n "checking whether -Wformat-nonliteral ... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -9215,7 +9684,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CFLAGS="$save_CFLAGS"
if test x"$can_add_to_cflags" = "xyes"
then
- V_CCOPT="$V_CCOPT -Wdocumentation"
+ V_CCOPT="$V_CCOPT -Wformat-nonliteral"
fi
else
@@ -9228,20 +9697,20 @@ fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wformat-nonliteral option" >&5
-$as_echo_n "checking whether the compiler supports the -Wformat-nonliteral option... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-noreturn option" >&5
+$as_echo_n "checking whether the compiler supports the -Wmissing-noreturn option... " >&6; }
save_CFLAGS="$CFLAGS"
- if expr "x-Wformat-nonliteral" : "x-W.*" >/dev/null
+ if expr "x-Wmissing-noreturn" : "x-W.*" >/dev/null
then
- CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wformat-nonliteral"
- elif expr "x-Wformat-nonliteral" : "x-f.*" >/dev/null
+ CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wmissing-noreturn"
+ elif expr "x-Wmissing-noreturn" : "x-f.*" >/dev/null
then
- CFLAGS="$CFLAGS -Werror -Wformat-nonliteral"
- elif expr "x-Wformat-nonliteral" : "x-m.*" >/dev/null
+ CFLAGS="$CFLAGS -Werror -Wmissing-noreturn"
+ elif expr "x-Wmissing-noreturn" : "x-m.*" >/dev/null
then
- CFLAGS="$CFLAGS -Werror -Wformat-nonliteral"
+ CFLAGS="$CFLAGS -Werror -Wmissing-noreturn"
else
- CFLAGS="$CFLAGS -Wformat-nonliteral"
+ CFLAGS="$CFLAGS -Wmissing-noreturn"
fi
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -9268,8 +9737,8 @@ $as_echo "yes" >&6; }
if test "x" != "x"
then
CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wformat-nonliteral " >&5
-$as_echo_n "checking whether -Wformat-nonliteral ... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wmissing-noreturn " >&5
+$as_echo_n "checking whether -Wmissing-noreturn ... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -9297,7 +9766,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CFLAGS="$save_CFLAGS"
if test x"$can_add_to_cflags" = "xyes"
then
- V_CCOPT="$V_CCOPT -Wformat-nonliteral"
+ V_CCOPT="$V_CCOPT -Wmissing-noreturn"
fi
else
@@ -9310,20 +9779,20 @@ fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-noreturn option" >&5
-$as_echo_n "checking whether the compiler supports the -Wmissing-noreturn option... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-prototypes option" >&5
+$as_echo_n "checking whether the compiler supports the -Wmissing-prototypes option... " >&6; }
save_CFLAGS="$CFLAGS"
- if expr "x-Wmissing-noreturn" : "x-W.*" >/dev/null
+ if expr "x-Wmissing-prototypes" : "x-W.*" >/dev/null
then
- CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wmissing-noreturn"
- elif expr "x-Wmissing-noreturn" : "x-f.*" >/dev/null
+ CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wmissing-prototypes"
+ elif expr "x-Wmissing-prototypes" : "x-f.*" >/dev/null
then
- CFLAGS="$CFLAGS -Werror -Wmissing-noreturn"
- elif expr "x-Wmissing-noreturn" : "x-m.*" >/dev/null
+ CFLAGS="$CFLAGS -Werror -Wmissing-prototypes"
+ elif expr "x-Wmissing-prototypes" : "x-m.*" >/dev/null
then
- CFLAGS="$CFLAGS -Werror -Wmissing-noreturn"
+ CFLAGS="$CFLAGS -Werror -Wmissing-prototypes"
else
- CFLAGS="$CFLAGS -Wmissing-noreturn"
+ CFLAGS="$CFLAGS -Wmissing-prototypes"
fi
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -9350,8 +9819,8 @@ $as_echo "yes" >&6; }
if test "x" != "x"
then
CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wmissing-noreturn " >&5
-$as_echo_n "checking whether -Wmissing-noreturn ... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wmissing-prototypes " >&5
+$as_echo_n "checking whether -Wmissing-prototypes ... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -9379,7 +9848,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CFLAGS="$save_CFLAGS"
if test x"$can_add_to_cflags" = "xyes"
then
- V_CCOPT="$V_CCOPT -Wmissing-noreturn"
+ V_CCOPT="$V_CCOPT -Wmissing-prototypes"
fi
else
@@ -9392,20 +9861,20 @@ fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-prototypes option" >&5
-$as_echo_n "checking whether the compiler supports the -Wmissing-prototypes option... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-variable-declarations option" >&5
+$as_echo_n "checking whether the compiler supports the -Wmissing-variable-declarations option... " >&6; }
save_CFLAGS="$CFLAGS"
- if expr "x-Wmissing-prototypes" : "x-W.*" >/dev/null
+ if expr "x-Wmissing-variable-declarations" : "x-W.*" >/dev/null
then
- CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wmissing-prototypes"
- elif expr "x-Wmissing-prototypes" : "x-f.*" >/dev/null
+ CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wmissing-variable-declarations"
+ elif expr "x-Wmissing-variable-declarations" : "x-f.*" >/dev/null
then
- CFLAGS="$CFLAGS -Werror -Wmissing-prototypes"
- elif expr "x-Wmissing-prototypes" : "x-m.*" >/dev/null
+ CFLAGS="$CFLAGS -Werror -Wmissing-variable-declarations"
+ elif expr "x-Wmissing-variable-declarations" : "x-m.*" >/dev/null
then
- CFLAGS="$CFLAGS -Werror -Wmissing-prototypes"
+ CFLAGS="$CFLAGS -Werror -Wmissing-variable-declarations"
else
- CFLAGS="$CFLAGS -Wmissing-prototypes"
+ CFLAGS="$CFLAGS -Wmissing-variable-declarations"
fi
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -9432,8 +9901,8 @@ $as_echo "yes" >&6; }
if test "x" != "x"
then
CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wmissing-prototypes " >&5
-$as_echo_n "checking whether -Wmissing-prototypes ... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wmissing-variable-declarations " >&5
+$as_echo_n "checking whether -Wmissing-variable-declarations ... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -9461,7 +9930,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CFLAGS="$save_CFLAGS"
if test x"$can_add_to_cflags" = "xyes"
then
- V_CCOPT="$V_CCOPT -Wmissing-prototypes"
+ V_CCOPT="$V_CCOPT -Wmissing-variable-declarations"
fi
else
@@ -9474,20 +9943,20 @@ fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-variable-declarations option" >&5
-$as_echo_n "checking whether the compiler supports the -Wmissing-variable-declarations option... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wpointer-arith option" >&5
+$as_echo_n "checking whether the compiler supports the -Wpointer-arith option... " >&6; }
save_CFLAGS="$CFLAGS"
- if expr "x-Wmissing-variable-declarations" : "x-W.*" >/dev/null
+ if expr "x-Wpointer-arith" : "x-W.*" >/dev/null
then
- CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wmissing-variable-declarations"
- elif expr "x-Wmissing-variable-declarations" : "x-f.*" >/dev/null
+ CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wpointer-arith"
+ elif expr "x-Wpointer-arith" : "x-f.*" >/dev/null
then
- CFLAGS="$CFLAGS -Werror -Wmissing-variable-declarations"
- elif expr "x-Wmissing-variable-declarations" : "x-m.*" >/dev/null
+ CFLAGS="$CFLAGS -Werror -Wpointer-arith"
+ elif expr "x-Wpointer-arith" : "x-m.*" >/dev/null
then
- CFLAGS="$CFLAGS -Werror -Wmissing-variable-declarations"
+ CFLAGS="$CFLAGS -Werror -Wpointer-arith"
else
- CFLAGS="$CFLAGS -Wmissing-variable-declarations"
+ CFLAGS="$CFLAGS -Wpointer-arith"
fi
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -9514,8 +9983,8 @@ $as_echo "yes" >&6; }
if test "x" != "x"
then
CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wmissing-variable-declarations " >&5
-$as_echo_n "checking whether -Wmissing-variable-declarations ... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wpointer-arith " >&5
+$as_echo_n "checking whether -Wpointer-arith ... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -9543,7 +10012,89 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CFLAGS="$save_CFLAGS"
if test x"$can_add_to_cflags" = "xyes"
then
- V_CCOPT="$V_CCOPT -Wmissing-variable-declarations"
+ V_CCOPT="$V_CCOPT -Wpointer-arith"
+ fi
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ CFLAGS="$save_CFLAGS"
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wpointer-sign option" >&5
+$as_echo_n "checking whether the compiler supports the -Wpointer-sign option... " >&6; }
+ save_CFLAGS="$CFLAGS"
+ if expr "x-Wpointer-sign" : "x-W.*" >/dev/null
+ then
+ CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wpointer-sign"
+ elif expr "x-Wpointer-sign" : "x-f.*" >/dev/null
+ then
+ CFLAGS="$CFLAGS -Werror -Wpointer-sign"
+ elif expr "x-Wpointer-sign" : "x-m.*" >/dev/null
+ then
+ CFLAGS="$CFLAGS -Werror -Wpointer-sign"
+ else
+ CFLAGS="$CFLAGS -Wpointer-sign"
+ fi
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+return 0
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ can_add_to_cflags=yes
+ #
+ # The compile supports this; do we have some C code for
+ # which the warning should *not* appear?
+ # We test the fourth argument because the third argument
+ # could contain quotes, breaking the test.
+ #
+ if test "x" != "x"
+ then
+ CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wpointer-sign " >&5
+$as_echo_n "checking whether -Wpointer-sign ... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ #
+ # Not a problem.
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+else
+
+ #
+ # A problem.
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ can_add_to_cflags=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+ CFLAGS="$save_CFLAGS"
+ if test x"$can_add_to_cflags" = "xyes"
+ then
+ V_CCOPT="$V_CCOPT -Wpointer-sign"
fi
else
@@ -10081,6 +10632,88 @@ $as_echo "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wshorten-64-to-32 option" >&5
+$as_echo_n "checking whether the compiler supports the -Wshorten-64-to-32 option... " >&6; }
+ save_CFLAGS="$CFLAGS"
+ if expr "x-Wshorten-64-to-32" : "x-W.*" >/dev/null
+ then
+ CFLAGS="$CFLAGS $ac_lbl_unknown_warning_option_error -Wshorten-64-to-32"
+ elif expr "x-Wshorten-64-to-32" : "x-f.*" >/dev/null
+ then
+ CFLAGS="$CFLAGS -Werror -Wshorten-64-to-32"
+ elif expr "x-Wshorten-64-to-32" : "x-m.*" >/dev/null
+ then
+ CFLAGS="$CFLAGS -Werror -Wshorten-64-to-32"
+ else
+ CFLAGS="$CFLAGS -Wshorten-64-to-32"
+ fi
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+return 0
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ can_add_to_cflags=yes
+ #
+ # The compile supports this; do we have some C code for
+ # which the warning should *not* appear?
+ # We test the fourth argument because the third argument
+ # could contain quotes, breaking the test.
+ #
+ if test "x" != "x"
+ then
+ CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -Wshorten-64-to-32 " >&5
+$as_echo_n "checking whether -Wshorten-64-to-32 ... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ #
+ # Not a problem.
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+else
+
+ #
+ # A problem.
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ can_add_to_cflags=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+ CFLAGS="$save_CFLAGS"
+ if test x"$can_add_to_cflags" = "xyes"
+ then
+ V_CCOPT="$V_CCOPT -Wshorten-64-to-32"
+ fi
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ CFLAGS="$save_CFLAGS"
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports generating dependencies" >&5
@@ -10161,7 +10794,7 @@ _ACEOF
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, with $ac_lbl_dependency_flag" >&5
$as_echo "yes, with $ac_lbl_dependency_flag" >&6; }
DEPENDENCY_CFLAG="$ac_lbl_dependency_flag"
- MKDEP='${srcdir}/mkdep'
+ MKDEP='${top_srcdir}/mkdep'
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
@@ -10169,7 +10802,7 @@ $as_echo "no" >&6; }
# We can't run mkdep, so have "make depend" do
# nothing.
#
- MKDEP='${srcdir}/nomkdep'
+ MKDEP='${top_srcdir}/nomkdep'
fi
rm -rf conftest*
else
@@ -10179,7 +10812,7 @@ $as_echo "no" >&6; }
# We can't run mkdep, so have "make depend" do
# nothing.
#
- MKDEP='${srcdir}/nomkdep'
+ MKDEP='${top_srcdir}/nomkdep'
fi
@@ -10268,100 +10901,6 @@ _ACEOF
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if unaligned accesses fail" >&5
-$as_echo_n "checking if unaligned accesses fail... " >&6; }
- if ${ac_cv_lbl_unaligned_fail+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- case "$host_cpu" in
-
- #
- # These are CPU types where:
- #
- # the CPU faults on an unaligned access, but at least some
- # OSes that support that CPU catch the fault and simulate
- # the unaligned access (e.g., Alpha/{Digital,Tru64} UNIX) -
- # the simulation is slow, so we don't want to use it;
- #
- # the CPU, I infer (from the old
- #
- # XXX: should also check that they don't do weird things (like on arm)
- #
- # comment) doesn't fault on unaligned accesses, but doesn't
- # do a normal unaligned fetch, either (e.g., presumably, ARM);
- #
- # for whatever reason, the test program doesn't work
- # (this has been claimed to be the case for several of those
- # CPUs - I don't know what the problem is; the problem
- # was reported as "the test program dumps core" for SuperH,
- # but that's what the test program is *supposed* to do -
- # it dumps core before it writes anything, so the test
- # for an empty output file should find an empty output
- # file and conclude that unaligned accesses don't work).
- #
- # This run-time test won't work if you're cross-compiling, so
- # in order to support cross-compiling for a particular CPU,
- # we have to wire in the list of CPU types anyway, as far as
- # I know, so perhaps we should just have a set of CPUs on
- # which we know it doesn't work, a set of CPUs on which we
- # know it does work, and have the script just fail on other
- # cpu types and update it when such a failure occurs.
- #
- alpha*|arm*|bfin*|hp*|mips*|sh*|sparc*|ia64|nv1)
- ac_cv_lbl_unaligned_fail=yes
- ;;
-
- *)
- cat >conftest.c <<EOF
-# include <sys/types.h>
-# include <sys/wait.h>
-# include <stdio.h>
- unsigned char a[5] = { 1, 2, 3, 4, 5 };
- main() {
- unsigned int i;
- pid_t pid;
- int status;
- /* avoid "core dumped" message */
- pid = fork();
- if (pid < 0)
- exit(2);
- if (pid > 0) {
- /* parent */
- pid = waitpid(pid, &status, 0);
- if (pid < 0)
- exit(3);
- exit(!WIFEXITED(status));
- }
- /* child */
- i = *(unsigned int *)&a[1];
- printf("%d\n", i);
- exit(0);
- }
-EOF
- ${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS \
- conftest.c $LIBS >/dev/null 2>&1
- if test ! -x conftest ; then
- ac_cv_lbl_unaligned_fail=yes
- else
- ./conftest >conftest.out
- if test ! -s conftest.out ; then
- ac_cv_lbl_unaligned_fail=yes
- else
- ac_cv_lbl_unaligned_fail=no
- fi
- fi
- rm -f -r conftest* core core.conftest
- ;;
- esac
-fi
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_unaligned_fail" >&5
-$as_echo "$ac_cv_lbl_unaligned_fail" >&6; }
- if test $ac_cv_lbl_unaligned_fail = yes ; then
-
-$as_echo "#define LBL_ALIGN 1" >>confdefs.h
-
- fi
@@ -10393,6 +10932,9 @@ $as_echo "#define LBL_ALIGN 1" >>confdefs.h
+#
+# Various Linux-specific mechanisms.
+#
# Check whether --enable-usb was given.
if test "${enable_usb+set}" = set; then :
enableval=$enable_usb;
@@ -10401,39 +10943,38 @@ else
fi
-if test "xxx_only" = yes; then
- # User requested something-else-only pcap, so they don't
- # want USB support.
- enable_usb=no
-fi
-
-if test "x$enable_usb" != "xno" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for USB sniffing support" >&5
-$as_echo_n "checking for USB sniffing support... " >&6; }
- case "$host_os" in
- linux*)
+#
+# If somebody requested an XXX-only pcap, that doesn't include
+# additional mechanisms.
+#
+if test "xxx_only" != yes; then
+ case "$host_os" in
+ linux*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Linux usbmon USB sniffing support" >&5
+$as_echo_n "checking for Linux usbmon USB sniffing support... " >&6; }
+ if test "x$enable_usb" != "xno" ; then
-$as_echo "#define PCAP_SUPPORT_USB 1" >>confdefs.h
+$as_echo "#define PCAP_SUPPORT_LINUX_USBMON 1" >>confdefs.h
- USB_SRC=pcap-usb-linux.c
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ MODULE_C_SRC="$MODULE_C_SRC pcap-usb-linux.c"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
- ac_usb_dev_name=`udevinfo -q name -p /sys/class/usb_device/usbmon 2>/dev/null`
- if test $? -ne 0 ; then
- ac_usb_dev_name="usbmon"
- fi
+ ac_usb_dev_name=`udevinfo -q name -p /sys/class/usb_device/usbmon 2>/dev/null`
+ if test $? -ne 0 ; then
+ ac_usb_dev_name="usbmon"
+ fi
cat >>confdefs.h <<_ACEOF
#define LINUX_USB_MON_DEV "/dev/$ac_usb_dev_name"
_ACEOF
- { $as_echo "$as_me:${as_lineno-$LINENO}: Device for USB sniffing is /dev/$ac_usb_dev_name" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Device for USB sniffing is /dev/$ac_usb_dev_name" >&5
$as_echo "$as_me: Device for USB sniffing is /dev/$ac_usb_dev_name" >&6;}
- #
- # Do we have a version of <linux/compiler.h> available?
- # If so, we might need it for <linux/usbdevice_fs.h>.
- #
- for ac_header in linux/compiler.h
+ #
+ # Do we have a version of <linux/compiler.h> available?
+ # If so, we might need it for <linux/usbdevice_fs.h>.
+ #
+ for ac_header in linux/compiler.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "linux/compiler.h" "ac_cv_header_linux_compiler_h" "$ac_includes_default"
if test "x$ac_cv_header_linux_compiler_h" = xyes; then :
@@ -10445,11 +10986,11 @@ fi
done
- if test "$ac_cv_header_linux_compiler_h" = yes; then
- #
- # Yes - include it when testing for <linux/usbdevice_fs.h>.
- #
- for ac_header in linux/usbdevice_fs.h
+ if test "$ac_cv_header_linux_compiler_h" = yes; then
+ #
+ # Yes - include it when testing for <linux/usbdevice_fs.h>.
+ #
+ for ac_header in linux/usbdevice_fs.h
do :
ac_fn_c_check_header_compile "$LINENO" "linux/usbdevice_fs.h" "ac_cv_header_linux_usbdevice_fs_h" "#include <linux/compiler.h>
"
@@ -10462,8 +11003,8 @@ fi
done
- else
- for ac_header in linux/usbdevice_fs.h
+ else
+ for ac_header in linux/usbdevice_fs.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "linux/usbdevice_fs.h" "ac_cv_header_linux_usbdevice_fs_h" "$ac_includes_default"
if test "x$ac_cv_header_linux_usbdevice_fs_h" = xyes; then :
@@ -10475,20 +11016,20 @@ fi
done
- fi
- if test "$ac_cv_header_linux_usbdevice_fs_h" = yes; then
- #
- # OK, does it define bRequestType? Older versions of the kernel
- # define fields with names like "requesttype, "request", and
- # "value", rather than "bRequestType", "bRequest", and
- # "wValue".
- #
- ac_fn_c_check_member "$LINENO" "struct usbdevfs_ctrltransfer" "bRequestType" "ac_cv_member_struct_usbdevfs_ctrltransfer_bRequestType" "
- $ac_includes_default
- #ifdef HAVE_LINUX_COMPILER_H
- #include <linux/compiler.h>
- #endif
- #include <linux/usbdevice_fs.h>
+ fi
+ if test "$ac_cv_header_linux_usbdevice_fs_h" = yes; then
+ #
+ # OK, does it define bRequestType? Older versions of the kernel
+ # define fields with names like "requesttype, "request", and
+ # "value", rather than "bRequestType", "bRequest", and
+ # "wValue".
+ #
+ ac_fn_c_check_member "$LINENO" "struct usbdevfs_ctrltransfer" "bRequestType" "ac_cv_member_struct_usbdevfs_ctrltransfer_bRequestType" "
+ $ac_includes_default
+ #ifdef HAVE_LINUX_COMPILER_H
+ #include <linux/compiler.h>
+ #endif
+ #include <linux/usbdevice_fs.h>
"
if test "x$ac_cv_member_struct_usbdevfs_ctrltransfer_bRequestType" = xyes; then :
@@ -10500,44 +11041,23 @@ _ACEOF
fi
- fi
- ;;
- freebsd*)
- #
- # This just uses BPF in FreeBSD 8.4 and later; we don't need
- # to check for anything special for capturing.
- #
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, in FreeBSD 8.4 and later" >&5
-$as_echo "yes, in FreeBSD 8.4 and later" >&6; }
- ;;
-
- *)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
- ;;
-esac
-fi
-
-
+ fi
-if test "xxx_only" != yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the platform could support netfilter sniffing" >&5
-$as_echo_n "checking whether the platform could support netfilter sniffing... " >&6; }
- case "$host_os" in
- linux*)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
- #
- # Life's too short to deal with trying to get this to compile
- # if you don't get the right types defined with
- # __KERNEL_STRICT_NAMES getting defined by some other include.
- #
- # Check whether the includes Just Work. If not, don't turn on
- # netfilter support.
- #
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can compile the netfilter support" >&5
+ #
+ # Life's too short to deal with trying to get this to compile
+ # if you don't get the right types defined with
+ # __KERNEL_STRICT_NAMES getting defined by some other include.
+ #
+ # Check whether the includes Just Work. If not, don't turn on
+ # netfilter support.
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can compile the netfilter support" >&5
$as_echo_n "checking whether we can compile the netfilter support... " >&6; }
- if ${ac_cv_netfilter_can_compile+:} false; then :
+ if ${ac_cv_netfilter_can_compile+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -10569,20 +11089,16 @@ fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_netfilter_can_compile" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_netfilter_can_compile" >&5
$as_echo "$ac_cv_netfilter_can_compile" >&6; }
- if test $ac_cv_netfilter_can_compile = yes ; then
+ if test $ac_cv_netfilter_can_compile = yes ; then
$as_echo "#define PCAP_SUPPORT_NETFILTER 1" >>confdefs.h
- NETFILTER_SRC=pcap-netfilter-linux.c
- fi
- ;;
- *)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- ;;
- esac
+ MODULE_C_SRC="$MODULE_C_SRC pcap-netfilter-linux.c"
+ fi
+ ;;
+ esac
fi
@@ -10635,12 +11151,296 @@ $as_echo "$ac_cv_net_netmap_user_can_compile" >&6; }
$as_echo "#define PCAP_SUPPORT_NETMAP 1" >>confdefs.h
- NETMAP_SRC=pcap-netmap.c
+ MODULE_C_SRC="$MODULE_C_SRC pcap-netmap.c"
+ fi
+
+fi
+
+# Check for DPDK support.
+
+# Check whether --with-dpdk was given.
+if test "${with_dpdk+set}" = set; then :
+ withval=$with_dpdk;
+ if test "$withval" = no
+ then
+ # User doesn't want DPDK support.
+ want_dpdk=no
+ elif test "$withval" = yes
+ then
+ # User wants DPDK support but hasn't specified a directory.
+ want_dpdk=yes
+ else
+ # User wants DPDK support and has specified a directory,
+ # so use the provided value.
+ want_dpdk=yes
+ dpdk_dir=$withval
+ fi
+
+else
+
+ if test "$V_PCAP" = dpdk; then
+ # User requested DPDK-only libpcap, so we'd better have
+ # the DPDK API.
+ want_dpdk=yes
+ elif test "xxx_only" = yes; then
+ # User requested something-else-only pcap, so they don't
+ # want DPDK support.
+ want_dpdk=no
+ else
+ #
+ # Use DPDK API if present, otherwise don't
+ #
+ want_dpdk=ifpresent
+ fi
+
+fi
+
+
+if test "$want_dpdk" != no; then
+ if test "x$PKGCONFIG" != "xno"
+ then
+ #
+ # We have pkg-config; see if we have DPDK installed
+ # as a package.
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DPDK with pkg-config" >&5
+$as_echo_n "checking for DPDK with pkg-config... " >&6; }
+ if "$PKGCONFIG" libdpdk
+ then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5
+$as_echo "found" >&6; }
+ found_dpdk_with_pkg_config=yes
+ DPDK_CFLAGS=`"$PKGCONFIG" --cflags libdpdk`
+ DPDK_LDFLAGS=`"$PKGCONFIG" --libs libdpdk`
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+ fi
+ fi
+
+ #
+ # If we didn't find it with pkg-config, try checking for
+ # it manually.
+ #
+ if test "x$found_dpdk_with_pkg_config" != "xyes"
+ then
+ if test -z "$dpdk_dir"; then
+ #
+ # The user didn't specify a directory containing
+ # the DPDK headers and libraries. If we find
+ # a /usr/local/include/dpdk directory, assume
+ # it's /usr/local, otherwise assume it's /usr.
+ #
+ if test -d "/usr/local/include/dpdk"; then
+ dpdk_dir="/usr/local"
+ else
+ dpdk_dir="/usr"
+ fi
+ fi
+ #
+ # The convention appears to be that 1) there's a "dpdk"
+ # subdirectory of the include directory, containing DPDK
+ # headers (at least in the installation on Ubuntu with
+ # the system DPDK packages) and 2) includes of DPDK
+ # headers don't use "dpdk/{header}" (at least from the
+ # way the DPDK documentation is written).
+ #
+ # So we add "/dpdk" to the include directory, and always
+ # add that to the list of include directories to search.
+ #
+ dpdk_inc_dir="$dpdk_dir/include/dpdk"
+ dpdk_inc_flags="-I$dpdk_inc_dir"
+ dpdk_lib_dir="$dpdk_dir/lib"
+ #
+ # Handle multiarch systems.
+ #
+ # Step 1: run the C compiler with the -dumpmachine option;
+ # if it succeeds, the output would be the multiarch directory
+ # name if your system has multiarch directories.
+ #
+ multiarch_dir=`$CC -dumpmachine 2>/dev/null`
+ if test ! -z "$multiarch_dir"
+ then
+ #
+ # OK, we have a multiarch directory.
+ #
+ # Now deal with includes. On Ubuntu 20.04, for
+ # example, we have /usr/include/dpdk *and*
+ # /usr/include/$multiarch_dir/dpdk, and must
+ # search both.
+ #
+ if test -d "$dpdk_dir/include/$multiarch_dir/dpdk"
+ then
+ dpdk_inc_flags="-I$dpdk_dir/include/$multiarch_dir/dpdk $dpdk_inc_flags"
+ fi
+
+ #
+ # Now deal with libraries.
+ #
+ if test -d "$dpdk_lib_dir/$multiarch_dir"
+ then
+ dpdk_lib_dir="$dpdk_lib_dir/$multiarch_dir"
+ fi
+ fi
+ DPDK_MACHINE_CFLAGS="-march=native"
+ DPDK_CFLAGS="$DPDK_MACHINE_CFLAGS $dpdk_inc_flags"
+ DPDK_LDFLAGS="-L$dpdk_lib_dir -ldpdk -lrt -lm -lnuma -ldl -pthread"
+ fi
+
+ save_CFLAGS="$CFLAGS"
+ save_LIBS="$LIBS"
+ save_LDFLAGS="$LDFLAGS"
+ CFLAGS="$CFLAGS $DPDK_CFLAGS"
+ LIBS="$LIBS $DPDK_LDFLAGS"
+ LDFLAGS="$LDFLAGS $DPDK_LDFLAGS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can compile the DPDK support" >&5
+$as_echo_n "checking whether we can compile the DPDK support... " >&6; }
+ if ${ac_cv_dpdk_can_compile+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+$ac_includes_default
+#include <rte_common.h>
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_dpdk_can_compile=yes
+else
+ ac_cv_dpdk_can_compile=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_dpdk_can_compile" >&5
+$as_echo "$ac_cv_dpdk_can_compile" >&6; }
+
+ #
+ # We include rte_bus.h, and older versions of DPDK
+ # didn't have it, so check for it.
+ #
+ if test "$ac_cv_dpdk_can_compile" = yes; then
+ #
+ # This runs the preprocessor, so make sure it
+ # looks in the DPDK directories. Instead of
+ # including dpdk/XXX.h, we include just XXX.h
+ # and assume DPDK_CFLAGS is the directory
+ # containing the DPDK headers (that's how
+ # pkg-config sets it, at least on Ubuntu),
+ # so just looking under /usr/include won't
+ # find it.
+ #
+ save_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $DPDK_CFLAGS"
+ ac_fn_c_check_header_mongrel "$LINENO" "rte_bus.h" "ac_cv_header_rte_bus_h" "$ac_includes_default"
+if test "x$ac_cv_header_rte_bus_h" = xyes; then :
+
+fi
+
+
+ CPPFLAGS="$save_CPPFLAGS"
fi
+ #
+ # We call rte_eth_dev_count_avail(), and older versions
+ # of DPDK didn't have it, so check for it.
+ #
+ if test "$ac_cv_header_rte_bus_h" = yes; then
+ ac_fn_c_check_func "$LINENO" "rte_eth_dev_count_avail" "ac_cv_func_rte_eth_dev_count_avail"
+if test "x$ac_cv_func_rte_eth_dev_count_avail" = xyes; then :
fi
+ fi
+
+ CFLAGS="$save_CFLAGS"
+ LIBS="$save_LIBS"
+ LDFLAGS="$save_LDFLAGS"
+
+ if test "$ac_cv_func_rte_eth_dev_count_avail" = yes; then
+ CFLAGS="$CFLAGS $DPDK_CFLAGS"
+ LIBS="$LIBS $DPDK_LDFLAGS"
+ LDFLAGS="$LDFLAGS $DPDK_LDFLAGS"
+ V_INCLS="$V_INCLS $DPDK_CFLAGS"
+
+$as_echo "#define PCAP_SUPPORT_DPDK 1" >>confdefs.h
+
+ if test $V_PCAP != dpdk ; then
+ MODULE_C_SRC="$MODULE_C_SRC pcap-dpdk.c"
+ fi
+
+ #
+ # Check whether the rte_ether.h file defines
+ # struct ether_addr or struct rte_ether_addr.
+ #
+ # ("API compatibility? That's for losers!")
+ #
+ ac_fn_c_check_type "$LINENO" "struct rte_ether_addr" "ac_cv_type_struct_rte_ether_addr" "
+ #include <rte_ether.h>
+
+"
+if test "x$ac_cv_type_struct_rte_ether_addr" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_RTE_ETHER_ADDR 1
+_ACEOF
+
+
+fi
+
+ else
+ if test "$V_PCAP" = dpdk; then
+ # User requested DPDK-only capture support, but
+ # we couldn't the DPDK API support at all, or we
+ # found it but it wasn't a sufficiently recent
+ # version.
+ if test "$ac_cv_dpdk_can_compile" != yes; then
+ #
+ # Couldn't even find the headers.
+ #
+ as_fn_error $? "DPDK support requested with --with-pcap=dpdk, but the DPDK headers weren't found at $dpdk_inc_dir: make sure the DPDK support is installed, specify a different path or paths if necessary, or don't request DPDK support" "$LINENO" 5
+ else
+ #
+ # Found the headers, but we couldn't find
+ # rte_bus.h or rte_eth_dev_count_avail(),
+ # we don't have a sufficiently recent
+ # version of DPDK.
+ #
+ as_fn_error $? "DPDK support requested with --with-pcap=dpdk, but we require DPDK 18.x or later; install a newer version of DPDK, or don't request DPDK support" "$LINENO" 5
+ fi
+ fi
+
+ if test "$want_dpdk" = yes; then
+ # User requested DPDK-only capture support, but
+ # we couldn't the DPDK API support at all, or we
+ # found it but it wasn't a sufficiently recent
+ # version.
+ if test "$ac_cv_dpdk_can_compile" != yes; then
+ #
+ # Couldn't even find the headers.
+ #
+ as_fn_error $? "DPDK support requested with --with-pcap=dpdk, but the DPDK headers weren't found at $dpdk_inc_dir: make sure the DPDK support is installed, specify a different path or paths if necessary, or don't request DPDK support" "$LINENO" 5
+ else
+ #
+ # Found the headers, but we couldn't find
+ # rte_bus.h or rte_eth_dev_count_avail(),
+ # we don't have a sufficiently recent
+ # version of DPDK.
+ #
+ as_fn_error $? "DPDK support requested with --with-pcap=dpdk, but we require DPDK 18.x or later: install a newer version of DPDK, or don't request DPDK support" "$LINENO" 5
+ fi
+ fi
+ fi
+fi
+
# Check whether --enable-bluetooth was given.
if test "${enable_bluetooth+set}" = set; then :
@@ -10669,7 +11469,7 @@ if test "x$ac_cv_header_bluetooth_bluetooth_h" = xyes; then :
$as_echo "#define PCAP_SUPPORT_BT 1" >>confdefs.h
- BT_SRC=pcap-bt-linux.c
+ MODULE_C_SRC="$MODULE_C_SRC pcap-bt-linux.c"
{ $as_echo "$as_me:${as_lineno-$LINENO}: Bluetooth sniffing is supported" >&5
$as_echo "$as_me: Bluetooth sniffing is supported" >&6;}
ac_lbl_bluetooth_available=yes
@@ -10721,7 +11521,7 @@ $as_echo "yes" >&6; }
$as_echo "#define PCAP_SUPPORT_BT_MONITOR /**/" >>confdefs.h
- BT_MONITOR_SRC=pcap-bt-monitor-linux.c
+ MODULE_C_SRC="$MODULE_C_SRC pcap-bt-monitor-linux.c"
else
@@ -10763,8 +11563,6 @@ $as_echo "$as_me: no Bluetooth sniffing support implemented for $host_os" >&6;}
;;
esac
-
-
fi
# Check whether --enable-dbus was given.
@@ -10814,44 +11612,6 @@ if test "x$enable_dbus" != "xno"; then
fi
if test "x$enable_dbus" != "xno"; then
- # Extract the first word of "pkg-config", so it can be a program name with args.
-set dummy pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_PKGCONFIG+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$PKGCONFIG"; then
- ac_cv_prog_PKGCONFIG="$PKGCONFIG" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_PKGCONFIG="pkg-config"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
- test -z "$ac_cv_prog_PKGCONFIG" && ac_cv_prog_PKGCONFIG="no"
-fi
-fi
-PKGCONFIG=$ac_cv_prog_PKGCONFIG
-if test -n "$PKGCONFIG"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5
-$as_echo "$PKGCONFIG" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
if test "x$PKGCONFIG" != "xno"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for D-Bus" >&5
$as_echo_n "checking for D-Bus... " >&6; }
@@ -10889,7 +11649,7 @@ $as_echo "yes" >&6; }
$as_echo "#define PCAP_SUPPORT_DBUS 1" >>confdefs.h
- DBUS_SRC=pcap-dbus.c
+ MODULE_C_SRC="$MODULE_C_SRC pcap-dbus.c"
V_INCLS="$V_INCLS $DBUS_CFLAGS"
else
@@ -10914,7 +11674,6 @@ $as_echo "no" >&6; }
fi
fi
-
fi
# Check whether --enable-rdma was given.
@@ -11009,7 +11768,7 @@ $as_echo "yes" >&6; }
$as_echo "#define PCAP_SUPPORT_RDMASNIFF /**/" >>confdefs.h
- RDMA_SRC=pcap-rdmasniff.c
+ MODULE_C_SRC="$MODULE_C_SRC pcap-rdmasniff.c"
LIBS="-libverbs $LIBS"
else
@@ -11029,7 +11788,6 @@ fi
fi
-
fi
# Find a good install program. We prefer a C program (faster),
@@ -11131,7 +11889,7 @@ ac_config_headers="$ac_config_headers config.h"
ac_config_commands="$ac_config_commands default-1"
-ac_config_files="$ac_config_files Makefile pcap-filter.manmisc pcap-linktype.manmisc pcap-tstamp.manmisc pcap-savefile.manfile pcap.3pcap pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap pcap_get_tstamp_precision.3pcap pcap_list_datalinks.3pcap pcap_list_tstamp_types.3pcap pcap_open_dead.3pcap pcap_open_offline.3pcap pcap_set_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 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
@@ -11639,7 +12397,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by pcap $as_me 1.9.1, which was
+This file was extended by pcap $as_me 1.10.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -11705,7 +12463,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-pcap config.status 1.9.1
+pcap config.status 1.10.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
@@ -11835,6 +12593,7 @@ do
"config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
"default-1") CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;;
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "grammar.y") CONFIG_FILES="$CONFIG_FILES grammar.y" ;;
"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" ;;
diff --git a/configure.ac b/configure.ac
index eba27239..2ad28bbe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -8,7 +8,7 @@ dnl
#
# See
#
-# http://ftp.gnu.org/gnu/config/README
+# https://ftp.gnu.org/gnu/config/README
#
# for the URLs to use to fetch new versions of config.guess and
# config.sub.
@@ -24,13 +24,23 @@ AC_CANONICAL_SYSTEM
AC_LBL_C_INIT_BEFORE_CC(V_CCOPT, V_INCLS)
#
-# Try to enable as many C99 features as we can.
-# At minimum, we want C++/C99-style // comments.
+# We require C99 or later.
+# Try to get it, which may involve adding compiler flags;
+# if that fails, give up.
#
AC_PROG_CC_C99
if test "$ac_cv_prog_cc_c99" = "no"; then
- AC_MSG_WARN([The C compiler does not support C99; there may be compiler errors])
+ AC_MSG_ERROR([The C compiler does not support C99])
fi
+case "$host_os" in
+haiku*)
+ #
+ # Haiku's platform file is in C++.
+ #
+ AC_PROG_CXX
+ ;;
+esac
+
AC_LBL_C_INIT(V_CCOPT, V_INCLS)
AC_LBL_SHLIBS_INIT
AC_LBL_C_INLINE
@@ -50,7 +60,7 @@ dnl in "aclocal.m4" uses it, so we would still have to test for it
dnl and set "HAVE_SYS_IOCCOM_H" if we have it, otherwise
dnl "AC_LBL_FIXINCLUDES" wouldn't work on some platforms such as Solaris.
dnl
-AC_CHECK_HEADERS(sys/ioccom.h sys/sockio.h limits.h)
+AC_CHECK_HEADERS(sys/ioccom.h sys/sockio.h)
AC_CHECK_HEADERS(netpacket/packet.h)
AC_CHECK_HEADERS(net/pfvar.h, , , [#include <sys/types.h>
#include <sys/socket.h>
@@ -75,12 +85,11 @@ if test "$ac_cv_header_net_pfvar_h" = yes; then
fi
case "$host_os" in
-linux*|uclinux*)
- AC_CHECK_HEADERS(linux/sockios.h linux/if_bonding.h,,,
- [
-#include <sys/socket.h>
-#include <linux/if.h>
- ])
+haiku*)
+ #
+ # Haiku needs _BSD_SOURCE for the _IO* macros because it doesn't use them.
+ #
+ CFLAGS="$CFLAGS -D_BSD_SOURCE"
;;
esac
@@ -124,9 +133,9 @@ main(void)
],
[
#
- # We don't have strerror_r; do we have strerror_s?
+ # We don't have strerror_r; do we have _wcserror_s?
#
- AC_CHECK_FUNCS(strerror_s)
+ AC_CHECK_FUNCS(_wcserror_s)
])
#
@@ -135,45 +144,17 @@ main(void)
AC_CHECK_FUNCS(vsyslog)
#
-# Either:
-#
-# we have snprintf() and vsnprintf(), and have asprintf() and
-# vasprintf();
-#
-# we have snprintf() and vsnprintf(), but don't have asprintf()
-# or vasprintf();
-#
-# we have neither snprintf() nor vsnprintf(), and don't have
-# asprintf() or vasprintf(), either.
-#
-# We assume that if we have asprintf() we have vasprintf(), as well
-# as snprintf() and vsnprintf(), and that if we have snprintf() we
-# have vsnprintf().
+# Make sure we have vsnprintf() and snprintf(); we require them.
#
-# For the first case, we don't need any replacement routines.
-# For the second case, we need replacement asprintf()/vasprintf()
-# routines.
-# For the third case, we need replacement snprintf()/vsnprintf() and
-# asprintf()/vasprintf() routines.
-#
-needsnprintf=no
-AC_CHECK_FUNCS(vsnprintf snprintf,,
- [needsnprintf=yes])
+AC_CHECK_FUNC(vsnprintf,,
+ AC_MSG_ERROR([vsnprintf() is required but wasn't found]))
+AC_CHECK_FUNC(snprintf,,
+ AC_MSG_ERROR([snprintf() is required but wasn't found]))
+
needasprintf=no
AC_CHECK_FUNCS(vasprintf asprintf,,
[needasprintf=yes])
-if test $needsnprintf = yes; then
- #
- # We assume we have none of them; missing/snprintf.c supplies
- # all of them.
- #
- AC_LIBOBJ([snprintf])
-elif test $needasprintf = yes; then
- #
- # We assume we have snprintf()/vsnprintf() but lack
- # asprintf()/vasprintf(); missing/asprintf.c supplies
- # the latter (using vsnprintf()).
- #
+if test $needasprintf = yes; then
AC_LIBOBJ([asprintf])
fi
@@ -609,20 +590,6 @@ AC_MSG_RESULT(${enable_protochain})
#
VALGRINDTEST_SRC=
-#
-# SITA support is mutually exclusive with native capture support;
-# "--with-sita" selects SITA support.
-#
-AC_ARG_WITH(sita,
-AC_HELP_STRING([--with-sita],[include SITA support]),
-[
- if test ! "x$withval" = "xno" ; then
- AC_DEFINE(SITA,1,[include ACN support])
- AC_MSG_NOTICE(Enabling SITA ACN support)
- V_PCAP=sita
- fi
-],
-[
AC_ARG_WITH(pcap,
AC_HELP_STRING([--with-pcap=TYPE],[use packet capture TYPE]))
if test ! -z "$with_pcap" ; then
@@ -688,6 +655,7 @@ else
AC_CHECK_HEADERS(net/pfilt.h net/enet.h)
AC_CHECK_HEADERS(net/nit.h sys/net/nit.h)
AC_CHECK_HEADERS(linux/socket.h net/raw.h sys/dlpi.h)
+ AC_CHECK_HEADERS(config/HaikuConfig.h)
if test "$ac_cv_lbl_bpf_h_defines_biocsetif" = yes; then
#
@@ -713,11 +681,6 @@ else
# No prizes for guessing this one.
#
V_PCAP=linux
-
- #
- # XXX - this won't work with older kernels that have
- # SOCK_PACKET sockets but not PF_PACKET sockets.
- #
VALGRINDTEST_SRC=valgrindtest.c
elif test "$ac_cv_header_net_pfilt_h" = yes; then
#
@@ -749,6 +712,11 @@ else
# DLPI on pre-Solaris 11 SunOS 5, HP-UX, possibly others.
#
V_PCAP=dlpi
+ elif test "$ac_cv_header_config_HaikuConfig_h" = yes; then
+ #
+ # Haiku.
+ #
+ V_PCAP=haiku
else
#
# Nothing we support.
@@ -763,16 +731,16 @@ AC_MSG_RESULT($V_PCAP)
AC_SUBST(VALGRINDTEST_SRC)
#
-# Do capture-mechanism-dependent tests.
+# Do we have pkg-config?
+#
+AC_CHECK_PROG([PKGCONFIG], [pkg-config], [pkg-config], [no])
+
+#
+# Handle each capture type.
#
case "$V_PCAP" in
dlpi)
#
- # Needed for common functions used by pcap-[dlpi,libdlpi].c
- #
- SSRC="dlpisubs.c"
-
- #
# Checks for some header files.
#
AC_CHECK_HEADERS(sys/bufmod.h sys/dlpi_ext.h)
@@ -788,16 +756,30 @@ dlpi)
# Also, due to the bug above applications that link to libpcap with
# libdlpi will have to add "-L/lib" option to "configure".
#
- saved_ldflags=$LDFLAGS
+ save_LDFLAGS="$LDFLAGS"
LDFLAGS="$LIBS -L/lib"
AC_CHECK_LIB(dlpi, dlpi_walk,
[
LIBS="-ldlpi $LIBS"
V_PCAP=libdlpi
+
+ #
+ # Capture module plus common code needed for
+ # common functions used by pcap-[dlpi,libdlpi].c
+ #
+ PLATFORM_C_SRC="pcap-libdlpi.c dlpisubs.c"
AC_DEFINE(HAVE_LIBDLPI,1,[if libdlpi exists])
],
- V_PCAP=dlpi)
- LDFLAGS=$saved_ldflags
+ [
+ V_PCAP=dlpi
+
+ #
+ # Capture module plus common code needed for
+ # common functions used by pcap-[dlpi,libdlpi].c
+ #
+ PLATFORM_C_SRC="pcap-dlpi.c dlpisubs.c"
+ ])
+ LDFLAGS="$save_LDFLAGS"
#
# Checks whether <sys/dlpi.h> is usable, to catch weird SCO
@@ -832,8 +814,32 @@ dlpi)
])
;;
+enet)
+ #
+ # Capture module
+ #
+ PLATFORM_C_SRC="pcap-enet.c"
+ ;;
+
+haiku)
+ #
+ # Capture module
+ #
+ PLATFORM_CXX_SRC="pcap-haiku.cpp"
+
+ #
+ # Just for the sake of it.
+ #
+ AC_CHECK_HEADERS(net/if.h net/if_dl.h net/if_types.h)
+ ;;
+
linux)
#
+ # Capture module
+ #
+ PLATFORM_C_SRC="pcap-linux.c"
+
+ #
# Do we have the wireless extensions?
#
AC_CHECK_HEADERS(linux/wireless.h, [], [],
@@ -845,107 +851,78 @@ linux)
#
# Do we have libnl?
+ # We only want version 3. Version 2 was, apparently,
+ # short-lived, and version 1 is source and binary
+ # incompatible with version 3, and it appears that,
+ # these days, everybody's using version 3. We're
+ # not supporting older versions of the Linux kernel;
+ # let's drop support for older versions of libnl, too.
#
AC_ARG_WITH(libnl,
AC_HELP_STRING([--without-libnl],[disable libnl support @<:@default=yes, on Linux, if present@:>@]),
with_libnl=$withval,with_libnl=if_available)
if test x$with_libnl != xno ; then
- have_any_nl="no"
-
- incdir=-I/usr/include/libnl3
- libnldir=
- case "$with_libnl" in
-
- yes|if_available)
- ;;
-
- *)
- if test -d $withval; then
- libnldir=-L${withval}/lib/.libs
- incdir=-I${withval}/include
- fi
- ;;
- esac
-
- #
- # Try libnl 3.x first.
- #
- AC_CHECK_LIB(nl-3, nl_socket_alloc,
- [
+ if test "x$PKGCONFIG" != "xno"; then
#
- # Yes, we have libnl 3.x.
+ # We have pkg-config; see if we have libnl-genl-3.0
+ # as a package.
#
- LIBS="${libnldir} -lnl-genl-3 -lnl-3 $LIBS"
- AC_DEFINE(HAVE_LIBNL,1,[if libnl exists])
- AC_DEFINE(HAVE_LIBNL_3_x,1,[if libnl exists and is version 3.x])
- AC_DEFINE(HAVE_LIBNL_NLE,1,[libnl has NLE_FAILURE])
- AC_DEFINE(HAVE_LIBNL_SOCKETS,1,[libnl has new-style socket api])
- V_INCLS="$V_INCLS ${incdir}"
- have_any_nl="yes"
- ],[], ${incdir} ${libnldir} -lnl-genl-3 -lnl-3 )
-
- if test x$have_any_nl = xno ; then
- #
- # Try libnl 2.x
- #
- AC_CHECK_LIB(nl, nl_socket_alloc,
- [
- #
- # Yes, we have libnl 2.x.
- #
- LIBS="${libnldir} -lnl-genl -lnl $LIBS"
+ AC_MSG_CHECKING([for libnl-genl-3.0 with pkg-config])
+ if "$PKGCONFIG" libnl-genl-3.0; then
+ AC_MSG_RESULT([found])
+ pkg_config_found_libnl=yes
+ libnl_genl_cflags=`"$PKGCONFIG" --cflags libnl-genl-3.0`
+ V_INCLS="$V_INCLS ${libnl_genl_cflags}"
+ libnl_genl_libs=`"$PKGCONFIG" --libs libnl-genl-3.0`
+ LIBS="${libnl_genl_libs} $LIBS"
AC_DEFINE(HAVE_LIBNL,1,[if libnl exists])
- AC_DEFINE(HAVE_LIBNL_2_x,1,[if libnl exists and is version 2.x])
- AC_DEFINE(HAVE_LIBNL_NLE,1,[libnl has NLE_FAILURE])
- AC_DEFINE(HAVE_LIBNL_SOCKETS,1,[libnl has new-style socket api])
- have_any_nl="yes"
- ])
+ else
+ AC_MSG_RESULT([not found])
+ fi
fi
- if test x$have_any_nl = xno ; then
+ if test x$pkg_config_found_libnl != xyes; then
#
- # No, we don't; do we have libnl 1.x?
+ # OK, either we don't have pkg-config or there
+ # wasn't a .pc file for it; Check for it directly.
#
- AC_CHECK_LIB(nl, nl_handle_alloc,
+ case "$with_libnl" in
+
+ yes|if_available)
+ incdir=-I/usr/include/libnl3
+ libnldir=
+ ;;
+
+ *)
+ if test -d $withval; then
+ libnldir=-L${withval}/lib
+ incdir=-I${withval}/include
+ fi
+ ;;
+ esac
+
+ AC_CHECK_LIB(nl-3, nl_socket_alloc,
[
#
- # Yes.
+ # Yes, we have libnl 3.x.
#
- LIBS="${libnldir} -lnl $LIBS"
+ LIBS="${libnldir} -lnl-genl-3 -lnl-3 $LIBS"
AC_DEFINE(HAVE_LIBNL,1,[if libnl exists])
- have_any_nl="yes"
- ])
- fi
-
- if test x$have_any_nl = xno ; then
- #
- # No, we don't have libnl at all.
- #
- if test x$with_libnl = xyes ; then
- AC_MSG_ERROR([libnl support requested but libnl not found])
- fi
+ V_INCLS="$V_INCLS ${incdir}"
+ ],[
+ #
+ # No, we don't have libnl at all.
+ # Fail if the user explicitly requested
+ # it.
+ #
+ if test x$with_libnl = xyes ; then
+ AC_MSG_ERROR([libnl support requested but libnl not found])
+ fi
+ ], ${incdir} ${libnldir} -lnl-genl-3 -lnl-3 )
fi
fi
- AC_CHECK_HEADERS(linux/ethtool.h,,,
- [
-AC_INCLUDES_DEFAULT
-#include <linux/types.h>
- ])
-
- #
- # Check to see if struct tpacket_stats is defined in
- # <linux/if_packet.h>. If so, then pcap-linux.c can use this
- # to report proper statistics.
- #
- # -Scott Barron
- #
- AC_CHECK_TYPES(struct tpacket_stats,,,
- [
- #include <linux/if_packet.h>
- ])
-
#
# Check to see if the tpacket_auxdata struct has a tp_vlan_tci member.
#
@@ -963,6 +940,11 @@ AC_INCLUDES_DEFAULT
bpf)
#
+ # Capture module
+ #
+ PLATFORM_C_SRC="pcap-bpf.c"
+
+ #
# Check whether we have the *BSD-style ioctls.
#
AC_CHECK_HEADERS(net/if_media.h)
@@ -981,12 +963,44 @@ bpf)
])
;;
+pf)
+ #
+ # Capture module
+ #
+ PLATFORM_C_SRC="pcap-pf.c"
+ ;;
+
+snit)
+ #
+ # Capture module
+ #
+ PLATFORM_C_SRC="pcap-snit.c"
+ ;;
+
+snoop)
+ #
+ # Capture module
+ #
+ PLATFORM_C_SRC="pcap-snoop.c"
+ ;;
+
dag)
#
# --with-pcap=dag is the only way to get here, and it means
# "DAG support but nothing else"
#
V_DEFS="$V_DEFS -DDAG_ONLY"
+ PLATFORM_C_SRC="pcap-dag.c"
+ xxx_only=yes
+ ;;
+
+dpdk)
+ #
+ # --with-pcap=dpdk is the only way to get here, and it means
+ # "DPDK support but nothing else"
+ #
+ V_DEFS="$V_DEFS -DDPDK_ONLY"
+ PLATFORM_C_SRC="pcap-dpdk.c"
xxx_only=yes
;;
@@ -996,6 +1010,7 @@ septel)
# "Septel support but nothing else"
#
V_DEFS="$V_DEFS -DSEPTEL_ONLY"
+ PLATFORM_C_SRC="pcap-septel.c"
xxx_only=yes
;;
@@ -1005,10 +1020,15 @@ snf)
# "SNF support but nothing else"
#
V_DEFS="$V_DEFS -DSNF_ONLY"
+ PLATFORM_C_SRC="pcap-snf.c"
xxx_only=yes
;;
null)
+ #
+ # Capture module
+ #
+ PLATFORM_C_SRC="pcap-null.c"
;;
*)
@@ -1033,7 +1053,7 @@ then
# We have the header, so we use "getifaddrs()" to
# get the list of interfaces.
#
- V_FINDALLDEVS=fad-getad.c
+ PLATFORM_C_SRC="$PLATFORM_C_SRC fad-getad.c"
],[
#
# We don't have the header - give up.
@@ -1077,13 +1097,12 @@ then
ac_cv_lbl_have_siocglifconf=no))
AC_MSG_RESULT($ac_cv_lbl_have_siocglifconf)
if test $ac_cv_lbl_have_siocglifconf = yes ; then
- V_FINDALLDEVS=fad-glifc.c
+ PLATFORM_C_SRC="$PLATFORM_C_SRC fad-glifc.c"
else
- V_FINDALLDEVS=fad-gifc.c
+ PLATFORM_C_SRC="$PLATFORM_C_SRC fad-gifc.c"
fi
])
fi
-])
dnl check for hardware timestamp support
case "$host_os" in
@@ -1095,15 +1114,6 @@ linux*)
;;
esac
-AC_ARG_ENABLE([packet-ring],
-[AC_HELP_STRING([--enable-packet-ring],[enable packet ring support on Linux @<:@default=yes@:>@])],
-,enable_packet_ring=yes)
-
-if test "x$enable_packet_ring" != "xno" ; then
- AC_DEFINE(PCAP_SUPPORT_PACKET_RING, 1, [use packet ring capture support on Linux if available])
- AC_SUBST(PCAP_SUPPORT_PACKET_RING)
-fi
-
#
# Check for socklen_t.
#
@@ -1188,22 +1198,31 @@ if test "$want_dag" != no; then
if test -z "$dag_lib_dir"; then
dag_lib_dir="$dag_root/lib"
+ #
+ # Handle multiarch systems.
+ #
+ if test -d "$dag_lib_dir/$host"
+ then
+ dag_lib_dir="$dag_lib_dir/$host"
+ fi
fi
- V_INCLS="$V_INCLS -I$dag_include_dir"
-
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -I$dag_include_dir"
AC_CHECK_HEADERS([dagapi.h])
if test "$ac_cv_header_dagapi_h" = yes; then
+ V_INCLS="$V_INCLS -I$dag_include_dir"
+
if test $V_PCAP != dag ; then
- SSRC="$SSRC pcap-dag.c"
+ MODULE_C_SRC="$MODULE_C_SRC pcap-dag.c"
fi
# Check for various DAG API functions.
# Don't need to save and restore LIBS to prevent -ldag being
# included if there's a found-action (arg 3).
- saved_ldflags=$LDFLAGS
+ save_LDFLAGS="$LDFLAGS"
LDFLAGS="-L$dag_lib_dir"
AC_CHECK_LIB([dag], [dag_attach_stream],
[],
@@ -1214,7 +1233,7 @@ if test "$want_dag" != no; then
AC_CHECK_LIB([dag],[dag_get_stream_erf_types], [
AC_DEFINE(HAVE_DAG_GET_STREAM_ERF_TYPES, 1, [define if you have dag_get_stream_erf_types()])])
- LDFLAGS=$saved_ldflags
+ LDFLAGS="$save_LDFLAGS"
#
# We assume that if we have libdag we have libdagconf,
@@ -1246,10 +1265,11 @@ if test "$want_dag" != no; then
fi
if test "$want_dag" = yes; then
- # User wanted DAG support but we couldn't find it.
+ # User wanted DAG support but we couldn't find it.
AC_MSG_ERROR([DAG support requested with --with-dag, but the DAG headers weren't found at $dag_include_dir: make sure the DAG support is installed, specify a different path or paths if necessary, or don't request DAG support])
fi
fi
+ CFLAGS="$save_CFLAGS"
fi
AC_ARG_WITH(septel,
@@ -1308,7 +1328,7 @@ if test "$with_septel" != no; then
ADDLARCHIVEOBJS="$ADDLARCHIVEOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o"
if test "$V_PCAP" != septel ; then
- SSRC="$SSRC pcap-septel.c"
+ MODULE_C_SRC="$MODULE_C_SRC pcap-septel.c"
fi
AC_DEFINE(HAVE_SEPTEL_API, 1, [define if you have the Septel API])
@@ -1322,7 +1342,7 @@ if test "$with_septel" != no; then
fi
if test "$want_septel" = yes; then
- # User wanted Septel support but we couldn't find it.
+ # User wanted Septel support but we couldn't find it.
AC_MSG_ERROR([Septel support requested with --with-septel, but the Septel headers weren't found at $septel_include_dir: make sure the Septel support is installed, specify a different path or paths if necessary, or don't request Septel support])
fi
fi
@@ -1394,14 +1414,21 @@ if test "$with_snf" != no; then
if test -z "$snf_lib_dir"; then
snf_lib_dir="$snf_root/lib"
+ #
+ # Handle multiarch systems.
+ #
+ if test -d "$snf_lib_dir/$host"
+ then
+ snf_lib_dir="$snf_lib_dir/$host"
+ fi
fi
if test -f "$snf_include_dir/snf.h"; then
# We found a header; make sure we can link with the library
- saved_ldflags=$LDFLAGS
+ save_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS -L$snf_lib_dir"
AC_CHECK_LIB([snf], [snf_init], [ac_cv_lbl_snf_api="yes"])
- LDFLAGS="$saved_ldflags"
+ LDFLAGS="$save_LDFLAGS"
if test "$ac_cv_lbl_snf_api" = no; then
AC_MSG_ERROR(SNF API cannot correctly be linked; check config.log)
fi
@@ -1415,7 +1442,7 @@ if test "$with_snf" != no; then
LDFLAGS="$LDFLAGS -L$snf_lib_dir"
if test "$V_PCAP" != snf ; then
- SSRC="$SSRC pcap-snf.c"
+ MODULE_C_SRC="$MODULE_C_SRC pcap-snf.c"
fi
AC_DEFINE(HAVE_SNF_API, 1, [define if you have the Myricom SNF API])
@@ -1492,7 +1519,7 @@ if test "$want_turbocap" != no; then
if test $ac_cv_lbl_turbocap_api = yes; then
AC_MSG_RESULT(yes)
- SSRC="$SSRC pcap-tc.c"
+ MODULE_C_SRC="$MODULE_C_SRC pcap-tc.c"
V_INCLS="$V_INCLS $TURBOCAP_CFLAGS"
LIBS="$LIBS $TURBOCAP_LIBS -lTcApi -lpthread -lstdc++"
@@ -1501,7 +1528,7 @@ if test "$want_turbocap" != no; then
AC_MSG_RESULT(no)
if test "$want_turbocap" = yes; then
- # User wanted Turbo support but we couldn't find it.
+ # User wanted Turbo support but we couldn't find it.
AC_MSG_ERROR([TurboCap support requested with --with-turbocap, but the TurboCap headers weren't found: make sure the TurboCap support is installed or don't request TurboCap support])
fi
fi
@@ -1567,9 +1594,103 @@ yes) AC_MSG_RESULT(yes)
#include <sys/socket.h>
])
+ #
+ # Optionally, we may want to support SSL.
+ # Check for OpenSSL/libressl.
+ #
+ # First, try looking for it as a regular system library.
+ # Make sure we can find SSL_library_init() using the
+ # standard headers, just in case we're running a version
+ # of macOS that ships with the OpenSSL library but not
+ # the OpenSSL headers, and have also installed another
+ # version of OpenSSL with headers.
+ #
+ save_LIBS="$LIBS"
+ LIBS="-lssl -lcrypto"
+ AC_MSG_CHECKING(whether we have a system OpenSSL/libressl that we can use)
+ AC_TRY_LINK(
+ [
+#include <openssl/ssl.h>
+ ],
+ [
+SSL_library_init();
+return 0;
+ ],
+ [
+ AC_MSG_RESULT(yes)
+ HAVE_OPENSSL=yes
+ OPENSSL_LIBS="-lssl -lcrypto"
+ ],
+ AC_MSG_RESULT(no))
+ LIBS="$save_LIBS"
+
+ #
+ # If we didn't find it, check for it with pkg-config.
+ #
+ if test "x$HAVE_OPENSSL" != "xyes"; then
+ if test "x$PKGCONFIG" != "xno"; then
+ #
+ # We have pkg-config; see if we have OpenSSL/
+ # libressl installed as a package.
+ #
+ AC_MSG_CHECKING([for OpenSSL/libressl with pkg-config])
+ if "$PKGCONFIG" openssl; then
+ AC_MSG_RESULT([found])
+ HAVE_OPENSSL=yes
+ OPENSSL_CFLAGS=`"$PKGCONFIG" --cflags openssl`
+ OPENSSL_LIBS=`"$PKGCONFIG" --libs openssl`
+ else
+ AC_MSG_RESULT([not found])
+ fi
+ fi
+ fi
+
+ #
+ # If we didn't find it, check for it under /usr/local/opt/openssl;
+ # that's where Homebrew puts it on macOS. Feel free to add other
+ # -L directories as necessary; the "system library" check should
+ # also handle "add-on library under /usr/local", so that shouldn't
+ # be necessary here.
+ #
+ if test "x$HAVE_OPENSSL" != "xyes"; then
+ save_CFLAGS="$CFLAGS"
+ save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS -L/usr/local/opt/openssl/include"
+ LIBS="$LIBS -L/usr/local/opt/openssl/lib -lssl -lcrypto"
+ AC_MSG_CHECKING(whether we have OpenSSL/libressl in /usr/local/opt that we can use)
+ AC_TRY_LINK(
+ [
+#include <openssl/ssl.h>
+ ],
+ [
+SSL_library_init();
+return 0;
+ ],
+ [
+ AC_MSG_RESULT(yes)
+ HAVE_OPENSSL=yes
+ OPENSSL_CFLAGS="-I/usr/local/opt/openssl/include"
+ OPENSSL_LIBS="-L/usr/local/opt/openssl/lib -lssl -lcrypto"
+ ],
+ AC_MSG_RESULT(no))
+ CFLAGS="$save_CFLAGS"
+ LIBS="$save_LIBS"
+ fi
+
+ #
+ # OK, did we find it?
+ #
+ if test "x$HAVE_OPENSSL" = "xyes"; then
+ AC_DEFINE([HAVE_OPENSSL], [1], [Use OpenSSL])
+ CFLAGS="$CFLAGS $OPENSSL_CFLAGS"
+ LIBS="$LIBS $OPENSSL_LIBS"
+ else
+ AC_MSG_NOTICE(OpenSSL not found)
+ fi
+
AC_DEFINE(ENABLE_REMOTE,,
[Define to 1 if remote packet capture is to be supported])
- SSRC="$SSRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c"
+ REMOTE_C_SRC="$REMOTE_C_SRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c sslutils.c"
BUILD_RPCAPD=build-rpcapd
INSTALL_RPCAPD=install-rpcapd
;;
@@ -1621,21 +1742,52 @@ fi
#
AC_PROG_YACC
-#
-# Make sure it supports the -p flag and supports processing our
-# grammar.y.
-#
-AC_CACHE_CHECK([for capable yacc/bison], tcpdump_cv_capable_yacc,
- if $YACC -p pcap_ -o /dev/null $srcdir/grammar.y >/dev/null 2>&1; then
- tcpdump_cv_capable_yacc=yes
- else
- tcpdump_cv_capable_yacc=insufficient
- fi)
-if test $tcpdump_cv_capable_yacc = insufficient ; then
- AC_MSG_ERROR([$YACC is insufficient to compile libpcap.
+case "$YACC" in
+
+*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.
+ #
+ AC_CACHE_CHECK([for capable yacc], tcpdump_cv_capable_yacc,
+ if $YACC -V >/dev/null 2>&1; then
+ tcpdump_cv_capable_yacc=yes
+ else
+ tcpdump_cv_capable_yacc=insufficient
+ fi)
+ if test $tcpdump_cv_capable_yacc = insufficient ; then
+ AC_MSG_ERROR([$YACC 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.])
-fi
+ fi
+
+ #
+ # Berkeley YACC doesn't support "%define api.pure", so use
+ # "%pure-parser".
+ #
+ REENTRANT_PARSER="%pure-parser"
+ ;;
+
+*)
+ #
+ # Bison prior to 2.4(.1) doesn't support "%define api.pure", so use
+ # "%pure-parser".
+ #
+ bison_major_version=`$YACC -V | sed -n 's/.* \(@<:@1-9@:>@@<:@0-9@:>@*\)\.@<:@1-9@:>@@<:@0-9.@:>@*/\1/p'`
+ bison_minor_version=`$YACC -V | sed -n 's/.* @<:@1-9@:>@@<:@0-9@:>@*\.\(@<:@1-9@:>@@<:@0-9@:>@*\).*/\1/p'`
+ if test "$bison_major_version" -lt 2 -o \
+ \( "$bison_major_version" -eq 2 -a "$bison_major_version" -lt 4 \)
+ then
+ REENTRANT_PARSER="%pure-parser"
+ else
+ REENTRANT_PARSER="%define api.pure"
+ fi
+ ;;
+esac
+AC_SUBST(REENTRANT_PARSER)
#
# Do various checks for various OSes and versions of those OSes.
@@ -1813,13 +1965,25 @@ darwin*)
AC_MSG_CHECKING(whether building for 32-bit x86 is supported)
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -arch i386"
- AC_TRY_COMPILE(
+ AC_TRY_LINK(
[],
[return 0;],
[
AC_MSG_RESULT(yes)
- V_LIB_CCOPT_FAT="-arch x86_64 -arch i386"
- V_LIB_LDFLAGS_FAT="-arch x86_64 -arch i386"
+ V_LIB_CCOPT_FAT="-arch x86_64"
+ V_LIB_LDFLAGS_FAT="-arch x86_64"
+
+ #
+ # OpenSSL installation on macOS seems
+ # to install only the libs for 64-bit
+ # x86 - at least that's what Brew does:
+ # only configure 32-bit builds if we
+ # don't have OpenSSL.
+ #
+ if test "$HAVE_OPENSSL" != yes; then
+ V_LIB_CCOPT_FAT="$V_LIB_CCOPT_FAT -arch i386"
+ V_LIB_LDFLAGS_FAT="$V_LIB_LDFLAGS_FAT -arch i386"
+ fi
],
[
AC_MSG_RESULT(no)
@@ -1920,7 +2084,7 @@ irix*)
MAN_MISC_INFO=5
;;
-linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*|midipix*)
+linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*|haiku*|midipix*)
DYEXT="so"
#
@@ -2040,18 +2204,14 @@ AC_CHECK_MEMBERS([dl_hp_ppa_info_t.dl_module_id_1],,,
#include <sys/dlpi_ext.h>
])
-AC_LBL_UNALIGNED_ACCESS
-
AC_SUBST(V_CCOPT)
AC_SUBST(V_LIB_CCOPT_FAT)
AC_SUBST(V_LIB_LDFLAGS_FAT)
AC_SUBST(V_PROG_CCOPT_FAT)
AC_SUBST(V_PROG_LDFLAGS_FAT)
AC_SUBST(V_DEFS)
-AC_SUBST(V_FINDALLDEVS)
AC_SUBST(V_INCLS)
AC_SUBST(V_LEX)
-AC_SUBST(V_PCAP)
AC_SUBST(V_SHLIB_CCOPT)
AC_SUBST(V_SHLIB_CMD)
AC_SUBST(V_SHLIB_OPT)
@@ -2060,7 +2220,10 @@ AC_SUBST(V_RPATH_OPT)
AC_SUBST(V_YACC)
AC_SUBST(ADDLOBJS)
AC_SUBST(ADDLARCHIVEOBJS)
-AC_SUBST(SSRC)
+AC_SUBST(PLATFORM_C_SRC)
+AC_SUBST(PLATFORM_CXX_SRC)
+AC_SUBST(MODULE_C_SRC)
+AC_SUBST(REMOTE_C_SRC)
AC_SUBST(DYEXT)
AC_SUBST(MAN_DEVICES)
AC_SUBST(MAN_FILE_FORMATS)
@@ -2072,94 +2235,77 @@ AC_SUBST(INSTALL_RPCAPD)
AC_SUBST(RPCAPD_LIBS)
AC_SUBST(EXTRA_NETWORK_LIBS)
+#
+# Various Linux-specific mechanisms.
+#
AC_ARG_ENABLE([usb],
-[AC_HELP_STRING([--enable-usb],[enable USB capture support @<:@default=yes, if support available@:>@])],
+[AC_HELP_STRING([--enable-usb],[enable Linux usbmon USB capture support @<:@default=yes, if support available@:>@])],
[],
[enable_usb=yes])
-if test "xxx_only" = yes; then
- # User requested something-else-only pcap, so they don't
- # want USB support.
- enable_usb=no
-fi
-
-if test "x$enable_usb" != "xno" ; then
- dnl check for USB sniffing support
- AC_MSG_CHECKING(for USB sniffing support)
- case "$host_os" in
- linux*)
- AC_DEFINE(PCAP_SUPPORT_USB, 1, [target host supports USB sniffing])
- USB_SRC=pcap-usb-linux.c
- AC_MSG_RESULT(yes)
- ac_usb_dev_name=`udevinfo -q name -p /sys/class/usb_device/usbmon 2>/dev/null`
- if test $? -ne 0 ; then
- ac_usb_dev_name="usbmon"
- fi
- AC_DEFINE_UNQUOTED(LINUX_USB_MON_DEV, "/dev/$ac_usb_dev_name", [path for device for USB sniffing])
- AC_MSG_NOTICE(Device for USB sniffing is /dev/$ac_usb_dev_name)
- #
- # Do we have a version of <linux/compiler.h> available?
- # If so, we might need it for <linux/usbdevice_fs.h>.
- #
- AC_CHECK_HEADERS(linux/compiler.h)
- if test "$ac_cv_header_linux_compiler_h" = yes; then
- #
- # Yes - include it when testing for <linux/usbdevice_fs.h>.
- #
- AC_CHECK_HEADERS(linux/usbdevice_fs.h,,,[#include <linux/compiler.h>])
- else
- AC_CHECK_HEADERS(linux/usbdevice_fs.h)
- fi
- if test "$ac_cv_header_linux_usbdevice_fs_h" = yes; then
- #
- # OK, does it define bRequestType? Older versions of the kernel
- # define fields with names like "requesttype, "request", and
- # "value", rather than "bRequestType", "bRequest", and
- # "wValue".
- #
- AC_CHECK_MEMBERS([struct usbdevfs_ctrltransfer.bRequestType],,,
- [
- AC_INCLUDES_DEFAULT
- #ifdef HAVE_LINUX_COMPILER_H
- #include <linux/compiler.h>
- #endif
- #include <linux/usbdevice_fs.h>
- ])
- fi
- ;;
- freebsd*)
- #
- # This just uses BPF in FreeBSD 8.4 and later; we don't need
- # to check for anything special for capturing.
- #
- AC_MSG_RESULT([yes, in FreeBSD 8.4 and later])
- ;;
-
- *)
- AC_MSG_RESULT(no)
- ;;
-esac
-fi
-AC_SUBST(PCAP_SUPPORT_USB)
-AC_SUBST(USB_SRC)
-
-dnl check for netfilter sniffing support
+#
+# If somebody requested an XXX-only pcap, that doesn't include
+# additional mechanisms.
+#
if test "xxx_only" != yes; then
- AC_MSG_CHECKING(whether the platform could support netfilter sniffing)
- case "$host_os" in
- linux*)
- AC_MSG_RESULT(yes)
- #
- # Life's too short to deal with trying to get this to compile
- # if you don't get the right types defined with
- # __KERNEL_STRICT_NAMES getting defined by some other include.
- #
- # Check whether the includes Just Work. If not, don't turn on
- # netfilter support.
- #
- AC_MSG_CHECKING(whether we can compile the netfilter support)
- AC_CACHE_VAL(ac_cv_netfilter_can_compile,
- AC_TRY_COMPILE([
+ case "$host_os" in
+ linux*)
+ dnl check for USB sniffing support
+ AC_MSG_CHECKING(for Linux usbmon USB sniffing support)
+ if test "x$enable_usb" != "xno" ; then
+ AC_DEFINE(PCAP_SUPPORT_LINUX_USBMON, 1, [target host supports Linux usbmon for USB sniffing])
+ MODULE_C_SRC="$MODULE_C_SRC pcap-usb-linux.c"
+ AC_MSG_RESULT(yes)
+ ac_usb_dev_name=`udevinfo -q name -p /sys/class/usb_device/usbmon 2>/dev/null`
+ if test $? -ne 0 ; then
+ ac_usb_dev_name="usbmon"
+ fi
+ AC_DEFINE_UNQUOTED(LINUX_USB_MON_DEV, "/dev/$ac_usb_dev_name", [path for device for USB sniffing])
+ AC_MSG_NOTICE(Device for USB sniffing is /dev/$ac_usb_dev_name)
+ #
+ # Do we have a version of <linux/compiler.h> available?
+ # If so, we might need it for <linux/usbdevice_fs.h>.
+ #
+ AC_CHECK_HEADERS(linux/compiler.h)
+ if test "$ac_cv_header_linux_compiler_h" = yes; then
+ #
+ # Yes - include it when testing for <linux/usbdevice_fs.h>.
+ #
+ AC_CHECK_HEADERS(linux/usbdevice_fs.h,,,[#include <linux/compiler.h>])
+ else
+ AC_CHECK_HEADERS(linux/usbdevice_fs.h)
+ fi
+ if test "$ac_cv_header_linux_usbdevice_fs_h" = yes; then
+ #
+ # OK, does it define bRequestType? Older versions of the kernel
+ # define fields with names like "requesttype, "request", and
+ # "value", rather than "bRequestType", "bRequest", and
+ # "wValue".
+ #
+ AC_CHECK_MEMBERS([struct usbdevfs_ctrltransfer.bRequestType],,,
+ [
+ AC_INCLUDES_DEFAULT
+ #ifdef HAVE_LINUX_COMPILER_H
+ #include <linux/compiler.h>
+ #endif
+ #include <linux/usbdevice_fs.h>
+ ])
+ fi
+ else
+ AC_MSG_RESULT(no)
+ fi
+
+ #
+ # Life's too short to deal with trying to get this to compile
+ # if you don't get the right types defined with
+ # __KERNEL_STRICT_NAMES getting defined by some other include.
+ #
+ # Check whether the includes Just Work. If not, don't turn on
+ # netfilter support.
+ #
+ AC_MSG_CHECKING(whether we can compile the netfilter support)
+ AC_CACHE_VAL(ac_cv_netfilter_can_compile,
+ AC_TRY_COMPILE([
AC_INCLUDES_DEFAULT
#include <sys/socket.h>
#include <netinet/in.h>
@@ -2170,23 +2316,20 @@ AC_INCLUDES_DEFAULT
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_log.h>
#include <linux/netfilter/nfnetlink_queue.h>],
- [],
- ac_cv_netfilter_can_compile=yes,
- ac_cv_netfilter_can_compile=no))
- AC_MSG_RESULT($ac_cv_netfilter_can_compile)
- if test $ac_cv_netfilter_can_compile = yes ; then
- AC_DEFINE(PCAP_SUPPORT_NETFILTER, 1,
- [target host supports netfilter sniffing])
- NETFILTER_SRC=pcap-netfilter-linux.c
- fi
- ;;
- *)
- AC_MSG_RESULT(no)
- ;;
- esac
+ [],
+ ac_cv_netfilter_can_compile=yes,
+ ac_cv_netfilter_can_compile=no))
+ AC_MSG_RESULT($ac_cv_netfilter_can_compile)
+ if test $ac_cv_netfilter_can_compile = yes ; then
+ AC_DEFINE(PCAP_SUPPORT_NETFILTER, 1,
+ [target host supports netfilter sniffing])
+ MODULE_C_SRC="$MODULE_C_SRC pcap-netfilter-linux.c"
+ fi
+ ;;
+ esac
fi
+AC_SUBST(PCAP_SUPPORT_LINUX_USBMON)
AC_SUBST(PCAP_SUPPORT_NETFILTER)
-AC_SUBST(NETFILTER_SRC)
AC_ARG_ENABLE([netmap],
[AC_HELP_STRING([--enable-netmap],[enable netmap support @<:@default=yes, if support available@:>@])],
@@ -2213,12 +2356,249 @@ AC_INCLUDES_DEFAULT
if test $ac_cv_net_netmap_user_can_compile = yes ; then
AC_DEFINE(PCAP_SUPPORT_NETMAP, 1,
[target host supports netmap])
- NETMAP_SRC=pcap-netmap.c
+ MODULE_C_SRC="$MODULE_C_SRC pcap-netmap.c"
fi
AC_SUBST(PCAP_SUPPORT_NETMAP)
- AC_SUBST(NETMAP_SRC)
fi
+# Check for DPDK support.
+AC_ARG_WITH([dpdk],
+AC_HELP_STRING([--with-dpdk@<:@=DIR@:>@],[include DPDK support (located in directory DIR, if supplied). @<:@default=yes, if present@:>@]),
+[
+ if test "$withval" = no
+ then
+ # User doesn't want DPDK support.
+ want_dpdk=no
+ elif test "$withval" = yes
+ then
+ # User wants DPDK support but hasn't specified a directory.
+ want_dpdk=yes
+ else
+ # User wants DPDK support and has specified a directory,
+ # so use the provided value.
+ want_dpdk=yes
+ dpdk_dir=$withval
+ fi
+],[
+ if test "$V_PCAP" = dpdk; then
+ # User requested DPDK-only libpcap, so we'd better have
+ # the DPDK API.
+ want_dpdk=yes
+ elif test "xxx_only" = yes; then
+ # User requested something-else-only pcap, so they don't
+ # want DPDK support.
+ want_dpdk=no
+ else
+ #
+ # Use DPDK API if present, otherwise don't
+ #
+ want_dpdk=ifpresent
+ fi
+])
+
+if test "$want_dpdk" != no; then
+ if test "x$PKGCONFIG" != "xno"
+ then
+ #
+ # We have pkg-config; see if we have DPDK installed
+ # as a package.
+ #
+ AC_MSG_CHECKING([for DPDK with pkg-config])
+ if "$PKGCONFIG" libdpdk
+ then
+ AC_MSG_RESULT([found])
+ found_dpdk_with_pkg_config=yes
+ DPDK_CFLAGS=`"$PKGCONFIG" --cflags libdpdk`
+ DPDK_LDFLAGS=`"$PKGCONFIG" --libs libdpdk`
+ else
+ AC_MSG_RESULT([not found])
+ fi
+ fi
+
+ #
+ # If we didn't find it with pkg-config, try checking for
+ # it manually.
+ #
+ if test "x$found_dpdk_with_pkg_config" != "xyes"
+ then
+ if test -z "$dpdk_dir"; then
+ #
+ # The user didn't specify a directory containing
+ # the DPDK headers and libraries. If we find
+ # a /usr/local/include/dpdk directory, assume
+ # it's /usr/local, otherwise assume it's /usr.
+ #
+ if test -d "/usr/local/include/dpdk"; then
+ dpdk_dir="/usr/local"
+ else
+ dpdk_dir="/usr"
+ fi
+ fi
+ #
+ # The convention appears to be that 1) there's a "dpdk"
+ # subdirectory of the include directory, containing DPDK
+ # headers (at least in the installation on Ubuntu with
+ # the system DPDK packages) and 2) includes of DPDK
+ # headers don't use "dpdk/{header}" (at least from the
+ # way the DPDK documentation is written).
+ #
+ # So we add "/dpdk" to the include directory, and always
+ # add that to the list of include directories to search.
+ #
+ dpdk_inc_dir="$dpdk_dir/include/dpdk"
+ dpdk_inc_flags="-I$dpdk_inc_dir"
+ dpdk_lib_dir="$dpdk_dir/lib"
+ #
+ # Handle multiarch systems.
+ #
+ # Step 1: run the C compiler with the -dumpmachine option;
+ # if it succeeds, the output would be the multiarch directory
+ # name if your system has multiarch directories.
+ #
+ multiarch_dir=`$CC -dumpmachine 2>/dev/null`
+ if test ! -z "$multiarch_dir"
+ then
+ #
+ # OK, we have a multiarch directory.
+ #
+ # Now deal with includes. On Ubuntu 20.04, for
+ # example, we have /usr/include/dpdk *and*
+ # /usr/include/$multiarch_dir/dpdk, and must
+ # search both.
+ #
+ if test -d "$dpdk_dir/include/$multiarch_dir/dpdk"
+ then
+ dpdk_inc_flags="-I$dpdk_dir/include/$multiarch_dir/dpdk $dpdk_inc_flags"
+ fi
+
+ #
+ # Now deal with libraries.
+ #
+ if test -d "$dpdk_lib_dir/$multiarch_dir"
+ then
+ dpdk_lib_dir="$dpdk_lib_dir/$multiarch_dir"
+ fi
+ fi
+ DPDK_MACHINE_CFLAGS="-march=native"
+ DPDK_CFLAGS="$DPDK_MACHINE_CFLAGS $dpdk_inc_flags"
+ DPDK_LDFLAGS="-L$dpdk_lib_dir -ldpdk -lrt -lm -lnuma -ldl -pthread"
+ fi
+
+ save_CFLAGS="$CFLAGS"
+ save_LIBS="$LIBS"
+ save_LDFLAGS="$LDFLAGS"
+ CFLAGS="$CFLAGS $DPDK_CFLAGS"
+ LIBS="$LIBS $DPDK_LDFLAGS"
+ LDFLAGS="$LDFLAGS $DPDK_LDFLAGS"
+
+ AC_MSG_CHECKING(whether we can compile the DPDK support)
+ AC_CACHE_VAL(ac_cv_dpdk_can_compile,
+ AC_TRY_COMPILE([
+AC_INCLUDES_DEFAULT
+#include <rte_common.h>],
+ [],
+ ac_cv_dpdk_can_compile=yes,
+ ac_cv_dpdk_can_compile=no))
+ AC_MSG_RESULT($ac_cv_dpdk_can_compile)
+
+ #
+ # We include rte_bus.h, and older versions of DPDK
+ # didn't have it, so check for it.
+ #
+ if test "$ac_cv_dpdk_can_compile" = yes; then
+ #
+ # This runs the preprocessor, so make sure it
+ # looks in the DPDK directories. Instead of
+ # including dpdk/XXX.h, we include just XXX.h
+ # and assume DPDK_CFLAGS is the directory
+ # containing the DPDK headers (that's how
+ # pkg-config sets it, at least on Ubuntu),
+ # so just looking under /usr/include won't
+ # find it.
+ #
+ save_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $DPDK_CFLAGS"
+ AC_CHECK_HEADER(rte_bus.h)
+ CPPFLAGS="$save_CPPFLAGS"
+ fi
+
+ #
+ # We call rte_eth_dev_count_avail(), and older versions
+ # of DPDK didn't have it, so check for it.
+ #
+ if test "$ac_cv_header_rte_bus_h" = yes; then
+ AC_CHECK_FUNC(rte_eth_dev_count_avail)
+ fi
+
+ CFLAGS="$save_CFLAGS"
+ LIBS="$save_LIBS"
+ LDFLAGS="$save_LDFLAGS"
+
+ if test "$ac_cv_func_rte_eth_dev_count_avail" = yes; then
+ CFLAGS="$CFLAGS $DPDK_CFLAGS"
+ LIBS="$LIBS $DPDK_LDFLAGS"
+ LDFLAGS="$LDFLAGS $DPDK_LDFLAGS"
+ V_INCLS="$V_INCLS $DPDK_CFLAGS"
+ AC_DEFINE(PCAP_SUPPORT_DPDK, 1, [target host supports DPDK])
+ if test $V_PCAP != dpdk ; then
+ MODULE_C_SRC="$MODULE_C_SRC pcap-dpdk.c"
+ fi
+
+ #
+ # Check whether the rte_ether.h file defines
+ # struct ether_addr or struct rte_ether_addr.
+ #
+ # ("API compatibility? That's for losers!")
+ #
+ AC_CHECK_TYPES(struct rte_ether_addr,,,
+ [
+ #include <rte_ether.h>
+ ])
+ else
+ if test "$V_PCAP" = dpdk; then
+ # User requested DPDK-only capture support, but
+ # we couldn't the DPDK API support at all, or we
+ # found it but it wasn't a sufficiently recent
+ # version.
+ if test "$ac_cv_dpdk_can_compile" != yes; then
+ #
+ # Couldn't even find the headers.
+ #
+ AC_MSG_ERROR([DPDK support requested with --with-pcap=dpdk, but the DPDK headers weren't found at $dpdk_inc_dir: make sure the DPDK support is installed, specify a different path or paths if necessary, or don't request DPDK support])
+ else
+ #
+ # Found the headers, but we couldn't find
+ # rte_bus.h or rte_eth_dev_count_avail(),
+ # we don't have a sufficiently recent
+ # version of DPDK.
+ #
+ AC_MSG_ERROR([DPDK support requested with --with-pcap=dpdk, but we require DPDK 18.x or later; install a newer version of DPDK, or don't request DPDK support])
+ fi
+ fi
+
+ if test "$want_dpdk" = yes; then
+ # User requested DPDK-only capture support, but
+ # we couldn't the DPDK API support at all, or we
+ # found it but it wasn't a sufficiently recent
+ # version.
+ if test "$ac_cv_dpdk_can_compile" != yes; then
+ #
+ # Couldn't even find the headers.
+ #
+ AC_MSG_ERROR([DPDK support requested with --with-pcap=dpdk, but the DPDK headers weren't found at $dpdk_inc_dir: make sure the DPDK support is installed, specify a different path or paths if necessary, or don't request DPDK support])
+ else
+ #
+ # Found the headers, but we couldn't find
+ # rte_bus.h or rte_eth_dev_count_avail(),
+ # we don't have a sufficiently recent
+ # version of DPDK.
+ #
+ AC_MSG_ERROR([DPDK support requested with --with-pcap=dpdk, but we require DPDK 18.x or later: install a newer version of DPDK, or don't request DPDK support])
+ fi
+ fi
+ fi
+fi
+AC_SUBST(PCAP_SUPPORT_DPDK)
AC_ARG_ENABLE([bluetooth],
[AC_HELP_STRING([--enable-bluetooth],[enable Bluetooth support @<:@default=yes, if support available@:>@])],
@@ -2242,7 +2622,7 @@ if test "x$enable_bluetooth" != "xno" ; then
# sniffing.
#
AC_DEFINE(PCAP_SUPPORT_BT, 1, [target host supports Bluetooth sniffing])
- BT_SRC=pcap-bt-linux.c
+ MODULE_C_SRC="$MODULE_C_SRC pcap-bt-linux.c"
AC_MSG_NOTICE(Bluetooth sniffing is supported)
ac_lbl_bluetooth_available=yes
@@ -2269,7 +2649,7 @@ if test "x$enable_bluetooth" != "xno" ; then
AC_MSG_RESULT(yes)
AC_DEFINE(PCAP_SUPPORT_BT_MONITOR,,
[target host supports Bluetooth Monitor])
- BT_MONITOR_SRC=pcap-bt-monitor-linux.c
+ MODULE_C_SRC="$MODULE_C_SRC pcap-bt-monitor-linux.c"
],
[
AC_MSG_RESULT(no)
@@ -2301,8 +2681,6 @@ if test "x$enable_bluetooth" != "xno" ; then
;;
esac
AC_SUBST(PCAP_SUPPORT_BT)
- AC_SUBST(BT_SRC)
- AC_SUBST(BT_MONITOR_SRC)
fi
AC_ARG_ENABLE([dbus],
@@ -2349,7 +2727,6 @@ if test "x$enable_dbus" != "xno"; then
fi
if test "x$enable_dbus" != "xno"; then
- AC_CHECK_PROG([PKGCONFIG], [pkg-config], [pkg-config], [no])
if test "x$PKGCONFIG" != "xno"; then
AC_MSG_CHECKING([for D-Bus])
if "$PKGCONFIG" dbus-1; then
@@ -2372,7 +2749,7 @@ if test "x$enable_dbus" != "xno"; then
[
AC_MSG_RESULT([yes])
AC_DEFINE(PCAP_SUPPORT_DBUS, 1, [support D-Bus sniffing])
- DBUS_SRC=pcap-dbus.c
+ MODULE_C_SRC="$MODULE_C_SRC pcap-dbus.c"
V_INCLS="$V_INCLS $DBUS_CFLAGS"
],
[
@@ -2391,7 +2768,6 @@ if test "x$enable_dbus" != "xno"; then
fi
fi
AC_SUBST(PCAP_SUPPORT_DBUS)
- AC_SUBST(DBUS_SRC)
fi
AC_ARG_ENABLE([rdma],
@@ -2431,7 +2807,7 @@ if test "x$enable_rdma" != "xno"; then
[
AC_MSG_RESULT([yes])
AC_DEFINE(PCAP_SUPPORT_RDMASNIFF, , [target host supports RDMA sniffing])
- RDMA_SRC=pcap-rdmasniff.c
+ MODULE_C_SRC="$MODULE_C_SRC pcap-rdmasniff.c"
LIBS="-libverbs $LIBS"
],
[
@@ -2441,7 +2817,6 @@ if test "x$enable_rdma" != "xno"; then
])
])
AC_SUBST(PCAP_SUPPORT_RDMASNIFF)
- AC_SUBST(RDMA_SRC)
fi
AC_PROG_INSTALL
@@ -2453,7 +2828,7 @@ AC_OUTPUT_COMMANDS([if test -f .devel; then
cat $srcdir/Makefile-devel-adds >> Makefile
make depend
fi])
-AC_OUTPUT(Makefile pcap-filter.manmisc pcap-linktype.manmisc
+AC_OUTPUT(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
diff --git a/diag-control.h b/diag-control.h
index cfc581b3..47d31b98 100644
--- a/diag-control.h
+++ b/diag-control.h
@@ -48,7 +48,43 @@
#endif
/*
- * Suppress Flex warnings.
+ * Suppress "enum value not explicitly handled in switch" warnings.
+ * We may have to build on multiple different Windows SDKs, so we
+ * may not be able to include all enum values in a switch, as they
+ * won't necessarily be defined on all the SDKs, and, unlike
+ * #defines, there's no easy way to test whether a given enum has
+ * a given value. It *could* be done by the configure script or
+ * CMake tests.
+ */
+#if defined(_MSC_VER)
+ #define DIAG_OFF_ENUM_SWITCH \
+ __pragma(warning(push)) \
+ __pragma(warning(disable:4061))
+ #define DIAG_ON_ENUM_SWITCH \
+ __pragma(warning(pop))
+#else
+ #define DIAG_OFF_ENUM_SWITCH
+ #define DIAG_ON_ENUM_SWITCH
+#endif
+
+/*
+ * Suppress "switch statement has only a default case" warnings.
+ * There's a switch in bpf_filter.c that only has additional
+ * cases on Linux.
+ */
+#if defined(_MSC_VER)
+ #define DIAG_OFF_DEFAULT_ONLY_SWITCH \
+ __pragma(warning(push)) \
+ __pragma(warning(disable:4065))
+ #define DIAG_ON_DEFAULT_ONLY_SWITCH \
+ __pragma(warning(pop))
+#else
+ #define DIAG_OFF_DEFAULT_ONLY_SWITCH
+ #define DIAG_ON_DEFAULT_ONLY_SWITCH
+#endif
+
+/*
+ * Suppress Flex, narrowing, and deprecation warnings.
*/
#if defined(_MSC_VER)
/*
@@ -64,7 +100,27 @@
__pragma(warning(disable:4242)) \
__pragma(warning(disable:4244)) \
__pragma(warning(disable:4702))
- #define DIAG_ON_FLEX __pragma(warning(pop))
+ #define DIAG_ON_FLEX \
+ __pragma(warning(pop))
+
+ /*
+ * Suppress narrowing warnings.
+ */
+ #define DIAG_OFF_NARROWING \
+ __pragma(warning(push)) \
+ __pragma(warning(disable:4242)) \
+ __pragma(warning(disable:4311))
+ #define DIAG_ON_NARROWING \
+ __pragma(warning(pop))
+
+ /*
+ * Suppress deprecation warnings.
+ */
+ #define DIAG_OFF_DEPRECATION \
+ __pragma(warning(push)) \
+ __pragma(warning(disable:4996))
+ #define DIAG_ON_DEPRECATION \
+ __pragma(warning(pop))
#elif PCAP_IS_AT_LEAST_CLANG_VERSION(2,8)
/*
* This is Clang 2.8 or later; we can use "clang diagnostic
@@ -79,11 +135,31 @@
PCAP_DO_PRAGMA(clang diagnostic push) \
PCAP_DO_PRAGMA(clang diagnostic ignored "-Wsign-compare") \
PCAP_DO_PRAGMA(clang diagnostic ignored "-Wdocumentation") \
+ PCAP_DO_PRAGMA(clang diagnostic ignored "-Wshorten-64-to-32") \
PCAP_DO_PRAGMA(clang diagnostic ignored "-Wmissing-noreturn") \
PCAP_DO_PRAGMA(clang diagnostic ignored "-Wunused-parameter") \
PCAP_DO_PRAGMA(clang diagnostic ignored "-Wunreachable-code")
#define DIAG_ON_FLEX \
PCAP_DO_PRAGMA(clang diagnostic pop)
+
+ /*
+ * Suppress the only narrowing warnings you get from Clang.
+ */
+ #define DIAG_OFF_NARROWING \
+ PCAP_DO_PRAGMA(clang diagnostic push) \
+ PCAP_DO_PRAGMA(clang diagnostic ignored "-Wshorten-64-to-32")
+
+ #define DIAG_ON_NARROWING \
+ PCAP_DO_PRAGMA(clang diagnostic pop)
+
+ /*
+ * Suppress deprecation warnings.
+ */
+ #define DIAG_OFF_DEPRECATION \
+ PCAP_DO_PRAGMA(clang diagnostic push) \
+ PCAP_DO_PRAGMA(clang diagnostic ignored "-Wdeprecated-declarations")
+ #define DIAG_ON_DEPRECATION \
+ PCAP_DO_PRAGMA(clang diagnostic pop)
#elif PCAP_IS_AT_LEAST_GNUC_VERSION(4,6)
/*
* This is GCC 4.6 or later, or a compiler claiming to be that.
@@ -97,6 +173,21 @@
PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wunreachable-code")
#define DIAG_ON_FLEX \
PCAP_DO_PRAGMA(GCC diagnostic pop)
+
+ /*
+ * GCC currently doesn't issue any narrowing warnings.
+ */
+ #define DIAG_OFF_NARROWING
+ #define DIAG_ON_NARROWING
+
+ /*
+ * Suppress deprecation warnings.
+ */
+ #define DIAG_OFF_DEPRECATION \
+ PCAP_DO_PRAGMA(GCC diagnostic push) \
+ PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wdeprecated-declarations")
+ #define DIAG_ON_DEPRECATION \
+ PCAP_DO_PRAGMA(GCC diagnostic pop)
#else
/*
* Neither Visual Studio, nor Clang 2.8 or later, nor GCC 4.6 or later
@@ -105,6 +196,10 @@
*/
#define DIAG_OFF_FLEX
#define DIAG_ON_FLEX
+ #define DIAG_OFF_NARROWING
+ #define DIAG_ON_NARROWING
+ #define DIAG_OFF_DEPRECATION
+ #define DIAG_ON_DEPRECATION
#endif
#ifdef YYBYACC
@@ -127,92 +222,75 @@
#if defined(_MSC_VER)
/*
* This is Microsoft Visual Studio; we can use
- * __pragma(warning(disable:XXXX)) and __pragma(warning(push/pop)).
+ * __pragma(warning(disable:XXXX)).
*/
#define DIAG_OFF_BISON_BYACC \
- __pragma(warning(push)) \
__pragma(warning(disable:4702))
- #define DIAG_ON_BISON_BYACC __pragma(warning(pop))
#elif PCAP_IS_AT_LEAST_CLANG_VERSION(2,8)
/*
* This is Clang 2.8 or later; we can use "clang diagnostic
- * ignored -Wxxx" and "clang diagnostic push/pop".
+ * ignored -Wxxx".
*/
#define DIAG_OFF_BISON_BYACC \
- PCAP_DO_PRAGMA(clang diagnostic push) \
PCAP_DO_PRAGMA(clang diagnostic ignored "-Wshadow") \
PCAP_DO_PRAGMA(clang diagnostic ignored "-Wunreachable-code")
- #define DIAG_ON_BISON_BYACC \
- PCAP_DO_PRAGMA(clang diagnostic pop)
#elif PCAP_IS_AT_LEAST_GNUC_VERSION(4,6)
/*
* This is GCC 4.6 or later, or a compiler claiming to be that.
- * We can use "GCC diagnostic ignored -Wxxx" (introduced in 4.2)
- * and "GCC diagnostic push/pop" (introduced in 4.6).
+ * We can use "GCC diagnostic ignored -Wxxx" (introduced in 4.2,
+ * but it may not actually work very well prior to 4.6).
*/
#define DIAG_OFF_BISON_BYACC \
- PCAP_DO_PRAGMA(GCC diagnostic push) \
PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wshadow") \
PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wunreachable-code")
- #define DIAG_ON_BISON_BYACC \
- PCAP_DO_PRAGMA(GCC diagnostic pop)
#else
/*
* Neither Clang 2.8 or later nor GCC 4.6 or later or a compiler
* claiming to be that; there's nothing we know of that we can do.
*/
#define DIAG_OFF_BISON_BYACC
- #define DIAG_ON_BISON_BYACC
#endif
#else
/*
* Bison.
*
- * The generated code may have functions with unreachable code, so
- * suppress warnings about those.
+ * The generated code may have functions with unreachable code and
+ * switches with only a default case, so suppress warnings about those.
*/
#if defined(_MSC_VER)
/*
* This is Microsoft Visual Studio; we can use
- * __pragma(warning(disable:XXXX)) and __pragma(warning(push/pop)).
+ * __pragma(warning(disable:XXXX)).
*
* Suppress some /Wall warnings.
*/
#define DIAG_OFF_BISON_BYACC \
- __pragma(warning(push)) \
+ __pragma(warning(disable:4065)) \
__pragma(warning(disable:4127)) \
__pragma(warning(disable:4242)) \
__pragma(warning(disable:4244)) \
__pragma(warning(disable:4702))
- #define DIAG_ON_BISON_BYACC __pragma(warning(pop))
#elif PCAP_IS_AT_LEAST_CLANG_VERSION(2,8)
/*
* This is Clang 2.8 or later; we can use "clang diagnostic
- * ignored -Wxxx" and "clang diagnostic push/pop".
+ * ignored -Wxxx".
*/
#define DIAG_OFF_BISON_BYACC \
- PCAP_DO_PRAGMA(clang diagnostic push) \
PCAP_DO_PRAGMA(clang diagnostic ignored "-Wunreachable-code")
- #define DIAG_ON_BISON_BYACC \
- PCAP_DO_PRAGMA(clang diagnostic pop)
#elif PCAP_IS_AT_LEAST_GNUC_VERSION(4,6)
/*
* This is GCC 4.6 or later, or a compiler claiming to be that.
- * We can use "GCC diagnostic ignored -Wxxx" (introduced in 4.2)
- * and "GCC diagnostic push/pop" (introduced in 4.6).
+ * We can use "GCC diagnostic ignored -Wxxx" (introduced in 4.2,
+ * but it may not actually work very well prior to 4.6).
*/
#define DIAG_OFF_BISON_BYACC \
- PCAP_DO_PRAGMA(GCC diagnostic push) \
PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wunreachable-code")
- #define DIAG_ON_BISON_BYACC \
- PCAP_DO_PRAGMA(GCC diagnostic pop)
#else
/*
* Neither Clang 2.8 or later nor GCC 4.6 or later or a compiler
* claiming to be that; there's nothing we know of that we can do.
*/
#define DIAG_OFF_BISON_BYACC
- #define DIAG_ON_BISON_BYACC
#endif
#endif
diff --git a/dlpisubs.c b/dlpisubs.c
index 5f6e41af..2ef09315 100644
--- a/dlpisubs.c
+++ b/dlpisubs.c
@@ -114,6 +114,20 @@ pcap_stats_dlpi(pcap_t *p, struct pcap_stat *ps)
}
/*
+ * Does the processor for which we're compiling this support aligned loads?
+ */
+#if (defined(__i386__) || defined(_M_IX86) || defined(__X86__) || defined(__x86_64__) || defined(_M_X64)) || \
+ (defined(__arm__) || defined(_M_ARM) || defined(__aarch64__)) || \
+ (defined(__m68k__) && (!defined(__mc68000__) && !defined(__mc68010__))) || \
+ (defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PPC64)) || \
+ (defined(__s390__) || defined(__s390x__) || defined(__zarch__))
+ /* Yes, it does. */
+#else
+ /* No, it doesn't. */
+ #define REQUIRE_ALIGNMENT
+#endif
+
+/*
* Loop through the packets and call the callback for each packet.
* Return the number of packets read.
*/
@@ -127,7 +141,7 @@ pcap_process_pkts(pcap_t *p, pcap_handler callback, u_char *user,
struct pcap_pkthdr pkthdr;
#ifdef HAVE_SYS_BUFMOD_H
struct sb_hdr *sbp;
-#ifdef LBL_ALIGN
+#ifdef REQUIRE_ALIGNMENT
struct sb_hdr sbhdr;
#endif
#endif
@@ -157,7 +171,7 @@ pcap_process_pkts(pcap_t *p, pcap_handler callback, u_char *user,
return (n);
}
}
-#ifdef LBL_ALIGN
+#ifdef REQUIRE_ALIGNMENT
if ((long)bufp & 3) {
sbp = &sbhdr;
memcpy(sbp, bufp, sizeof(*sbp));
@@ -176,7 +190,7 @@ pcap_process_pkts(pcap_t *p, pcap_handler callback, u_char *user,
bufp += caplen;
#endif
++pd->stat.ps_recv;
- if (bpf_filter(p->fcode.bf_insns, pk, origlen, caplen)) {
+ if (pcap_filter(p->fcode.bf_insns, pk, origlen, caplen)) {
#ifdef HAVE_SYS_BUFMOD_H
pkthdr.ts.tv_sec = sbp->sbh_timestamp.tv_sec;
pkthdr.ts.tv_usec = sbp->sbh_timestamp.tv_usec;
@@ -275,7 +289,7 @@ pcap_process_mactype(pcap_t *p, u_int mactype)
* XXX - DL_IPNET devices default to "raw IP" rather than
* "IPNET header"; see
*
- * http://seclists.org/tcpdump/2009/q1/202
+ * https://seclists.org/tcpdump/2009/q1/202
*
* We'd have to do DL_IOC_IPNET_INFO to enable getting
* the IPNET header.
@@ -286,7 +300,7 @@ pcap_process_mactype(pcap_t *p, u_int mactype)
#endif
default:
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown mactype 0x%x",
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown mactype 0x%x",
mactype);
retv = -1;
}
diff --git a/doc/README.Win32.md b/doc/README.Win32.md
index 8de25c85..626f89ba 100644
--- a/doc/README.Win32.md
+++ b/doc/README.Win32.md
@@ -1,3 +1,198 @@
-Win32 used to build with Visual Studio 6, but we now use cmake.
+Building libpcap on Windows with Visual Studio
+==============================================
-This file needs to be adopted by a windows expert developer.
+Unlike the UN*Xes on which libpcap can capture network traffic, Windows
+has no network traffic capture mechanism that libpcap can use.
+Therefore, libpcap requires a driver, and a library to access the
+driver, provided by the Npcap or WinPcap projects.
+
+Those projects include versions of libpcap built to use that driver and
+library; these instructions are for people who want to build libpcap
+source releases, or libpcap from the Git repository, as a replacement
+for the version provided with Npcap or WinPcap.
+
+Npcap and WinPcap SDK
+---------------------
+
+In order to build libpcap, you will need to download Npcap and its
+software development kit (SDK) or WinPcap and its software development
+kit.
+
+Npcap is currently being developed and maintained, and offers many
+additional capabilities that WinPcap does not.
+
+WinPcap is no longer being developed or maintained; it should be used
+only if there is some other requirement to use it rather than Npcap,
+such as a requirement to support versions of Windows earlier than
+Windows Vista, which is the earliest version supported by Npcap.
+
+Npcap and its SDK can be downloaded from its home page:
+
+ https://npcap.org
+
+The SDK is a ZIP archive; create a folder on your C: drive, e.g.
+C:\npcap-sdk, and put the contents of the ZIP archive into that folder.
+
+The WinPcap installer can be downloaded from
+
+ https://www.winpcap.org/install/default.htm
+
+and the WinPcap Developer's Kit can be downloaded from
+
+ https://www.winpcap.org/devel.htm
+
+Required build tools
+--------------------
+
+The Developer's Kit is a ZIP archive; it contains a folder named
+WpdPack, which you should place on your C: drive, e.g. C:\WpdPack.
+
+Building libpcap on Windows requires Visual Studio 2015 or later. The
+Community Edition of Visual Studio can be downloaded at no cost from
+
+ https://visualstudio.microsoft.com
+
+Additional tools are also required. Chocolatey is a package manager for
+Windows with which those tools, and other tools, can be installed; it
+can be downloaded from
+
+ https://chocolatey.org
+
+It is a command-line tool; a GUI tool, Chocolatey GUI, is provided as a
+Chocolatey package, which can be installed from the command line:
+
+ choco install chocolateygui
+
+For convenience, the "choco install" command can be run with the "-y"
+flag, forcing it to automatically answer all questions asked of the user
+with "yes":
+
+ choco install -y chocolateygui
+
+The required tools are:
+
+### CMake ###
+
+libpcap does not provide supported project files for Visual Studio
+(there are currently unsupported project files provided, but we do not
+guarantee that they will work or that we will continue to provide them).
+It does provide files for CMake, which is a cross-platform tool that
+runs on UN*Xes and on Windows and that can generate project files for
+UN*X Make, the Ninja build system, and Visual Studio, among other build
+systems.
+
+Visual Studio 2015 does not provide CMake; an installer can be
+downloaded from
+
+ https://cmake.org/download/
+
+When you run the installer, you should choose to add CMake to the system
+PATH for all users and to create the desktop icon.
+
+CMake can also be installed as the Chocolatey package "cmake":
+
+ choco install -y cmake
+
+Visual Studio 2017 and later provide CMake, so you will not need to
+install CMake if you have installed Visual Studio 2017 or later. They
+include built-in support for CMake-based projects:
+
+ https://devblogs.microsoft.com/cppblog/cmake-support-in-visual-studio/
+
+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.
+
+### winflexbison ###
+
+libpcap uses the Flex lexical-analyzer generator and the Bison or
+Berkeley YACC parser generators to generate the parser for filter
+expressions. Windows versions of Flex and Bison can be downloaded from
+
+ https://sourceforge.net/projects/winflexbison/
+
+The downloaded file is a ZIP archive; create a folder on your C: drive,
+e.g. C:\Program Files\winflexbison, and put the contents of the ZIP
+archive into that folder. Then add that folder to the system PATH
+environment variable.
+
+Git
+---
+
+An optional tool, required only if you will be building from a Git
+repository rather than from a release source tarball, is Git. Git is
+provided as an optional installation component, "Git for Windows", with
+Visual Studio 2017 and later.
+
+Building from the Visual Studio GUI
+-----------------------------------
+
+### Visual Studio 2017 ###
+
+Open the folder containing the libpcap source with Open > Folder.
+Visual Studio will run CMake; however, you will need to indicate where
+the Npcap or WinPcap SDK is installed.
+
+To do this, go to Project > "Change CMake Settings" > pcap and:
+
+Choose which configuration type to build, if you don't want the default
+Debug build.
+
+In the CMakeSettings.json tab, change cmakeCommandArgs to include
+
+ -DPacket_ROOT={path-to-sdk}
+
+where {path-to-sdk} is the path of the directory containing the Npcap or
+WinPcap SDK. Note that backslashes in the path must be specified as two
+backslashes.
+
+Save the configuration changes with File > "Save CMakeSettings.json" or
+with control-S.
+
+Visual Studio will then re-run CMake. If that completes without errors,
+you can build with CMake > "Build All".
+
+### Visual Studio 2019 ###
+
+Open the folder containing the libpcap source with Open > Folder.
+Visual Studio will run CMake; however, you will need to indicate where
+the Npcap or WinPcap SDK is installed.
+
+To do this, go to Project > "CMake Settings for pcap" and:
+
+Choose which configuration type to build, if you don't want the default
+Debug build.
+
+Scroll down to "Cmake variables and cache", scroll through the list
+looking for the entry for Packet_ROOT, and either type in the path of
+the directory containing the Npcap or WinPcap SDK or use the "Browse..."
+button to browse for that directory.
+
+Save the configuration changes with File > "Save CMakeSettings.json" or
+with control-S.
+
+Visual Studio will then re-run CMake. If that completes without errors,
+you can build with Build > "Build All".
+
+Building from the command line
+------------------------------
+
+Start the appropriate Native Tools command line prompt.
+
+Change to the directory into which you want to build libpcap, possibly
+after creating it first. One choice is to create it as a subdirectory
+of the libpcap source directory.
+
+Run the command
+
+ cmake "-DPacket_ROOT={path-to-sdk}" {path-to-libpcap-source}
+
+where {path-to-sdk} is the path of the directory containing the Npcap or
+WinPcap SDK and {path-to-libpcap-source} is the pathname of the
+top-level source directory for libpcap.
+
+Run the command
+
+ msbuild/m pcap.sln
+
+to compile libpcap.
diff --git a/doc/README.aix b/doc/README.aix
index 92e513ff..9e9a23d3 100644
--- a/doc/README.aix
+++ b/doc/README.aix
@@ -27,7 +27,7 @@ Using BPF:
If you fix the problems yourself, please submit a patch by forking
the branch at
- https://github.com/the-tcpdump-group/libpcap/issues
+ https://github.com/the-tcpdump-group/libpcap/tree/master
and issuing a pull request, so we can incorporate the fixes into the
next release.
diff --git a/doc/README.capture-module b/doc/README.capture-module
new file mode 100644
index 00000000..e13eaf31
--- /dev/null
+++ b/doc/README.capture-module
@@ -0,0 +1,353 @@
+ How to write a libpcap module
+
+WARNING: this document describes an unstable interface; future releases
+of libpcap may, and some probably will, change the interface in an
+incompatible fashion. If you submit your module to the libpcap
+developers for inclusion in libpcap, not only does that make it more
+likely that it will be available in the libpcap provided by operating
+system vendors (such as Linux distributions), but it also means that we
+will attempt to update it to handle future changes to this interface.
+If we add new capabilities, we may have to ask you how to provide those
+additional capabilities if you're using an underlying mechanism for
+which we have neither the source code nor the documentation.
+
+NOTE: this document assumes familiarity with the entire libpcap API.
+
+TODO: more routines, more stuff that the activate routine has to do
+(such as setting the list of DLT_s), convert to Markdown?
+
+On Linux, *BSD, macOS, Solaris, AIX, HP-UX, IRIX, and Tru64 UNIX,
+Libpcap supports capturing on network interfaces as supported by the
+operating system networking stack, using the native packet capture
+mechanism provided by the OS. On Windows, it supports it with the help
+of the driver and library supplied by WinPcap and Npcap.
+
+In addition, it also supports capturing on other types of devices, such
+as:
+
+ specialized capture cards, such as Endace DAG cards;
+
+ network adapters that provide special high-performance code
+ paths, such as CSPI Myricom adapters;
+
+ buses such as USB;
+
+ software communication channels such as D-Bus and Linux netlink;
+
+ etc..
+
+Support for those devices is provided by modules compiled into libpcap.
+
+If you want to add such a module, you would first have to check the list
+of link-layer header types supported by libpcap, to see if one of those
+would be sufficient for your device. The current version of the list
+can be found at
+
+ https://www.tcpdump.org/linktypes.html
+
+If none of those would work for your device, please read
+doc/DLT_ALLOCATE_HOWTO.md and the introductory paragraphs on the Web
+page mentioned above, and then send a request for the new link-layer
+header type to tcpdump-workers@lists.tcpdump.org.
+
+Once you have a link-layer header type value or values that you can use,
+you can add new module.
+
+The module should be a C source file, with a name of the form
+pcap-{MOD}.c, where {MOD} is a name appropriate for your device; for
+example, the support for DAG cards is in pcap-dag.c, and the support for
+capturing USB traffic on Linux is pcap-usb-linux.c.
+
+Your module is assumed to support one or more named devices. The names
+should be relatively short names, containing only lower-case
+alphanumeric characters, consisting of a prefix that ends with an
+alphabetic character and, if there can be more than one device instance,
+possibly followed by a numerical device ID, such as "mydevice" or
+"mydevice0"/"mydevice1"/.... If you have more than one type of device
+that you can support, you can have more than one prefix, each of which
+can be followed by a numerical device ID.
+
+The two exported functions that your module must provide are routines to
+provide a list of device instances and a program to initialize a
+created-but-not-activated pcap_t for an instance of one of your devices.
+
+The "list of device instances" routine takes, as arguments:
+
+ a pointer to a pcap_if_list_t;
+
+ a pointer to an error message buffer.
+
+The error message buffer may be assumed to be PCAP_ERRBUF_SIZE bytes
+large, but must not be assumed to be larger. By convention, the routine
+typically has a name containing "findalldevs".
+
+The routine should attempt to determine what device instances are
+available and add them to the list pointed to by the first argument;
+this may be impossible for some modules, but, for those modules, it may
+be difficult to capture on the devices using Wirehshark (although it
+should be possible to capture on them using tcpdump, TShark, or other
+programs that take a device name on the command line), so we recommend
+that your routine provide the list of devices if possible. If it
+cannot, it should just immediately return 0.
+
+The routine should add devices to the list by calling the add_dev()
+routine in libpcap, declared in the pcap-int.h header. It takes, as
+arguments:
+
+ the pointer to the pcap_if_list_t passed as an argument to the
+ routine;
+
+ the device name, as described above;
+
+ a 32-bit word of flags, as provided by pcap_findalldevs();
+
+ a text description of the device, or NULL if there is no
+ description;
+
+ the error message buffer pointer provided to the routine.
+
+add_dev() will, if it succeeds, return a pointer to a pcap_if_t that was
+added to the list of devices. If it fails, it will return NULL; in this
+case, the error message buffer has been filled in with an error string,
+and your routine must return -1 to indicate the error.
+
+If your routine succeeds, it must return 0. If it fails, it must fill
+in the error message buffer with an error string and return -1.
+
+The "initialize the pcap_t" routine takes, as arguments:
+
+ a pointer to a device name;
+
+ a pointer to an error message buffer;
+
+ a pointer to an int.
+
+It returns a pointer to a pcap_t.
+
+Your module will probably need, for each pcap_t for an opened device, a
+private data structure to maintain its own information about the opened
+device. These should be allocated per opened instance, not per device;
+if, for example, mydevice0 can be captured on by more than one program
+at the same time, there will be more than one pcap_t opened for
+mydevice0, and so there will be separate private data structures for
+each pcap_t. If you need to maintain per-device, rather than per-opened
+instance information, you will have to maintain that yourself.
+
+The routine should first check the device to see whether it looks like a
+device that this module would handle; for example, it should begin with
+one of the device name prefixes for your module and, if your devices
+have instance numbers, be followed by a number. If it is not one of
+those devices, you must set the integer pointed to by the third
+argument to 0, to indicate that this is *not* one of the devices for
+your module, and return NULL.
+
+If it *is* one of those devices, it should call pcap_create_common,
+passing to it the error message buffer as the first argument and the
+size of the per-opened instance data structure as the second argument.
+If it fails, it will return NULL; you must return NULL in this case.
+
+If it succeeds, the pcap_t pointed to by the return value has been
+partially initialized, but you will need to complete the process. It
+has a "priv" member, which is a void * that points to the private data
+structure attached to it; that structure has been initialized to zeroes.
+
+What you need to set are some function pointers to your routines to
+handle certain operations:
+
+ activate_op
+ the routine called when pcap_activate() is done on the
+ pcap_t
+
+ can_set_rfmon_op
+ the routine called when pcap_can_set_rfmon() is done on
+ the pcap_t - if your device doesn't support 802.11
+ monitor mode, you can leave this as initialized by
+ pcap_create_common(), as that routine will return "no,
+ monitor mode isn't supported".
+
+Once you've set the activate_op and, if necessary, the can_set_rfmon_op,
+you must return the pcap_t * that was returned to you.
+
+Your activate routine takes, as an argument, a pointer to the pcap_t
+being activated, and returns an int.
+
+The perameters set for the device in the pcap_create() call, and after
+that call(), are mostly in the opt member of the pcap_t:
+
+ device
+ the name of the device
+
+ timeout
+ the buffering timeout, in milliseconds
+
+ buffer_size
+ the buffer size to use
+
+ promisc
+ 1 if promiscuous mode is to be used, 0 otherwise
+
+ rfmon
+ 1 if monitor mode is to be used, 0 otherwise
+
+ immediate
+ 1 if the device should be in immediate mode, 0 otherwise
+
+ nonblock
+ 1 if the device should be in non-blocking mode, 0
+ otherwise
+
+ tstamp_type
+ the type of time stamp to supply
+
+ tstamp_precision
+ the time stamp precision to supply
+
+The snapshot member of the pcap_t structure will contain the snapshot
+length to be used.
+
+Your routine should attempt to set up the device for capturing. If it
+fails, it must return an error indication which is one of the PCAP_ERROR
+values. For PCAP_ERROR, it must also set the errbuf member of the
+pcap_t to an error string. For PCAP_ERROR_NO_SUCH_DEVICE and
+PCAP_ERROR_PERM_DENIED, it may set it to an error string providing
+additional information that may be useful for debugging, or may just
+leave it as a null string.
+
+If it succeeds, it must set certain function pointers in the pcap_t
+structure:
+
+ read_op
+ called whenever packets are to be read
+
+ inject_op
+ called whenever packets are to be injected
+
+ setfilter_op
+ called whenever pcap_setfilter() is called
+
+ setdirection_op
+ called whenever pcap_setdirection() is called
+
+ set_datalink_op
+ called whnever pcap_set_datalink() is called
+
+ getnonblock_op
+ called whenever pcap_getnonblock() is called
+
+ setnonblock_op
+ called whenever pcap_setnonblock() is called
+
+ stats_op
+ called whenever pcap_stats() is called
+
+ cleanup_op
+ called if the activate routine fails or pcap_close() is
+ called
+
+and must also set the linktype member to the DLT_ value for the device.
+
+On UN*Xes, if the device supports waiting for packets to arrive with
+select()/poll()/epoll()/kqueues etc., it should set the selectable_fd
+member of the structure to the descriptor you would use with those
+calls. If it does not, then, if that's because the device polls for
+packets rather than receiving interrupts or other signals when packets
+arrive, it should have a struct timeval in the private data structure,
+set the value of that struct timeval to the poll timeout, and set the
+required_select_timeout member of the pcap_t to point to the struct
+timeval.
+
+The read_op routine is called when pcap_dispatch(), pcap_loop(),
+pcap_next(), or pcap_next_ex() is called. It is passed the same
+arguments as pcap_dispatch() is called.
+
+The routine should first check if the break_loop member of the pcap_t is
+non-zero and, if so, set that member to zero and return
+PCAP_ERROR_BREAK.
+
+Then, if the pcap_t is in blocking mode (as opposed to non-blocking
+mode), and there are no packets immediately available to be passed to
+the callback, it should block waiting for packets to arrive, using the
+buffering timeout, first, and read packets from the device if necessary.
+
+Then it should loop through the available packets, calling the callback
+routine for each packet:
+
+ If the PACKET_COUNT_IS_UNLIMITED() macro evaluates to true when
+ passed the packet count argument, the loop should continue until
+ there are no more packets immediately available or the
+ break_loop member of the pcap_t is non-zero. If the break_loop
+ member is fount to be non-zero, it should set that member to
+ zero and return PCAP_ERROR_BREAK.
+
+ If it doesn't evaluat to true, then the loop should also
+ terminate if the specified number of packets have been delivered
+ to the callback.
+
+Note that there is *NO* requirement that the packet header or data
+provided to the callback remain available, or valid, after the callback
+routine returns; if the callback needs to save the data for other code
+to use, it must make a copy of that data. This means that the module is
+free to, for example, overwrite the buffer into which it read the
+packet, or release back to the kernel a packet in a memory-mapped
+buffer shared between the kernel and userland, after the callback
+returns.
+
+If an error occurs when reading packets from the device, it must set the
+errbuf member of the pcap_t to an error string and return PCAP_ERROR.
+
+If no error occurs, it must return the number of packets that were
+supplied to the callback routine.
+
+The inject routine is passed a pointer to the pcap_t, a buffer
+containing the contents of the packet to inject, and the number of bytes
+in the packet. If the device doesn't support packet injection, the
+routine must set the errbuf member of the pcap_t to a message indicating
+that packet injection isn't supported and return PCAP_ERROR. Otherwise,
+it should attempt to inject the packet; if the attempt fails, it must
+set the errbuf member of the pcap_t to an error message and return
+PCAP_ERROR. Otherwise, it should return the number of bytes injected.
+
+The setfilter routine is passed a pointer to the pcap_t and a pointer
+to a struct bpf_program containing a BPF program to be used as a filter.
+If the mechanism used by your module can perform filtering with a BPF
+program, it would attempt to set that filter to the specified program.
+
+If that failed because the program was too large, or used BPF features
+not supported by that mechanism, the module should fall back on
+filtering in userland by saving a copy of the filter with a call to
+install_bpf_program(), setting a flag in the private data instructure
+indicating that filtering is being done by the module and, in the read
+routine's main loop, checking the flag and, if it's set, calling
+pcap_filter(), passing it the fcode.bf_insns member of the pcap_t, the
+raw packet data, the on-the-wire length of the packet, and the captured
+length of the packet, and only passing the packet to the callback
+routine, and counting it, if pcap_filter() returns a non-zero value.
+(If the flag is not set, all packets should be passed to the callback
+routine and counted, as the filtering is being done by the mechanism
+used by the module.) If install_bpf_program() returns a negative value,
+the routine should return PCAP_ERROR.
+
+If the attempt to set the filter failed for any other reason, the
+routine must set the errbuf member of the pcap_t to an error message and
+return PCAP_ERROR.
+
+If the attempt to set the filter succeeded, or it failed because the
+mechanism used by the module rejected it and the call to
+install_bpf_program() succeeded, the routine should return 0.
+
+If the mechanism the module uses doesn't support filtering, the pointer
+to the setfilter routine can just be set to point to
+install_bpf_program; the module does not need a routine of its own to
+handle that.
+
+The setdirection routine is passed a pointer to the pcap_t and a
+pcap_direction_t indicating which packet directions should be accepted.
+If the module can't arrange to handle only incoming packets or only
+outgoing packets, it can set the pointer to the setdirection routine to
+NULL, and calls to pcap_setdirection() will fail with an error message
+indicating that setting the direction isn't supported.
+
+XXX describe set_datalink, including what the activate routine has to do
+XXX
+
+XXX describe the rest of the routines XXX
diff --git a/doc/README.dag b/doc/README.dag
index 7ea25040..13332c62 100644
--- a/doc/README.dag
+++ b/doc/README.dag
@@ -1,7 +1,7 @@
The following instructions apply if you have a Linux or FreeBSD platform and
want libpcap to support the DAG range of passive network monitoring cards from
-Endace (http://www.endace.com, see below for further contact details).
+Endace (https://www.endace.com, see below for further contact details).
1) Install and build the DAG software distribution by following the
instructions supplied with that package. Current Endace customers can download
@@ -117,6 +117,6 @@ Please submit bug reports via <support@endace.com>.
Please also visit our Web site at:
- http://www.endace.com/
+ https://www.endace.com/
For more information about Endace DAG cards contact <sales@endace.com>.
diff --git a/doc/README.hpux b/doc/README.hpux
index 65ecff97..b995eeea 100644
--- a/doc/README.hpux
+++ b/doc/README.hpux
@@ -8,7 +8,7 @@ Note that packet-capture programs such as tcpdump may, on HP-UX, not be
able to see packets sent from the machine on which they're running.
Some articles on groups.google.com discussing this are:
- http://groups.google.com/groups?selm=82ld3v%2480i%241%40mamenchi.zrz.TU-Berlin.DE
+ https://groups.google.com/groups?selm=82ld3v%2480i%241%40mamenchi.zrz.TU-Berlin.DE
which says:
@@ -69,7 +69,7 @@ which says:
and
- http://groups.google.com/groups?selm=38AA973E.96BE7DF7%40cc.uit.no
+ https://groups.google.com/groups?selm=38AA973E.96BE7DF7%40cc.uit.no
which says:
@@ -118,7 +118,7 @@ And another message to tcpdump-workers@tcpdump.org, from Rick Jones:
Another posting:
- http://groups.google.com/groups?selm=7d6gvn%24b3%241%40ocean.cup.hp.com
+ https://groups.google.com/groups?selm=7d6gvn%24b3%241%40ocean.cup.hp.com
indicates that you need to install the optional STREAMS product to do
captures on HP-UX 9.x:
@@ -159,7 +159,7 @@ An additional note, from Jost Martin, for HP-UX 10.20:
of an interface
A: You need to get PHNE_20892,PHNE_20725 and PHCO_10947 (or
newer, this is as of 4.4.00) and its dependencies. Then you can
- enable the feature as descibed below:
+ enable the feature as described below:
Patch Name: PHNE_20892
Patch Description: s700 10.20 PCI 100Base-T cumulative patch
diff --git a/doc/README.linux.md b/doc/README.linux.md
index ddca4fec..143dff65 100644
--- a/doc/README.linux.md
+++ b/doc/README.linux.md
@@ -1,73 +1,8 @@
-In order for libpcap to be able to capture packets on a Linux system,
-the "packet" protocol must be supported by your kernel. If it is not,
-you may get error messages such as
+Currently, libpcap supports packet capturing on Linux 2.6.27 and later;
+earlier versions are not supported.
- modprobe: can't locate module net-pf-17
-
-in "/var/adm/messages", or may get messages such as
-
- socket: Address family not supported by protocol
-
-from applications using libpcap.
-
-You must configure the kernel with the CONFIG_PACKET option for this
-protocol; the following note is from the Linux "Configure.help" file for
-the 2.0[.x] kernel:
-
- Packet socket
- CONFIG_PACKET
- The Packet protocol is used by applications which communicate
- directly with network devices without an intermediate network
- protocol implemented in the kernel, e.g. tcpdump. If you want them
- to work, choose Y.
-
- This driver is also available as a module called af_packet.o ( =
- code which can be inserted in and removed from the running kernel
- whenever you want). If you want to compile it as a module, say M
- here and read Documentation/modules.txt; if you use modprobe or
- kmod, you may also want to add "alias net-pf-17 af_packet" to
- /etc/modules.conf.
-
-and the note for the 2.2[.x] kernel says:
-
- Packet socket
- CONFIG_PACKET
- The Packet protocol is used by applications which communicate
- directly with network devices without an intermediate network
- protocol implemented in the kernel, e.g. tcpdump. If you want them
- to work, choose Y. This driver is also available as a module called
- af_packet.o ( = code which can be inserted in and removed from the
- running kernel whenever you want). If you want to compile it as a
- module, say M here and read Documentation/modules.txt. You will
- need to add 'alias net-pf-17 af_packet' to your /etc/conf.modules
- file for the module version to function automatically. If unsure,
- say Y.
-
-In addition, there is an option that, in 2.2 and later kernels, will
-allow packet capture filters specified to programs such as tcpdump to be
-executed in the kernel, so that packets that don't pass the filter won't
-be copied from the kernel to the program, rather than having all packets
-copied to the program and libpcap doing the filtering in user mode.
-
-Copying packets from the kernel to the program consumes a significant
-amount of CPU, so filtering in the kernel can reduce the overhead of
-capturing packets if a filter has been specified that discards a
-significant number of packets. (If no filter is specified, it makes no
-difference whether the filtering isn't performed in the kernel or isn't
-performed in user mode. :-))
-
-The option for this is the CONFIG_FILTER option; the "Configure.help"
-file says:
-
- Socket filtering
- CONFIG_FILTER
- The Linux Socket Filter is derived from the Berkeley Packet Filter.
- If you say Y here, user-space programs can attach a filter to any
- socket and thereby tell the kernel that it should allow or disallow
- certain types of data to get through the socket. Linux Socket
- Filtering works on all socket types except TCP for now. See the text
- file linux/Documentation/networking/filter.txt for more information.
- If unsure, say N.
+You must configure 2.26.x kernels with the CONFIG_PACKET_MMAP option for
+this protocol. 3.x and later kernels do not require that.
Note that, by default, libpcap will, if libnl is present, build with it;
it uses libnl to support monitor mode on mac80211 devices. There is a
@@ -94,13 +29,6 @@ Statistics:
Statistics reported by pcap are platform specific. The statistics
reported by pcap_stats on Linux are as follows:
-2.2.x
-=====
-ps_recv Number of packets that were accepted by the pcap filter
-ps_drop Always 0, this statistic is not gathered on this platform
-
-2.4.x and later
-=====
ps_recv Number of packets that were accepted by the pcap filter
ps_drop Number of packets that had passed filtering but were not
passed on to pcap due to things like buffer shortage, etc.
diff --git a/doc/README.septel b/doc/README.septel
index fa2c0c9a..203ec1a6 100644
--- a/doc/README.septel
+++ b/doc/README.septel
@@ -1,6 +1,6 @@
The following instructions apply if you have a Linux platform and want
libpcap to support the Septel range of passive network monitoring cards
-from Intel (http://www.intel.com)
+from Intel (https://www.intel.com)
1) Install and build the Septel software distribution by following the
instructions supplied with that package.
diff --git a/doc/README.sita b/doc/README.sita
index 5a65822e..37003f53 100644
--- a/doc/README.sita
+++ b/doc/README.sita
@@ -1,6 +1,13 @@
+NOTE: this is not currently supported; the configure script doesn't
+support --with-sita, and CMake doesn't support enabling SITA ACN
+support. The code currently does not compile; it should really be
+implemented as an additional remote capture mechanism, using a URL,
+rather than as a separate version of libpcap that supports only the ACN
+product, but the infrastructure for that isn't yet available.
+
The following instructions apply if you have a Linux platform and want
libpcap to support the 'ACN' WAN/LAN router product from SITA
-(http://www.sita.aero)
+(https://www.sita.aero)
This might also work on non-Linux Unix-compatible platforms, but that
has not been tested.
@@ -12,7 +19,7 @@ These additions/extensions have been made to PCAP to allow it to
capture packets from a SITA ACN device (and potentially others).
To enable its support you need to ensure that the distribution has
-a correct configure.ac file; that can be created if neccessay by
+a correct configure.ac file; that can be created if necessary by
using the normal autoconf procedure of:
aclocal
diff --git a/etherent.c b/etherent.c
index 5f499613..69da9a54 100644
--- a/etherent.c
+++ b/etherent.c
@@ -25,7 +25,6 @@
#include <pcap-types.h>
-#include <ctype.h>
#include <memory.h>
#include <stdio.h>
#include <string.h>
@@ -45,14 +44,18 @@ static inline int skip_line(FILE *);
static inline u_char
xdtoi(u_char c)
{
- if (isdigit(c))
+ if (c >= '0' && c <= '9')
return (u_char)(c - '0');
- else if (islower(c))
+ else if (c >= 'a' && c <= 'f')
return (u_char)(c - 'a' + 10);
else
return (u_char)(c - 'A' + 10);
}
+/*
+ * Skip linear white space (space and tab) and any CRs before LF.
+ * Stop when we hit a non-white-space character or an end-of-line LF.
+ */
static inline int
skip_space(FILE *f)
{
@@ -60,7 +63,7 @@ skip_space(FILE *f)
do {
c = getc(f);
- } while (isspace(c) && c != '\n');
+ } while (c == ' ' || c == '\t' || c == '\r');
return c;
}
@@ -97,7 +100,7 @@ pcap_next_etherent(FILE *fp)
/* If this is a comment, or first thing on line
cannot be Ethernet address, skip the line. */
- if (!isxdigit(c)) {
+ if (!PCAP_ISXDIGIT(c)) {
c = skip_line(fp);
if (c == EOF)
return (NULL);
@@ -110,7 +113,7 @@ pcap_next_etherent(FILE *fp)
c = getc(fp);
if (c == EOF)
return (NULL);
- if (isxdigit(c)) {
+ if (PCAP_ISXDIGIT(c)) {
d <<= 4;
d |= xdtoi((u_char)c);
c = getc(fp);
@@ -126,7 +129,7 @@ pcap_next_etherent(FILE *fp)
}
/* Must be whitespace */
- if (!isspace(c)) {
+ if (c != ' ' && c != '\t' && c != '\r' && c != '\n') {
c = skip_line(fp);
if (c == EOF)
return (NULL);
@@ -156,7 +159,8 @@ pcap_next_etherent(FILE *fp)
c = getc(fp);
if (c == EOF)
return (NULL);
- } while (!isspace(c) && --namesize != 0);
+ } while (c != ' ' && c != '\t' && c != '\r' && c != '\n'
+ && --namesize != 0);
*bp = '\0';
/* Eat trailing junk */
diff --git a/ethertype.h b/ethertype.h
index 51f63083..e34e07b9 100644
--- a/ethertype.h
+++ b/ethertype.h
@@ -32,58 +32,58 @@
*/
#ifndef ETHERTYPE_PUP
-#define ETHERTYPE_PUP 0x0200 /* PUP protocol */
+#define ETHERTYPE_PUP 0x0200 /* PUP protocol */
#endif
#ifndef ETHERTYPE_IP
-#define ETHERTYPE_IP 0x0800 /* IP protocol */
+#define ETHERTYPE_IP 0x0800 /* IP protocol */
#endif
#ifndef ETHERTYPE_ARP
#define ETHERTYPE_ARP 0x0806 /* Addr. resolution protocol */
#endif
-#ifndef ETHERTYPE_REVARP
-#define ETHERTYPE_REVARP 0x8035 /* reverse Addr. resolution protocol */
-#endif
#ifndef ETHERTYPE_NS
#define ETHERTYPE_NS 0x0600
#endif
#ifndef ETHERTYPE_SPRITE
-#define ETHERTYPE_SPRITE 0x0500
+#define ETHERTYPE_SPRITE 0x0500
#endif
#ifndef ETHERTYPE_TRAIL
#define ETHERTYPE_TRAIL 0x1000
#endif
#ifndef ETHERTYPE_MOPDL
-#define ETHERTYPE_MOPDL 0x6001
+#define ETHERTYPE_MOPDL 0x6001
#endif
#ifndef ETHERTYPE_MOPRC
-#define ETHERTYPE_MOPRC 0x6002
+#define ETHERTYPE_MOPRC 0x6002
#endif
#ifndef ETHERTYPE_DN
-#define ETHERTYPE_DN 0x6003
+#define ETHERTYPE_DN 0x6003
#endif
#ifndef ETHERTYPE_LAT
-#define ETHERTYPE_LAT 0x6004
+#define ETHERTYPE_LAT 0x6004
#endif
#ifndef ETHERTYPE_SCA
#define ETHERTYPE_SCA 0x6007
#endif
+#ifndef ETHERTYPE_TEB
+#define ETHERTYPE_TEB 0x6558
+#endif
#ifndef ETHERTYPE_REVARP
-#define ETHERTYPE_REVARP 0x8035
+#define ETHERTYPE_REVARP 0x8035 /* reverse Addr. resolution protocol */
#endif
#ifndef ETHERTYPE_LANBRIDGE
-#define ETHERTYPE_LANBRIDGE 0x8038
+#define ETHERTYPE_LANBRIDGE 0x8038
#endif
#ifndef ETHERTYPE_DECDNS
-#define ETHERTYPE_DECDNS 0x803c
+#define ETHERTYPE_DECDNS 0x803c
#endif
#ifndef ETHERTYPE_DECDTS
-#define ETHERTYPE_DECDTS 0x803e
+#define ETHERTYPE_DECDTS 0x803e
#endif
#ifndef ETHERTYPE_VEXP
-#define ETHERTYPE_VEXP 0x805b
+#define ETHERTYPE_VEXP 0x805b
#endif
#ifndef ETHERTYPE_VPROD
-#define ETHERTYPE_VPROD 0x805c
+#define ETHERTYPE_VPROD 0x805c
#endif
#ifndef ETHERTYPE_ATALK
#define ETHERTYPE_ATALK 0x809b
@@ -101,10 +101,10 @@
#define ETHERTYPE_IPV6 0x86dd
#endif
#ifndef ETHERTYPE_MPLS
-#define ETHERTYPE_MPLS 0x8847
+#define ETHERTYPE_MPLS 0x8847
#endif
#ifndef ETHERTYPE_MPLS_MULTI
-#define ETHERTYPE_MPLS_MULTI 0x8848
+#define ETHERTYPE_MPLS_MULTI 0x8848
#endif
#ifndef ETHERTYPE_PPPOED
#define ETHERTYPE_PPPOED 0x8863
@@ -116,7 +116,7 @@
#define ETHERTYPE_8021AD 0x88a8
#endif
#ifndef ETHERTYPE_LOOPBACK
-#define ETHERTYPE_LOOPBACK 0x9000
+#define ETHERTYPE_LOOPBACK 0x9000
#endif
#ifndef ETHERTYPE_8021QINQ
#define ETHERTYPE_8021QINQ 0x9100
diff --git a/extract.h b/extract.h
index aa3ff991..e776a9eb 100644
--- a/extract.h
+++ b/extract.h
@@ -25,15 +25,94 @@
#include <pcap/pcap-inttypes.h>
#include <pcap/compiler-tests.h>
+#include "portability.h"
/*
- * Macros to extract possibly-unaligned big-endian integral values.
+ * If we have versions of GCC or Clang that support an __attribute__
+ * to say "if we're building with unsigned behavior sanitization,
+ * don't complain about undefined behavior in this function", we
+ * label these functions with that attribute - we *know* it's undefined
+ * in the C standard, but we *also* know it does what we want with
+ * the ISA we're targeting and the compiler we're using.
+ *
+ * For GCC 4.9.0 and later, we use __attribute__((no_sanitize_undefined));
+ * pre-5.0 GCC doesn't have __has_attribute, and I'm not sure whether
+ * GCC or Clang first had __attribute__((no_sanitize(XXX)).
+ *
+ * For Clang, we check for __attribute__((no_sanitize(XXX)) with
+ * __has_attribute, as there are versions of Clang that support
+ * __attribute__((no_sanitize("undefined")) but don't support
+ * __attribute__((no_sanitize_undefined)).
+ *
+ * We define this here, rather than in funcattrs.h, because we
+ * only want it used here, we don't want it to be broadly used.
+ * (Any printer will get this defined, but this should at least
+ * make it harder for people to find.)
*/
-#ifdef LBL_ALIGN
+#if defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 409)
+#define UNALIGNED_OK __attribute__((no_sanitize_undefined))
+#elif __has_attribute(no_sanitize)
+#define UNALIGNED_OK __attribute__((no_sanitize("undefined")))
+#else
+#define UNALIGNED_OK
+#endif
+
+#if (defined(__i386__) || defined(_M_IX86) || defined(__X86__) || defined(__x86_64__) || defined(_M_X64)) || \
+ (defined(__m68k__) && (!defined(__mc68000__) && !defined(__mc68010__))) || \
+ (defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PPC64)) || \
+ (defined(__s390__) || defined(__s390x__) || defined(__zarch__))
/*
- * The processor doesn't natively handle unaligned loads.
+ * The processor natively handles unaligned loads, so we can just
+ * cast the pointer and fetch through it.
+ *
+ * XXX - are those all the x86 tests we need?
+ * XXX - are those the only 68k tests we need not to generated
+ * unaligned accesses if the target is the 68000 or 68010?
+ * XXX - are there any tests we don't need, because some definitions are for
+ * compilers that also predefine the GCC symbols?
+ * XXX - do we need to test for both 32-bit and 64-bit versions of those
+ * architectures in all cases?
*/
-#if PCAP_IS_AT_LEAST_GNUC_VERSION(2,0) && \
+UNALIGNED_OK static inline uint16_t
+EXTRACT_BE_U_2(const void *p)
+{
+ return ((uint16_t)ntohs(*(const uint16_t *)(p)));
+}
+
+UNALIGNED_OK static inline int16_t
+EXTRACT_BE_S_2(const void *p)
+{
+ return ((int16_t)ntohs(*(const int16_t *)(p)));
+}
+
+UNALIGNED_OK static inline uint32_t
+EXTRACT_BE_U_4(const void *p)
+{
+ return ((uint32_t)ntohl(*(const uint32_t *)(p)));
+}
+
+UNALIGNED_OK static inline int32_t
+EXTRACT_BE_S_4(const void *p)
+{
+ return ((int32_t)ntohl(*(const int32_t *)(p)));
+}
+
+UNALIGNED_OK static inline uint64_t
+EXTRACT_BE_U_8(const void *p)
+{
+ return ((uint64_t)(((uint64_t)ntohl(*((const uint32_t *)(p) + 0))) << 32 |
+ ((uint64_t)ntohl(*((const uint32_t *)(p) + 1))) << 0));
+
+}
+
+UNALIGNED_OK static inline int64_t
+EXTRACT_BE_S_8(const void *p)
+{
+ return ((int64_t)(((int64_t)ntohl(*((const uint32_t *)(p) + 0))) << 32 |
+ ((uint64_t)ntohl(*((const uint32_t *)(p) + 1))) << 0));
+
+}
+#elif PCAP_IS_AT_LEAST_GNUC_VERSION(2,0) && \
(defined(__alpha) || defined(__alpha__) || \
defined(__mips) || defined(__mips__))
/*
@@ -52,7 +131,7 @@
*
* We do this in case the compiler can generate code using those
* instructions to do an unaligned load and pass stuff to "ntohs()" or
- * "ntohl()", which might be better than than the code to fetch the
+ * "ntohl()", which might be better than the code to fetch the
* bytes one at a time and assemble them. (That might not be the
* case on a little-endian platform, such as DEC's MIPS machines and
* Alpha machines, where "ntohs()" and "ntohl()" might not be done
@@ -93,45 +172,90 @@ typedef struct {
} __attribute__((packed)) unaligned_uint16_t;
typedef struct {
+ int16_t val;
+} __attribute__((packed)) unaligned_int16_t;
+
+typedef struct {
uint32_t val;
} __attribute__((packed)) unaligned_uint32_t;
-static inline uint16_t
-EXTRACT_16BITS(const void *p)
+typedef struct {
+ int32_t val;
+} __attribute__((packed)) unaligned_int32_t;
+
+UNALIGNED_OK static inline uint16_t
+EXTRACT_BE_U_2(const void *p)
{
return ((uint16_t)ntohs(((const unaligned_uint16_t *)(p))->val));
}
-static inline uint32_t
-EXTRACT_32BITS(const void *p)
+UNALIGNED_OK static inline int16_t
+EXTRACT_BE_S_2(const void *p)
+{
+ return ((int16_t)ntohs(((const unaligned_int16_t *)(p))->val));
+}
+
+UNALIGNED_OK static inline uint32_t
+EXTRACT_BE_U_4(const void *p)
{
return ((uint32_t)ntohl(((const unaligned_uint32_t *)(p))->val));
}
-static inline uint64_t
-EXTRACT_64BITS(const void *p)
+UNALIGNED_OK static inline int32_t
+EXTRACT_BE_S_4(const void *p)
+{
+ return ((int32_t)ntohl(((const unaligned_int32_t *)(p))->val));
+}
+
+UNALIGNED_OK static inline uint64_t
+EXTRACT_BE_U_8(const void *p)
{
- return ((uint64_t)(((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 0)->val)) << 32 | \
+ return ((uint64_t)(((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 0)->val)) << 32 |
((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 1)->val)) << 0));
}
-#else /* have to do it a byte at a time */
+UNALIGNED_OK static inline int64_t
+EXTRACT_BE_S_8(const void *p)
+{
+ return ((int64_t)(((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 0)->val)) << 32 |
+ ((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 1)->val)) << 0));
+}
+#else
/*
- * This isn't a GCC-compatible compiler, we don't have __attribute__,
+ * This architecture doesn't natively support unaligned loads, and either
+ * this isn't a GCC-compatible compiler, we don't have __attribute__,
* or we do but we don't know of any better way with this instruction
* set to do unaligned loads, so do unaligned loads of big-endian
* quantities the hard way - fetch the bytes one at a time and
* assemble them.
+ *
+ * XXX - ARM is a special case. ARMv1 through ARMv5 didn't suppory
+ * unaligned loads; ARMv6 and later support it *but* have a bit in
+ * the system control register that the OS can set and that causes
+ * unaligned loads to fault rather than succeeding.
+ *
+ * At least some OSes may set that flag, so we do *not* treat ARM
+ * as supporting unaligned loads. If your OS supports them on ARM,
+ * and you want to use them, please update the tests in the #if above
+ * to check for ARM *and* for your OS.
*/
-#define EXTRACT_16BITS(p) \
+#define EXTRACT_BE_U_2(p) \
((uint16_t)(((uint16_t)(*((const uint8_t *)(p) + 0)) << 8) | \
((uint16_t)(*((const uint8_t *)(p) + 1)) << 0)))
-#define EXTRACT_32BITS(p) \
+#define EXTRACT_BE_S_2(p) \
+ ((int16_t)(((uint16_t)(*((const uint8_t *)(p) + 0)) << 8) | \
+ ((uint16_t)(*((const uint8_t *)(p) + 1)) << 0)))
+#define EXTRACT_BE_U_4(p) \
((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 24) | \
((uint32_t)(*((const uint8_t *)(p) + 1)) << 16) | \
((uint32_t)(*((const uint8_t *)(p) + 2)) << 8) | \
((uint32_t)(*((const uint8_t *)(p) + 3)) << 0)))
-#define EXTRACT_64BITS(p) \
+#define EXTRACT_BE_S_4(p) \
+ ((int32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 24) | \
+ ((uint32_t)(*((const uint8_t *)(p) + 1)) << 16) | \
+ ((uint32_t)(*((const uint8_t *)(p) + 2)) << 8) | \
+ ((uint32_t)(*((const uint8_t *)(p) + 3)) << 0)))
+#define EXTRACT_BE_U_8(p) \
((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 56) | \
((uint64_t)(*((const uint8_t *)(p) + 1)) << 48) | \
((uint64_t)(*((const uint8_t *)(p) + 2)) << 40) | \
@@ -140,47 +264,67 @@ EXTRACT_64BITS(const void *p)
((uint64_t)(*((const uint8_t *)(p) + 5)) << 16) | \
((uint64_t)(*((const uint8_t *)(p) + 6)) << 8) | \
((uint64_t)(*((const uint8_t *)(p) + 7)) << 0)))
-#endif /* must special-case unaligned accesses */
-#else /* LBL_ALIGN */
+#define EXTRACT_BE_S_8(p) \
+ ((int64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 56) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 1)) << 48) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 2)) << 40) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 3)) << 32) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 4)) << 24) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 5)) << 16) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 6)) << 8) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 7)) << 0)))
+
/*
- * The processor natively handles unaligned loads, so we can just
- * cast the pointer and fetch through it.
+ * Extract an IPv4 address, which is in network byte order, and not
+ * necessarily aligned, and provide the result in host byte order.
*/
-static inline uint16_t
-EXTRACT_16BITS(const void *p)
-{
- return ((uint16_t)ntohs(*(const uint16_t *)(p)));
-}
-
-static inline uint32_t
-EXTRACT_32BITS(const void *p)
-{
- return ((uint32_t)ntohl(*(const uint32_t *)(p)));
-}
-
-static inline uint64_t
-EXTRACT_64BITS(const void *p)
-{
- return ((uint64_t)(((uint64_t)ntohl(*((const uint32_t *)(p) + 0))) << 32 | \
- ((uint64_t)ntohl(*((const uint32_t *)(p) + 1))) << 0));
-
-}
-
-#endif /* LBL_ALIGN */
+#define EXTRACT_IPV4_TO_HOST_ORDER(p) \
+ ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 24) | \
+ ((uint32_t)(*((const uint8_t *)(p) + 1)) << 16) | \
+ ((uint32_t)(*((const uint8_t *)(p) + 2)) << 8) | \
+ ((uint32_t)(*((const uint8_t *)(p) + 3)) << 0)))
+#endif /* unaligned access checks */
-#define EXTRACT_24BITS(p) \
+/*
+ * Non-power-of-2 sizes.
+ */
+#define EXTRACT_BE_U_3(p) \
((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 16) | \
((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
((uint32_t)(*((const uint8_t *)(p) + 2)) << 0)))
-#define EXTRACT_40BITS(p) \
+#define EXTRACT_BE_S_3(p) \
+ (((*((const uint8_t *)(p) + 0)) & 0x80) ? \
+ ((int32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 16) | \
+ ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+ ((uint32_t)(*((const uint8_t *)(p) + 2)) << 0))) : \
+ ((int32_t)(0xFF000000U | \
+ ((uint32_t)(*((const uint8_t *)(p) + 0)) << 16) | \
+ ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+ ((uint32_t)(*((const uint8_t *)(p) + 2)) << 0))))
+
+#define EXTRACT_BE_U_5(p) \
((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 32) | \
((uint64_t)(*((const uint8_t *)(p) + 1)) << 24) | \
((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \
((uint64_t)(*((const uint8_t *)(p) + 3)) << 8) | \
((uint64_t)(*((const uint8_t *)(p) + 4)) << 0)))
-#define EXTRACT_48BITS(p) \
+#define EXTRACT_BE_S_5(p) \
+ (((*((const uint8_t *)(p) + 0)) & 0x80) ? \
+ ((int64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 32) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 1)) << 24) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 3)) << 8) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 4)) << 0))) : \
+ ((int64_t)(INT64_T_CONSTANT(0xFFFFFF0000000000U) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 0)) << 32) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 1)) << 24) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 3)) << 8) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 4)) << 0))))
+
+#define EXTRACT_BE_U_6(p) \
((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 40) | \
((uint64_t)(*((const uint8_t *)(p) + 1)) << 32) | \
((uint64_t)(*((const uint8_t *)(p) + 2)) << 24) | \
@@ -188,7 +332,23 @@ EXTRACT_64BITS(const void *p)
((uint64_t)(*((const uint8_t *)(p) + 4)) << 8) | \
((uint64_t)(*((const uint8_t *)(p) + 5)) << 0)))
-#define EXTRACT_56BITS(p) \
+#define EXTRACT_BE_S_6(p) \
+ (((*((const uint8_t *)(p) + 0)) & 0x80) ? \
+ ((int64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 40) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 1)) << 32) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 2)) << 24) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 3)) << 16) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 4)) << 8) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 5)) << 0))) : \
+ ((int64_t)(INT64_T_CONSTANT(0xFFFFFFFF00000000U) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 0)) << 40) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 1)) << 32) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 2)) << 24) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 3)) << 16) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 4)) << 8) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 5)) << 0))))
+
+#define EXTRACT_BE_U_7(p) \
((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 48) | \
((uint64_t)(*((const uint8_t *)(p) + 1)) << 40) | \
((uint64_t)(*((const uint8_t *)(p) + 2)) << 32) | \
@@ -197,24 +357,53 @@ EXTRACT_64BITS(const void *p)
((uint64_t)(*((const uint8_t *)(p) + 5)) << 8) | \
((uint64_t)(*((const uint8_t *)(p) + 6)) << 0)))
+#define EXTRACT_BE_S_7(p) \
+ (((*((const uint8_t *)(p) + 0)) & 0x80) ? \
+ ((int64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 48) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 1)) << 40) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 2)) << 32) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 4)) << 16) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 5)) << 8) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 6)) << 0))) : \
+ ((int64_t)(INT64_T_CONSTANT(0xFFFFFFFFFF000000U) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 0)) << 48) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 1)) << 40) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 2)) << 32) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 4)) << 16) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 5)) << 8) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 6)) << 0))))
+
/*
* Macros to extract possibly-unaligned little-endian integral values.
* XXX - do loads on little-endian machines that support unaligned loads?
*/
-#define EXTRACT_LE_8BITS(p) (*(p))
-#define EXTRACT_LE_16BITS(p) \
+#define EXTRACT_LE_U_2(p) \
((uint16_t)(((uint16_t)(*((const uint8_t *)(p) + 1)) << 8) | \
((uint16_t)(*((const uint8_t *)(p) + 0)) << 0)))
-#define EXTRACT_LE_32BITS(p) \
+#define EXTRACT_LE_S_2(p) \
+ ((int16_t)(((uint16_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+ ((uint16_t)(*((const uint8_t *)(p) + 0)) << 0)))
+#define EXTRACT_LE_U_4(p) \
((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 3)) << 24) | \
((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \
((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
((uint32_t)(*((const uint8_t *)(p) + 0)) << 0)))
-#define EXTRACT_LE_24BITS(p) \
+#define EXTRACT_LE_S_4(p) \
+ ((int32_t)(((uint32_t)(*((const uint8_t *)(p) + 3)) << 24) | \
+ ((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+ ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+ ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0)))
+#define EXTRACT_LE_U_3(p) \
((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \
((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
((uint32_t)(*((const uint8_t *)(p) + 0)) << 0)))
-#define EXTRACT_LE_64BITS(p) \
+#define EXTRACT_LE_S_3(p) \
+ ((int32_t)(((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+ ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+ ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0)))
+#define EXTRACT_LE_U_8(p) \
((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 7)) << 56) | \
((uint64_t)(*((const uint8_t *)(p) + 6)) << 48) | \
((uint64_t)(*((const uint8_t *)(p) + 5)) << 40) | \
@@ -223,3 +412,12 @@ EXTRACT_64BITS(const void *p)
((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \
((uint64_t)(*((const uint8_t *)(p) + 1)) << 8) | \
((uint64_t)(*((const uint8_t *)(p) + 0)) << 0)))
+#define EXTRACT_LE_S_8(p) \
+ ((int64_t)(((uint64_t)(*((const uint8_t *)(p) + 7)) << 56) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 6)) << 48) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 5)) << 40) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 4)) << 32) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+ ((uint64_t)(*((const uint8_t *)(p) + 0)) << 0)))
diff --git a/fad-getad.c b/fad-getad.c
index 5236fbb9..ba8f9753 100644
--- a/fad-getad.c
+++ b/fad-getad.c
@@ -42,7 +42,6 @@
#include <net/if.h>
-#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
@@ -190,7 +189,7 @@ pcap_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf,
* We have a ":"; is it followed by a number?
*/
q = p + 1;
- while (isdigit((unsigned char)*q))
+ while (PCAP_ISDIGIT(*q))
q++;
if (*q == '\0') {
/*
diff --git a/fad-gifc.c b/fad-gifc.c
index 6b161274..8940876a 100644
--- a/fad-gifc.c
+++ b/fad-gifc.c
@@ -49,19 +49,13 @@ struct rtentry; /* declarations in <net/if.h> */
#include <net/if.h>
#include <netinet/in.h>
-#include <ctype.h>
#include <errno.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-
-#ifdef HAVE_LIMITS_H
#include <limits.h>
-#else
-#define INT_MAX 2147483647
-#endif
#include "pcap-int.h"
@@ -178,7 +172,7 @@ pcap_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf,
* Don't let the buffer size get bigger than INT_MAX.
*/
if (buf_size > INT_MAX) {
- (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"interface information requires more than %u bytes",
INT_MAX);
(void)close(fd);
@@ -399,7 +393,7 @@ pcap_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf,
* We have a ":"; is it followed by a number?
*/
q = p + 1;
- while (isdigit((unsigned char)*q))
+ while (PCAP_ISDIGIT(*q))
q++;
if (*q == '\0') {
/*
diff --git a/fad-glifc.c b/fad-glifc.c
index f22f56d7..6b275eb3 100644
--- a/fad-glifc.c
+++ b/fad-glifc.c
@@ -50,7 +50,6 @@ struct rtentry; /* declarations in <net/if.h> */
#include <net/if.h>
#include <netinet/in.h>
-#include <ctype.h>
#include <errno.h>
#include <memory.h>
#include <stdio.h>
@@ -311,7 +310,7 @@ pcap_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf,
* We have a ":"; is it followed by a number?
*/
q = p + 1;
- while (isdigit((unsigned char)*q))
+ while (PCAP_ISDIGIT(*q))
q++;
if (*q == '\0') {
/*
diff --git a/fmtutils.c b/fmtutils.c
index 091e0d35..5c7ddadf 100644
--- a/fmtutils.c
+++ b/fmtutils.c
@@ -47,12 +47,220 @@
#include <string.h>
#include <errno.h>
-#include <pcap/pcap.h>
+#include "pcap-int.h"
#include "portability.h"
#include "fmtutils.h"
+#ifdef _WIN32
+#include "charconv.h"
+#endif
+
+/*
+ * Set the encoding.
+ */
+#ifdef _WIN32
+/*
+ * True if we shouold use UTF-8.
+ */
+static int use_utf_8;
+
+void
+pcap_fmt_set_encoding(unsigned int opts)
+{
+ if (opts == PCAP_CHAR_ENC_UTF_8)
+ use_utf_8 = 1;
+}
+#else
+void
+pcap_fmt_set_encoding(unsigned int opts _U_)
+{
+ /*
+ * Nothing to do here.
+ */
+}
+#endif
+
+#ifdef _WIN32
+/*
+ * Convert a null-terminated UTF-16LE string to UTF-8, putting it into
+ * a buffer starting at the specified location and stopping if we go
+ * past the specified size. This will only put out complete UTF-8
+ * sequences.
+ *
+ * We do this ourselves because Microsoft doesn't offer a "convert and
+ * stop at a UTF-8 character boundary if we run out of space" routine.
+ */
+#define IS_LEADING_SURROGATE(c) \
+ ((c) >= 0xd800 && (c) < 0xdc00)
+#define IS_TRAILING_SURROGATE(c) \
+ ((c) >= 0xdc00 && (c) < 0xe000)
+#define SURROGATE_VALUE(leading, trailing) \
+ (((((leading) - 0xd800) << 10) | ((trailing) - 0xdc00)) + 0x10000)
+#define REPLACEMENT_CHARACTER 0x0FFFD
+
+static char *
+utf_16le_to_utf_8_truncated(const wchar_t *utf_16, char *utf_8,
+ size_t utf_8_len)
+{
+ wchar_t c, c2;
+ uint32_t uc;
+
+ if (utf_8_len == 0) {
+ /*
+ * Not even enough room for a trailing '\0'.
+ * Don't put anything into the buffer.
+ */
+ return (utf_8);
+ }
+
+ while ((c = *utf_16++) != '\0') {
+ if (IS_LEADING_SURROGATE(c)) {
+ /*
+ * Leading surrogate. Must be followed by
+ * a trailing surrogate.
+ */
+ c2 = *utf_16;
+ if (c2 == '\0') {
+ /*
+ * Oops, string ends with a lead
+ * surrogate. Try to drop in
+ * a REPLACEMENT CHARACTER, and
+ * don't move the string pointer,
+ * so on the next trip through
+ * the loop we grab the terminating
+ * '\0' and quit.
+ */
+ uc = REPLACEMENT_CHARACTER;
+ } else {
+ /*
+ * OK, we can consume this 2-octet
+ * value.
+ */
+ utf_16++;
+ if (IS_TRAILING_SURROGATE(c2)) {
+ /*
+ * Trailing surrogate.
+ * This calculation will,
+ * for c being a leading
+ * surrogate and c2 being
+ * a trailing surrogate,
+ * produce a value between
+ * 0x100000 and 0x10ffff,
+ * so it's always going to be
+ * a valid Unicode code point.
+ */
+ uc = SURROGATE_VALUE(c, c2);
+ } else {
+ /*
+ * Not a trailing surroage;
+ * try to drop in a
+ * REPLACEMENT CHARACTER.
+ */
+ uc = REPLACEMENT_CHARACTER;
+ }
+ }
+ } else {
+ /*
+ * Not a leading surrogate.
+ */
+ if (IS_TRAILING_SURROGATE(c)) {
+ /*
+ * Trailing surrogate without
+ * a preceding leading surrogate.
+ * Try to drop in a REPLACEMENT
+ * CHARACTER.
+ */
+ uc = REPLACEMENT_CHARACTER;
+ } else {
+ /*
+ * This is a valid BMP character;
+ * drop it in.
+ */
+ uc = c;
+ }
+ }
+
+ /*
+ * OK, uc is a valid Unicode character; how
+ * many bytes worth of UTF-8 does it require?
+ */
+ if (uc < 0x0080) {
+ /* 1 byte. */
+ if (utf_8_len < 2) {
+ /*
+ * Not enough room for that byte
+ * plus a trailing '\0'.
+ */
+ break;
+ }
+ *utf_8++ = (char)uc;
+ utf_8_len--;
+ } else if (uc < 0x0800) {
+ /* 2 bytes. */
+ if (utf_8_len < 3) {
+ /*
+ * Not enough room for those bytes
+ * plus a trailing '\0'.
+ */
+ break;
+ }
+ *utf_8++ = ((uc >> 6) & 0x3F) | 0xC0;
+ *utf_8++ = ((uc >> 0) & 0x3F) | 0x80;
+ utf_8_len -= 2;
+ } else if (uc < 0x010000) {
+ /* 3 bytes. */
+ if (utf_8_len < 4) {
+ /*
+ * Not enough room for those bytes
+ * plus a trailing '\0'.
+ */
+ break;
+ }
+ *utf_8++ = ((uc >> 12) & 0x0F) | 0xE0;
+ *utf_8++ = ((uc >> 6) & 0x3F) | 0x80;
+ *utf_8++ = ((uc >> 0) & 0x3F) | 0x80;
+ utf_8_len -= 3;
+ } else {
+ /* 4 bytes. */
+ if (utf_8_len < 5) {
+ /*
+ * Not enough room for those bytes
+ * plus a trailing '\0'.
+ */
+ break;
+ }
+ *utf_8++ = ((uc >> 18) & 0x03) | 0xF0;
+ *utf_8++ = ((uc >> 12) & 0x3F) | 0x80;
+ *utf_8++ = ((uc >> 6) & 0x3F) | 0x80;
+ *utf_8++ = ((uc >> 0) & 0x3F) | 0x80;
+ utf_8_len -= 3;
+ }
+ }
+
+ /*
+ * OK, we have enough room for (at least) a trailing '\0'.
+ * (We started out with enough room, thanks to the test
+ * for a zero-length buffer at the beginning, and if
+ * there wasn't enough room for any character we wanted
+ * to put into the buffer *plus* a trailing '\0',
+ * we'd have quit before putting it into the buffer,
+ * and thus would have left enough room for the trailing
+ * '\0'.)
+ *
+ * Drop it in.
+ */
+ *utf_8 = '\0';
+
+ /*
+ * Return a pointer to the terminating '\0', in case we
+ * want to drop something in after that.
+ */
+ return (utf_8);
+}
+#endif /* _WIN32 */
+
/*
* Generate an error message based on a format, arguments, and an
* errno, with a message for the errno after the formatted output.
@@ -67,7 +275,7 @@ pcap_fmt_errmsg_for_errno(char *errbuf, size_t errbuflen, int errnum,
size_t errbuflen_remaining;
va_start(ap, fmt);
- pcap_vsnprintf(errbuf, errbuflen, fmt, ap);
+ vsnprintf(errbuf, errbuflen, fmt, ap);
va_end(ap);
msglen = strlen(errbuf);
@@ -84,24 +292,40 @@ pcap_fmt_errmsg_for_errno(char *errbuf, size_t errbuflen, int errnum,
*p++ = ':';
*p++ = ' ';
*p = '\0';
- msglen += 2;
errbuflen_remaining -= 2;
/*
* Now append the string for the error code.
*/
-#if defined(HAVE_STRERROR_S)
+#if defined(HAVE__WCSERROR_S)
/*
- * We have a Windows-style strerror_s().
+ * We have a Windows-style _wcserror_s().
+ * Generate a UTF-16LE error message.
*/
- errno_t err = strerror_s(p, errbuflen_remaining, errnum);
+ wchar_t utf_16_errbuf[PCAP_ERRBUF_SIZE];
+ errno_t err = _wcserror_s(utf_16_errbuf, PCAP_ERRBUF_SIZE, errnum);
if (err != 0) {
/*
* It doesn't appear to be documented anywhere obvious
- * what the error returns from strerror_s().
+ * what the error returns from _wcserror_s().
*/
- pcap_snprintf(p, errbuflen_remaining, "Error %d", errnum);
+ snprintf(p, errbuflen_remaining, "Error %d", errnum);
+ return;
}
+
+ /*
+ * Now convert it from UTF-16LE to UTF-8, dropping it in the
+ * remaining space in the buffer, and truncating it - cleanly,
+ * on a UTF-8 character boundary - if it doesn't fit.
+ */
+ utf_16le_to_utf_8_truncated(utf_16_errbuf, p, errbuflen_remaining);
+
+ /*
+ * Now, if we're not in UTF-8 mode, convert errbuf to the
+ * local code page.
+ */
+ if (!use_utf_8)
+ utf_8_to_acp_truncated(errbuf);
#elif defined(HAVE_GNU_STRERROR_R)
/*
* We have a GNU-style strerror_r(), which is *not* guaranteed to
@@ -113,7 +337,7 @@ pcap_fmt_errmsg_for_errno(char *errbuf, size_t errbuflen, int errnum,
*/
char strerror_buf[PCAP_ERRBUF_SIZE];
char *errstring = strerror_r(errnum, strerror_buf, PCAP_ERRBUF_SIZE);
- pcap_snprintf(p, errbuflen_remaining, "%s", errstring);
+ snprintf(p, errbuflen_remaining, "%s", errstring);
#elif defined(HAVE_POSIX_STRERROR_R)
/*
* We have a POSIX-style strerror_r(), which is guaranteed to fill
@@ -125,22 +349,22 @@ pcap_fmt_errmsg_for_errno(char *errbuf, size_t errbuflen, int errnum,
* UNIX 03 says this isn't guaranteed to produce a
* fallback error message.
*/
- pcap_snprintf(p, errbuflen_remaining, "Unknown error: %d",
+ snprintf(p, errbuflen_remaining, "Unknown error: %d",
errnum);
} else if (err == ERANGE) {
/*
* UNIX 03 says this isn't guaranteed to produce a
* fallback error message.
*/
- pcap_snprintf(p, errbuflen_remaining,
+ snprintf(p, errbuflen_remaining,
"Message for error %d is too long", errnum);
}
#else
/*
- * We have neither strerror_s() nor strerror_r(), so we're
+ * We have neither _wcserror_s() nor strerror_r(), so we're
* stuck with using pcap_strerror().
*/
- pcap_snprintf(p, errbuflen_remaining, "%s", pcap_strerror(errnum));
+ snprintf(p, errbuflen_remaining, "%s", pcap_strerror(errnum));
#endif
}
@@ -158,10 +382,11 @@ pcap_fmt_errmsg_for_win32_err(char *errbuf, size_t errbuflen, DWORD errnum,
char *p;
size_t errbuflen_remaining;
DWORD retval;
- char win32_errbuf[PCAP_ERRBUF_SIZE+1];
+ wchar_t utf_16_errbuf[PCAP_ERRBUF_SIZE];
+ size_t utf_8_len;
va_start(ap, fmt);
- pcap_vsnprintf(errbuf, errbuflen, fmt, ap);
+ vsnprintf(errbuf, errbuflen, fmt, ap);
va_end(ap);
msglen = strlen(errbuf);
@@ -197,18 +422,39 @@ pcap_fmt_errmsg_for_win32_err(char *errbuf, size_t errbuflen, DWORD errnum,
* get the message translated if it's in a language they don't
* happen to understand.
*/
- retval = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ retval = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- win32_errbuf, PCAP_ERRBUF_SIZE, NULL);
+ utf_16_errbuf, PCAP_ERRBUF_SIZE, NULL);
if (retval == 0) {
/*
* Failed.
*/
- pcap_snprintf(p, errbuflen_remaining,
+ snprintf(p, errbuflen_remaining,
"Couldn't get error message for error (%lu)", errnum);
return;
}
- pcap_snprintf(p, errbuflen_remaining, "%s (%lu)", win32_errbuf, errnum);
+ /*
+ * Now convert it from UTF-16LE to UTF-8.
+ */
+ p = utf_16le_to_utf_8_truncated(utf_16_errbuf, p, errbuflen_remaining);
+
+ /*
+ * Now append the error number, if it fits.
+ */
+ utf_8_len = p - errbuf;
+ errbuflen_remaining -= utf_8_len;
+ if (utf_8_len == 0) {
+ /* The message was empty. */
+ snprintf(p, errbuflen_remaining, "(%lu)", errnum);
+ } else
+ snprintf(p, errbuflen_remaining, " (%lu)", errnum);
+
+ /*
+ * Now, if we're not in UTF-8 mode, convert errbuf to the
+ * local code page.
+ */
+ if (!use_utf_8)
+ utf_8_to_acp_truncated(errbuf);
}
#endif
diff --git a/fmtutils.h b/fmtutils.h
index 838948bc..ba0f66ca 100644
--- a/fmtutils.h
+++ b/fmtutils.h
@@ -40,6 +40,8 @@
extern "C" {
#endif
+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);
diff --git a/ftmacros.h b/ftmacros.h
index cd3daebd..3fafab80 100644
--- a/ftmacros.h
+++ b/ftmacros.h
@@ -83,14 +83,18 @@
* least with HP's C compiler; hopefully doing so won't make it
* *not* work with *un*-threaded code.
*/
-#elif defined(__linux__) || defined(linux) || defined(__linux)
+#else
/*
* Turn on _GNU_SOURCE to get everything GNU libc has to offer,
- * including asprintf().
+ * including asprintf(), if we're using GNU libc.
*
* Unfortunately, one thing it has to offer is a strerror_r()
* that's not POSIX-compliant, but we deal with that in
* pcap_fmt_errmsg_for_errno().
+ *
+ * We don't limit this to, for example, Linux and Cygwin, because
+ * this might, for example, be GNU/HURD or one of Debian's kFreeBSD
+ * OSes ("GNU/FreeBSD").
*/
#define _GNU_SOURCE
diff --git a/gencode.c b/gencode.c
index e3425cd9..29788598 100644
--- a/gencode.c
+++ b/gencode.c
@@ -67,7 +67,7 @@
#include "grammar.h"
#include "scanner.h"
-#if defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER)
+#if defined(linux)
#include <linux/types.h>
#include <linux/if_packet.h>
#include <linux/filter.h>
@@ -139,10 +139,6 @@ struct addrinfo {
#define ETHERMTU 1500
-#ifndef ETHERTYPE_TEB
-#define ETHERTYPE_TEB 0x6558
-#endif
-
#ifndef IPPROTO_HOPOPTS
#define IPPROTO_HOPOPTS 0
#endif
@@ -248,6 +244,7 @@ struct chunk {
struct _compiler_state {
jmp_buf top_ctx;
pcap_t *bpf_pcap;
+ int error_set;
struct icode ic;
@@ -435,10 +432,22 @@ bpf_set_error(compiler_state_t *cstate, const char *fmt, ...)
{
va_list ap;
- va_start(ap, fmt);
- (void)pcap_vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE,
- fmt, ap);
- va_end(ap);
+ /*
+ * If we've already set an error, don't override it.
+ * The lexical analyzer reports some errors by setting
+ * the error and then returning a LEX_ERROR token, which
+ * is not recognized by any grammar rule, and thus forces
+ * the parse to stop. We don't want the error reported
+ * by the lexical analyzer to be overwritten by the syntax
+ * error.
+ */
+ if (!cstate->error_set) {
+ va_start(ap, fmt);
+ (void)vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE,
+ fmt, ap);
+ va_end(ap);
+ cstate->error_set = 1;
+ }
}
/*
@@ -454,7 +463,7 @@ bpf_error(compiler_state_t *cstate, const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- (void)pcap_vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE,
+ (void)vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE,
fmt, ap);
va_end(ap);
longjmp(cstate->top_ctx, 1);
@@ -479,21 +488,21 @@ static inline void syntax(compiler_state_t *cstate);
static void backpatch(struct block *, struct block *);
static void merge(struct block *, struct block *);
static struct block *gen_cmp(compiler_state_t *, enum e_offrel, u_int,
- u_int, bpf_int32);
+ u_int, bpf_u_int32);
static struct block *gen_cmp_gt(compiler_state_t *, enum e_offrel, u_int,
- u_int, bpf_int32);
+ u_int, bpf_u_int32);
static struct block *gen_cmp_ge(compiler_state_t *, enum e_offrel, u_int,
- u_int, bpf_int32);
+ u_int, bpf_u_int32);
static struct block *gen_cmp_lt(compiler_state_t *, enum e_offrel, u_int,
- u_int, bpf_int32);
+ u_int, bpf_u_int32);
static struct block *gen_cmp_le(compiler_state_t *, enum e_offrel, u_int,
- u_int, bpf_int32);
+ u_int, bpf_u_int32);
static struct block *gen_mcmp(compiler_state_t *, enum e_offrel, u_int,
- u_int, bpf_int32, bpf_u_int32);
+ u_int, bpf_u_int32, bpf_u_int32);
static struct block *gen_bcmp(compiler_state_t *, enum e_offrel, u_int,
u_int, const u_char *);
-static struct block *gen_ncmp(compiler_state_t *, enum e_offrel, bpf_u_int32,
- bpf_u_int32, bpf_u_int32, bpf_u_int32, int, bpf_int32);
+static struct block *gen_ncmp(compiler_state_t *, enum e_offrel, u_int,
+ u_int, bpf_u_int32, int, int, bpf_u_int32);
static struct slist *gen_load_absoffsetrel(compiler_state_t *, bpf_abs_offset *,
u_int, u_int);
static struct slist *gen_load_a(compiler_state_t *, enum e_offrel, u_int,
@@ -502,9 +511,9 @@ static struct slist *gen_loadx_iphdrlen(compiler_state_t *);
static struct block *gen_uncond(compiler_state_t *, int);
static inline struct block *gen_true(compiler_state_t *);
static inline struct block *gen_false(compiler_state_t *);
-static struct block *gen_ether_linktype(compiler_state_t *, int);
-static struct block *gen_ipnet_linktype(compiler_state_t *, int);
-static struct block *gen_linux_sll_linktype(compiler_state_t *, int);
+static struct block *gen_ether_linktype(compiler_state_t *, bpf_u_int32);
+static struct block *gen_ipnet_linktype(compiler_state_t *, bpf_u_int32);
+static struct block *gen_linux_sll_linktype(compiler_state_t *, bpf_u_int32);
static struct slist *gen_load_prism_llprefixlen(compiler_state_t *);
static struct slist *gen_load_avs_llprefixlen(compiler_state_t *);
static struct slist *gen_load_radiotap_llprefixlen(compiler_state_t *);
@@ -512,15 +521,15 @@ static struct slist *gen_load_ppi_llprefixlen(compiler_state_t *);
static void insert_compute_vloffsets(compiler_state_t *, struct block *);
static struct slist *gen_abs_offset_varpart(compiler_state_t *,
bpf_abs_offset *);
-static int ethertype_to_ppptype(int);
-static struct block *gen_linktype(compiler_state_t *, int);
+static bpf_u_int32 ethertype_to_ppptype(bpf_u_int32);
+static struct block *gen_linktype(compiler_state_t *, bpf_u_int32);
static struct block *gen_snap(compiler_state_t *, bpf_u_int32, bpf_u_int32);
-static struct block *gen_llc_linktype(compiler_state_t *, int);
+static struct block *gen_llc_linktype(compiler_state_t *, bpf_u_int32);
static struct block *gen_hostop(compiler_state_t *, bpf_u_int32, bpf_u_int32,
- int, int, u_int, u_int);
+ int, bpf_u_int32, u_int, u_int);
#ifdef INET6
static struct block *gen_hostop6(compiler_state_t *, struct in6_addr *,
- struct in6_addr *, int, int, u_int, u_int);
+ struct in6_addr *, int, bpf_u_int32, u_int, u_int);
#endif
static struct block *gen_ahostop(compiler_state_t *, const u_char *, int);
static struct block *gen_ehostop(compiler_state_t *, const u_char *, int);
@@ -529,7 +538,7 @@ static struct block *gen_thostop(compiler_state_t *, const u_char *, int);
static struct block *gen_wlanhostop(compiler_state_t *, const u_char *, int);
static struct block *gen_ipfchostop(compiler_state_t *, const u_char *, int);
static struct block *gen_dnhostop(compiler_state_t *, bpf_u_int32, int);
-static struct block *gen_mpls_linktype(compiler_state_t *, int);
+static struct block *gen_mpls_linktype(compiler_state_t *, bpf_u_int32);
static struct block *gen_host(compiler_state_t *, bpf_u_int32, bpf_u_int32,
int, int, int);
#ifdef INET6
@@ -541,23 +550,25 @@ static struct block *gen_gateway(compiler_state_t *, const u_char *,
struct addrinfo *, int, int);
#endif
static struct block *gen_ipfrag(compiler_state_t *);
-static struct block *gen_portatom(compiler_state_t *, int, bpf_int32);
-static struct block *gen_portrangeatom(compiler_state_t *, int, bpf_int32,
- bpf_int32);
-static struct block *gen_portatom6(compiler_state_t *, int, bpf_int32);
-static struct block *gen_portrangeatom6(compiler_state_t *, int, bpf_int32,
- bpf_int32);
-struct block *gen_portop(compiler_state_t *, int, int, int);
-static struct block *gen_port(compiler_state_t *, int, int, int);
-struct block *gen_portrangeop(compiler_state_t *, int, int, int, int);
-static struct block *gen_portrange(compiler_state_t *, int, int, int, int);
-struct block *gen_portop6(compiler_state_t *, int, int, int);
-static struct block *gen_port6(compiler_state_t *, int, int, int);
-struct block *gen_portrangeop6(compiler_state_t *, int, int, int, int);
-static struct block *gen_portrange6(compiler_state_t *, int, int, int, int);
+static struct block *gen_portatom(compiler_state_t *, int, bpf_u_int32);
+static struct block *gen_portrangeatom(compiler_state_t *, u_int, bpf_u_int32,
+ bpf_u_int32);
+static struct block *gen_portatom6(compiler_state_t *, int, bpf_u_int32);
+static struct block *gen_portrangeatom6(compiler_state_t *, u_int, bpf_u_int32,
+ bpf_u_int32);
+static struct block *gen_portop(compiler_state_t *, u_int, u_int, int);
+static struct block *gen_port(compiler_state_t *, u_int, int, int);
+static struct block *gen_portrangeop(compiler_state_t *, u_int, u_int,
+ bpf_u_int32, int);
+static struct block *gen_portrange(compiler_state_t *, u_int, u_int, int, int);
+struct block *gen_portop6(compiler_state_t *, u_int, u_int, int);
+static struct block *gen_port6(compiler_state_t *, u_int, int, int);
+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);
-static struct block *gen_protochain(compiler_state_t *, int, int, int);
-static struct block *gen_proto(compiler_state_t *, int, int, int);
+static struct block *gen_protochain(compiler_state_t *, bpf_u_int32, int);
+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 *);
static struct block *gen_mac_multicast(compiler_state_t *, int);
@@ -567,7 +578,7 @@ static struct block *gen_geneve_ll_check(compiler_state_t *cstate);
static struct block *gen_ppi_dlt_check(compiler_state_t *);
static struct block *gen_atmfield_code_internal(compiler_state_t *, int,
- bpf_int32, bpf_u_int32, int);
+ bpf_u_int32, int, int);
static struct block *gen_atmtype_llc(compiler_state_t *);
static struct block *gen_msg_abbrev(compiler_state_t *, int type);
@@ -721,7 +732,7 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
* link-layer type, so we can't use it.
*/
if (!p->activated) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"not-yet-activated pcap_t passed to pcap_compile");
return (-1);
}
@@ -762,13 +773,14 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
cstate.ic.root = NULL;
cstate.ic.cur_mark = 0;
cstate.bpf_pcap = p;
+ cstate.error_set = 0;
init_regs(&cstate);
cstate.netmask = mask;
cstate.snaplen = pcap_snapshot(p);
if (cstate.snaplen == 0) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"snaplen of 0 rejects all packets");
rc = -1;
goto quit;
@@ -819,7 +831,7 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
}
if (cstate.ic.root == NULL ||
(cstate.ic.root->s.code == (BPF_RET|BPF_K) && cstate.ic.root->s.k == 0)) {
- (void)pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"expression rejects all packets");
rc = -1;
goto quit;
@@ -1013,42 +1025,42 @@ gen_not(struct block *b)
static struct block *
gen_cmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
- u_int size, bpf_int32 v)
+ u_int size, bpf_u_int32 v)
{
return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JEQ, 0, v);
}
static struct block *
gen_cmp_gt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
- u_int size, bpf_int32 v)
+ u_int size, bpf_u_int32 v)
{
return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 0, v);
}
static struct block *
gen_cmp_ge(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
- u_int size, bpf_int32 v)
+ u_int size, bpf_u_int32 v)
{
return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 0, v);
}
static struct block *
gen_cmp_lt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
- u_int size, bpf_int32 v)
+ u_int size, bpf_u_int32 v)
{
return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 1, v);
}
static struct block *
gen_cmp_le(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
- u_int size, bpf_int32 v)
+ u_int size, bpf_u_int32 v)
{
return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 1, v);
}
static struct block *
gen_mcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
- u_int size, bpf_int32 v, bpf_u_int32 mask)
+ u_int size, bpf_u_int32 v, bpf_u_int32 mask)
{
return gen_ncmp(cstate, offrel, offset, size, mask, BPF_JEQ, 0, v);
}
@@ -1059,22 +1071,12 @@ gen_bcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
{
register struct block *b, *tmp;
- /*
- * XXX - the actual *instructions* do unsigned comparisons on
- * most platforms, and the load instructions don't do sign
- * extension, so gen_cmp() should really take an unsigned
- * value argument.
- *
- * As the load instructons also don't do sign-extension, we
- * fetch the values from the byte array as unsigned. We don't
- * want to use the signed versions of the extract calls.
- */
b = NULL;
while (size >= 4) {
register const u_char *p = &v[size - 4];
tmp = gen_cmp(cstate, offrel, offset + size - 4, BPF_W,
- (bpf_int32)EXTRACT_32BITS(p));
+ EXTRACT_BE_U_4(p));
if (b != NULL)
gen_and(b, tmp);
b = tmp;
@@ -1084,14 +1086,14 @@ gen_bcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
register const u_char *p = &v[size - 2];
tmp = gen_cmp(cstate, offrel, offset + size - 2, BPF_H,
- (bpf_int32)EXTRACT_16BITS(p));
+ EXTRACT_BE_U_2(p));
if (b != NULL)
gen_and(b, tmp);
b = tmp;
size -= 2;
}
if (size > 0) {
- tmp = gen_cmp(cstate, offrel, offset, BPF_B, (bpf_int32)v[0]);
+ tmp = gen_cmp(cstate, offrel, offset, BPF_B, v[0]);
if (b != NULL)
gen_and(b, tmp);
b = tmp;
@@ -1106,9 +1108,9 @@ gen_bcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
* should test the opposite of "jtype".
*/
static struct block *
-gen_ncmp(compiler_state_t *cstate, enum e_offrel offrel, bpf_u_int32 offset,
- bpf_u_int32 size, bpf_u_int32 mask, bpf_u_int32 jtype, int reverse,
- bpf_int32 v)
+gen_ncmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset,
+ u_int size, bpf_u_int32 mask, int jtype, int reverse,
+ bpf_u_int32 v)
{
struct slist *s, *s2;
struct block *b;
@@ -1956,11 +1958,11 @@ gen_false(compiler_state_t *cstate)
* the appropriate test.
*/
static struct block *
-gen_ether_linktype(compiler_state_t *cstate, int proto)
+gen_ether_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
{
struct block *b0, *b1;
- switch (proto) {
+ switch (ll_proto) {
case LLCSAP_ISONS:
case LLCSAP_IP:
@@ -1979,8 +1981,7 @@ gen_ether_linktype(compiler_state_t *cstate, int proto)
*/
b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
gen_not(b0);
- b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_int32)
- ((proto << 8) | proto));
+ b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (ll_proto << 8) | ll_proto);
gen_and(b0, b1);
return b1;
@@ -2017,8 +2018,8 @@ gen_ether_linktype(compiler_state_t *cstate, int proto)
* This generates code to check both for the
* IPX LSAP (Ethernet_802.2) and for Ethernet_802.3.
*/
- b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, (bpf_int32)LLCSAP_IPX);
- b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_int32)0xFFFF);
+ b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX);
+ b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, 0xFFFF);
gen_or(b0, b1);
/*
@@ -2048,7 +2049,7 @@ gen_ether_linktype(compiler_state_t *cstate, int proto)
* do that before checking for the other frame
* types.
*/
- b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)ETHERTYPE_IPX);
+ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ETHERTYPE_IPX);
gen_or(b0, b1);
return b1;
@@ -2078,9 +2079,9 @@ gen_ether_linktype(compiler_state_t *cstate, int proto)
* 0x000000 (encapsulated Ethernet) and a protocol
* type of ETHERTYPE_AARP (Appletalk ARP).
*/
- if (proto == ETHERTYPE_ATALK)
+ if (ll_proto == ETHERTYPE_ATALK)
b1 = gen_snap(cstate, 0x080007, ETHERTYPE_ATALK);
- else /* proto == ETHERTYPE_AARP */
+ else /* ll_proto == ETHERTYPE_AARP */
b1 = gen_snap(cstate, 0x000000, ETHERTYPE_AARP);
gen_and(b0, b1);
@@ -2089,13 +2090,13 @@ gen_ether_linktype(compiler_state_t *cstate, int proto)
* phase 1?); we just check for the Ethernet
* protocol type.
*/
- b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
+ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
gen_or(b0, b1);
return b1;
default:
- if (proto <= ETHERMTU) {
+ if (ll_proto <= ETHERMTU) {
/*
* This is an LLC SAP value, so the frames
* that match would be 802.2 frames.
@@ -2106,7 +2107,7 @@ gen_ether_linktype(compiler_state_t *cstate, int proto)
*/
b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU);
gen_not(b0);
- b1 = gen_cmp(cstate, OR_LINKTYPE, 2, BPF_B, (bpf_int32)proto);
+ b1 = gen_cmp(cstate, OR_LINKTYPE, 2, BPF_B, ll_proto);
gen_and(b0, b1);
return b1;
} else {
@@ -2115,18 +2116,17 @@ gen_ether_linktype(compiler_state_t *cstate, int proto)
* the length/type field with it (if
* the frame is an 802.2 frame, the length
* field will be <= ETHERMTU, and, as
- * "proto" is > ETHERMTU, this test
+ * "ll_proto" is > ETHERMTU, this test
* will fail and the frame won't match,
* which is what we want).
*/
- return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H,
- (bpf_int32)proto);
+ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
}
}
}
static struct block *
-gen_loopback_linktype(compiler_state_t *cstate, int proto)
+gen_loopback_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
{
/*
* For DLT_NULL, the link-layer header is a 32-bit word
@@ -2154,10 +2154,10 @@ gen_loopback_linktype(compiler_state_t *cstate, int proto)
* code to compare against the result.
*/
if (cstate->bpf_pcap->rfile != NULL && cstate->bpf_pcap->swapped)
- proto = SWAPLONG(proto);
- proto = htonl(proto);
+ ll_proto = SWAPLONG(ll_proto);
+ ll_proto = htonl(ll_proto);
}
- return (gen_cmp(cstate, OR_LINKHDR, 0, BPF_W, (bpf_int32)proto));
+ return (gen_cmp(cstate, OR_LINKHDR, 0, BPF_W, ll_proto));
}
/*
@@ -2165,17 +2165,16 @@ gen_loopback_linktype(compiler_state_t *cstate, int proto)
* or IPv6 then we have an error.
*/
static struct block *
-gen_ipnet_linktype(compiler_state_t *cstate, int proto)
+gen_ipnet_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
{
- switch (proto) {
+ switch (ll_proto) {
case ETHERTYPE_IP:
- return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, (bpf_int32)IPH_AF_INET);
+ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, IPH_AF_INET);
/*NOTREACHED*/
case ETHERTYPE_IPV6:
- return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
- (bpf_int32)IPH_AF_INET6);
+ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, IPH_AF_INET6);
/*NOTREACHED*/
default:
@@ -2188,17 +2187,17 @@ gen_ipnet_linktype(compiler_state_t *cstate, int proto)
/*
* Generate code to match a particular packet type.
*
- * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP
+ * "ll_proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP
* value, if <= ETHERMTU. We use that to determine whether to
* match the type field or to check the type field for the special
* LINUX_SLL_P_802_2 value and then do the appropriate test.
*/
static struct block *
-gen_linux_sll_linktype(compiler_state_t *cstate, int proto)
+gen_linux_sll_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
{
struct block *b0, *b1;
- switch (proto) {
+ switch (ll_proto) {
case LLCSAP_ISONS:
case LLCSAP_IP:
@@ -2216,8 +2215,7 @@ gen_linux_sll_linktype(compiler_state_t *cstate, int proto)
* (i.e., other SAP values)?
*/
b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
- b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_int32)
- ((proto << 8) | proto));
+ b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (ll_proto << 8) | ll_proto);
gen_and(b0, b1);
return b1;
@@ -2247,7 +2245,7 @@ gen_linux_sll_linktype(compiler_state_t *cstate, int proto)
* then put a check for LINUX_SLL_P_802_2 frames
* before it.
*/
- b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, (bpf_int32)LLCSAP_IPX);
+ b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX);
b1 = gen_snap(cstate, 0x000000, ETHERTYPE_IPX);
gen_or(b0, b1);
b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
@@ -2265,7 +2263,7 @@ gen_linux_sll_linktype(compiler_state_t *cstate, int proto)
* do that before checking for the other frame
* types.
*/
- b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)ETHERTYPE_IPX);
+ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ETHERTYPE_IPX);
gen_or(b0, b1);
return b1;
@@ -2294,9 +2292,9 @@ gen_linux_sll_linktype(compiler_state_t *cstate, int proto)
* 0x000000 (encapsulated Ethernet) and a protocol
* type of ETHERTYPE_AARP (Appletalk ARP).
*/
- if (proto == ETHERTYPE_ATALK)
+ if (ll_proto == ETHERTYPE_ATALK)
b1 = gen_snap(cstate, 0x080007, ETHERTYPE_ATALK);
- else /* proto == ETHERTYPE_AARP */
+ else /* ll_proto == ETHERTYPE_AARP */
b1 = gen_snap(cstate, 0x000000, ETHERTYPE_AARP);
gen_and(b0, b1);
@@ -2305,13 +2303,13 @@ gen_linux_sll_linktype(compiler_state_t *cstate, int proto)
* phase 1?); we just check for the Ethernet
* protocol type.
*/
- b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
+ b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
gen_or(b0, b1);
return b1;
default:
- if (proto <= ETHERMTU) {
+ if (ll_proto <= ETHERMTU) {
/*
* This is an LLC SAP value, so the frames
* that match would be 802.2 frames.
@@ -2321,7 +2319,7 @@ gen_linux_sll_linktype(compiler_state_t *cstate, int proto)
*/
b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2);
b1 = gen_cmp(cstate, OR_LINKHDR, cstate->off_linkpl.constant_part, BPF_B,
- (bpf_int32)proto);
+ ll_proto);
gen_and(b0, b1);
return b1;
} else {
@@ -2330,11 +2328,11 @@ gen_linux_sll_linktype(compiler_state_t *cstate, int proto)
* the length/type field with it (if
* the frame is an 802.2 frame, the length
* field will be <= ETHERMTU, and, as
- * "proto" is > ETHERMTU, this test
+ * "ll_proto" is > ETHERMTU, this test
* will fail and the frame won't match,
* which is what we want).
*/
- return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
+ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
}
}
}
@@ -2848,7 +2846,7 @@ gen_load_802_11_header_len(compiler_state_t *cstate, struct slist *s, struct sli
s2->s.k = 3;
sappend(s, s2);
s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_IMM);
- s2->s.k = ~3;
+ s2->s.k = (bpf_u_int32)~3;
sappend(s, s2);
s2 = new_stmt(cstate, BPF_ST);
s2->s.k = cstate->off_linkpl.reg;
@@ -2929,7 +2927,7 @@ insert_compute_vloffsets(compiler_state_t *cstate, struct block *b)
}
/*
- * If there there is no initialization yet and we need variable
+ * If there is no initialization yet and we need variable
* length offsets for VLAN, initialize them to zero
*/
if (s == NULL && cstate->is_vlan_vloffset) {
@@ -3035,33 +3033,33 @@ gen_abs_offset_varpart(compiler_state_t *cstate, bpf_abs_offset *off)
/*
* Map an Ethernet type to the equivalent PPP type.
*/
-static int
-ethertype_to_ppptype(int proto)
+static bpf_u_int32
+ethertype_to_ppptype(bpf_u_int32 ll_proto)
{
- switch (proto) {
+ switch (ll_proto) {
case ETHERTYPE_IP:
- proto = PPP_IP;
+ ll_proto = PPP_IP;
break;
case ETHERTYPE_IPV6:
- proto = PPP_IPV6;
+ ll_proto = PPP_IPV6;
break;
case ETHERTYPE_DN:
- proto = PPP_DECNET;
+ ll_proto = PPP_DECNET;
break;
case ETHERTYPE_ATALK:
- proto = PPP_APPLE;
+ ll_proto = PPP_APPLE;
break;
case ETHERTYPE_NS:
- proto = PPP_NS;
+ ll_proto = PPP_NS;
break;
case LLCSAP_ISONS:
- proto = PPP_OSI;
+ ll_proto = PPP_OSI;
break;
case LLCSAP_8021D:
@@ -3070,14 +3068,14 @@ ethertype_to_ppptype(int proto)
* over PPP are Spanning Tree Protocol
* Bridging PDUs.
*/
- proto = PPP_BRPDU;
+ ll_proto = PPP_BRPDU;
break;
case LLCSAP_IPX:
- proto = PPP_IPX;
+ ll_proto = PPP_IPX;
break;
}
- return (proto);
+ return (ll_proto);
}
/*
@@ -3133,29 +3131,14 @@ gen_prevlinkhdr_check(compiler_state_t *cstate)
* value, if <= ETHERMTU.
*/
static struct block *
-gen_linktype(compiler_state_t *cstate, int proto)
+gen_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
{
struct block *b0, *b1, *b2;
const char *description;
/* are we checking MPLS-encapsulated packets? */
- if (cstate->label_stack_depth > 0) {
- switch (proto) {
- case ETHERTYPE_IP:
- case PPP_IP:
- /* FIXME add other L3 proto IDs */
- return gen_mpls_linktype(cstate, Q_IP);
-
- case ETHERTYPE_IPV6:
- case PPP_IPV6:
- /* FIXME add other L3 proto IDs */
- return gen_mpls_linktype(cstate, Q_IPV6);
-
- default:
- bpf_error(cstate, "unsupported protocol over mpls");
- /*NOTREACHED*/
- }
- }
+ if (cstate->label_stack_depth > 0)
+ return gen_mpls_linktype(cstate, ll_proto);
switch (cstate->linktype) {
@@ -3169,21 +3152,21 @@ gen_linktype(compiler_state_t *cstate, int proto)
else
b0 = NULL;
- b1 = gen_ether_linktype(cstate, proto);
+ b1 = gen_ether_linktype(cstate, ll_proto);
if (b0 != NULL)
gen_and(b0, b1);
return b1;
/*NOTREACHED*/
case DLT_C_HDLC:
- switch (proto) {
+ switch (ll_proto) {
case LLCSAP_ISONS:
- proto = (proto << 8 | LLCSAP_ISONS);
+ ll_proto = (ll_proto << 8 | LLCSAP_ISONS);
/* fall through */
default:
- return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
+ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
/*NOTREACHED*/
}
@@ -3200,7 +3183,7 @@ gen_linktype(compiler_state_t *cstate, int proto)
/*
* Now check for the specified link-layer type.
*/
- b1 = gen_llc_linktype(cstate, proto);
+ b1 = gen_llc_linktype(cstate, ll_proto);
gen_and(b0, b1);
return b1;
/*NOTREACHED*/
@@ -3209,20 +3192,20 @@ gen_linktype(compiler_state_t *cstate, int proto)
/*
* XXX - check for LLC frames.
*/
- return gen_llc_linktype(cstate, proto);
+ return gen_llc_linktype(cstate, ll_proto);
/*NOTREACHED*/
case DLT_IEEE802:
/*
* XXX - check for LLC PDUs, as per IEEE 802.5.
*/
- return gen_llc_linktype(cstate, proto);
+ return gen_llc_linktype(cstate, ll_proto);
/*NOTREACHED*/
case DLT_ATM_RFC1483:
case DLT_ATM_CLIP:
case DLT_IP_OVER_FC:
- return gen_llc_linktype(cstate, proto);
+ return gen_llc_linktype(cstate, ll_proto);
/*NOTREACHED*/
case DLT_SUNATM:
@@ -3234,13 +3217,13 @@ gen_linktype(compiler_state_t *cstate, int proto)
* Check for LLC encapsulation and then check the protocol.
*/
b0 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0);
- b1 = gen_llc_linktype(cstate, proto);
+ b1 = gen_llc_linktype(cstate, ll_proto);
gen_and(b0, b1);
return b1;
/*NOTREACHED*/
case DLT_LINUX_SLL:
- return gen_linux_sll_linktype(cstate, proto);
+ return gen_linux_sll_linktype(cstate, ll_proto);
/*NOTREACHED*/
case DLT_SLIP:
@@ -3253,7 +3236,7 @@ gen_linktype(compiler_state_t *cstate, int proto)
* XXX - for IPv4, check for a version number of 4, and,
* for IPv6, check for a version number of 6?
*/
- switch (proto) {
+ switch (ll_proto) {
case ETHERTYPE_IP:
/* Check for a version number of 4. */
@@ -3272,7 +3255,7 @@ gen_linktype(compiler_state_t *cstate, int proto)
/*
* Raw IPv4, so no type field.
*/
- if (proto == ETHERTYPE_IP)
+ if (ll_proto == ETHERTYPE_IP)
return gen_true(cstate); /* always true */
/* Checking for something other than IPv4; always false */
@@ -3283,7 +3266,7 @@ gen_linktype(compiler_state_t *cstate, int proto)
/*
* Raw IPv6, so no type field.
*/
- if (proto == ETHERTYPE_IPV6)
+ if (ll_proto == ETHERTYPE_IPV6)
return gen_true(cstate); /* always true */
/* Checking for something other than IPv6; always false */
@@ -3298,8 +3281,8 @@ gen_linktype(compiler_state_t *cstate, int proto)
* We use Ethernet protocol types inside libpcap;
* map them to the corresponding PPP protocol types.
*/
- proto = ethertype_to_ppptype(proto);
- return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
+ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H,
+ ethertype_to_ppptype(ll_proto));
/*NOTREACHED*/
case DLT_PPP_BSDOS:
@@ -3307,7 +3290,7 @@ gen_linktype(compiler_state_t *cstate, int proto)
* We use Ethernet protocol types inside libpcap;
* map them to the corresponding PPP protocol types.
*/
- switch (proto) {
+ switch (ll_proto) {
case ETHERTYPE_IP:
/*
@@ -3322,16 +3305,15 @@ gen_linktype(compiler_state_t *cstate, int proto)
return b0;
default:
- proto = ethertype_to_ppptype(proto);
return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H,
- (bpf_int32)proto);
+ ethertype_to_ppptype(ll_proto));
}
/*NOTREACHED*/
case DLT_NULL:
case DLT_LOOP:
case DLT_ENC:
- switch (proto) {
+ switch (ll_proto) {
case ETHERTYPE_IP:
return (gen_loopback_linktype(cstate, AF_INET));
@@ -3412,12 +3394,12 @@ gen_linktype(compiler_state_t *cstate, int proto)
* af field is host byte order in contrast to the rest of
* the packet.
*/
- if (proto == ETHERTYPE_IP)
+ if (ll_proto == ETHERTYPE_IP)
return (gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, af),
- BPF_B, (bpf_int32)AF_INET));
- else if (proto == ETHERTYPE_IPV6)
+ BPF_B, AF_INET));
+ else if (ll_proto == ETHERTYPE_IPV6)
return (gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, af),
- BPF_B, (bpf_int32)AF_INET6));
+ BPF_B, AF_INET6));
else
return gen_false(cstate);
/*NOTREACHED*/
@@ -3429,43 +3411,43 @@ gen_linktype(compiler_state_t *cstate, int proto)
* XXX should we check for first fragment if the protocol
* uses PHDS?
*/
- switch (proto) {
+ switch (ll_proto) {
default:
return gen_false(cstate);
case ETHERTYPE_IPV6:
return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
- (bpf_int32)ARCTYPE_INET6));
+ ARCTYPE_INET6));
case ETHERTYPE_IP:
b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
- (bpf_int32)ARCTYPE_IP);
+ ARCTYPE_IP);
b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
- (bpf_int32)ARCTYPE_IP_OLD);
+ ARCTYPE_IP_OLD);
gen_or(b0, b1);
return (b1);
case ETHERTYPE_ARP:
b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
- (bpf_int32)ARCTYPE_ARP);
+ ARCTYPE_ARP);
b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
- (bpf_int32)ARCTYPE_ARP_OLD);
+ ARCTYPE_ARP_OLD);
gen_or(b0, b1);
return (b1);
case ETHERTYPE_REVARP:
return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
- (bpf_int32)ARCTYPE_REVARP));
+ ARCTYPE_REVARP));
case ETHERTYPE_ATALK:
return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B,
- (bpf_int32)ARCTYPE_ATALK));
+ ARCTYPE_ATALK));
}
/*NOTREACHED*/
case DLT_LTALK:
- switch (proto) {
+ switch (ll_proto) {
case ETHERTYPE_ATALK:
return gen_true(cstate);
default:
@@ -3478,7 +3460,7 @@ gen_linktype(compiler_state_t *cstate, int proto)
* XXX - assumes a 2-byte Frame Relay header with
* DLCI and flags. What if the address is longer?
*/
- switch (proto) {
+ switch (ll_proto) {
case ETHERTYPE_IP:
/*
@@ -3555,7 +3537,7 @@ gen_linktype(compiler_state_t *cstate, int proto)
return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_W, 0x55FF0000, 0xffff0000);
case DLT_IPNET:
- return gen_ipnet_linktype(cstate, proto);
+ return gen_ipnet_linktype(cstate, ll_proto);
case DLT_LINUX_IRDA:
bpf_error(cstate, "IrDA link-layer type filtering not implemented");
@@ -3594,6 +3576,7 @@ gen_linktype(compiler_state_t *cstate, int proto)
case DLT_IEEE802_15_4_LINUX:
case DLT_IEEE802_15_4_NONASK_PHY:
case DLT_IEEE802_15_4_NOFCS:
+ case DLT_IEEE802_15_4_TAP:
bpf_error(cstate, "IEEE 802.15.4 link-layer type filtering not implemented");
case DLT_IEEE802_16_MAC_CPS_RADIO:
@@ -3632,7 +3615,7 @@ gen_linktype(compiler_state_t *cstate, int proto)
* it's not, it needs to be handled specially
* above.)
*/
- return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, (bpf_int32)proto);
+ return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto);
/*NOTREACHED */
} else {
/*
@@ -3691,7 +3674,7 @@ gen_llc_internal(compiler_state_t *cstate)
* Now check for the purported DSAP and SSAP not being
* 0xFF, to rule out NetWare-over-802.3.
*/
- b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_int32)0xFFFF);
+ b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, 0xFFFF);
gen_not(b1);
gen_and(b0, b1);
return b1;
@@ -3903,12 +3886,12 @@ gen_llc_u_subtype(compiler_state_t *cstate, bpf_u_int32 subtype)
* protocol ID in a SNAP header.
*/
static struct block *
-gen_llc_linktype(compiler_state_t *cstate, int proto)
+gen_llc_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
{
/*
* XXX - handle token-ring variable-length header.
*/
- switch (proto) {
+ switch (ll_proto) {
case LLCSAP_IP:
case LLCSAP_ISONS:
@@ -3919,15 +3902,14 @@ gen_llc_linktype(compiler_state_t *cstate, int proto)
* DSAP, as we do for other SAP values?
*/
return gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_u_int32)
- ((proto << 8) | proto));
+ ((ll_proto << 8) | ll_proto));
case LLCSAP_IPX:
/*
* XXX - are there ever SNAP frames for IPX on
* non-Ethernet 802.x networks?
*/
- return gen_cmp(cstate, OR_LLC, 0, BPF_B,
- (bpf_int32)LLCSAP_IPX);
+ return gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX);
case ETHERTYPE_ATALK:
/*
@@ -3946,12 +3928,12 @@ gen_llc_linktype(compiler_state_t *cstate, int proto)
* XXX - we don't have to check for IPX 802.3
* here, but should we check for the IPX Ethertype?
*/
- if (proto <= ETHERMTU) {
+ if (ll_proto <= ETHERMTU) {
/*
* This is an LLC SAP value, so check
* the DSAP.
*/
- return gen_cmp(cstate, OR_LLC, 0, BPF_B, (bpf_int32)proto);
+ return gen_cmp(cstate, OR_LLC, 0, BPF_B, ll_proto);
} else {
/*
* This is an Ethernet type; we assume that it's
@@ -3966,20 +3948,20 @@ gen_llc_linktype(compiler_state_t *cstate, int proto)
* organization code of 0x000000 (encapsulated
* Ethernet), we'd do
*
- * return gen_snap(cstate, 0x000000, proto);
+ * return gen_snap(cstate, 0x000000, ll_proto);
*
* here; for now, we don't, as per the above.
* I don't know whether it's worth the extra CPU
* time to do the right check or not.
*/
- return gen_cmp(cstate, OR_LLC, 6, BPF_H, (bpf_int32)proto);
+ return gen_cmp(cstate, OR_LLC, 6, BPF_H, ll_proto);
}
}
}
static struct block *
gen_hostop(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask,
- int dir, int proto, u_int src_off, u_int dst_off)
+ int dir, bpf_u_int32 ll_proto, u_int src_off, u_int dst_off)
{
struct block *b0, *b1;
u_int offset;
@@ -3995,15 +3977,15 @@ gen_hostop(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask,
break;
case Q_AND:
- b0 = gen_hostop(cstate, addr, mask, Q_SRC, proto, src_off, dst_off);
- b1 = gen_hostop(cstate, addr, mask, Q_DST, proto, src_off, dst_off);
+ b0 = gen_hostop(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off);
+ b1 = gen_hostop(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off);
gen_and(b0, b1);
return b1;
case Q_DEFAULT:
case Q_OR:
- b0 = gen_hostop(cstate, addr, mask, Q_SRC, proto, src_off, dst_off);
- b1 = gen_hostop(cstate, addr, mask, Q_DST, proto, src_off, dst_off);
+ b0 = gen_hostop(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off);
+ b1 = gen_hostop(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off);
gen_or(b0, b1);
return b1;
@@ -4035,8 +4017,8 @@ gen_hostop(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask,
abort();
/*NOTREACHED*/
}
- b0 = gen_linktype(cstate, proto);
- b1 = gen_mcmp(cstate, OR_LINKPL, offset, BPF_W, (bpf_int32)addr, mask);
+ b0 = gen_linktype(cstate, ll_proto);
+ b1 = gen_mcmp(cstate, OR_LINKPL, offset, BPF_W, addr, mask);
gen_and(b0, b1);
return b1;
}
@@ -4044,7 +4026,8 @@ gen_hostop(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask,
#ifdef INET6
static struct block *
gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr,
- struct in6_addr *mask, int dir, int proto, u_int src_off, u_int dst_off)
+ struct in6_addr *mask, int dir, bpf_u_int32 ll_proto, u_int src_off,
+ u_int dst_off)
{
struct block *b0, *b1;
u_int offset;
@@ -4061,15 +4044,15 @@ gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr,
break;
case Q_AND:
- b0 = gen_hostop6(cstate, addr, mask, Q_SRC, proto, src_off, dst_off);
- b1 = gen_hostop6(cstate, addr, mask, Q_DST, proto, src_off, dst_off);
+ b0 = gen_hostop6(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off);
+ b1 = gen_hostop6(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off);
gen_and(b0, b1);
return b1;
case Q_DEFAULT:
case Q_OR:
- b0 = gen_hostop6(cstate, addr, mask, Q_SRC, proto, src_off, dst_off);
- b1 = gen_hostop6(cstate, addr, mask, Q_DST, proto, src_off, dst_off);
+ b0 = gen_hostop6(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off);
+ b1 = gen_hostop6(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off);
gen_or(b0, b1);
return b1;
@@ -4111,7 +4094,7 @@ gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr,
gen_and(b0, b1);
b0 = gen_mcmp(cstate, OR_LINKPL, offset + 0, BPF_W, ntohl(a[0]), ntohl(m[0]));
gen_and(b0, b1);
- b0 = gen_linktype(cstate, proto);
+ b0 = gen_linktype(cstate, ll_proto);
gen_and(b0, b1);
return b1;
}
@@ -4846,24 +4829,29 @@ gen_dnhostop(compiler_state_t *cstate, bpf_u_int32 addr, int dir)
b0 = gen_linktype(cstate, ETHERTYPE_DN);
/* Check for pad = 1, long header case */
tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H,
- (bpf_int32)ntohs(0x0681), (bpf_int32)ntohs(0x07FF));
+ (bpf_u_int32)ntohs(0x0681), (bpf_u_int32)ntohs(0x07FF));
b1 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_lh,
- BPF_H, (bpf_int32)ntohs((u_short)addr));
+ BPF_H, (bpf_u_int32)ntohs((u_short)addr));
gen_and(tmp, b1);
/* Check for pad = 0, long header case */
- tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_int32)0x06, (bpf_int32)0x7);
- b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_lh, BPF_H, (bpf_int32)ntohs((u_short)addr));
+ tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_u_int32)0x06,
+ (bpf_u_int32)0x7);
+ b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_lh, BPF_H,
+ (bpf_u_int32)ntohs((u_short)addr));
gen_and(tmp, b2);
gen_or(b2, b1);
/* Check for pad = 1, short header case */
tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H,
- (bpf_int32)ntohs(0x0281), (bpf_int32)ntohs(0x07FF));
- b2 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr));
+ (bpf_u_int32)ntohs(0x0281), (bpf_u_int32)ntohs(0x07FF));
+ b2 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_sh, BPF_H,
+ (bpf_u_int32)ntohs((u_short)addr));
gen_and(tmp, b2);
gen_or(b2, b1);
/* Check for pad = 0, short header case */
- tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_int32)0x02, (bpf_int32)0x7);
- b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr));
+ tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_u_int32)0x02,
+ (bpf_u_int32)0x7);
+ b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_sh, BPF_H,
+ (bpf_u_int32)ntohs((u_short)addr));
gen_and(tmp, b2);
gen_or(b2, b1);
@@ -4878,13 +4866,13 @@ gen_dnhostop(compiler_state_t *cstate, bpf_u_int32 addr, int dir)
* field in the IP header.
*/
static struct block *
-gen_mpls_linktype(compiler_state_t *cstate, int proto)
+gen_mpls_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto)
{
struct block *b0, *b1;
- switch (proto) {
+ switch (ll_proto) {
- case Q_IP:
+ case ETHERTYPE_IP:
/* match the bottom-of-stack bit */
b0 = gen_mcmp(cstate, OR_LINKPL, (u_int)-2, BPF_B, 0x01, 0x01);
/* match the IPv4 version number */
@@ -4892,7 +4880,7 @@ gen_mpls_linktype(compiler_state_t *cstate, int proto)
gen_and(b0, b1);
return b1;
- case Q_IPV6:
+ case ETHERTYPE_IPV6:
/* match the bottom-of-stack bit */
b0 = gen_mcmp(cstate, OR_LINKPL, (u_int)-2, BPF_B, 0x01, 0x01);
/* match the IPv4 version number */
@@ -4900,8 +4888,10 @@ gen_mpls_linktype(compiler_state_t *cstate, int proto)
gen_and(b0, b1);
return b1;
- default:
- abort();
+ default:
+ /* FIXME add other L3 proto IDs */
+ bpf_error(cstate, "unsupported protocol over mpls");
+ /*NOTREACHED*/
}
}
@@ -5583,46 +5573,46 @@ gen_ipfrag(compiler_state_t *cstate)
* headers).
*/
static struct block *
-gen_portatom(compiler_state_t *cstate, int off, bpf_int32 v)
+gen_portatom(compiler_state_t *cstate, int off, bpf_u_int32 v)
{
return gen_cmp(cstate, OR_TRAN_IPV4, off, BPF_H, v);
}
static struct block *
-gen_portatom6(compiler_state_t *cstate, int off, bpf_int32 v)
+gen_portatom6(compiler_state_t *cstate, int off, bpf_u_int32 v)
{
return gen_cmp(cstate, OR_TRAN_IPV6, off, BPF_H, v);
}
-struct block *
-gen_portop(compiler_state_t *cstate, int port, int proto, int dir)
+static struct block *
+gen_portop(compiler_state_t *cstate, u_int port, u_int proto, int dir)
{
struct block *b0, *b1, *tmp;
/* ip proto 'proto' and not a fragment other than the first fragment */
- tmp = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, (bpf_int32)proto);
+ tmp = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, proto);
b0 = gen_ipfrag(cstate);
gen_and(tmp, b0);
switch (dir) {
case Q_SRC:
- b1 = gen_portatom(cstate, 0, (bpf_int32)port);
+ b1 = gen_portatom(cstate, 0, port);
break;
case Q_DST:
- b1 = gen_portatom(cstate, 2, (bpf_int32)port);
+ b1 = gen_portatom(cstate, 2, port);
break;
case Q_AND:
- tmp = gen_portatom(cstate, 0, (bpf_int32)port);
- b1 = gen_portatom(cstate, 2, (bpf_int32)port);
+ tmp = gen_portatom(cstate, 0, port);
+ b1 = gen_portatom(cstate, 2, port);
gen_and(tmp, b1);
break;
case Q_DEFAULT:
case Q_OR:
- tmp = gen_portatom(cstate, 0, (bpf_int32)port);
- b1 = gen_portatom(cstate, 2, (bpf_int32)port);
+ tmp = gen_portatom(cstate, 0, port);
+ b1 = gen_portatom(cstate, 2, port);
gen_or(tmp, b1);
break;
@@ -5660,7 +5650,7 @@ gen_portop(compiler_state_t *cstate, int port, int proto, int dir)
}
static struct block *
-gen_port(compiler_state_t *cstate, int port, int ip_proto, int dir)
+gen_port(compiler_state_t *cstate, u_int port, int ip_proto, int dir)
{
struct block *b0, *b1, *tmp;
@@ -5687,7 +5677,7 @@ gen_port(compiler_state_t *cstate, int port, int ip_proto, int dir)
case IPPROTO_UDP:
case IPPROTO_TCP:
case IPPROTO_SCTP:
- b1 = gen_portop(cstate, port, ip_proto, dir);
+ b1 = gen_portop(cstate, port, (u_int)ip_proto, dir);
break;
case PROTO_UNDEF:
@@ -5706,33 +5696,33 @@ gen_port(compiler_state_t *cstate, int port, int ip_proto, int dir)
}
struct block *
-gen_portop6(compiler_state_t *cstate, int port, int proto, int dir)
+gen_portop6(compiler_state_t *cstate, u_int port, u_int proto, int dir)
{
struct block *b0, *b1, *tmp;
/* ip6 proto 'proto' */
/* XXX - catch the first fragment of a fragmented packet? */
- b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, (bpf_int32)proto);
+ b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, proto);
switch (dir) {
case Q_SRC:
- b1 = gen_portatom6(cstate, 0, (bpf_int32)port);
+ b1 = gen_portatom6(cstate, 0, port);
break;
case Q_DST:
- b1 = gen_portatom6(cstate, 2, (bpf_int32)port);
+ b1 = gen_portatom6(cstate, 2, port);
break;
case Q_AND:
- tmp = gen_portatom6(cstate, 0, (bpf_int32)port);
- b1 = gen_portatom6(cstate, 2, (bpf_int32)port);
+ tmp = gen_portatom6(cstate, 0, port);
+ b1 = gen_portatom6(cstate, 2, port);
gen_and(tmp, b1);
break;
case Q_DEFAULT:
case Q_OR:
- tmp = gen_portatom6(cstate, 0, (bpf_int32)port);
- b1 = gen_portatom6(cstate, 2, (bpf_int32)port);
+ tmp = gen_portatom6(cstate, 0, port);
+ b1 = gen_portatom6(cstate, 2, port);
gen_or(tmp, b1);
break;
@@ -5745,7 +5735,7 @@ gen_portop6(compiler_state_t *cstate, int port, int proto, int dir)
}
static struct block *
-gen_port6(compiler_state_t *cstate, int port, int ip_proto, int dir)
+gen_port6(compiler_state_t *cstate, u_int port, int ip_proto, int dir)
{
struct block *b0, *b1, *tmp;
@@ -5756,7 +5746,7 @@ gen_port6(compiler_state_t *cstate, int port, int ip_proto, int dir)
case IPPROTO_UDP:
case IPPROTO_TCP:
case IPPROTO_SCTP:
- b1 = gen_portop6(cstate, port, ip_proto, dir);
+ b1 = gen_portop6(cstate, port, (u_int)ip_proto, dir);
break;
case PROTO_UNDEF:
@@ -5776,8 +5766,8 @@ gen_port6(compiler_state_t *cstate, int port, int ip_proto, int dir)
/* gen_portrange code */
static struct block *
-gen_portrangeatom(compiler_state_t *cstate, int off, bpf_int32 v1,
- bpf_int32 v2)
+gen_portrangeatom(compiler_state_t *cstate, u_int off, bpf_u_int32 v1,
+ bpf_u_int32 v2)
{
struct block *b1, *b2;
@@ -5785,7 +5775,7 @@ gen_portrangeatom(compiler_state_t *cstate, int off, bpf_int32 v1,
/*
* Reverse the order of the ports, so v1 is the lower one.
*/
- bpf_int32 vtemp;
+ bpf_u_int32 vtemp;
vtemp = v1;
v1 = v2;
@@ -5800,36 +5790,36 @@ gen_portrangeatom(compiler_state_t *cstate, int off, bpf_int32 v1,
return b2;
}
-struct block *
-gen_portrangeop(compiler_state_t *cstate, int port1, int port2, int proto,
- int dir)
+static struct block *
+gen_portrangeop(compiler_state_t *cstate, u_int port1, u_int port2,
+ bpf_u_int32 proto, int dir)
{
struct block *b0, *b1, *tmp;
/* ip proto 'proto' and not a fragment other than the first fragment */
- tmp = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, (bpf_int32)proto);
+ tmp = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, proto);
b0 = gen_ipfrag(cstate);
gen_and(tmp, b0);
switch (dir) {
case Q_SRC:
- b1 = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2);
+ b1 = gen_portrangeatom(cstate, 0, port1, port2);
break;
case Q_DST:
- b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2);
+ b1 = gen_portrangeatom(cstate, 2, port1, port2);
break;
case Q_AND:
- tmp = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2);
- b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2);
+ tmp = gen_portrangeatom(cstate, 0, port1, port2);
+ b1 = gen_portrangeatom(cstate, 2, port1, port2);
gen_and(tmp, b1);
break;
case Q_DEFAULT:
case Q_OR:
- tmp = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2);
- b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2);
+ tmp = gen_portrangeatom(cstate, 0, port1, port2);
+ b1 = gen_portrangeatom(cstate, 2, port1, port2);
gen_or(tmp, b1);
break;
@@ -5867,7 +5857,7 @@ gen_portrangeop(compiler_state_t *cstate, int port1, int port2, int proto,
}
static struct block *
-gen_portrange(compiler_state_t *cstate, int port1, int port2, int ip_proto,
+gen_portrange(compiler_state_t *cstate, u_int port1, u_int port2, int ip_proto,
int dir)
{
struct block *b0, *b1, *tmp;
@@ -5879,7 +5869,8 @@ gen_portrange(compiler_state_t *cstate, int port1, int port2, int ip_proto,
case IPPROTO_UDP:
case IPPROTO_TCP:
case IPPROTO_SCTP:
- b1 = gen_portrangeop(cstate, port1, port2, ip_proto, dir);
+ b1 = gen_portrangeop(cstate, port1, port2, (bpf_u_int32)ip_proto,
+ dir);
break;
case PROTO_UNDEF:
@@ -5898,8 +5889,8 @@ gen_portrange(compiler_state_t *cstate, int port1, int port2, int ip_proto,
}
static struct block *
-gen_portrangeatom6(compiler_state_t *cstate, int off, bpf_int32 v1,
- bpf_int32 v2)
+gen_portrangeatom6(compiler_state_t *cstate, u_int off, bpf_u_int32 v1,
+ bpf_u_int32 v2)
{
struct block *b1, *b2;
@@ -5907,7 +5898,7 @@ gen_portrangeatom6(compiler_state_t *cstate, int off, bpf_int32 v1,
/*
* Reverse the order of the ports, so v1 is the lower one.
*/
- bpf_int32 vtemp;
+ bpf_u_int32 vtemp;
vtemp = v1;
v1 = v2;
@@ -5922,35 +5913,35 @@ gen_portrangeatom6(compiler_state_t *cstate, int off, bpf_int32 v1,
return b2;
}
-struct block *
-gen_portrangeop6(compiler_state_t *cstate, int port1, int port2, int proto,
- int dir)
+static struct block *
+gen_portrangeop6(compiler_state_t *cstate, u_int port1, u_int port2,
+ bpf_u_int32 proto, int dir)
{
struct block *b0, *b1, *tmp;
/* ip6 proto 'proto' */
/* XXX - catch the first fragment of a fragmented packet? */
- b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, (bpf_int32)proto);
+ b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, proto);
switch (dir) {
case Q_SRC:
- b1 = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2);
+ b1 = gen_portrangeatom6(cstate, 0, port1, port2);
break;
case Q_DST:
- b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2);
+ b1 = gen_portrangeatom6(cstate, 2, port1, port2);
break;
case Q_AND:
- tmp = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2);
- b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2);
+ tmp = gen_portrangeatom6(cstate, 0, port1, port2);
+ b1 = gen_portrangeatom6(cstate, 2, port1, port2);
gen_and(tmp, b1);
break;
case Q_DEFAULT:
case Q_OR:
- tmp = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2);
- b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2);
+ tmp = gen_portrangeatom6(cstate, 0, port1, port2);
+ b1 = gen_portrangeatom6(cstate, 2, port1, port2);
gen_or(tmp, b1);
break;
@@ -5963,7 +5954,7 @@ gen_portrangeop6(compiler_state_t *cstate, int port1, int port2, int proto,
}
static struct block *
-gen_portrange6(compiler_state_t *cstate, int port1, int port2, int ip_proto,
+gen_portrange6(compiler_state_t *cstate, u_int port1, u_int port2, int ip_proto,
int dir)
{
struct block *b0, *b1, *tmp;
@@ -5975,7 +5966,8 @@ gen_portrange6(compiler_state_t *cstate, int port1, int port2, int ip_proto,
case IPPROTO_UDP:
case IPPROTO_TCP:
case IPPROTO_SCTP:
- b1 = gen_portrangeop6(cstate, port1, port2, ip_proto, dir);
+ b1 = gen_portrangeop6(cstate, port1, port2, (bpf_u_int32)ip_proto,
+ dir);
break;
case PROTO_UNDEF:
@@ -6045,10 +6037,10 @@ gen_joinsp(struct stmt **s, int n)
#endif
static struct block *
-gen_protochain(compiler_state_t *cstate, int v, int proto, int dir)
+gen_protochain(compiler_state_t *cstate, bpf_u_int32 v, int proto)
{
#ifdef NO_PROTOCHAIN
- return gen_proto(cstate, v, proto, dir);
+ return gen_proto(cstate, v, proto);
#else
struct block *b0, *b;
struct slist *s[100];
@@ -6065,8 +6057,8 @@ gen_protochain(compiler_state_t *cstate, int v, int proto, int dir)
case Q_IPV6:
break;
case Q_DEFAULT:
- b0 = gen_protochain(cstate, v, Q_IP, dir);
- b = gen_protochain(cstate, v, Q_IPV6, dir);
+ b0 = gen_protochain(cstate, v, Q_IP);
+ b = gen_protochain(cstate, v, Q_IPV6);
gen_or(b0, b);
return b;
default:
@@ -6371,7 +6363,7 @@ gen_check_802_11_data_frame(compiler_state_t *cstate)
* against Q_IP and Q_IPV6.
*/
static struct block *
-gen_proto(compiler_state_t *cstate, int v, int proto, int dir)
+gen_proto(compiler_state_t *cstate, bpf_u_int32 v, int proto, int dir)
{
struct block *b0, *b1;
#ifndef CHASE_CHAIN
@@ -6409,7 +6401,7 @@ gen_proto(compiler_state_t *cstate, int v, int proto, int dir)
*/
b0 = gen_linktype(cstate, ETHERTYPE_IP);
#ifndef CHASE_CHAIN
- b1 = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, (bpf_int32)v);
+ b1 = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, v);
#else
b1 = gen_protochain(cstate, v, Q_IP);
#endif
@@ -6480,9 +6472,9 @@ gen_proto(compiler_state_t *cstate, int v, int proto, int dir)
* header.
*/
b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, IPPROTO_FRAGMENT);
- b1 = gen_cmp(cstate, OR_LINKPL, 40, BPF_B, (bpf_int32)v);
+ b1 = gen_cmp(cstate, OR_LINKPL, 40, BPF_B, v);
gen_and(b2, b1);
- b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, (bpf_int32)v);
+ b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, v);
gen_or(b2, b1);
#else
b1 = gen_protochain(cstate, v, Q_IPV6);
@@ -6499,7 +6491,7 @@ gen_proto(compiler_state_t *cstate, int v, int proto, int dir)
/*NOTREACHED*/
case Q_ESP:
- bpf_error(cstate, "'ah proto' is bogus");
+ bpf_error(cstate, "'esp proto' is bogus");
/*NOTREACHED*/
case Q_PIM:
@@ -6546,13 +6538,13 @@ gen_proto(compiler_state_t *cstate, int v, int proto, int dir)
*/
b0 = gen_linktype(cstate, LLCSAP_ISONS<<8 | LLCSAP_ISONS);
/* OSI in C-HDLC is stuffed with a fudge byte */
- b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 1, BPF_B, (long)v);
+ b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 1, BPF_B, v);
gen_and(b0, b1);
return b1;
default:
b0 = gen_linktype(cstate, LLCSAP_ISONS);
- b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 0, BPF_B, (long)v);
+ b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 0, BPF_B, v);
gen_and(b0, b1);
return b1;
}
@@ -6567,7 +6559,7 @@ gen_proto(compiler_state_t *cstate, int v, int proto, int dir)
* 4 is the offset of the PDU type relative to the IS-IS
* header.
*/
- b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 4, BPF_B, (long)v);
+ b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 4, BPF_B, v);
gen_and(b0, b1);
return b1;
@@ -6928,7 +6920,7 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
case Q_PROTOCHAIN:
real_proto = lookup_proto(cstate, name, proto);
if (real_proto >= 0)
- return gen_protochain(cstate, real_proto, proto, dir);
+ return gen_protochain(cstate, real_proto, proto);
else
bpf_error(cstate, "unknown protocol: %s", name);
@@ -6942,7 +6934,7 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
struct block *
gen_mcode(compiler_state_t *cstate, const char *s1, const char *s2,
- unsigned int masklen, struct qual q)
+ bpf_u_int32 masklen, struct qual q)
{
register int nlen, mlen;
bpf_u_int32 n, m;
@@ -6955,11 +6947,15 @@ gen_mcode(compiler_state_t *cstate, const char *s1, const char *s2,
return (NULL);
nlen = __pcap_atoin(s1, &n);
+ if (nlen < 0)
+ bpf_error(cstate, "invalid IPv4 address '%s'", s1);
/* Promote short ipaddr */
n <<= 32 - nlen;
if (s2 != NULL) {
mlen = __pcap_atoin(s2, &m);
+ if (mlen < 0)
+ bpf_error(cstate, "invalid IPv4 address '%s'", s2);
/* Promote short ipaddr */
m <<= 32 - mlen;
if ((n & ~m) != 0)
@@ -7017,8 +7013,11 @@ gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q)
vlen = __pcap_atodn(s, &v);
if (vlen == 0)
bpf_error(cstate, "malformed decnet address '%s'", s);
- } else
+ } else {
vlen = __pcap_atoin(s, &v);
+ if (vlen < 0)
+ bpf_error(cstate, "invalid IPv4 address '%s'", s);
+ }
switch (q.addr) {
@@ -7062,8 +7061,8 @@ gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q)
{
struct block *b;
- b = gen_port(cstate, (int)v, proto, dir);
- gen_or(gen_port6(cstate, (int)v, proto, dir), b);
+ b = gen_port(cstate, v, proto, dir);
+ gen_or(gen_port6(cstate, v, proto, dir), b);
return b;
}
@@ -7084,8 +7083,8 @@ gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q)
{
struct block *b;
- b = gen_portrange(cstate, (int)v, (int)v, proto, dir);
- gen_or(gen_portrange6(cstate, (int)v, (int)v, proto, dir), b);
+ b = gen_portrange(cstate, v, v, proto, dir);
+ gen_or(gen_portrange6(cstate, v, v, proto, dir), b);
return b;
}
@@ -7094,10 +7093,10 @@ gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q)
/*NOTREACHED*/
case Q_PROTO:
- return gen_proto(cstate, (int)v, proto, dir);
+ return gen_proto(cstate, v, proto, dir);
case Q_PROTOCHAIN:
- return gen_protochain(cstate, (int)v, proto, dir);
+ return gen_protochain(cstate, v, proto);
case Q_UNDEF:
syntax(cstate);
@@ -7113,7 +7112,7 @@ 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,
- unsigned int masklen, struct qual q)
+ bpf_u_int32 masklen, struct qual q)
{
struct addrinfo *res;
struct in6_addr *addr;
@@ -7139,10 +7138,10 @@ gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2,
bpf_error(cstate, "%s resolved to multiple address", s1);
addr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
- if (sizeof(mask) * 8 < masklen)
- bpf_error(cstate, "mask length must be <= %u", (unsigned int)(sizeof(mask) * 8));
+ if (masklen > sizeof(mask.s6_addr) * 8)
+ bpf_error(cstate, "mask length must be <= %u", (unsigned int)(sizeof(mask.s6_addr) * 8));
memset(&mask, 0, sizeof(mask));
- memset(&mask, 0xff, masklen / 8);
+ memset(&mask.s6_addr, 0xff, masklen / 8);
if (masklen % 8) {
mask.s6_addr[masklen / 8] =
(0xff << (8 - masklen % 8)) & 0xff;
@@ -7271,8 +7270,10 @@ xfer_to_a(compiler_state_t *cstate, struct arth *a)
* for "index".
*/
static struct arth *
-gen_load_internal(compiler_state_t *cstate, int proto, struct arth *inst, int size)
+gen_load_internal(compiler_state_t *cstate, int proto, struct arth *inst,
+ bpf_u_int32 size)
{
+ int size_code;
struct slist *s, *tmp;
struct block *b;
int regno = alloc_reg(cstate);
@@ -7282,17 +7283,18 @@ gen_load_internal(compiler_state_t *cstate, int proto, struct arth *inst, int si
default:
bpf_error(cstate, "data size must be 1, 2, or 4");
+ /*NOTREACHED*/
case 1:
- size = BPF_B;
+ size_code = BPF_B;
break;
case 2:
- size = BPF_H;
+ size_code = BPF_H;
break;
case 4:
- size = BPF_W;
+ size_code = BPF_W;
break;
}
switch (proto) {
@@ -7319,7 +7321,7 @@ gen_load_internal(compiler_state_t *cstate, int proto, struct arth *inst, int si
/*
* Load the item at that offset.
*/
- tmp = new_stmt(cstate, BPF_LD|BPF_IND|size);
+ tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
sappend(s, tmp);
sappend(inst->s, s);
break;
@@ -7361,7 +7363,7 @@ gen_load_internal(compiler_state_t *cstate, int proto, struct arth *inst, int si
* variable-length; that header length is what we put
* into the X register and then added to the index).
*/
- tmp = new_stmt(cstate, BPF_LD|BPF_IND|size);
+ tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
tmp->s.k = cstate->off_linkhdr.constant_part;
sappend(s, tmp);
sappend(inst->s, s);
@@ -7408,7 +7410,7 @@ gen_load_internal(compiler_state_t *cstate, int proto, struct arth *inst, int si
* payload, and the constant part of the offset of the
* start of the link-layer payload.
*/
- tmp = new_stmt(cstate, BPF_LD|BPF_IND|size);
+ tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
sappend(s, tmp);
sappend(inst->s, s);
@@ -7465,7 +7467,7 @@ gen_load_internal(compiler_state_t *cstate, int proto, struct arth *inst, int si
sappend(s, xfer_to_a(cstate, inst));
sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X));
sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX));
- sappend(s, tmp = new_stmt(cstate, BPF_LD|BPF_IND|size));
+ sappend(s, tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code));
tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl;
sappend(inst->s, s);
@@ -7527,7 +7529,7 @@ gen_load_internal(compiler_state_t *cstate, int proto, struct arth *inst, int si
* payload, and the constant part of the offset of the
* start of the link-layer payload.
*/
- tmp = new_stmt(cstate, BPF_LD|BPF_IND|size);
+ tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code);
tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 40;
sappend(s, tmp);
@@ -7544,7 +7546,8 @@ gen_load_internal(compiler_state_t *cstate, int proto, struct arth *inst, int si
}
struct arth *
-gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size)
+gen_load(compiler_state_t *cstate, int proto, struct arth *inst,
+ bpf_u_int32 size)
{
/*
* Catch errors reported by us and routines below us, and return NULL
@@ -7640,7 +7643,7 @@ gen_loadlen(compiler_state_t *cstate)
}
static struct arth *
-gen_loadi_internal(compiler_state_t *cstate, int val)
+gen_loadi_internal(compiler_state_t *cstate, bpf_u_int32 val)
{
struct arth *a;
struct slist *s;
@@ -7661,7 +7664,7 @@ gen_loadi_internal(compiler_state_t *cstate, int val)
}
struct arth *
-gen_loadi(compiler_state_t *cstate, int val)
+gen_loadi(compiler_state_t *cstate, bpf_u_int32 val)
{
/*
* Catch errors reported by us and routines below us, and return NULL
@@ -7736,13 +7739,7 @@ gen_arth(compiler_state_t *cstate, int code, struct arth *a0_arg,
if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0)
bpf_error(cstate, "modulus by zero");
} else if (code == BPF_LSH || code == BPF_RSH) {
- /*
- * XXX - we need to make up our minds as to what integers
- * are signed and what integers are unsigned in BPF programs
- * and in our IR.
- */
- if (a1->s->s.code == (BPF_LD|BPF_IMM) &&
- (a1->s->s.k < 0 || a1->s->s.k > 31))
+ if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k > 31)
bpf_error(cstate, "shift by more than 31 bits");
}
s0 = xfer_to_x(cstate, a1);
@@ -7863,7 +7860,7 @@ gen_less(compiler_state_t *cstate, int n)
* would generate code appropriate to the radio header in question.
*/
struct block *
-gen_byteop(compiler_state_t *cstate, int op, int idx, int val)
+gen_byteop(compiler_state_t *cstate, int op, int idx, bpf_u_int32 val)
{
struct block *b;
struct slist *s;
@@ -7880,14 +7877,14 @@ gen_byteop(compiler_state_t *cstate, int op, int idx, int val)
abort();
case '=':
- return gen_cmp(cstate, OR_LINKHDR, (u_int)idx, BPF_B, (bpf_int32)val);
+ return gen_cmp(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val);
case '<':
- b = gen_cmp_lt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, (bpf_int32)val);
+ b = gen_cmp_lt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val);
return b;
case '>':
- b = gen_cmp_gt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, (bpf_int32)val);
+ b = gen_cmp_gt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val);
return b;
case '|':
@@ -7965,9 +7962,9 @@ gen_broadcast(compiler_state_t *cstate, int proto)
bpf_error(cstate, "netmask not known, so 'ip broadcast' not supported");
b0 = gen_linktype(cstate, ETHERTYPE_IP);
hostmask = ~cstate->netmask;
- b1 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W, (bpf_int32)0, hostmask);
+ b1 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W, 0, hostmask);
b2 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W,
- (bpf_int32)(~0 & hostmask), hostmask);
+ ~0 & hostmask, hostmask);
gen_or(b1, b2);
gen_and(b0, b2);
return b2;
@@ -8164,13 +8161,13 @@ gen_multicast(compiler_state_t *cstate, int proto)
case Q_IP:
b0 = gen_linktype(cstate, ETHERTYPE_IP);
- b1 = gen_cmp_ge(cstate, OR_LINKPL, 16, BPF_B, (bpf_int32)224);
+ b1 = gen_cmp_ge(cstate, OR_LINKPL, 16, BPF_B, 224);
gen_and(b0, b1);
return b1;
case Q_IPV6:
b0 = gen_linktype(cstate, ETHERTYPE_IPV6);
- b1 = gen_cmp(cstate, OR_LINKPL, 24, BPF_B, (bpf_int32)255);
+ b1 = gen_cmp(cstate, OR_LINKPL, 24, BPF_B, 255);
gen_and(b0, b1);
return b1;
}
@@ -8178,6 +8175,53 @@ gen_multicast(compiler_state_t *cstate, int proto)
/*NOTREACHED*/
}
+struct block *
+gen_ifindex(compiler_state_t *cstate, int ifindex)
+{
+ register struct block *b0;
+
+ /*
+ * Catch errors reported by us and routines below us, and return NULL
+ * on an error.
+ */
+ if (setjmp(cstate->top_ctx))
+ return (NULL);
+
+ /*
+ * Only some data link types support ifindex qualifiers.
+ */
+ switch (cstate->linktype) {
+ case DLT_LINUX_SLL2:
+ /* match packets on this interface */
+ b0 = gen_cmp(cstate, OR_LINKHDR, 4, BPF_W, ifindex);
+ break;
+ default:
+#if defined(linux)
+ /*
+ * This is Linux; we require PF_PACKET support.
+ * If this is a *live* capture, we can look at
+ * special meta-data in the filter expression;
+ * if it's a savefile, we can't.
+ */
+ if (cstate->bpf_pcap->rfile != NULL) {
+ /* We have a FILE *, so this is a savefile */
+ bpf_error(cstate, "ifindex not supported on %s when reading savefiles",
+ pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+ b0 = NULL;
+ /*NOTREACHED*/
+ }
+ /* match ifindex */
+ b0 = gen_cmp(cstate, OR_LINKHDR, SKF_AD_OFF + SKF_AD_IFINDEX, BPF_W,
+ ifindex);
+#else /* defined(linux) */
+ bpf_error(cstate, "ifindex not supported on %s",
+ pcap_datalink_val_to_description_or_dlt(cstate->linktype));
+ /*NOTREACHED*/
+#endif /* defined(linux) */
+ }
+ return (b0);
+}
+
/*
* Filter on inbound (dir == 0) or outbound (dir == 1) traffic.
* Outbound traffic is sent by this machine, while inbound traffic is
@@ -8241,7 +8285,7 @@ gen_inbound(compiler_state_t *cstate, int dir)
#ifdef HAVE_NET_PFVAR_H
case DLT_PFLOG:
b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, dir), BPF_B,
- (bpf_int32)((dir == 0) ? PF_IN : PF_OUT));
+ ((dir == 0) ? PF_IN : PF_OUT));
break;
#endif
@@ -8305,9 +8349,9 @@ gen_inbound(compiler_state_t *cstate, int dir)
* with newer capture APIs, allowing it to be saved
* in pcapng files.
*/
-#if defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER)
+#if defined(linux)
/*
- * This is Linux with PF_PACKET support.
+ * This is Linux; we require PF_PACKET support.
* If this is a *live* capture, we can look at
* special meta-data in the filter expression;
* if it's a savefile, we can't.
@@ -8316,7 +8360,6 @@ gen_inbound(compiler_state_t *cstate, int dir)
/* We have a FILE *, so this is a savefile */
bpf_error(cstate, "inbound/outbound not supported on %s when reading savefiles",
pcap_datalink_val_to_description_or_dlt(cstate->linktype));
- b0 = NULL;
/*NOTREACHED*/
}
/* match outgoing packets */
@@ -8326,11 +8369,11 @@ gen_inbound(compiler_state_t *cstate, int dir)
/* to filter on inbound traffic, invert the match */
gen_not(b0);
}
-#else /* defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */
+#else /* defined(linux) */
bpf_error(cstate, "inbound/outbound not supported on %s",
pcap_datalink_val_to_description_or_dlt(cstate->linktype));
/*NOTREACHED*/
-#endif /* defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */
+#endif /* defined(linux) */
}
return (b0);
}
@@ -8414,7 +8457,7 @@ gen_pf_rnr(compiler_state_t *cstate, int rnr)
}
b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, rulenr), BPF_W,
- (bpf_int32)rnr);
+ (bpf_u_int32)rnr);
return (b0);
}
@@ -8437,7 +8480,7 @@ gen_pf_srnr(compiler_state_t *cstate, int srnr)
}
b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, subrulenr), BPF_W,
- (bpf_int32)srnr);
+ (bpf_u_int32)srnr);
return (b0);
}
@@ -8460,7 +8503,7 @@ gen_pf_reason(compiler_state_t *cstate, int reason)
}
b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, reason), BPF_B,
- (bpf_int32)reason);
+ (bpf_u_int32)reason);
return (b0);
}
@@ -8483,7 +8526,7 @@ gen_pf_action(compiler_state_t *cstate, int action)
}
b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, action), BPF_B,
- (bpf_int32)action);
+ (bpf_u_int32)action);
return (b0);
}
#else /* !HAVE_NET_PFVAR_H */
@@ -8574,7 +8617,7 @@ gen_pf_action(compiler_state_t *cstate, int action _U_)
/* IEEE 802.11 wireless header */
struct block *
-gen_p80211_type(compiler_state_t *cstate, int type, int mask)
+gen_p80211_type(compiler_state_t *cstate, bpf_u_int32 type, bpf_u_int32 mask)
{
struct block *b0;
@@ -8591,8 +8634,7 @@ gen_p80211_type(compiler_state_t *cstate, int type, int mask)
case DLT_PRISM_HEADER:
case DLT_IEEE802_11_RADIO_AVS:
case DLT_IEEE802_11_RADIO:
- b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, (bpf_int32)type,
- (bpf_int32)mask);
+ b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, type, mask);
break;
default:
@@ -8604,7 +8646,7 @@ gen_p80211_type(compiler_state_t *cstate, int type, int mask)
}
struct block *
-gen_p80211_fcdir(compiler_state_t *cstate, int fcdir)
+gen_p80211_fcdir(compiler_state_t *cstate, bpf_u_int32 fcdir)
{
struct block *b0;
@@ -8628,8 +8670,8 @@ gen_p80211_fcdir(compiler_state_t *cstate, int fcdir)
/*NOTREACHED*/
}
- b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, (bpf_int32)fcdir,
- (bpf_u_int32)IEEE80211_FC1_DIR_MASK);
+ b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, fcdir,
+ IEEE80211_FC1_DIR_MASK);
return (b0);
}
@@ -8746,7 +8788,7 @@ gen_vlan_vid_test(compiler_state_t *cstate, bpf_u_int32 vlan_num)
bpf_error(cstate, "VLAN tag %u greater than maximum %u",
vlan_num, 0x0fff);
}
- return gen_mcmp(cstate, OR_LINKPL, 0, BPF_H, (bpf_int32)vlan_num, 0x0fff);
+ return gen_mcmp(cstate, OR_LINKPL, 0, BPF_H, vlan_num, 0x0fff);
}
static struct block *
@@ -8776,7 +8818,8 @@ gen_vlan_no_bpf_extensions(compiler_state_t *cstate, bpf_u_int32 vlan_num,
#if defined(SKF_AD_VLAN_TAG_PRESENT)
/* add v to variable part of off */
static void
-gen_vlan_vloffset_add(compiler_state_t *cstate, bpf_abs_offset *off, int v, struct slist *s)
+gen_vlan_vloffset_add(compiler_state_t *cstate, bpf_abs_offset *off,
+ bpf_u_int32 v, struct slist *s)
{
struct slist *s2;
@@ -8882,7 +8925,7 @@ gen_vlan_bpf_extensions(compiler_state_t *cstate, bpf_u_int32 vlan_num,
/*
* This is tricky. We need to insert the statements updating variable
- * parts of offsets before the the traditional TPID and VID tests so
+ * parts of offsets before the traditional TPID and VID tests so
* that they are called whenever SKF_AD_VLAN_TAG_PRESENT fails but
* we do not want this update to affect those checks. That's why we
* generate both test blocks first and insert the statements updating
@@ -9062,7 +9105,7 @@ gen_mpls(compiler_state_t *cstate, bpf_u_int32 label_num_arg,
label_num, 0xFFFFF);
}
label_num = label_num << 12; /* label is shifted 12 bits on the wire */
- b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, (bpf_int32)label_num,
+ b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, label_num,
0xfffff000); /* only compare the first 20 bits */
gen_and(b0, b1);
b0 = b1;
@@ -9102,7 +9145,7 @@ gen_pppoed(compiler_state_t *cstate)
return (NULL);
/* check for PPPoE discovery */
- return gen_linktype(cstate, (bpf_int32)ETHERTYPE_PPPOED);
+ return gen_linktype(cstate, ETHERTYPE_PPPOED);
}
struct block *
@@ -9120,7 +9163,7 @@ gen_pppoes(compiler_state_t *cstate, bpf_u_int32 sess_num, int has_sess_num)
/*
* Test against the PPPoE session link-layer type.
*/
- b0 = gen_linktype(cstate, (bpf_int32)ETHERTYPE_PPPOES);
+ b0 = gen_linktype(cstate, ETHERTYPE_PPPOES);
/* If a specific session is requested, check PPPoE session id */
if (has_sess_num) {
@@ -9128,8 +9171,7 @@ gen_pppoes(compiler_state_t *cstate, bpf_u_int32 sess_num, int has_sess_num)
bpf_error(cstate, "PPPoE session number %u greater than maximum %u",
sess_num, 0x0000ffff);
}
- b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W,
- (bpf_int32)sess_num, 0x0000ffff);
+ b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, sess_num, 0x0000ffff);
gen_and(b0, b1);
b0 = b1;
}
@@ -9169,7 +9211,7 @@ gen_pppoes(compiler_state_t *cstate, bpf_u_int32 sess_num, int has_sess_num)
* specified. Parameterized to handle both IPv4 and IPv6. */
static struct block *
gen_geneve_check(compiler_state_t *cstate,
- struct block *(*gen_portfn)(compiler_state_t *, int, int, int),
+ struct block *(*gen_portfn)(compiler_state_t *, u_int, int, int),
enum e_offrel offrel, bpf_u_int32 vni, int has_vni)
{
struct block *b0, *b1;
@@ -9179,7 +9221,7 @@ gen_geneve_check(compiler_state_t *cstate,
/* Check that we are operating on version 0. Otherwise, we
* can't decode the rest of the fields. The version is 2 bits
* in the first byte of the Geneve header. */
- b1 = gen_mcmp(cstate, offrel, 8, BPF_B, (bpf_int32)0, 0xc0);
+ b1 = gen_mcmp(cstate, offrel, 8, BPF_B, 0, 0xc0);
gen_and(b0, b1);
b0 = b1;
@@ -9189,8 +9231,7 @@ gen_geneve_check(compiler_state_t *cstate,
vni, 0xffffff);
}
vni <<= 8; /* VNI is in the upper 3 bytes */
- b1 = gen_mcmp(cstate, offrel, 12, BPF_W, (bpf_int32)vni,
- 0xffffff00);
+ b1 = gen_mcmp(cstate, offrel, 12, BPF_W, vni, 0xffffff00);
gen_and(b0, b1);
b0 = b1;
}
@@ -9473,7 +9514,7 @@ gen_geneve_ll_check(compiler_state_t *cstate)
static struct block *
gen_atmfield_code_internal(compiler_state_t *cstate, int atmfield,
- bpf_int32 jvalue, bpf_u_int32 jtype, int reverse)
+ bpf_u_int32 jvalue, int jtype, int reverse)
{
struct block *b0;
@@ -9484,8 +9525,8 @@ gen_atmfield_code_internal(compiler_state_t *cstate, int atmfield,
bpf_error(cstate, "'vpi' supported only on raw ATM");
if (cstate->off_vpi == OFFSET_NOT_SET)
abort();
- b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vpi, BPF_B, 0xffffffff, jtype,
- reverse, jvalue);
+ b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vpi, BPF_B,
+ 0xffffffffU, jtype, reverse, jvalue);
break;
case A_VCI:
@@ -9493,22 +9534,22 @@ gen_atmfield_code_internal(compiler_state_t *cstate, int atmfield,
bpf_error(cstate, "'vci' supported only on raw ATM");
if (cstate->off_vci == OFFSET_NOT_SET)
abort();
- b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vci, BPF_H, 0xffffffff, jtype,
- reverse, jvalue);
+ b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vci, BPF_H,
+ 0xffffffffU, jtype, reverse, jvalue);
break;
case A_PROTOTYPE:
if (cstate->off_proto == OFFSET_NOT_SET)
abort(); /* XXX - this isn't on FreeBSD */
- b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B, 0x0f, jtype,
- reverse, jvalue);
+ b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B,
+ 0x0fU, jtype, reverse, jvalue);
break;
case A_MSGTYPE:
if (cstate->off_payload == OFFSET_NOT_SET)
abort();
b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_payload + MSG_TYPE_POS, BPF_B,
- 0xffffffff, jtype, reverse, jvalue);
+ 0xffffffffU, jtype, reverse, jvalue);
break;
case A_CALLREFTYPE:
@@ -9516,8 +9557,8 @@ gen_atmfield_code_internal(compiler_state_t *cstate, int atmfield,
bpf_error(cstate, "'callref' supported only on raw ATM");
if (cstate->off_proto == OFFSET_NOT_SET)
abort();
- b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B, 0xffffffff,
- jtype, reverse, jvalue);
+ b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B,
+ 0xffffffffU, jtype, reverse, jvalue);
break;
default:
@@ -9560,7 +9601,7 @@ gen_atmtype_llc(compiler_state_t *cstate)
struct block *
gen_atmfield_code(compiler_state_t *cstate, int atmfield,
- bpf_int32 jvalue, bpf_u_int32 jtype, int reverse)
+ bpf_u_int32 jvalue, int jtype, int reverse)
{
/*
* Catch errors reported by us and routines below us, and return NULL
@@ -9700,7 +9741,8 @@ gen_mtp2type_abbrev(compiler_state_t *cstate, int type)
(cstate->linktype != DLT_MTP2_WITH_PHDR) )
bpf_error(cstate, "'fisu' supported only on MTP2");
/* gen_ncmp(cstate, offrel, offset, size, mask, jtype, reverse, value) */
- b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, 0x3f, BPF_JEQ, 0, 0);
+ b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+ 0x3fU, BPF_JEQ, 0, 0U);
break;
case M_LSSU:
@@ -9708,8 +9750,10 @@ gen_mtp2type_abbrev(compiler_state_t *cstate, int type)
(cstate->linktype != DLT_ERF) &&
(cstate->linktype != DLT_MTP2_WITH_PHDR) )
bpf_error(cstate, "'lssu' supported only on MTP2");
- b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, 0x3f, BPF_JGT, 1, 2);
- b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, 0x3f, BPF_JGT, 0, 0);
+ b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+ 0x3fU, BPF_JGT, 1, 2U);
+ b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+ 0x3fU, BPF_JGT, 0, 0U);
gen_and(b1, b0);
break;
@@ -9718,7 +9762,8 @@ gen_mtp2type_abbrev(compiler_state_t *cstate, int type)
(cstate->linktype != DLT_ERF) &&
(cstate->linktype != DLT_MTP2_WITH_PHDR) )
bpf_error(cstate, "'msu' supported only on MTP2");
- b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, 0x3f, BPF_JGT, 0, 2);
+ b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B,
+ 0x3fU, BPF_JGT, 0, 2U);
break;
case MH_FISU:
@@ -9727,7 +9772,8 @@ gen_mtp2type_abbrev(compiler_state_t *cstate, int type)
(cstate->linktype != DLT_MTP2_WITH_PHDR) )
bpf_error(cstate, "'hfisu' supported only on MTP2_HSL");
/* gen_ncmp(cstate, offrel, offset, size, mask, jtype, reverse, value) */
- b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, 0xff80, BPF_JEQ, 0, 0);
+ b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+ 0xff80U, BPF_JEQ, 0, 0U);
break;
case MH_LSSU:
@@ -9735,8 +9781,10 @@ gen_mtp2type_abbrev(compiler_state_t *cstate, int type)
(cstate->linktype != DLT_ERF) &&
(cstate->linktype != DLT_MTP2_WITH_PHDR) )
bpf_error(cstate, "'hlssu' supported only on MTP2_HSL");
- b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, 0xff80, BPF_JGT, 1, 0x0100);
- b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, 0xff80, BPF_JGT, 0, 0);
+ b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+ 0xff80U, BPF_JGT, 1, 0x0100U);
+ b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+ 0xff80U, BPF_JGT, 0, 0U);
gen_and(b1, b0);
break;
@@ -9745,7 +9793,8 @@ gen_mtp2type_abbrev(compiler_state_t *cstate, int type)
(cstate->linktype != DLT_ERF) &&
(cstate->linktype != DLT_MTP2_WITH_PHDR) )
bpf_error(cstate, "'hmsu' supported only on MTP2_HSL");
- b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, 0xff80, BPF_JGT, 0, 0x0100);
+ b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H,
+ 0xff80U, BPF_JGT, 0, 0x0100U);
break;
default:
@@ -9761,7 +9810,7 @@ gen_mtp2type_abbrev(compiler_state_t *cstate, int type)
*/
struct block *
gen_mtp3field_code(compiler_state_t *cstate, int mtp3field,
- bpf_u_int32 jvalue_arg, bpf_u_int32 jtype, int reverse)
+ bpf_u_int32 jvalue_arg, int jtype, int reverse)
{
volatile bpf_u_int32 jvalue = jvalue_arg;
struct block *b0;
@@ -9795,8 +9844,8 @@ gen_mtp3field_code(compiler_state_t *cstate, int mtp3field,
if(jvalue > 255)
bpf_error(cstate, "sio value %u too big; max value = 255",
jvalue);
- b0 = gen_ncmp(cstate, OR_PACKET, newoff_sio, BPF_B, 0xffffffff,
- (u_int)jtype, reverse, (u_int)jvalue);
+ b0 = gen_ncmp(cstate, OR_PACKET, newoff_sio, BPF_B, 0xffffffffU,
+ jtype, reverse, jvalue);
break;
case MH_OPC:
@@ -9819,8 +9868,8 @@ gen_mtp3field_code(compiler_state_t *cstate, int mtp3field,
val3 = jvalue & 0x00000003;
val3 = val3 <<22;
jvalue = val1 + val2 + val3;
- b0 = gen_ncmp(cstate, OR_PACKET, newoff_opc, BPF_W, 0x00c0ff0f,
- (u_int)jtype, reverse, (u_int)jvalue);
+ b0 = gen_ncmp(cstate, OR_PACKET, newoff_opc, BPF_W, 0x00c0ff0fU,
+ jtype, reverse, jvalue);
break;
case MH_DPC:
@@ -9841,8 +9890,8 @@ gen_mtp3field_code(compiler_state_t *cstate, int mtp3field,
val2 = jvalue & 0x00003f00;
val2 = val2 << 8;
jvalue = val1 + val2;
- b0 = gen_ncmp(cstate, OR_PACKET, newoff_dpc, BPF_W, 0xff3f0000,
- (u_int)jtype, reverse, (u_int)jvalue);
+ b0 = gen_ncmp(cstate, OR_PACKET, newoff_dpc, BPF_W, 0xff3f0000U,
+ jtype, reverse, jvalue);
break;
case MH_SLS:
@@ -9859,8 +9908,8 @@ gen_mtp3field_code(compiler_state_t *cstate, int mtp3field,
/* the following instruction is made to convert jvalue
* to the forme used to write sls in an ss7 message*/
jvalue = jvalue << 4;
- b0 = gen_ncmp(cstate, OR_PACKET, newoff_sls, BPF_B, 0xf0,
- (u_int)jtype,reverse, (u_int)jvalue);
+ b0 = gen_ncmp(cstate, OR_PACKET, newoff_sls, BPF_B, 0xf0U,
+ jtype, reverse, jvalue);
break;
default:
diff --git a/gencode.h b/gencode.h
index cc21e043..053e85f9 100644
--- a/gencode.h
+++ b/gencode.h
@@ -200,11 +200,14 @@
struct slist;
+/*
+ * A single statement, corresponding to an instruction in a block.
+ */
struct stmt {
- int code;
- struct slist *jt; /*only for relative jump in block*/
- struct slist *jf; /*only for relative jump in block*/
- bpf_int32 k;
+ int code; /* opcode */
+ struct slist *jt; /* only for relative jump in block */
+ struct slist *jf; /* only for relative jump in block */
+ bpf_u_int32 k; /* k field */
};
struct slist {
@@ -231,17 +234,27 @@ typedef bpf_u_int32 *uset;
*/
#define N_ATOMS (BPF_MEMWORDS+2)
+/*
+ * Control flow graph of a program.
+ * This corresponds to an edge in the CFG.
+ * It's a directed graph, so an edge has a predecessor and a successor.
+ */
struct edge {
- int id;
- int code;
+ u_int id;
+ int code; /* opcode for branch corresponding to this edge */
uset edom;
- struct block *succ;
- struct block *pred;
+ struct block *succ; /* successor vertex */
+ struct block *pred; /* predecessor vertex */
struct edge *next; /* link list of incoming edges for a node */
};
+/*
+ * A block is a vertex in the CFG.
+ * It has a list of statements, with the final statement being a
+ * branch to successor blocks.
+ */
struct block {
- int id;
+ u_int id;
struct slist *stmts; /* side effect stmts */
struct stmt s; /* branch stmt */
int mark;
@@ -250,18 +263,18 @@ struct block {
int level;
int offset;
int sense;
- struct edge et;
- struct edge ef;
+ struct edge et; /* edge corresponding to the jt branch */
+ struct edge ef; /* edge corresponding to the jf branch */
struct block *head;
struct block *link; /* link field used by optimizer */
uset dom;
uset closure;
- struct edge *in_edges;
+ struct edge *in_edges; /* first edge in the set (linked list) of edges with this as a successor */
atomset def, kill;
atomset in_use;
atomset out_use;
- int oval;
- int val[N_ATOMS];
+ int oval; /* value ID for value tested in branch stmt */
+ bpf_u_int32 val[N_ATOMS];
};
/*
@@ -286,8 +299,8 @@ struct _compiler_state;
typedef struct _compiler_state compiler_state_t;
-struct arth *gen_loadi(compiler_state_t *, int);
-struct arth *gen_load(compiler_state_t *, int, struct arth *, int);
+struct arth *gen_loadi(compiler_state_t *, bpf_u_int32);
+struct arth *gen_load(compiler_state_t *, int, struct arth *, bpf_u_int32);
struct arth *gen_loadlen(compiler_state_t *);
struct arth *gen_neg(compiler_state_t *, struct arth *);
struct arth *gen_arth(compiler_state_t *, int, struct arth *, struct arth *);
@@ -300,10 +313,10 @@ struct block *gen_scode(compiler_state_t *, const char *, struct qual);
struct block *gen_ecode(compiler_state_t *, const char *, struct qual);
struct block *gen_acode(compiler_state_t *, const char *, struct qual);
struct block *gen_mcode(compiler_state_t *, const char *, const char *,
- unsigned int, struct qual);
+ bpf_u_int32, struct qual);
#ifdef INET6
struct block *gen_mcode6(compiler_state_t *, const char *, const char *,
- unsigned int, struct qual);
+ bpf_u_int32, struct qual);
#endif
struct block *gen_ncode(compiler_state_t *, const char *, bpf_u_int32,
struct qual);
@@ -312,9 +325,10 @@ struct block *gen_relation(compiler_state_t *, int, struct arth *,
struct arth *, int);
struct block *gen_less(compiler_state_t *, int);
struct block *gen_greater(compiler_state_t *, int);
-struct block *gen_byteop(compiler_state_t *, int, int, int);
+struct block *gen_byteop(compiler_state_t *, int, int, bpf_u_int32);
struct block *gen_broadcast(compiler_state_t *, int);
struct block *gen_multicast(compiler_state_t *, int);
+struct block *gen_ifindex(compiler_state_t *, int);
struct block *gen_inbound(compiler_state_t *, int);
struct block *gen_llc(compiler_state_t *);
@@ -332,14 +346,14 @@ struct block *gen_pppoes(compiler_state_t *, bpf_u_int32, int);
struct block *gen_geneve(compiler_state_t *, bpf_u_int32, int);
-struct block *gen_atmfield_code(compiler_state_t *, int, bpf_int32,
- bpf_u_int32, int);
-struct block *gen_atmtype_abbrev(compiler_state_t *, int type);
-struct block *gen_atmmulti_abbrev(compiler_state_t *, int type);
+struct block *gen_atmfield_code(compiler_state_t *, int, bpf_u_int32,
+ int, int);
+struct block *gen_atmtype_abbrev(compiler_state_t *, int);
+struct block *gen_atmmulti_abbrev(compiler_state_t *, int);
-struct block *gen_mtp2type_abbrev(compiler_state_t *, int type);
+struct block *gen_mtp2type_abbrev(compiler_state_t *, int);
struct block *gen_mtp3field_code(compiler_state_t *, int, bpf_u_int32,
- bpf_u_int32, int);
+ int, int);
struct block *gen_pf_ifname(compiler_state_t *, const char *);
struct block *gen_pf_rnr(compiler_state_t *, int);
@@ -348,8 +362,8 @@ struct block *gen_pf_ruleset(compiler_state_t *, char *);
struct block *gen_pf_reason(compiler_state_t *, int);
struct block *gen_pf_action(compiler_state_t *, int);
-struct block *gen_p80211_type(compiler_state_t *, int, int);
-struct block *gen_p80211_fcdir(compiler_state_t *, int);
+struct block *gen_p80211_type(compiler_state_t *, bpf_u_int32, bpf_u_int32);
+struct block *gen_p80211_fcdir(compiler_state_t *, bpf_u_int32);
/*
* Representation of a program as a tree of blocks, plus current mark.
diff --git a/grammar.y b/grammar.y.in
index 32cb19c1..fe565155 100644
--- a/grammar.y
+++ b/grammar.y.in
@@ -1,7 +1,7 @@
/*
* We want a reentrant parser.
*/
-%pure-parser
+@REENTRANT_PARSER@
/*
* We also want a reentrant scanner, so we have to pass the
@@ -19,6 +19,27 @@
%lex-param {void *yyscanner}
/*
+ * According to bison documentation, shift/reduce conflicts are not an issue
+ * in most parsers as long as the number does not evolve over time:
+ * https://www.gnu.org/software/bison/manual/html_node/Expect-Decl.html
+ * So, following the advice use %expect to check the amount of shift/reduce
+ * warnings.
+ *
+ * This doesn't appear to work in Berkeley YACC - 1.9 20170709; it still
+ * warns of 38 shift/reduce conflicts.
+ *
+ * The Berkeley YACC documentation:
+ *
+ * https://invisible-island.net/byacc/manpage/yacc.html
+ *
+ * claims that "Bison's support for "%expect" is broken in more than one
+ * release.", but doesn't give details. Hopefully, that only means that
+ * you get warnings even if you have the expected number of shift/reduce
+ * conflicts, not that anything else fails.
+ */
+%expect 38
+
+/*
* And we need to pass the compiler state to the scanner.
*/
%parse-param { compiler_state_t *cstate }
@@ -210,8 +231,17 @@ str2tok(const char *str, const struct tok *toks)
int i;
for (i = 0; toks[i].s != NULL; i++) {
- if (pcap_strcasecmp(toks[i].s, str) == 0)
+ if (pcap_strcasecmp(toks[i].s, str) == 0) {
+ /*
+ * Just in case somebody is using this to
+ * generate values of -1/0xFFFFFFFF.
+ * That won't work, as it's indistinguishable
+ * from an error.
+ */
+ if (toks[i].v == -1)
+ abort();
return (toks[i].v);
+ }
}
return (-1);
}
@@ -235,7 +265,7 @@ pfreason_to_num(compiler_state_t *cstate, const char *reason)
if (pcap_strcasecmp(reason, reasons[i]) == 0)
return (i);
}
- bpf_set_error(cstate, "unknown PF reason");
+ bpf_set_error(cstate, "unknown PF reason \"%s\"", reason);
return (-1);
}
@@ -259,7 +289,7 @@ pfaction_to_num(compiler_state_t *cstate, const char *action)
return (PF_NORDR);
#endif
else {
- bpf_set_error(cstate, "unknown PF action");
+ bpf_set_error(cstate, "unknown PF action \"%s\"", action);
return (-1);
}
}
@@ -307,7 +337,8 @@ DIAG_OFF_BISON_BYACC
%type <blk> head
%type <i> pqual dqual aqual ndaqual
%type <a> arth narth
-%type <i> byteop pname pnum relop irelop
+%type <i> byteop pname relop irelop
+%type <h> pnum
%type <blk> and or paren not null prog
%type <rblk> other pfvar p80211 pllc
%type <i> atmtype atmmultitype
@@ -324,6 +355,7 @@ DIAG_OFF_BISON_BYACC
%token ATALK AARP DECNET LAT SCA MOPRC MOPDL
%token TK_BROADCAST TK_MULTICAST
%token NUM INBOUND OUTBOUND
+%token IFINDEX
%token PF_IFNAME PF_RSET PF_RNR PF_SRNR PF_REASON PF_ACTION
%token TYPE SUBTYPE DIR ADDR1 ADDR2 ADDR3 ADDR4 RA TA
%token LINK
@@ -348,7 +380,8 @@ DIAG_OFF_BISON_BYACC
%type <s> ID EID AID
%type <s> HID HID6
-%type <i> NUM action reason type subtype type_subtype dir
+%type <h> NUM
+%type <i> action reason type subtype type_subtype dir
%left OR AND
%nonassoc '!'
@@ -378,7 +411,7 @@ and: AND { $$ = $<blk>0; }
or: OR { $$ = $<blk>0; }
;
id: nid
- | pnum { CHECK_PTR_VAL(($$.b = gen_ncode(cstate, NULL, (bpf_u_int32)$1,
+ | pnum { CHECK_PTR_VAL(($$.b = gen_ncode(cstate, NULL, $1,
$$.q = $<blk>0.q))); }
| paren pid ')' { $$ = $2; }
;
@@ -392,17 +425,17 @@ nid: ID { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_scode(cstate, $1, $$.
/* Decide how to parse HID based on proto */
$$.q = $<blk>0.q;
if ($$.q.addr == Q_PORT) {
- bpf_set_error(cstate, "'port' modifier applied to ip host");
- YYABORT;
+ bpf_set_error(cstate, "'port' modifier applied to ip host");
+ YYABORT;
} else if ($$.q.addr == Q_PORTRANGE) {
- bpf_set_error(cstate, "'portrange' modifier applied to ip host");
- YYABORT;
+ bpf_set_error(cstate, "'portrange' modifier applied to ip host");
+ YYABORT;
} else if ($$.q.addr == Q_PROTO) {
- bpf_set_error(cstate, "'proto' modifier applied to ip host");
- YYABORT;
+ bpf_set_error(cstate, "'proto' modifier applied to ip host");
+ YYABORT;
} else if ($$.q.addr == Q_PROTOCHAIN) {
- bpf_set_error(cstate, "'protochain' modifier applied to ip host");
- YYABORT;
+ bpf_set_error(cstate, "'protochain' modifier applied to ip host");
+ YYABORT;
}
CHECK_PTR_VAL(($$.b = gen_ncode(cstate, $1, 0, $$.q)));
}
@@ -440,7 +473,7 @@ pid: nid
| qid and id { gen_and($1.b, $3.b); $$ = $3; }
| qid or id { gen_or($1.b, $3.b); $$ = $3; }
;
-qid: pnum { CHECK_PTR_VAL(($$.b = gen_ncode(cstate, NULL, (bpf_u_int32)$1,
+qid: pnum { CHECK_PTR_VAL(($$.b = gen_ncode(cstate, NULL, $1,
$$.q = $<blk>0.q))); }
| pid
;
@@ -514,7 +547,7 @@ pname: LINK { $$ = Q_LINK; }
| IGRP { $$ = Q_IGRP; }
| PIM { $$ = Q_PIM; }
| VRRP { $$ = Q_VRRP; }
- | CARP { $$ = Q_CARP; }
+ | CARP { $$ = Q_CARP; }
| ATALK { $$ = Q_ATALK; }
| AARP { $$ = Q_AARP; }
| DECNET { $$ = Q_DECNET; }
@@ -549,14 +582,15 @@ other: pqual TK_BROADCAST { CHECK_PTR_VAL(($$ = gen_broadcast(cstate, $1))); }
| CBYTE NUM byteop NUM { CHECK_PTR_VAL(($$ = gen_byteop(cstate, $3, $2, $4))); }
| INBOUND { CHECK_PTR_VAL(($$ = gen_inbound(cstate, 0))); }
| OUTBOUND { CHECK_PTR_VAL(($$ = gen_inbound(cstate, 1))); }
- | VLAN pnum { CHECK_PTR_VAL(($$ = gen_vlan(cstate, (bpf_u_int32)$2, 1))); }
+ | IFINDEX NUM { CHECK_PTR_VAL(($$ = gen_ifindex(cstate, $2))); }
+ | VLAN pnum { CHECK_PTR_VAL(($$ = gen_vlan(cstate, $2, 1))); }
| VLAN { CHECK_PTR_VAL(($$ = gen_vlan(cstate, 0, 0))); }
- | MPLS pnum { CHECK_PTR_VAL(($$ = gen_mpls(cstate, (bpf_u_int32)$2, 1))); }
+ | MPLS pnum { CHECK_PTR_VAL(($$ = gen_mpls(cstate, $2, 1))); }
| MPLS { CHECK_PTR_VAL(($$ = gen_mpls(cstate, 0, 0))); }
| PPPOED { CHECK_PTR_VAL(($$ = gen_pppoed(cstate))); }
- | PPPOES pnum { CHECK_PTR_VAL(($$ = gen_pppoes(cstate, (bpf_u_int32)$2, 1))); }
+ | PPPOES pnum { CHECK_PTR_VAL(($$ = gen_pppoes(cstate, $2, 1))); }
| PPPOES { CHECK_PTR_VAL(($$ = gen_pppoes(cstate, 0, 0))); }
- | GENEVE pnum { CHECK_PTR_VAL(($$ = gen_geneve(cstate, (bpf_u_int32)$2, 1))); }
+ | GENEVE pnum { CHECK_PTR_VAL(($$ = gen_geneve(cstate, $2, 1))); }
| GENEVE { CHECK_PTR_VAL(($$ = gen_geneve(cstate, 0, 0))); }
| pfvar { $$ = $1; }
| pqual p80211 { $$ = $2; }
@@ -586,27 +620,37 @@ p80211: TYPE type SUBTYPE subtype
| DIR dir { CHECK_PTR_VAL(($$ = gen_p80211_fcdir(cstate, $2))); }
;
-type: NUM
+type: NUM { if (($1 & (~IEEE80211_FC0_TYPE_MASK)) != 0) {
+ bpf_set_error(cstate, "invalid 802.11 type value 0x%02x", $1);
+ YYABORT;
+ }
+ $$ = (int)$1;
+ }
| ID { CHECK_PTR_VAL($1);
$$ = str2tok($1, ieee80211_types);
if ($$ == -1) {
- bpf_set_error(cstate, "unknown 802.11 type name");
- YYABORT;
+ bpf_set_error(cstate, "unknown 802.11 type name \"%s\"", $1);
+ YYABORT;
}
}
;
-subtype: NUM
+subtype: NUM { if (($1 & (~IEEE80211_FC0_SUBTYPE_MASK)) != 0) {
+ bpf_set_error(cstate, "invalid 802.11 subtype value 0x%02x", $1);
+ YYABORT;
+ }
+ $$ = (int)$1;
+ }
| ID { const struct tok *types = NULL;
int i;
CHECK_PTR_VAL($1);
for (i = 0;; i++) {
- if (ieee80211_type_subtypes[i].tok == NULL) {
- /* Ran out of types */
+ if (ieee80211_type_subtypes[i].tok == NULL) {
+ /* Ran out of types */
bpf_set_error(cstate, "unknown 802.11 type");
YYABORT;
}
- if ($<i>-1 == ieee80211_type_subtypes[i].type) {
+ if (-1 == ieee80211_type_subtypes[i].type) {
types = ieee80211_type_subtypes[i].tok;
break;
}
@@ -614,7 +658,7 @@ subtype: NUM
$$ = str2tok($1, types);
if ($$ == -1) {
- bpf_set_error(cstate, "unknown 802.11 subtype name");
+ bpf_set_error(cstate, "unknown 802.11 subtype name \"%s\"", $1);
YYABORT;
}
}
@@ -623,8 +667,8 @@ subtype: NUM
type_subtype: ID { int i;
CHECK_PTR_VAL($1);
for (i = 0;; i++) {
- if (ieee80211_type_subtypes[i].tok == NULL) {
- /* Ran out of types */
+ if (ieee80211_type_subtypes[i].tok == NULL) {
+ /* Ran out of types */
bpf_set_error(cstate, "unknown 802.11 type name");
YYABORT;
}
@@ -654,9 +698,9 @@ pllc: LLC { CHECK_PTR_VAL(($$ = gen_llc(cstate))); }
} else {
subtype = str2tok($2, llc_u_subtypes);
if (subtype == -1) {
- bpf_set_error(cstate, "unknown LLC type name \"%s\"", $2);
- YYABORT;
- }
+ bpf_set_error(cstate, "unknown LLC type name \"%s\"", $2);
+ YYABORT;
+ }
CHECK_PTR_VAL(($$ = gen_llc_u_subtype(cstate, subtype)));
}
}
@@ -665,7 +709,7 @@ pllc: LLC { CHECK_PTR_VAL(($$ = gen_llc(cstate))); }
| LLC PF_RNR { CHECK_PTR_VAL(($$ = gen_llc_s_subtype(cstate, LLC_RNR))); }
;
-dir: NUM
+dir: NUM { $$ = (int)$1; }
| ID { CHECK_PTR_VAL($1);
if (pcap_strcasecmp($1, "nods") == 0)
$$ = IEEE80211_FC1_DIR_NODS;
@@ -743,15 +787,15 @@ atmfield: VPI { $$.atmfieldtype = A_VPI; }
| VCI { $$.atmfieldtype = A_VCI; }
;
atmvalue: atmfieldvalue
- | relop NUM { CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $<blk>0.atmfieldtype, (bpf_int32)$2, (bpf_u_int32)$1, 0))); }
- | irelop NUM { CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $<blk>0.atmfieldtype, (bpf_int32)$2, (bpf_u_int32)$1, 1))); }
+ | relop NUM { CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $<blk>0.atmfieldtype, $2, $1, 0))); }
+ | irelop NUM { CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $<blk>0.atmfieldtype, $2, $1, 1))); }
| paren atmlistvalue ')' { $$.b = $2.b; $$.q = qerr; }
;
atmfieldvalue: NUM {
$$.atmfieldtype = $<blk>0.atmfieldtype;
if ($$.atmfieldtype == A_VPI ||
$$.atmfieldtype == A_VCI)
- CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $$.atmfieldtype, (bpf_int32) $1, BPF_JEQ, 0)));
+ CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $$.atmfieldtype, $1, BPF_JEQ, 0)));
}
;
atmlistvalue: atmfieldvalue
@@ -776,8 +820,8 @@ mtp3field: SIO { $$.mtp3fieldtype = M_SIO; }
| HSLS { $$.mtp3fieldtype = MH_SLS; }
;
mtp3value: mtp3fieldvalue
- | relop NUM { CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $<blk>0.mtp3fieldtype, (u_int)$2, (u_int)$1, 0))); }
- | irelop NUM { CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $<blk>0.mtp3fieldtype, (u_int)$2, (u_int)$1, 1))); }
+ | relop NUM { CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $<blk>0.mtp3fieldtype, $2, $1, 0))); }
+ | irelop NUM { CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $<blk>0.mtp3fieldtype, $2, $1, 1))); }
| paren mtp3listvalue ')' { $$.b = $2.b; $$.q = qerr; }
;
mtp3fieldvalue: NUM {
@@ -790,7 +834,7 @@ mtp3fieldvalue: NUM {
$$.mtp3fieldtype == MH_OPC ||
$$.mtp3fieldtype == MH_DPC ||
$$.mtp3fieldtype == MH_SLS)
- CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $$.mtp3fieldtype, (u_int) $1, BPF_JEQ, 0)));
+ CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $$.mtp3fieldtype, $1, BPF_JEQ, 0)));
}
;
mtp3listvalue: mtp3fieldvalue
diff --git a/lbl/os-osf4.h b/lbl/os-osf4.h
index 055eb80a..f461eeaf 100644
--- a/lbl/os-osf4.h
+++ b/lbl/os-osf4.h
@@ -20,7 +20,7 @@
*/
/* Prototypes missing in Digital UNIX 4.x */
-int pcap_snprintf(char *, size_t, const char *, ...);
-int pcap_vsnprintf(char *, size_t, const char *, va_list);
+int snprintf(char *, size_t, const char *, ...);
+int vsnprintf(char *, size_t, const char *, va_list);
int pfopen(char *, int);
diff --git a/lbl/os-osf5.h b/lbl/os-osf5.h
index 5422f18f..52ab1750 100644
--- a/lbl/os-osf5.h
+++ b/lbl/os-osf5.h
@@ -21,10 +21,10 @@
/*
* Prototypes missing in Tru64 UNIX 5.x
- * XXX - "pcap_snprintf()" and "pcap_vsnprintf()" aren't missing, but you have to
+ * XXX - "snprintf()" and "vsnprintf()" aren't missing, but you have to
* #define the right value to get them defined by <stdio.h>.
*/
-int pcap_snprintf(char *, size_t, const char *, ...);
-int pcap_vsnprintf(char *, size_t, const char *, va_list);
+int snprintf(char *, size_t, const char *, ...);
+int vsnprintf(char *, size_t, const char *, va_list);
int pfopen(char *, int);
diff --git a/lbl/os-solaris2.h b/lbl/os-solaris2.h
index a555f5ed..22948b4a 100644
--- a/lbl/os-solaris2.h
+++ b/lbl/os-solaris2.h
@@ -21,4 +21,4 @@
/* Prototypes missing in SunOS 5 */
char *strerror(int);
-int pcap_snprintf(char *, size_t, const char *, ...);
+int snprintf(char *, size_t, const char *, ...);
diff --git a/lbl/os-sunos4.h b/lbl/os-sunos4.h
index 6353fb09..ab032ef9 100644
--- a/lbl/os-sunos4.h
+++ b/lbl/os-sunos4.h
@@ -155,7 +155,7 @@ int sigsetmask(int);
struct sigvec;
#endif
int sigvec(int, struct sigvec *, struct sigvec*);
-int pcap_snprintf(char *, size_t, const char *, ...);
+int snprintf(char *, size_t, const char *, ...);
int socket(int, int, int);
int socketpair(int, int, int, int *);
int symlink(const char *, const char *);
diff --git a/missing/getopt.c b/missing/getopt.c
index 7c897c6f..c535776d 100644
--- a/missing/getopt.c
+++ b/missing/getopt.c
@@ -80,9 +80,18 @@ getopt(int nargc, char * const *nargv, const char *ostr)
place = EMSG;
return (-1);
}
- } /* option letter okay? */
- if ((optopt = (int)*place++) == (int)':' ||
- !(oli = strchr(ostr, optopt))) {
+ }
+ optopt = (int)*place++;
+ if (optopt == (int)':') { /* option letter okay? */
+ if (!*place)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: illegal option -- %c\n", __progname, optopt);
+ return (BADCH);
+ }
+ oli = strchr(ostr, optopt);
+ if (!oli) {
/*
* if the user didn't specify '-' as an option,
* assume it means -1.
@@ -114,7 +123,7 @@ getopt(int nargc, char * const *nargv, const char *ostr)
__progname, optopt);
return (BADCH);
}
- else /* white space */
+ else /* white space */
optarg = nargv[optind];
place = EMSG;
++optind;
diff --git a/missing/snprintf.c b/missing/snprintf.c
deleted file mode 100644
index 672aeb86..00000000
--- a/missing/snprintf.c
+++ /dev/null
@@ -1,631 +0,0 @@
-/*
- * Copyright (c) 1995-1999 Kungliga Tekniska Högskolan
- * (Royal Institute of Technology, Stockholm, Sweden).
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * 3. Neither the name of the Institute nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE 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.
- */
-
-/*
- * We use this for platforms that don't have snprintf() at all.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <sys/types.h>
-
-#include "portability.h"
-
-enum format_flags {
- minus_flag = 1,
- plus_flag = 2,
- space_flag = 4,
- alternate_flag = 8,
- zero_flag = 16
-};
-
-/*
- * Common state
- */
-
-struct state {
- unsigned char *str;
- unsigned char *s;
- unsigned char *theend;
- size_t sz;
- size_t max_sz;
- int (*append_char)(struct state *, unsigned char);
- int (*reserve)(struct state *, size_t);
- /* XXX - methods */
-};
-
-#ifndef HAVE_VSNPRINTF
-static int
-sn_reserve (struct state *state, size_t n)
-{
- return state->s + n > state->theend;
-}
-
-static int
-sn_append_char (struct state *state, unsigned char c)
-{
- if (sn_reserve (state, 1)) {
- return 1;
- } else {
- *state->s++ = c;
- return 0;
- }
-}
-#endif
-
-#if 0
-static int
-as_reserve (struct state *state, size_t n)
-{
- if (state->s + n > state->theend) {
- int off = state->s - state->str;
- unsigned char *tmp;
-
- if (state->max_sz && state->sz >= state->max_sz)
- return 1;
-
- state->sz = max(state->sz * 2, state->sz + n);
- if (state->max_sz)
- state->sz = min(state->sz, state->max_sz);
- tmp = realloc (state->str, state->sz);
- if (tmp == NULL)
- return 1;
- state->str = tmp;
- state->s = state->str + off;
- state->theend = state->str + state->sz - 1;
- }
- return 0;
-}
-
-static int
-as_append_char (struct state *state, unsigned char c)
-{
- if(as_reserve (state, 1))
- return 1;
- else {
- *state->s++ = c;
- return 0;
- }
-}
-#endif
-
-static int
-append_number(struct state *state,
- unsigned long num, unsigned base, char *rep,
- int width, int prec, int flags, int minusp)
-{
- int len = 0;
- int i;
-
- /* given precision, ignore zero flag */
- if(prec != -1)
- flags &= ~zero_flag;
- else
- prec = 1;
- /* zero value with zero precision -> "" */
- if(prec == 0 && num == 0)
- return 0;
- do{
- if((*state->append_char)(state, rep[num % base]))
- return 1;
- len++;
- num /= base;
- }while(num);
- prec -= len;
- /* pad with prec zeros */
- while(prec-- > 0){
- if((*state->append_char)(state, '0'))
- return 1;
- len++;
- }
- /* add length of alternate prefix (added later) to len */
- if(flags & alternate_flag && (base == 16 || base == 8))
- len += base / 8;
- /* pad with zeros */
- if(flags & zero_flag){
- width -= len;
- if(minusp || (flags & space_flag) || (flags & plus_flag))
- width--;
- while(width-- > 0){
- if((*state->append_char)(state, '0'))
- return 1;
- len++;
- }
- }
- /* add alternate prefix */
- if(flags & alternate_flag && (base == 16 || base == 8)){
- if(base == 16)
- if((*state->append_char)(state, rep[10] + 23)) /* XXX */
- return 1;
- if((*state->append_char)(state, '0'))
- return 1;
- }
- /* add sign */
- if(minusp){
- if((*state->append_char)(state, '-'))
- return 1;
- len++;
- } else if(flags & plus_flag) {
- if((*state->append_char)(state, '+'))
- return 1;
- len++;
- } else if(flags & space_flag) {
- if((*state->append_char)(state, ' '))
- return 1;
- len++;
- }
- if(flags & minus_flag)
- /* swap before padding with spaces */
- for(i = 0; i < len / 2; i++){
- char c = state->s[-i-1];
- state->s[-i-1] = state->s[-len+i];
- state->s[-len+i] = c;
- }
- width -= len;
- while(width-- > 0){
- if((*state->append_char)(state, ' '))
- return 1;
- len++;
- }
- if(!(flags & minus_flag))
- /* swap after padding with spaces */
- for(i = 0; i < len / 2; i++){
- char c = state->s[-i-1];
- state->s[-i-1] = state->s[-len+i];
- state->s[-len+i] = c;
- }
-
- return 0;
-}
-
-static int
-append_string (struct state *state,
- unsigned char *arg,
- int width,
- int prec,
- int flags)
-{
- if(prec != -1)
- width -= prec;
- else
- width -= strlen((char *)arg);
- if(!(flags & minus_flag))
- while(width-- > 0)
- if((*state->append_char) (state, ' '))
- return 1;
- if (prec != -1) {
- while (*arg && prec--)
- if ((*state->append_char) (state, *arg++))
- return 1;
- } else {
- while (*arg)
- if ((*state->append_char) (state, *arg++))
- return 1;
- }
- if(flags & minus_flag)
- while(width-- > 0)
- if((*state->append_char) (state, ' '))
- return 1;
- return 0;
-}
-
-static int
-append_char(struct state *state,
- unsigned char arg,
- int width,
- int flags)
-{
- while(!(flags & minus_flag) && --width > 0)
- if((*state->append_char) (state, ' '))
- return 1;
-
- if((*state->append_char) (state, arg))
- return 1;
- while((flags & minus_flag) && --width > 0)
- if((*state->append_char) (state, ' '))
- return 1;
-
- return 0;
-}
-
-/*
- * This can't be made into a function...
- */
-
-#define PARSE_INT_FORMAT(res, arg, unsig) \
-if (long_flag) \
- res = (unsig long)va_arg(arg, unsig long); \
-else if (short_flag) \
- res = (unsig short)va_arg(arg, unsig int); \
-else \
- res = (unsig int)va_arg(arg, unsig int)
-
-/*
- * zyxprintf - return 0 or -1
- */
-
-static int
-xyzprintf (struct state *state, const char *char_format, va_list ap)
-{
- const unsigned char *format = (const unsigned char *)char_format;
- unsigned char c;
-
- while((c = *format++)) {
- if (c == '%') {
- int flags = 0;
- int width = 0;
- int prec = -1;
- int long_flag = 0;
- int short_flag = 0;
-
- /* flags */
- while((c = *format++)){
- if(c == '-')
- flags |= minus_flag;
- else if(c == '+')
- flags |= plus_flag;
- else if(c == ' ')
- flags |= space_flag;
- else if(c == '#')
- flags |= alternate_flag;
- else if(c == '0')
- flags |= zero_flag;
- else
- break;
- }
-
- if((flags & space_flag) && (flags & plus_flag))
- flags ^= space_flag;
-
- if((flags & minus_flag) && (flags & zero_flag))
- flags ^= zero_flag;
-
- /* width */
- if (isdigit(c))
- do {
- width = width * 10 + c - '0';
- c = *format++;
- } while(isdigit(c));
- else if(c == '*') {
- width = va_arg(ap, int);
- c = *format++;
- }
-
- /* precision */
- if (c == '.') {
- prec = 0;
- c = *format++;
- if (isdigit(c))
- do {
- prec = prec * 10 + c - '0';
- c = *format++;
- } while(isdigit(c));
- else if (c == '*') {
- prec = va_arg(ap, int);
- c = *format++;
- }
- }
-
- /* size */
-
- if (c == 'h') {
- short_flag = 1;
- c = *format++;
- } else if (c == 'l') {
- long_flag = 1;
- c = *format++;
- }
-
- switch (c) {
- case 'c' :
- if(append_char(state, va_arg(ap, int), width, flags))
- return -1;
- break;
- case 's' :
- if (append_string(state,
- va_arg(ap, unsigned char*),
- width,
- prec,
- flags))
- return -1;
- break;
- case 'd' :
- case 'i' : {
- long arg;
- unsigned long num;
- int minusp = 0;
-
- PARSE_INT_FORMAT(arg, ap, signed);
-
- if (arg < 0) {
- minusp = 1;
- num = -arg;
- } else
- num = arg;
-
- if (append_number (state, num, 10, "0123456789",
- width, prec, flags, minusp))
- return -1;
- break;
- }
- case 'u' : {
- unsigned long arg;
-
- PARSE_INT_FORMAT(arg, ap, unsigned);
-
- if (append_number (state, arg, 10, "0123456789",
- width, prec, flags, 0))
- return -1;
- break;
- }
- case 'o' : {
- unsigned long arg;
-
- PARSE_INT_FORMAT(arg, ap, unsigned);
-
- if (append_number (state, arg, 010, "01234567",
- width, prec, flags, 0))
- return -1;
- break;
- }
- case 'x' : {
- unsigned long arg;
-
- PARSE_INT_FORMAT(arg, ap, unsigned);
-
- if (append_number (state, arg, 0x10, "0123456789abcdef",
- width, prec, flags, 0))
- return -1;
- break;
- }
- case 'X' :{
- unsigned long arg;
-
- PARSE_INT_FORMAT(arg, ap, unsigned);
-
- if (append_number (state, arg, 0x10, "0123456789ABCDEF",
- width, prec, flags, 0))
- return -1;
- break;
- }
- case 'p' : {
- unsigned long arg = (unsigned long)va_arg(ap, void*);
-
- if (append_number (state, arg, 0x10, "0123456789ABCDEF",
- width, prec, flags, 0))
- return -1;
- break;
- }
- case 'n' : {
- int *arg = va_arg(ap, int*);
- *arg = state->s - state->str;
- break;
- }
- case '\0' :
- --format;
- /* FALLTHROUGH */
- case '%' :
- if ((*state->append_char)(state, c))
- return -1;
- break;
- default :
- if ( (*state->append_char)(state, '%')
- || (*state->append_char)(state, c))
- return -1;
- break;
- }
- } else
- if ((*state->append_char) (state, c))
- return -1;
- }
- return 0;
-}
-
-#ifndef HAVE_SNPRINTF
-int
-pcap_snprintf (char *str, size_t sz, const char *format, ...)
-{
- va_list args;
- int ret;
-
- va_start(args, format);
- ret = pcap_vsnprintf (str, sz, format, args);
-
-#ifdef PARANOIA
- {
- int ret2;
- char *tmp;
-
- tmp = malloc (sz);
- if (tmp == NULL)
- abort ();
-
- ret2 = pcap_vsprintf (tmp, format, args);
- if (ret != ret2 || strcmp(str, tmp))
- abort ();
- free (tmp);
- }
-#endif
-
- va_end(args);
- return ret;
-}
-#endif
-
-#if 0
-#ifndef HAVE_ASPRINTF
-int
-asprintf (char **ret, const char *format, ...)
-{
- va_list args;
- int val;
-
- va_start(args, format);
- val = vasprintf (ret, format, args);
-
-#ifdef PARANOIA
- {
- int ret2;
- char *tmp;
- tmp = malloc (val + 1);
- if (tmp == NULL)
- abort ();
-
- ret2 = vsprintf (tmp, format, args);
- if (val != ret2 || strcmp(*ret, tmp))
- abort ();
- free (tmp);
- }
-#endif
-
- va_end(args);
- return val;
-}
-#endif
-
-#ifndef HAVE_ASNPRINTF
-int
-pcap_asnprintf (char **ret, size_t max_sz, const char *format, ...)
-{
- va_list args;
- int val;
-
- va_start(args, format);
- val = pcap_vasnprintf (ret, max_sz, format, args);
- va_end(args);
-
-#ifdef PARANOIA
- {
- int ret2;
- char *tmp;
- tmp = malloc (val + 1);
- if (tmp == NULL)
- abort ();
-
- va_start(args, format);
- ret2 = pcap_vsprintf (tmp, format, args);
- va_end(args);
- if (val != ret2 || strcmp(*ret, tmp))
- abort ();
- free (tmp);
- }
-#endif
-
- return val;
-}
-#endif
-
-#ifndef HAVE_VASPRINTF
-int
-pcap_vasprintf (char **ret, const char *format, va_list args)
-{
- return pcap_vasnprintf (ret, 0, format, args);
-}
-#endif
-
-
-#ifndef HAVE_VASNPRINTF
-int
-pcap_vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
-{
- int st;
- size_t len;
- struct state state;
-
- state.max_sz = max_sz;
- state.sz = 1;
- state.str = malloc(state.sz);
- if (state.str == NULL) {
- *ret = NULL;
- return -1;
- }
- state.s = state.str;
- state.theend = state.s + state.sz - 1;
- state.append_char = as_append_char;
- state.reserve = as_reserve;
-
- st = xyzprintf (&state, format, args);
- if (st) {
- free (state.str);
- *ret = NULL;
- return -1;
- } else {
- char *tmp;
-
- *state.s = '\0';
- len = state.s - state.str;
- tmp = realloc (state.str, len+1);
- if (tmp == NULL) {
- free (state.str);
- *ret = NULL;
- return -1;
- }
- *ret = tmp;
- return len;
- }
-}
-#endif
-#endif
-
-#ifndef HAVE_VSNPRINTF
-int
-pcap_vsnprintf (char *str, size_t sz, const char *format, va_list args)
-{
- struct state state;
- int ret;
- unsigned char *ustr = (unsigned char *)str;
-
- state.max_sz = 0;
- state.sz = sz;
- state.str = ustr;
- state.s = ustr;
- state.theend = ustr + sz - 1;
- state.append_char = sn_append_char;
- state.reserve = sn_reserve;
-
- ret = xyzprintf (&state, format, args);
- *state.s = '\0';
- if (ret)
- return sz;
- else
- return state.s - state.str;
-}
-#endif
-
diff --git a/missing/win_asprintf.c b/missing/win_asprintf.c
index cce62960..e4bd13c6 100644
--- a/missing/win_asprintf.c
+++ b/missing/win_asprintf.c
@@ -23,7 +23,7 @@ pcap_vasprintf(char **strp, const char *format, va_list args)
*strp = NULL;
return (-1);
}
- ret = pcap_vsnprintf(str, str_size, format, args);
+ ret = vsnprintf(str, str_size, format, args);
if (ret == -1) {
free(str);
*strp = NULL;
@@ -31,7 +31,7 @@ pcap_vasprintf(char **strp, const char *format, va_list args)
}
*strp = str;
/*
- * pcap_vsnprintf() shouldn't truncate the string, as we have
+ * vsnprintf() shouldn't truncate the string, as we have
* allocated a buffer large enough to hold the string, so its
* return value should be the number of characters printed.
*/
diff --git a/missing/win_snprintf.c b/missing/win_snprintf.c
deleted file mode 100644
index f4224035..00000000
--- a/missing/win_snprintf.c
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <stdio.h>
-#include <stdarg.h>
-
-#include "portability.h"
-
-int
-pcap_vsnprintf(char *str, size_t str_size, const char *format, va_list args)
-{
- int ret;
-
- ret = _vsnprintf_s(str, str_size, _TRUNCATE, format, args);
-
- /*
- * XXX - _vsnprintf() and _snprintf() do *not* guarantee
- * that str is null-terminated, but C99's vsnprintf()
- * and snprintf() do, and we want to offer C99 behavior,
- * so forcibly null-terminate the string.
- *
- * We don't, however, offer C99 behavior for the return
- * value; _vsnprintf_s() returns -1, not the number of
- * characters that would have been put into the buffer
- * had it been large enough, if the string is truncated.
- * The only way to get that value is to use _vscprintf();
- * getting that count isn't worth the re-formatting.
- *
- * XXX - does _vsnprintf_s() return -1 on a formatting
- * error?
- */
- str[str_size - 1] = '\0';
- return (ret);
-}
-
-int
-pcap_snprintf(char *str, size_t str_size, const char *format, ...)
-{
- va_list args;
- int ret;
-
- va_start(args, format);
- ret = pcap_vsnprintf(str, str_size, format, args);
- va_end(args);
- return (ret);
-}
diff --git a/mkdep b/mkdep
index 1486b185..6e8dbd6f 100755
--- a/mkdep
+++ b/mkdep
@@ -16,7 +16,10 @@
MAKE=Makefile # default makefile name is "Makefile"
CC=cc # default C compiler is "cc"
DEPENDENCY_CFLAG=-M # default dependency-generation flag is -M
+SOURCE_DIRECTORY=. # default source directory is the current directory
+# No command-line flags seen yet.
+flags=""
while :
do case "$1" in
# -c allows you to specify the C compiler
@@ -39,13 +42,29 @@ while :
-p)
SED='s;\.o;;'
shift ;;
+
+ # -s allows you to specify the source directory
+ -s)
+ SOURCE_DIRECTORY=$2
+ shift; shift ;;
+
+ # -include takes an argument
+ -include)
+ flags="$flags $1 $2"
+ shift; shift ;;
+
+ # other command-line flag
+ -*)
+ flags="$flags $1"
+ shift ;;
+
*)
break ;;
esac
done
if [ $# = 0 ] ; then
- echo 'usage: mkdep [-p] [-c cc] [-f makefile] [-m dependency-cflag] [flags] file ...'
+ echo 'usage: mkdep [-p] [-c cc] [-f makefile] [-m dependency-cflag] [-s source-directory] [flags] file ...'
exit 1
fi
@@ -76,8 +95,17 @@ _EOF_
# egrep '^#include[ ]*".*"' /dev/null $* |
# sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' -e 's/\.c/.o/' |
+#
+# Construct a list of source files with paths relative to the source directory.
+#
+sources=""
+for srcfile in $*
+do
+ sources="$sources $SOURCE_DIRECTORY/$srcfile"
+done
+
# XXX this doesn't work with things like "-DDECLWAITSTATUS=union\ wait"
-$CC $DEPENDENCY_CFLAG $* |
+$CC $DEPENDENCY_CFLAG $flags $sources |
sed "
s; \./; ;g
$SED" |
diff --git a/msdos/readme.dos b/msdos/readme.dos
index b95483fc..ec056dd0 100644
--- a/msdos/readme.dos
+++ b/msdos/readme.dos
@@ -24,7 +24,7 @@ Note for djgpp users:
If you got the libpcap from the official site www.tcpdump, then that
distribution does NOT contain any sources for building 32-bit drivers.
Instead get the full version at
- http://www.watt-32.net/pcap/libpcap.zip
+ https://www.watt-32.net/pcap/libpcap.zip
and set "USE_32BIT_DRIVERS = 1" in msdos\common.dj.
@@ -51,12 +51,12 @@ The following packages and tools must be present for all targets.
receive network data. It's mostly used to access the 'hosts'
file and other <netdb.h> features. Get 'watt32s*.zip' at:
- http://www.watt-32.net
+ https://www.watt-32.net
2. Exception handler and disassember library (libexc.a) is needed if
"USE_EXCEPT = 1" in common.dj. Available at:
- http://www.watt-32.net/misc/exc_dx07.zip
+ https://www.watt-32.net/misc/exc_dx07.zip
3. Flex & Bison is used to generate parser for the filter handler
pcap_compile:
@@ -65,7 +65,7 @@ The following packages and tools must be present for all targets.
4. NASM assembler v 0.98 or later is required when building djgpp and
Watcom targets:
- http://www.nasm.us/
+ https://www.nasm.us/
5. sed (Stream Editor) is required for doing `make depend'.
It's available at:
diff --git a/nametoaddr.c b/nametoaddr.c
index 7c48bd3a..c944ad36 100644
--- a/nametoaddr.c
+++ b/nametoaddr.c
@@ -127,7 +127,6 @@
#include <netdb.h>
#endif /* _WIN32 */
-#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
@@ -135,6 +134,8 @@
#include "pcap-int.h"
+#include "diag-control.h"
+
#include "gencode.h"
#include <pcap/namedb.h>
#include "nametoaddr.h"
@@ -162,7 +163,23 @@ pcap_nametoaddr(const char *name)
bpf_u_int32 **p;
struct hostent *hp;
+ /*
+ * gethostbyname() is deprecated on Windows, perhaps because
+ * it's not thread-safe, or because it doesn't support IPv6,
+ * or both.
+ *
+ * We deprecate pcap_nametoaddr() on all platforms because
+ * it's not thread-safe; we supply it for backwards compatibility,
+ * so suppress the deprecation warning. We could, I guess,
+ * use getaddrinfo() and construct the array ourselves, but
+ * that's probably not worth the effort, as that wouldn't make
+ * this thread-safe - we can't change the API to require that
+ * our caller free the address array, so we still have to reuse
+ * a local array.
+ */
+DIAG_OFF_DEPRECATION
if ((hp = gethostbyname(name)) != NULL) {
+DIAG_ON_DEPRECATION
#ifndef h_addr
hlist[0] = (bpf_u_int32 *)hp->h_addr;
NTOHL(hp->h_addr);
@@ -200,10 +217,10 @@ pcap_nametoaddrinfo(const char *name)
* XXX - not guaranteed to be thread-safe! See below for platforms
* on which it is thread-safe and on which it isn't.
*/
+#if defined(_WIN32) || defined(__CYGWIN__)
bpf_u_int32
-pcap_nametonetaddr(const char *name)
+pcap_nametonetaddr(const char *name _U_)
{
-#ifdef _WIN32
/*
* There's no "getnetbyname()" on Windows.
*
@@ -217,7 +234,11 @@ pcap_nametonetaddr(const char *name)
* of *UN*X* machines.)
*/
return 0;
-#else
+}
+#else /* _WIN32 */
+bpf_u_int32
+pcap_nametonetaddr(const char *name)
+{
/*
* UN*X.
*/
@@ -291,8 +312,8 @@ pcap_nametonetaddr(const char *name)
return np->n_net;
else
return 0;
-#endif /* _WIN32 */
}
+#endif /* _WIN32 */
/*
* Convert a port name to its port and protocol numbers.
@@ -569,28 +590,20 @@ struct eproto {
*/
PCAP_API struct eproto eproto_db[];
PCAP_API_DEF struct eproto eproto_db[] = {
- { "pup", ETHERTYPE_PUP },
- { "xns", ETHERTYPE_NS },
+ { "aarp", ETHERTYPE_AARP },
+ { "arp", ETHERTYPE_ARP },
+ { "atalk", ETHERTYPE_ATALK },
+ { "decnet", ETHERTYPE_DN },
{ "ip", ETHERTYPE_IP },
#ifdef INET6
{ "ip6", ETHERTYPE_IPV6 },
#endif
- { "arp", ETHERTYPE_ARP },
- { "rarp", ETHERTYPE_REVARP },
- { "sprite", ETHERTYPE_SPRITE },
+ { "lat", ETHERTYPE_LAT },
+ { "loopback", ETHERTYPE_LOOPBACK },
{ "mopdl", ETHERTYPE_MOPDL },
{ "moprc", ETHERTYPE_MOPRC },
- { "decnet", ETHERTYPE_DN },
- { "lat", ETHERTYPE_LAT },
+ { "rarp", ETHERTYPE_REVARP },
{ "sca", ETHERTYPE_SCA },
- { "lanbridge", ETHERTYPE_LANBRIDGE },
- { "vexp", ETHERTYPE_VEXP },
- { "vprod", ETHERTYPE_VPROD },
- { "atalk", ETHERTYPE_ATALK },
- { "atalkarp", ETHERTYPE_AARP },
- { "loopback", ETHERTYPE_LOOPBACK },
- { "decdts", ETHERTYPE_DECDTS },
- { "decdns", ETHERTYPE_DECDNS },
{ (char *)0, 0 }
};
@@ -635,9 +648,9 @@ pcap_nametollc(const char *s)
static inline u_char
xdtoi(u_char c)
{
- if (isdigit(c))
+ if (c >= '0' && c <= '9')
return (u_char)(c - '0');
- else if (islower(c))
+ else if (c >= 'a' && c <= 'f')
return (u_char)(c - 'a' + 10);
else
return (u_char)(c - 'A' + 10);
@@ -653,8 +666,15 @@ __pcap_atoin(const char *s, bpf_u_int32 *addr)
len = 0;
for (;;) {
n = 0;
- while (*s && *s != '.')
+ while (*s && *s != '.') {
+ if (n > 25) {
+ /* The result will be > 255 */
+ return -1;
+ }
n = n * 10 + *s++ - '0';
+ }
+ if (n > 255)
+ return -1;
*addr <<= 8;
*addr |= n & 0xff;
len += 8;
@@ -709,7 +729,7 @@ pcap_ether_aton(const char *s)
if (*s == ':' || *s == '.' || *s == '-')
s += 1;
d = xdtoi(*s++);
- if (isxdigit((unsigned char)*s)) {
+ if (PCAP_ISXDIGIT(*s)) {
d <<= 4;
d |= xdtoi(*s++);
}
diff --git a/optimize.c b/optimize.c
index 448452d2..610a0303 100644
--- a/optimize.c
+++ b/optimize.c
@@ -103,7 +103,7 @@ pcap_set_print_dot_graph(int value)
* Takes a 32-bit integer as an argument.
*
* If handed a non-zero value, returns the index of the lowest set bit,
- * counting upwards fro zero.
+ * counting upwards from zero.
*
* If handed zero, the results are platform- and compiler-dependent.
* Keep it out of the light, don't give it any water, don't feed it
@@ -115,7 +115,7 @@ pcap_set_print_dot_graph(int value)
/*
* GCC 3.4 and later; we have __builtin_ctz().
*/
- #define lowest_set_bit(mask) __builtin_ctz(mask)
+ #define lowest_set_bit(mask) ((u_int)__builtin_ctz(mask))
#elif defined(_MSC_VER)
/*
* Visual Studio; we support only 2005 and later, so use
@@ -127,7 +127,7 @@ pcap_set_print_dot_graph(int value)
#pragma intrinsic(_BitScanForward)
#endif
-static __forceinline int
+static __forceinline u_int
lowest_set_bit(int mask)
{
unsigned long bit;
@@ -137,15 +137,15 @@ lowest_set_bit(int mask)
* (It's currently not, in MSVC, even on 64-bit platforms, but....)
*/
if (_BitScanForward(&bit, (unsigned int)mask) == 0)
- return -1; /* mask is zero */
- return (int)bit;
+ abort(); /* mask is zero */
+ return (u_int)bit;
}
#elif defined(MSDOS) && defined(__DJGPP__)
/*
* MS-DOS with DJGPP, which declares ffs() in <string.h>, which
* we've already included.
*/
- #define lowest_set_bit(mask) (ffs((mask)) - 1)
+ #define lowest_set_bit(mask) ((u_int)(ffs((mask)) - 1))
#elif (defined(MSDOS) && defined(__WATCOMC__)) || defined(STRINGS_H_DECLARES_FFS)
/*
* MS-DOS with Watcom C, which has <strings.h> and declares ffs() there,
@@ -153,18 +153,18 @@ lowest_set_bit(int mask)
* of the Single UNIX Specification).
*/
#include <strings.h>
- #define lowest_set_bit(mask) (ffs((mask)) - 1)
+ #define lowest_set_bit(mask) (u_int)((ffs((mask)) - 1))
#else
/*
* None of the above.
* Use a perfect-hash-function-based function.
*/
-static int
+static u_int
lowest_set_bit(int mask)
{
unsigned int v = (unsigned int)mask;
- static const int MultiplyDeBruijnBitPosition[32] = {
+ static const u_int MultiplyDeBruijnBitPosition[32] = {
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
@@ -213,17 +213,17 @@ lowest_set_bit(int mask)
*/
struct valnode {
int code;
- int v0, v1;
- int val;
+ bpf_u_int32 v0, v1;
+ int val; /* the value number */
struct valnode *next;
};
/* Integer constants mapped with the load immediate opcode. */
-#define K(i) F(opt_state, BPF_LD|BPF_IMM|BPF_W, i, 0L)
+#define K(i) F(opt_state, BPF_LD|BPF_IMM|BPF_W, i, 0U)
struct vmapinfo {
int is_const;
- bpf_int32 const_val;
+ bpf_u_int32 const_val;
};
typedef struct {
@@ -240,21 +240,34 @@ typedef struct {
/*
* A flag to indicate that further optimization is needed.
* Iterative passes are continued until a given pass yields no
- * branch movement.
+ * code simplification or branch movement.
*/
int done;
- int n_blocks;
+ /*
+ * XXX - detect loops that do nothing but repeated AND/OR pullups
+ * and edge moves.
+ * If 100 passes in a row do nothing but that, treat that as a
+ * sign that we're in a loop that just shuffles in a cycle in
+ * which each pass just shuffles the code and we eventually
+ * get back to the original configuration.
+ *
+ * XXX - we need a non-heuristic way of detecting, or preventing,
+ * such a cycle.
+ */
+ int non_branch_movement_performed;
+
+ u_int n_blocks; /* number of blocks in the CFG; guaranteed to be > 0, as it's a RET instruction at a minimum */
struct block **blocks;
- int n_edges;
+ u_int n_edges; /* twice n_blocks, so guaranteed to be > 0 */
struct edge **edges;
/*
* A bit vector set representation of the dominators.
* We round up the set size to the next power of two.
*/
- int nodewords;
- int edgewords;
+ u_int nodewords; /* number of 32-bit words for a bit vector of "number of nodes" bits; guaranteed to be > 0 */
+ u_int edgewords; /* number of 32-bit words for a bit vector of "number of edges" bits; guaranteed to be > 0 */
struct block **levels;
bpf_u_int32 *space;
@@ -279,32 +292,35 @@ typedef struct {
/*
* a := a intersect b
+ * n must be guaranteed to be > 0
*/
#define SET_INTERSECT(a, b, n)\
{\
register bpf_u_int32 *_x = a, *_y = b;\
- register int _n = n;\
- while (--_n >= 0) *_x++ &= *_y++;\
+ register u_int _n = n;\
+ do *_x++ &= *_y++; while (--_n != 0);\
}
/*
* a := a - b
+ * n must be guaranteed to be > 0
*/
#define SET_SUBTRACT(a, b, n)\
{\
register bpf_u_int32 *_x = a, *_y = b;\
- register int _n = n;\
- while (--_n >= 0) *_x++ &=~ *_y++;\
+ register u_int _n = n;\
+ do *_x++ &=~ *_y++; while (--_n != 0);\
}
/*
* a := a union b
+ * n must be guaranteed to be > 0
*/
#define SET_UNION(a, b, n)\
{\
register bpf_u_int32 *_x = a, *_y = b;\
- register int _n = n;\
- while (--_n >= 0) *_x++ |= *_y++;\
+ register u_int _n = n;\
+ do *_x++ |= *_y++; while (--_n != 0);\
}
uset all_dom_sets;
@@ -313,8 +329,8 @@ typedef struct {
#define MODULUS 213
struct valnode *hashtbl[MODULUS];
- int curval;
- int maxval;
+ bpf_u_int32 curval;
+ bpf_u_int32 maxval;
struct vmapinfo *vmap;
struct valnode *vnode_base;
@@ -401,7 +417,8 @@ find_levels(opt_state_t *opt_state, struct icode *ic)
static void
find_dom(opt_state_t *opt_state, struct block *root)
{
- int i;
+ u_int i;
+ int level;
struct block *b;
bpf_u_int32 *x;
@@ -409,16 +426,23 @@ find_dom(opt_state_t *opt_state, struct block *root)
* Initialize sets to contain all nodes.
*/
x = opt_state->all_dom_sets;
+ /*
+ * In opt_init(), we've made sure the product doesn't overflow.
+ */
i = opt_state->n_blocks * opt_state->nodewords;
- while (--i >= 0)
+ while (i != 0) {
+ --i;
*x++ = 0xFFFFFFFFU;
+ }
/* Root starts off empty. */
- for (i = opt_state->nodewords; --i >= 0;)
+ for (i = opt_state->nodewords; i != 0;) {
+ --i;
root->dom[i] = 0;
+ }
/* root->level is the highest level no found. */
- for (i = root->level; i >= 0; --i) {
- for (b = opt_state->levels[i]; b; b = b->link) {
+ for (level = root->level; level >= 0; --level) {
+ for (b = opt_state->levels[level]; b; b = b->link) {
SET_INSERT(b->dom, b->id);
if (JT(b) == 0)
continue;
@@ -445,19 +469,25 @@ propedom(opt_state_t *opt_state, struct edge *ep)
static void
find_edom(opt_state_t *opt_state, struct block *root)
{
- int i;
+ u_int i;
uset x;
+ int level;
struct block *b;
x = opt_state->all_edge_sets;
- for (i = opt_state->n_edges * opt_state->edgewords; --i >= 0; )
+ /*
+ * In opt_init(), we've made sure the product doesn't overflow.
+ */
+ for (i = opt_state->n_edges * opt_state->edgewords; i != 0; ) {
+ --i;
x[i] = 0xFFFFFFFFU;
+ }
/* root->level is the highest level no found. */
memset(root->et.edom, 0, opt_state->edgewords * sizeof(*(uset)0));
memset(root->ef.edom, 0, opt_state->edgewords * sizeof(*(uset)0));
- for (i = root->level; i >= 0; --i) {
- for (b = opt_state->levels[i]; b != 0; b = b->link) {
+ for (level = root->level; level >= 0; --level) {
+ for (b = opt_state->levels[level]; b != 0; b = b->link) {
propedom(opt_state, &b->et);
propedom(opt_state, &b->ef);
}
@@ -474,7 +504,7 @@ find_edom(opt_state_t *opt_state, struct block *root)
static void
find_closure(opt_state_t *opt_state, struct block *root)
{
- int i;
+ int level;
struct block *b;
/*
@@ -484,8 +514,8 @@ find_closure(opt_state_t *opt_state, struct block *root)
opt_state->n_blocks * opt_state->nodewords * sizeof(*opt_state->all_closure_sets));
/* root->level is the highest level no found. */
- for (i = root->level; i >= 0; --i) {
- for (b = opt_state->levels[i]; b; b = b->link) {
+ for (level = root->level; level >= 0; --level) {
+ for (b = opt_state->levels[level]; b; b = b->link) {
SET_INSERT(b->closure, b->id);
if (JT(b) == 0)
continue;
@@ -496,8 +526,11 @@ find_closure(opt_state_t *opt_state, struct block *root)
}
/*
- * Return the register number that is used by s. If A and X are both
- * used, return AX_ATOM. If no register is used, return -1.
+ * Return the register number that is used by s.
+ *
+ * Returns ATOM_A if A is used, ATOM_X if X is used, AX_ATOM if both A and X
+ * are used, the scratch memory location's number if a scratch memory
+ * location is used (e.g., 0 for M[0]), or -1 if none of those are used.
*
* The implementation should probably change to an array access.
*/
@@ -517,8 +550,12 @@ atomuse(struct stmt *s)
case BPF_LD:
case BPF_LDX:
+ /*
+ * As there are fewer than 2^31 memory locations,
+ * s->k should be convertible to int without problems.
+ */
return (BPF_MODE(c) == BPF_IND) ? X_ATOM :
- (BPF_MODE(c) == BPF_MEM) ? s->k : -1;
+ (BPF_MODE(c) == BPF_MEM) ? (int)s->k : -1;
case BPF_ST:
return A_ATOM;
@@ -676,21 +713,40 @@ init_val(opt_state_t *opt_state)
memset((char *)opt_state->hashtbl, 0, sizeof opt_state->hashtbl);
}
-/* Because we really don't have an IR, this stuff is a little messy. */
-static int
-F(opt_state_t *opt_state, int code, int v0, int v1)
+/*
+ * Because we really don't have an IR, this stuff is a little messy.
+ *
+ * This routine looks in the table of existing value number for a value
+ * with generated from an operation with the specified opcode and
+ * the specified values. If it finds it, it returns its value number,
+ * otherwise it makes a new entry in the table and returns the
+ * value number of that entry.
+ */
+static bpf_u_int32
+F(opt_state_t *opt_state, int code, bpf_u_int32 v0, bpf_u_int32 v1)
{
u_int hash;
- int val;
+ bpf_u_int32 val;
struct valnode *p;
- hash = (u_int)code ^ ((u_int)v0 << 4) ^ ((u_int)v1 << 8);
+ hash = (u_int)code ^ (v0 << 4) ^ (v1 << 8);
hash %= MODULUS;
for (p = opt_state->hashtbl[hash]; p; p = p->next)
if (p->code == code && p->v0 == v0 && p->v1 == v1)
return p->val;
+ /*
+ * Not found. Allocate a new value, and assign it a new
+ * value number.
+ *
+ * opt_state->curval starts out as 0, which means VAL_UNKNOWN; we
+ * increment it before using it as the new value number, which
+ * means we never assign VAL_UNKNOWN.
+ *
+ * XXX - unless we overflow, but we probably won't have 2^32-1
+ * values; we treat 32 bits as effectively infinite.
+ */
val = ++opt_state->curval;
if (BPF_MODE(code) == BPF_IMM &&
(BPF_CLASS(code) == BPF_LD || BPF_CLASS(code) == BPF_LDX)) {
@@ -709,7 +765,7 @@ F(opt_state_t *opt_state, int code, int v0, int v1)
}
static inline void
-vstore(struct stmt *s, int *valp, int newval, int alter)
+vstore(struct stmt *s, bpf_u_int32 *valp, bpf_u_int32 newval, int alter)
{
if (alter && newval != VAL_UNKNOWN && *valp == newval)
s->code = NOP;
@@ -722,7 +778,7 @@ vstore(struct stmt *s, int *valp, int newval, int alter)
* (Unary operators are handled elsewhere.)
*/
static void
-fold_op(opt_state_t *opt_state, struct stmt *s, int v0, int v1)
+fold_op(opt_state_t *opt_state, struct stmt *s, bpf_u_int32 v0, bpf_u_int32 v1)
{
bpf_u_int32 a, b;
@@ -807,6 +863,10 @@ fold_op(opt_state_t *opt_state, struct stmt *s, int v0, int v1)
}
s->k = a;
s->code = BPF_LD|BPF_IMM;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
opt_state->done = 0;
}
@@ -832,7 +892,7 @@ opt_peep(opt_state_t *opt_state, struct block *b)
{
struct slist *s;
struct slist *next, *last;
- int val;
+ bpf_u_int32 val;
s = b->stmts;
if (s == 0)
@@ -863,6 +923,10 @@ opt_peep(opt_state_t *opt_state, struct block *b)
if (s->s.code == BPF_ST &&
next->s.code == (BPF_LDX|BPF_MEM) &&
s->s.k == next->s.k) {
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
opt_state->done = 0;
next->s.code = BPF_MISC|BPF_TAX;
}
@@ -874,6 +938,10 @@ opt_peep(opt_state_t *opt_state, struct block *b)
next->s.code == (BPF_MISC|BPF_TAX)) {
s->s.code = BPF_LDX|BPF_IMM;
next->s.code = BPF_MISC|BPF_TXA;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
opt_state->done = 0;
}
/*
@@ -953,6 +1021,10 @@ opt_peep(opt_state_t *opt_state, struct block *b)
s->s.code = NOP;
add->s.code = NOP;
tax->s.code = NOP;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
opt_state->done = 0;
}
}
@@ -965,10 +1037,10 @@ opt_peep(opt_state_t *opt_state, struct block *b)
*/
if (b->s.code == (BPF_JMP|BPF_JEQ|BPF_K) &&
!ATOMELEM(b->out_use, A_ATOM)) {
- /*
- * We can optimize away certain subtractions of the
- * X register.
- */
+ /*
+ * We can optimize away certain subtractions of the
+ * X register.
+ */
if (last->s.code == (BPF_ALU|BPF_SUB|BPF_X)) {
val = b->val[X_ATOM];
if (opt_state->vmap[val].is_const) {
@@ -983,6 +1055,10 @@ opt_peep(opt_state_t *opt_state, struct block *b)
*/
b->s.k += opt_state->vmap[val].const_val;
last->s.code = NOP;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
opt_state->done = 0;
} else if (b->s.k == 0) {
/*
@@ -996,6 +1072,10 @@ opt_peep(opt_state_t *opt_state, struct block *b)
*/
last->s.code = NOP;
b->s.code = BPF_JMP|BPF_JEQ|BPF_X;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
opt_state->done = 0;
}
}
@@ -1008,6 +1088,10 @@ opt_peep(opt_state_t *opt_state, struct block *b)
else if (last->s.code == (BPF_ALU|BPF_SUB|BPF_K)) {
last->s.code = NOP;
b->s.k += last->s.k;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
opt_state->done = 0;
}
/*
@@ -1022,6 +1106,10 @@ opt_peep(opt_state_t *opt_state, struct block *b)
b->s.k = last->s.k;
b->s.code = BPF_JMP|BPF_K|BPF_JSET;
last->s.code = NOP;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
opt_state->done = 0;
opt_not(b);
}
@@ -1033,7 +1121,7 @@ opt_peep(opt_state_t *opt_state, struct block *b)
if (b->s.code == (BPF_JMP|BPF_K|BPF_JSET)) {
if (b->s.k == 0)
JT(b) = JF(b);
- if ((u_int)b->s.k == 0xffffffffU)
+ if (b->s.k == 0xffffffffU)
JF(b) = JT(b);
}
/*
@@ -1043,7 +1131,7 @@ opt_peep(opt_state_t *opt_state, struct block *b)
*/
val = b->val[X_ATOM];
if (opt_state->vmap[val].is_const && BPF_SRC(b->s.code) == BPF_X) {
- bpf_int32 v = opt_state->vmap[val].const_val;
+ bpf_u_int32 v = opt_state->vmap[val].const_val;
b->s.code &= ~BPF_X;
b->s.k = v;
}
@@ -1053,7 +1141,7 @@ opt_peep(opt_state_t *opt_state, struct block *b)
*/
val = b->val[A_ATOM];
if (opt_state->vmap[val].is_const && BPF_SRC(b->s.code) == BPF_K) {
- bpf_int32 v = opt_state->vmap[val].const_val;
+ bpf_u_int32 v = opt_state->vmap[val].const_val;
switch (BPF_OP(b->s.code)) {
case BPF_JEQ:
@@ -1061,11 +1149,11 @@ opt_peep(opt_state_t *opt_state, struct block *b)
break;
case BPF_JGT:
- v = (unsigned)v > (unsigned)b->s.k;
+ v = v > b->s.k;
break;
case BPF_JGE:
- v = (unsigned)v >= (unsigned)b->s.k;
+ v = v >= b->s.k;
break;
case BPF_JSET:
@@ -1075,8 +1163,13 @@ opt_peep(opt_state_t *opt_state, struct block *b)
default:
abort();
}
- if (JF(b) != JT(b))
+ if (JF(b) != JT(b)) {
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
opt_state->done = 0;
+ }
if (v)
JF(b) = JT(b);
else
@@ -1091,10 +1184,10 @@ opt_peep(opt_state_t *opt_state, struct block *b)
* evaluation and code transformations weren't folded together.
*/
static void
-opt_stmt(opt_state_t *opt_state, struct stmt *s, int val[], int alter)
+opt_stmt(opt_state_t *opt_state, struct stmt *s, bpf_u_int32 val[], int alter)
{
int op;
- int v;
+ bpf_u_int32 v;
switch (s->code) {
@@ -1113,6 +1206,10 @@ opt_stmt(opt_state_t *opt_state, struct stmt *s, int val[], int alter)
s->code = BPF_LD|BPF_ABS|BPF_SIZE(s->code);
s->k += opt_state->vmap[v].const_val;
v = F(opt_state, s->code, s->k, 0L);
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
opt_state->done = 0;
}
else
@@ -1159,7 +1256,7 @@ opt_stmt(opt_state_t *opt_state, struct stmt *s, int val[], int alter)
* about the result of negating 0x80000000 being
* undefined.
*/
- s->k = 0U - (bpf_u_int32)(opt_state->vmap[val[A_ATOM]].const_val);
+ s->k = 0U - opt_state->vmap[val[A_ATOM]].const_val;
val[A_ATOM] = K(s->k);
}
else
@@ -1236,16 +1333,14 @@ opt_stmt(opt_state_t *opt_state, struct stmt *s, int val[], int alter)
else {
s->code = BPF_ALU|BPF_K|op;
s->k = opt_state->vmap[val[X_ATOM]].const_val;
- /*
- * XXX - we need to make up our minds
- * as to what integers are signed and
- * what integers are unsigned in BPF
- * programs and in our IR.
- */
if ((op == BPF_LSH || op == BPF_RSH) &&
- (s->k < 0 || s->k > 31))
+ s->k > 31)
opt_error(opt_state,
"shift by more than 31 bits");
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
opt_state->done = 0;
val[A_ATOM] =
F(opt_state, s->code, val[A_ATOM], K(s->k));
@@ -1290,6 +1385,10 @@ opt_stmt(opt_state_t *opt_state, struct stmt *s, int val[], int alter)
if (alter && opt_state->vmap[v].is_const) {
s->code = BPF_LD|BPF_IMM;
s->k = opt_state->vmap[v].const_val;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
opt_state->done = 0;
}
vstore(s, &val[A_ATOM], v, alter);
@@ -1304,6 +1403,10 @@ opt_stmt(opt_state_t *opt_state, struct stmt *s, int val[], int alter)
if (alter && opt_state->vmap[v].is_const) {
s->code = BPF_LDX|BPF_IMM;
s->k = opt_state->vmap[v].const_val;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
opt_state->done = 0;
}
vstore(s, &val[X_ATOM], v, alter);
@@ -1336,6 +1439,10 @@ deadstmt(opt_state_t *opt_state, register struct stmt *s, register struct stmt *
atom = atomdef(s);
if (atom >= 0) {
if (last[atom]) {
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
opt_state->done = 0;
last[atom]->code = NOP;
}
@@ -1359,6 +1466,10 @@ opt_deadstores(opt_state_t *opt_state, register struct block *b)
for (atom = 0; atom < N_ATOMS; ++atom)
if (last[atom] && !ATOMELEM(b->out_use, atom)) {
last[atom]->code = NOP;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
opt_state->done = 0;
}
}
@@ -1369,7 +1480,7 @@ opt_blk(opt_state_t *opt_state, struct block *b, int do_stmts)
struct slist *s;
struct edge *p;
int i;
- bpf_int32 aval, xval;
+ bpf_u_int32 aval, xval;
#if 0
for (s = b->stmts; s && s->next; s = s->next)
@@ -1422,7 +1533,10 @@ opt_blk(opt_state_t *opt_state, struct block *b, int do_stmts)
* value that is already there, or if this block is a return,
* eliminate all the statements.
*
- * XXX - what if it does a store?
+ * XXX - what if it does a store? Presumably that falls under
+ * the heading of "if we don't use anything from this block",
+ * i.e., if we use any memory location set to a different
+ * value by this block, then we use something from this block.
*
* XXX - why does it matter whether we use anything from this
* block? If the accumulator or index register doesn't change
@@ -1446,6 +1560,10 @@ opt_blk(opt_state_t *opt_state, struct block *b, int do_stmts)
BPF_CLASS(b->s.code) == BPF_RET)) {
if (b->stmts != 0) {
b->stmts = 0;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
opt_state->done = 0;
}
} else {
@@ -1484,19 +1602,41 @@ use_conflict(struct block *b, struct block *succ)
return 0;
}
+/*
+ * Given a block that is the successor of an edge, and an edge that
+ * dominates that edge, return either a pointer to a child of that
+ * block (a block to which that block jumps) if that block is a
+ * candidate to replace the successor of the latter edge or NULL
+ * if neither of the children of the first block are candidates.
+ */
static struct block *
fold_edge(struct block *child, struct edge *ep)
{
int sense;
- int aval0, aval1, oval0, oval1;
+ bpf_u_int32 aval0, aval1, oval0, oval1;
int code = ep->code;
if (code < 0) {
+ /*
+ * This edge is a "branch if false" edge.
+ */
code = -code;
sense = 0;
- } else
+ } else {
+ /*
+ * This edge is a "branch if true" edge.
+ */
sense = 1;
+ }
+ /*
+ * If the opcode for the branch at the end of the block we
+ * were handed isn't the same as the opcode for the branch
+ * to which the edge we were handed corresponds, the tests
+ * for those branches aren't testing the same conditions,
+ * so the blocks to which the first block branches aren't
+ * candidates to replace the successor of the edge.
+ */
if (child->s.code != code)
return 0;
@@ -1505,13 +1645,21 @@ fold_edge(struct block *child, struct edge *ep)
aval1 = ep->pred->val[A_ATOM];
oval1 = ep->pred->oval;
+ /*
+ * If the A register value on exit from the successor block
+ * isn't the same as the A register value on exit from the
+ * predecessor of the edge, the blocks to which the first
+ * block branches aren't candidates to replace the successor
+ * of the edge.
+ */
if (aval0 != aval1)
return 0;
if (oval0 == oval1)
/*
* The operands of the branch instructions are
- * identical, so the result is true if a true
+ * identical, so the branches are testing the
+ * same condition, and the result is true if a true
* branch was taken to get here, otherwise false.
*/
return sense ? JT(child) : JF(child);
@@ -1536,21 +1684,58 @@ fold_edge(struct block *child, struct edge *ep)
return 0;
}
+/*
+ * If we can make this edge go directly to a child of the edge's current
+ * successor, do so.
+ */
static void
opt_j(opt_state_t *opt_state, struct edge *ep)
{
- register int i, k;
+ register u_int i, k;
register struct block *target;
+ /*
+ * Does this edge go to a block where, if the test
+ * at the end of it succeeds, it goes to a block
+ * that's a leaf node of the DAG, i.e. a return
+ * statement?
+ * If so, there's nothing to optimize.
+ */
if (JT(ep->succ) == 0)
return;
+ /*
+ * Does this edge go to a block that goes, in turn, to
+ * the same block regardless of whether the test at the
+ * end succeeds or fails?
+ */
if (JT(ep->succ) == JF(ep->succ)) {
/*
* Common branch targets can be eliminated, provided
* there is no data dependency.
+ *
+ * Check whether any register used on exit from the
+ * block to which the successor of this edge goes
+ * has a value at that point that's different from
+ * the value it has on exit from the predecessor of
+ * this edge. If not, the predecessor of this edge
+ * can just go to the block to which the successor
+ * of this edge goes, bypassing the successor of this
+ * edge, as the successor of this edge isn't doing
+ * any calculations whose results are different
+ * from what the blocks before it did and isn't
+ * doing any tests the results of which matter.
*/
- if (!use_conflict(ep->pred, ep->succ->et.succ)) {
+ if (!use_conflict(ep->pred, JT(ep->succ))) {
+ /*
+ * No, there isn't.
+ * Make this edge go to the block to
+ * which the successor of that edge
+ * goes.
+ *
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 1;
opt_state->done = 0;
ep->succ = JT(ep->succ);
}
@@ -1564,19 +1749,38 @@ opt_j(opt_state_t *opt_state, struct edge *ep)
*/
top:
for (i = 0; i < opt_state->edgewords; ++i) {
+ /* i'th word in the bitset of dominators */
register bpf_u_int32 x = ep->edom[i];
while (x != 0) {
+ /* Find the next dominator in that word and mark it as found */
k = lowest_set_bit(x);
x &=~ ((bpf_u_int32)1 << k);
k += i * BITS_PER_WORD;
target = fold_edge(ep->succ, opt_state->edges[k]);
/*
+ * We have a candidate to replace the successor
+ * of ep.
+ *
* Check that there is no data dependency between
- * nodes that will be violated if we move the edge.
+ * nodes that will be violated if we move the edge;
+ * i.e., if any register used on exit from the
+ * candidate has a value at that point different
+ * from the value it has when we exit the
+ * predecessor of that edge, there's a data
+ * dependency that will be violated.
*/
if (target != 0 && !use_conflict(ep->pred, target)) {
+ /*
+ * It's safe to replace the successor of
+ * ep; do so, and note that we've made
+ * at least one change.
+ *
+ * XXX - this is one of the operations that
+ * happens when the optimizer gets into
+ * one of those infinite loops.
+ */
opt_state->done = 0;
ep->succ = target;
if (JT(target) != 0)
@@ -1590,11 +1794,30 @@ opt_j(opt_state_t *opt_state, struct edge *ep)
}
}
-
+/*
+ * XXX - is this, and and_pullup(), what's described in section 6.1.2
+ * "Predicate Assertion Propagation" in the BPF+ paper?
+ *
+ * Note that this looks at block dominators, not edge dominators.
+ * Don't think so.
+ *
+ * "A or B" compiles into
+ *
+ * A
+ * t / \ f
+ * / B
+ * / t / \ f
+ * \ /
+ * \ /
+ * X
+ *
+ *
+ */
static void
or_pullup(opt_state_t *opt_state, struct block *b)
{
- int val, at_top;
+ bpf_u_int32 val;
+ int at_top;
struct block *pull;
struct block **diffp, **samep;
struct edge *ep;
@@ -1612,39 +1835,106 @@ or_pullup(opt_state_t *opt_state, struct block *b)
if (val != ep->pred->val[A_ATOM])
return;
+ /*
+ * For the first edge in the list of edges coming into this block,
+ * see whether the predecessor of that edge comes here via a true
+ * branch or a false branch.
+ */
if (JT(b->in_edges->pred) == b)
- diffp = &JT(b->in_edges->pred);
+ diffp = &JT(b->in_edges->pred); /* jt */
else
- diffp = &JF(b->in_edges->pred);
+ diffp = &JF(b->in_edges->pred); /* jf */
+ /*
+ * diffp is a pointer to a pointer to the block.
+ *
+ * Go down the false chain looking as far as you can,
+ * making sure that each jump-compare is doing the
+ * same as the original block.
+ *
+ * If you reach the bottom before you reach a
+ * different jump-compare, just exit. There's nothing
+ * to do here. XXX - no, this version is checking for
+ * the value leaving the block; that's from the BPF+
+ * pullup routine.
+ */
at_top = 1;
for (;;) {
+ /*
+ * Done if that's not going anywhere XXX
+ */
if (*diffp == 0)
return;
+ /*
+ * Done if that predecessor blah blah blah isn't
+ * going the same place we're going XXX
+ *
+ * Does the true edge of this block point to the same
+ * location as the true edge of b?
+ */
if (JT(*diffp) != JT(b))
return;
+ /*
+ * Done if this node isn't a dominator of that
+ * node blah blah blah XXX
+ *
+ * Does b dominate diffp?
+ */
if (!SET_MEMBER((*diffp)->dom, b->id))
return;
+ /*
+ * Break out of the loop if that node's value of A
+ * isn't the value of A above XXX
+ */
if ((*diffp)->val[A_ATOM] != val)
break;
+ /*
+ * Get the JF for that node XXX
+ * Go down the false path.
+ */
diffp = &JF(*diffp);
at_top = 0;
}
+
+ /*
+ * Now that we've found a different jump-compare in a chain
+ * below b, search further down until we find another
+ * jump-compare that looks at the original value. This
+ * jump-compare should get pulled up. XXX again we're
+ * comparing values not jump-compares.
+ */
samep = &JF(*diffp);
for (;;) {
+ /*
+ * Done if that's not going anywhere XXX
+ */
if (*samep == 0)
return;
+ /*
+ * Done if that predecessor blah blah blah isn't
+ * going the same place we're going XXX
+ */
if (JT(*samep) != JT(b))
return;
+ /*
+ * Done if this node isn't a dominator of that
+ * node blah blah blah XXX
+ *
+ * Does b dominate samep?
+ */
if (!SET_MEMBER((*samep)->dom, b->id))
return;
+ /*
+ * Break out of the loop if that node's value of A
+ * is the value of A above XXX
+ */
if ((*samep)->val[A_ATOM] == val)
break;
@@ -1680,13 +1970,18 @@ or_pullup(opt_state_t *opt_state, struct block *b)
else
*diffp = pull;
+ /*
+ * XXX - this is one of the operations that happens when the
+ * optimizer gets into one of those infinite loops.
+ */
opt_state->done = 0;
}
static void
and_pullup(opt_state_t *opt_state, struct block *b)
{
- int val, at_top;
+ bpf_u_int32 val;
+ int at_top;
struct block *pull;
struct block **diffp, **samep;
struct edge *ep;
@@ -1771,6 +2066,10 @@ and_pullup(opt_state_t *opt_state, struct block *b)
else
*diffp = pull;
+ /*
+ * XXX - this is one of the operations that happens when the
+ * optimizer gets into one of those infinite loops.
+ */
opt_state->done = 0;
}
@@ -1792,9 +2091,22 @@ opt_blks(opt_state_t *opt_state, struct icode *ic, int do_stmts)
/*
* No point trying to move branches; it can't possibly
* make a difference at this point.
+ *
+ * XXX - this might be after we detect a loop where
+ * we were just looping infinitely moving branches
+ * in such a fashion that we went through two or more
+ * 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
+ * move branches.)
*/
return;
+ /*
+ * Is this what the BPF+ paper describes in sections 6.1.1,
+ * 6.1.2, and 6.1.3?
+ */
for (i = 1; i <= maxlevel; ++i) {
for (p = opt_state->levels[i]; p; p = p->link) {
opt_j(opt_state, &p->et);
@@ -1821,7 +2133,8 @@ link_inedge(struct edge *parent, struct block *child)
static void
find_inedges(opt_state_t *opt_state, struct block *root)
{
- int i;
+ u_int i;
+ int level;
struct block *b;
for (i = 0; i < opt_state->n_blocks; ++i)
@@ -1831,8 +2144,8 @@ find_inedges(opt_state_t *opt_state, struct block *root)
* Traverse the graph, adding each edge to the predecessor
* list of its successors. Skip the leaves (i.e. level 0).
*/
- for (i = root->level; i > 0; --i) {
- for (b = opt_state->levels[i]; b != 0; b = b->link) {
+ for (level = root->level; level > 0; --level) {
+ for (b = opt_state->levels[level]; b != 0; b = b->link) {
link_inedge(&b->et, JT(b));
link_inedge(&b->ef, JF(b));
}
@@ -1873,8 +2186,17 @@ opt_loop(opt_state_t *opt_state, struct icode *ic, int do_stmts)
opt_dump(opt_state, ic);
}
#endif
- do {
+
+ /*
+ * XXX - optimizer loop detection.
+ */
+ int loop_count = 0;
+ for (;;) {
opt_state->done = 1;
+ /*
+ * XXX - optimizer loop detection.
+ */
+ opt_state->non_branch_movement_performed = 0;
find_levels(opt_state, ic);
find_dom(opt_state, ic->root);
find_closure(opt_state, ic->root);
@@ -1887,7 +2209,51 @@ opt_loop(opt_state_t *opt_state, struct icode *ic, int do_stmts)
opt_dump(opt_state, ic);
}
#endif
- } while (!opt_state->done);
+
+ /*
+ * Was anything done in this optimizer pass?
+ */
+ if (opt_state->done) {
+ /*
+ * No, so we've reached a fixed point.
+ * We're done.
+ */
+ break;
+ }
+
+ /*
+ * XXX - was anything done other than branch movement
+ * in this pass?
+ */
+ if (opt_state->non_branch_movement_performed) {
+ /*
+ * Yes. Clear any loop-detection counter;
+ * we're making some form of progress (assuming
+ * we can't get into a cycle doing *other*
+ * optimizations...).
+ */
+ loop_count = 0;
+ } else {
+ /*
+ * No - increment the counter, and quit if
+ * it's up to 100.
+ */
+ loop_count++;
+ if (loop_count >= 100) {
+ /*
+ * We've done nothing but branch movement
+ * for 100 passes; we're probably
+ * in a cycle and will never reach a
+ * fixed point.
+ *
+ * XXX - yes, we really need a non-
+ * heuristic way of detecting a cycle.
+ */
+ opt_state->done = 1;
+ break;
+ }
+ }
+ }
}
/*
@@ -1901,6 +2267,7 @@ bpf_optimize(struct icode *ic, char *errbuf)
memset(&opt_state, 0, sizeof(opt_state));
opt_state.errbuf = errbuf;
+ opt_state.non_branch_movement_performed = 0;
if (setjmp(opt_state.top_ctx)) {
opt_cleanup(&opt_state);
return -1;
@@ -1987,7 +2354,7 @@ static void
intern_blocks(opt_state_t *opt_state, struct icode *ic)
{
struct block *p;
- int i, j;
+ u_int i, j;
int done1; /* don't shadow global */
top:
done1 = 1;
@@ -1996,7 +2363,8 @@ intern_blocks(opt_state_t *opt_state, struct icode *ic)
mark_code(ic);
- for (i = opt_state->n_blocks - 1; --i >= 0; ) {
+ for (i = opt_state->n_blocks - 1; i != 0; ) {
+ --i;
if (!isMarked(ic, opt_state->blocks[i]))
continue;
for (j = i + 1; j < opt_state->n_blocks; ++j) {
@@ -2047,7 +2415,7 @@ opt_error(opt_state_t *opt_state, const char *fmt, ...)
if (opt_state->errbuf != NULL) {
va_start(ap, fmt);
- (void)pcap_vsnprintf(opt_state->errbuf,
+ (void)vsnprintf(opt_state->errbuf,
PCAP_ERRBUF_SIZE, fmt, ap);
va_end(ap);
}
@@ -2089,13 +2457,19 @@ count_blocks(struct icode *ic, struct block *p)
static void
number_blks_r(opt_state_t *opt_state, struct icode *ic, struct block *p)
{
- int n;
+ u_int n;
if (p == 0 || isMarked(ic, p))
return;
Mark(ic, p);
n = opt_state->n_blocks++;
+ if (opt_state->n_blocks == 0) {
+ /*
+ * Overflow.
+ */
+ opt_error(opt_state, "filter is too complex to optimize");
+ }
p->id = n;
opt_state->blocks[n] = p;
@@ -2143,6 +2517,8 @@ opt_init(opt_state_t *opt_state, struct icode *ic)
{
bpf_u_int32 *p;
int i, n, max_stmts;
+ u_int product;
+ size_t block_memsize, edge_memsize;
/*
* First, count the blocks, so we can malloc an array to map
@@ -2157,7 +2533,19 @@ opt_init(opt_state_t *opt_state, struct icode *ic)
opt_state->n_blocks = 0;
number_blks_r(opt_state, ic, ic->root);
+ /*
+ * This "should not happen".
+ */
+ if (opt_state->n_blocks == 0)
+ opt_error(opt_state, "filter has no instructions; please report this as a libpcap issue");
+
opt_state->n_edges = 2 * opt_state->n_blocks;
+ if ((opt_state->n_edges / 2) != opt_state->n_blocks) {
+ /*
+ * Overflow.
+ */
+ opt_error(opt_state, "filter is too complex to optimize");
+ }
opt_state->edges = (struct edge **)calloc(opt_state->n_edges, sizeof(*opt_state->edges));
if (opt_state->edges == NULL) {
opt_error(opt_state, "malloc");
@@ -2171,12 +2559,62 @@ opt_init(opt_state_t *opt_state, struct icode *ic)
opt_error(opt_state, "malloc");
}
- opt_state->edgewords = opt_state->n_edges / (8 * sizeof(bpf_u_int32)) + 1;
- opt_state->nodewords = opt_state->n_blocks / (8 * sizeof(bpf_u_int32)) + 1;
+ opt_state->edgewords = opt_state->n_edges / BITS_PER_WORD + 1;
+ opt_state->nodewords = opt_state->n_blocks / BITS_PER_WORD + 1;
+
+ /*
+ * Make sure opt_state->n_blocks * opt_state->nodewords fits
+ * in a u_int; we use it as a u_int number-of-iterations
+ * value.
+ */
+ product = opt_state->n_blocks * opt_state->nodewords;
+ if ((product / opt_state->n_blocks) != opt_state->nodewords) {
+ /*
+ * XXX - just punt and don't try to optimize?
+ * In practice, this is unlikely to happen with
+ * a normal filter.
+ */
+ opt_error(opt_state, "filter is too complex to optimize");
+ }
+
+ /*
+ * Make sure the total memory required for that doesn't
+ * overflow.
+ */
+ block_memsize = (size_t)2 * product * sizeof(*opt_state->space);
+ if ((block_memsize / product) != 2 * sizeof(*opt_state->space)) {
+ opt_error(opt_state, "filter is too complex to optimize");
+ }
+
+ /*
+ * Make sure opt_state->n_edges * opt_state->edgewords fits
+ * in a u_int; we use it as a u_int number-of-iterations
+ * value.
+ */
+ product = opt_state->n_edges * opt_state->edgewords;
+ if ((product / opt_state->n_edges) != opt_state->edgewords) {
+ opt_error(opt_state, "filter is too complex to optimize");
+ }
+
+ /*
+ * Make sure the total memory required for that doesn't
+ * overflow.
+ */
+ edge_memsize = (size_t)product * sizeof(*opt_state->space);
+ if (edge_memsize / product != sizeof(*opt_state->space)) {
+ opt_error(opt_state, "filter is too complex to optimize");
+ }
+
+ /*
+ * Make sure the total memory required for both of them dosn't
+ * overflow.
+ */
+ if (block_memsize > SIZE_MAX - edge_memsize) {
+ opt_error(opt_state, "filter is too complex to optimize");
+ }
/* XXX */
- opt_state->space = (bpf_u_int32 *)malloc(2 * opt_state->n_blocks * opt_state->nodewords * sizeof(*opt_state->space)
- + opt_state->n_edges * opt_state->edgewords * sizeof(*opt_state->space));
+ opt_state->space = (bpf_u_int32 *)malloc(block_memsize + edge_memsize);
if (opt_state->space == NULL) {
opt_error(opt_state, "malloc");
}
@@ -2250,7 +2688,6 @@ convert_code_r(conv_state_t *conv_state, struct icode *ic, struct block *p)
struct slist *src;
u_int slen;
u_int off;
- u_int extrajmps; /* number of extra jumps inserted */
struct slist **offset = NULL;
if (p == 0 || isMarked(ic, p))
@@ -2374,21 +2811,17 @@ filled:
dst->code = (u_short)p->s.code;
dst->k = p->s.k;
if (JT(p)) {
- extrajmps = 0;
+ /* number of extra jumps inserted */
+ u_char extrajmps = 0;
off = JT(p)->offset - (p->offset + slen) - 1;
if (off >= 256) {
/* offset too large for branch, must add a jump */
if (p->longjt == 0) {
- /* mark this instruction and retry */
+ /* mark this instruction and retry */
p->longjt++;
return(0);
}
- /* branch if T to following jump */
- if (extrajmps >= 256) {
- conv_error(conv_state, "too many extra jumps");
- /*NOTREACHED*/
- }
- dst->jt = (u_char)extrajmps;
+ dst->jt = extrajmps;
extrajmps++;
dst[extrajmps].code = BPF_JMP|BPF_JA;
dst[extrajmps].k = off - extrajmps;
@@ -2399,17 +2832,13 @@ filled:
if (off >= 256) {
/* offset too large for branch, must add a jump */
if (p->longjf == 0) {
- /* mark this instruction and retry */
+ /* mark this instruction and retry */
p->longjf++;
return(0);
}
/* branch if F to following jump */
/* if two jumps are inserted, F goes to second one */
- if (extrajmps >= 256) {
- conv_error(conv_state, "too many extra jumps");
- /*NOTREACHED*/
- }
- dst->jf = (u_char)extrajmps;
+ dst->jf = extrajmps;
extrajmps++;
dst[extrajmps].code = BPF_JMP|BPF_JA;
dst[extrajmps].k = off - extrajmps;
@@ -2440,7 +2869,7 @@ filled:
* done with the filter program. See the pcap man page.
*/
struct bpf_insn *
-icode_to_fcode(struct icode *ic, struct block *root, u_int *lenp,
+icode_to_fcode(struct icode *ic, struct block *root, u_int *lenp,
char *errbuf)
{
u_int n;
@@ -2464,7 +2893,7 @@ icode_to_fcode(struct icode *ic, struct block *root, u_int *lenp,
fp = (struct bpf_insn *)malloc(sizeof(*fp) * n);
if (fp == NULL) {
- (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"malloc");
free(fp);
return NULL;
@@ -2491,7 +2920,7 @@ conv_error(conv_state_t *conv_state, const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- (void)pcap_vsnprintf(conv_state->errbuf,
+ (void)vsnprintf(conv_state->errbuf,
PCAP_ERRBUF_SIZE, fmt, ap);
va_end(ap);
longjmp(conv_state->top_ctx, 1);
@@ -2514,8 +2943,8 @@ install_bpf_program(pcap_t *p, struct bpf_program *fp)
/*
* Validate the program.
*/
- if (!bpf_validate(fp->bf_insns, fp->bf_len)) {
- pcap_snprintf(p->errbuf, sizeof(p->errbuf),
+ if (!pcap_validate_filter(fp->bf_insns, fp->bf_len)) {
+ snprintf(p->errbuf, sizeof(p->errbuf),
"BPF program is not valid");
return (-1);
}
@@ -2552,7 +2981,7 @@ dot_dump_node(struct icode *ic, struct block *block, struct bpf_program *prog,
icount = slength(block->stmts) + 1 + block->longjt + block->longjf;
noffset = min(block->offset + icount, (int)prog->bf_len);
- fprintf(out, "\tblock%d [shape=ellipse, id=\"block-%d\" label=\"BLOCK%d\\n", block->id, block->id, block->id);
+ fprintf(out, "\tblock%u [shape=ellipse, id=\"block-%u\" label=\"BLOCK%u\\n", block->id, block->id, block->id);
for (i = block->offset; i < noffset; i++) {
fprintf(out, "\\n%s", bpf_image(prog->bf_insns + i, i));
}
@@ -2579,9 +3008,9 @@ dot_dump_edge(struct icode *ic, struct block *block, FILE *out)
Mark(ic, block);
if (JT(block)) {
- fprintf(out, "\t\"block%d\":se -> \"block%d\":n [label=\"T\"]; \n",
+ fprintf(out, "\t\"block%u\":se -> \"block%u\":n [label=\"T\"]; \n",
block->id, JT(block)->id);
- fprintf(out, "\t\"block%d\":sw -> \"block%d\":n [label=\"F\"]; \n",
+ fprintf(out, "\t\"block%u\":sw -> \"block%u\":n [label=\"F\"]; \n",
block->id, JF(block)->id);
}
dot_dump_edge(ic, JT(block), out);
@@ -2604,7 +3033,7 @@ dot_dump_edge(struct icode *ic, struct block *block, FILE *out)
"block1":sw -> "block3":n [label="F"];
}
*
- * After install graphviz on http://www.graphviz.org/, save it as bpf.dot
+ * After install graphviz on https://www.graphviz.org/, save it as bpf.dot
* and run `dot -Tpng -O bpf.dot' to draw the graph.
*/
static int
diff --git a/org.tcpdump.chmod_bpf.plist b/org.tcpdump.chmod_bpf.plist
index 8ad68526..f6fdfec7 100644
--- a/org.tcpdump.chmod_bpf.plist
+++ b/org.tcpdump.chmod_bpf.plist
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
diff --git a/pcap-airpcap.c b/pcap-airpcap.c
new file mode 100644
index 00000000..703f23ac
--- /dev/null
+++ b/pcap-airpcap.c
@@ -0,0 +1,1044 @@
+/*
+ * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
+ * Copyright (c) 2005 - 2010 CACE Technologies, Davis (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. Neither the name of the Politecnico di Torino, CACE Technologies
+ * nor the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pcap-int.h"
+
+#include <airpcap.h>
+
+#include "pcap-airpcap.h"
+
+/* Default size of the buffer we allocate in userland. */
+#define AIRPCAP_DEFAULT_USER_BUFFER_SIZE 256000
+
+/* Default size of the buffer for the AirPcap adapter. */
+#define AIRPCAP_DEFAULT_KERNEL_BUFFER_SIZE 1000000
+
+//
+// We load the AirPcap DLL dynamically, so that the code will
+// work whether you have it installed or not, and there don't
+// have to be two different versions of the library, one linked
+// to the AirPcap library and one not linked to it.
+//
+static pcap_code_handle_t airpcap_lib;
+
+typedef PCHAR (*AirpcapGetLastErrorHandler)(PAirpcapHandle);
+typedef BOOL (*AirpcapGetDeviceListHandler)(PAirpcapDeviceDescription *, PCHAR);
+typedef VOID (*AirpcapFreeDeviceListHandler)(PAirpcapDeviceDescription);
+typedef PAirpcapHandle (*AirpcapOpenHandler)(PCHAR, PCHAR);
+typedef VOID (*AirpcapCloseHandler)(PAirpcapHandle);
+typedef BOOL (*AirpcapSetDeviceMacFlagsHandler)(PAirpcapHandle, UINT);
+typedef BOOL (*AirpcapSetLinkTypeHandler)(PAirpcapHandle, AirpcapLinkType);
+typedef BOOL (*AirpcapGetLinkTypeHandler)(PAirpcapHandle, PAirpcapLinkType);
+typedef BOOL (*AirpcapSetKernelBufferHandler)(PAirpcapHandle, UINT);
+typedef BOOL (*AirpcapSetFilterHandler)(PAirpcapHandle, PVOID, UINT);
+typedef BOOL (*AirpcapSetMinToCopyHandler)(PAirpcapHandle, UINT);
+typedef BOOL (*AirpcapGetReadEventHandler)(PAirpcapHandle, HANDLE *);
+typedef BOOL (*AirpcapReadHandler)(PAirpcapHandle, PBYTE, UINT, PUINT);
+typedef BOOL (*AirpcapWriteHandler)(PAirpcapHandle, PCHAR, ULONG);
+typedef BOOL (*AirpcapGetStatsHandler)(PAirpcapHandle, PAirpcapStats);
+
+static AirpcapGetLastErrorHandler p_AirpcapGetLastError;
+static AirpcapGetDeviceListHandler p_AirpcapGetDeviceList;
+static AirpcapFreeDeviceListHandler p_AirpcapFreeDeviceList;
+static AirpcapOpenHandler p_AirpcapOpen;
+static AirpcapCloseHandler p_AirpcapClose;
+static AirpcapSetDeviceMacFlagsHandler p_AirpcapSetDeviceMacFlags;
+static AirpcapSetLinkTypeHandler p_AirpcapSetLinkType;
+static AirpcapGetLinkTypeHandler p_AirpcapGetLinkType;
+static AirpcapSetKernelBufferHandler p_AirpcapSetKernelBuffer;
+static AirpcapSetFilterHandler p_AirpcapSetFilter;
+static AirpcapSetMinToCopyHandler p_AirpcapSetMinToCopy;
+static AirpcapGetReadEventHandler p_AirpcapGetReadEvent;
+static AirpcapReadHandler p_AirpcapRead;
+static AirpcapWriteHandler p_AirpcapWrite;
+static AirpcapGetStatsHandler p_AirpcapGetStats;
+
+typedef enum LONG
+{
+ AIRPCAP_API_UNLOADED = 0,
+ AIRPCAP_API_LOADED,
+ AIRPCAP_API_CANNOT_LOAD,
+ AIRPCAP_API_LOADING
+} AIRPCAP_API_LOAD_STATUS;
+
+static AIRPCAP_API_LOAD_STATUS airpcap_load_status;
+
+/*
+ * NOTE: this function should be called by the pcap functions that can
+ * theoretically deal with the AirPcap library for the first time,
+ * namely listing the adapters and creating a pcap_t for an adapter.
+ * All the other ones (activate, close, read, write, set parameters)
+ * work on a pcap_t for an AirPcap device, meaning we've already
+ * created the pcap_t and thus have loaded the functions, so we do
+ * not need to call this function.
+ */
+static AIRPCAP_API_LOAD_STATUS
+load_airpcap_functions(void)
+{
+ AIRPCAP_API_LOAD_STATUS current_status;
+
+ /*
+ * We don't use a mutex because there's no place that
+ * we can guarantee we'll be called before any threads
+ * other than the main thread exists. (For example,
+ * this might be a static library, so we can't arrange
+ * to be called by DllMain(), and there's no guarantee
+ * that the application called pcap_init() - which is
+ * supposed to be called only from one thread - so
+ * we can't arrange to be called from it.)
+ *
+ * If nobody's tried to load it yet, mark it as
+ * loading; in any case, return the status before
+ * we modified it.
+ */
+ current_status = InterlockedCompareExchange((LONG *)&airpcap_load_status,
+ AIRPCAP_API_LOADING, AIRPCAP_API_UNLOADED);
+
+ /*
+ * If the status was AIRPCAP_API_UNLOADED, we've set it
+ * to AIRPCAP_API_LOADING, because we're going to be
+ * the ones to load the library but current_status is
+ * AIRPCAP_API_UNLOADED.
+ *
+ * if it was AIRPCAP_API_LOADING, meaning somebody else
+ * was trying to load it, spin until they finish and
+ * set the status to a value reflecting whether they
+ * succeeded.
+ */
+ while (current_status == AIRPCAP_API_LOADING) {
+ current_status = InterlockedCompareExchange((LONG*)&airpcap_load_status,
+ AIRPCAP_API_LOADING, AIRPCAP_API_LOADING);
+ Sleep(10);
+ }
+
+ /*
+ * At this point, current_status is either:
+ *
+ * AIRPCAP_API_LOADED, in which case another thread
+ * loaded the library, so we're done;
+ *
+ * AIRPCAP_API_CANNOT_LOAD, in which another thread
+ * tried and failed to load the library, so we're
+ * done - we won't try it ourselves;
+ *
+ * AIRPCAP_API_LOADING, in which case *we're* the
+ * ones loading it, and should now try to do so.
+ */
+ if (current_status == AIRPCAP_API_LOADED)
+ return AIRPCAP_API_LOADED;
+
+ if (current_status == AIRPCAP_API_CANNOT_LOAD)
+ return AIRPCAP_API_CANNOT_LOAD;
+
+ /*
+ * Start out assuming we can't load it.
+ */
+ current_status = AIRPCAP_API_CANNOT_LOAD;
+
+ airpcap_lib = pcap_load_code("airpcap.dll");
+ if (airpcap_lib != NULL) {
+ /*
+ * OK, we've loaded the library; now try to find the
+ * functions we need in it.
+ */
+ p_AirpcapGetLastError = (AirpcapGetLastErrorHandler) pcap_find_function(airpcap_lib, "AirpcapGetLastError");
+ p_AirpcapGetDeviceList = (AirpcapGetDeviceListHandler) pcap_find_function(airpcap_lib, "AirpcapGetDeviceList");
+ p_AirpcapFreeDeviceList = (AirpcapFreeDeviceListHandler) pcap_find_function(airpcap_lib, "AirpcapFreeDeviceList");
+ p_AirpcapOpen = (AirpcapOpenHandler) pcap_find_function(airpcap_lib, "AirpcapOpen");
+ p_AirpcapClose = (AirpcapCloseHandler) pcap_find_function(airpcap_lib, "AirpcapClose");
+ p_AirpcapSetDeviceMacFlags = (AirpcapSetDeviceMacFlagsHandler) pcap_find_function(airpcap_lib, "AirpcapSetDeviceMacFlags");
+ p_AirpcapSetLinkType = (AirpcapSetLinkTypeHandler) pcap_find_function(airpcap_lib, "AirpcapSetLinkType");
+ p_AirpcapGetLinkType = (AirpcapGetLinkTypeHandler) pcap_find_function(airpcap_lib, "AirpcapGetLinkType");
+ p_AirpcapSetKernelBuffer = (AirpcapSetKernelBufferHandler) pcap_find_function(airpcap_lib, "AirpcapSetKernelBuffer");
+ p_AirpcapSetFilter = (AirpcapSetFilterHandler) pcap_find_function(airpcap_lib, "AirpcapSetFilter");
+ p_AirpcapSetMinToCopy = (AirpcapSetMinToCopyHandler) pcap_find_function(airpcap_lib, "AirpcapSetMinToCopy");
+ p_AirpcapGetReadEvent = (AirpcapGetReadEventHandler) pcap_find_function(airpcap_lib, "AirpcapGetReadEvent");
+ p_AirpcapRead = (AirpcapReadHandler) pcap_find_function(airpcap_lib, "AirpcapRead");
+ p_AirpcapWrite = (AirpcapWriteHandler) pcap_find_function(airpcap_lib, "AirpcapWrite");
+ p_AirpcapGetStats = (AirpcapGetStatsHandler) pcap_find_function(airpcap_lib, "AirpcapGetStats");
+
+ //
+ // Make sure that we found everything
+ //
+ if (p_AirpcapGetLastError != NULL &&
+ p_AirpcapGetDeviceList != NULL &&
+ p_AirpcapFreeDeviceList != NULL &&
+ p_AirpcapOpen != NULL &&
+ p_AirpcapClose != NULL &&
+ p_AirpcapSetDeviceMacFlags != NULL &&
+ p_AirpcapSetLinkType != NULL &&
+ p_AirpcapGetLinkType != NULL &&
+ p_AirpcapSetKernelBuffer != NULL &&
+ p_AirpcapSetFilter != NULL &&
+ p_AirpcapSetMinToCopy != NULL &&
+ p_AirpcapGetReadEvent != NULL &&
+ p_AirpcapRead != NULL &&
+ p_AirpcapWrite != NULL &&
+ p_AirpcapGetStats != NULL) {
+ /*
+ * We have all we need.
+ */
+ current_status = AIRPCAP_API_LOADED;
+ }
+ }
+
+ if (current_status != AIRPCAP_API_LOADED) {
+ /*
+ * We failed; if we found the DLL, close the
+ * handle for it.
+ */
+ if (airpcap_lib != NULL) {
+ FreeLibrary(airpcap_lib);
+ airpcap_lib = NULL;
+ }
+ }
+
+ /*
+ * Now set the status appropriately - and atomically.
+ */
+ InterlockedExchange((LONG *)&airpcap_load_status, current_status);
+
+ return current_status;
+}
+
+/*
+ * Private data for capturing on AirPcap devices.
+ */
+struct pcap_airpcap {
+ PAirpcapHandle adapter;
+ int filtering_in_kernel;
+ int nonblock;
+ int read_timeout;
+ HANDLE read_event;
+ struct pcap_stat stat;
+};
+
+static int
+airpcap_setfilter(pcap_t *p, struct bpf_program *fp)
+{
+ struct pcap_airpcap *pa = p->priv;
+
+ if (!p_AirpcapSetFilter(pa->adapter, fp->bf_insns,
+ fp->bf_len * sizeof(struct bpf_insn))) {
+ /*
+ * Kernel filter not installed.
+ *
+ * XXX - we don't know whether this failed because:
+ *
+ * the kernel rejected the filter program as invalid,
+ * in which case we should fall back on userland
+ * filtering;
+ *
+ * the kernel rejected the filter program as too big,
+ * in which case we should again fall back on
+ * userland filtering;
+ *
+ * there was some other problem, in which case we
+ * should probably report an error;
+ *
+ * So we just fall back on userland filtering in
+ * all cases.
+ */
+
+ /*
+ * install_bpf_program() validates the program.
+ *
+ * XXX - what if we already have a filter in the kernel?
+ */
+ if (install_bpf_program(p, fp) < 0)
+ return (-1);
+ pa->filtering_in_kernel = 0; /* filtering in userland */
+ return (0);
+ }
+
+ /*
+ * It worked.
+ */
+ pa->filtering_in_kernel = 1; /* filtering in the kernel */
+
+ /*
+ * Discard any previously-received packets, as they might have
+ * passed whatever filter was formerly in effect, but might
+ * not pass this filter (BIOCSETF discards packets buffered
+ * in the kernel, so you can lose packets in any case).
+ */
+ p->cc = 0;
+ return (0);
+}
+
+static int
+airpcap_set_datalink(pcap_t *p, int dlt)
+{
+ struct pcap_airpcap *pa = p->priv;
+ AirpcapLinkType type;
+
+ switch (dlt) {
+
+ case DLT_IEEE802_11_RADIO:
+ type = AIRPCAP_LT_802_11_PLUS_RADIO;
+ break;
+
+ case DLT_PPI:
+ type = AIRPCAP_LT_802_11_PLUS_PPI;
+ break;
+
+ case DLT_IEEE802_11:
+ type = AIRPCAP_LT_802_11;
+ break;
+
+ default:
+ /* This can't happen; just return. */
+ return (0);
+ }
+ if (!p_AirpcapSetLinkType(pa->adapter, type)) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "AirpcapSetLinkType() failed: %s",
+ p_AirpcapGetLastError(pa->adapter));
+ return (-1);
+ }
+ p->linktype = dlt;
+ return (0);
+}
+
+static int
+airpcap_getnonblock(pcap_t *p)
+{
+ struct pcap_airpcap *pa = p->priv;
+
+ return (pa->nonblock);
+}
+
+static int
+airpcap_setnonblock(pcap_t *p, int nonblock)
+{
+ struct pcap_airpcap *pa = p->priv;
+ int newtimeout;
+
+ if (nonblock) {
+ /*
+ * Set the packet buffer timeout to -1 for non-blocking
+ * mode.
+ */
+ newtimeout = -1;
+ } else {
+ /*
+ * Restore the timeout set when the device was opened.
+ * (Note that this may be -1, in which case we're not
+ * really leaving non-blocking mode. However, although
+ * the timeout argument to pcap_set_timeout() and
+ * pcap_open_live() is an int, you're not supposed to
+ * supply a negative value, so that "shouldn't happen".)
+ */
+ newtimeout = p->opt.timeout;
+ }
+ pa->read_timeout = newtimeout;
+ pa->nonblock = (newtimeout == -1);
+ return (0);
+}
+
+static int
+airpcap_stats(pcap_t *p, struct pcap_stat *ps)
+{
+ struct pcap_airpcap *pa = p->priv;
+ AirpcapStats tas;
+
+ /*
+ * Try to get statistics.
+ */
+ if (!p_AirpcapGetStats(pa->adapter, &tas)) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "AirpcapGetStats() failed: %s",
+ p_AirpcapGetLastError(pa->adapter));
+ return (-1);
+ }
+
+ ps->ps_drop = tas.Drops;
+ ps->ps_recv = tas.Recvs;
+ ps->ps_ifdrop = tas.IfDrops;
+
+ return (0);
+}
+
+/*
+ * Win32-only routine for getting statistics.
+ *
+ * This way is definitely safer than passing the pcap_stat * from the userland.
+ * In fact, there could happen than the user allocates a variable which is not
+ * big enough for the new structure, and the library will write in a zone
+ * which is not allocated to this variable.
+ *
+ * In this way, we're pretty sure we are writing on memory allocated to this
+ * variable.
+ *
+ * XXX - but this is the wrong way to handle statistics. Instead, we should
+ * have an API that returns data in a form like the Options section of a
+ * pcapng Interface Statistics Block:
+ *
+ * https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://raw.githubusercontent.com/pcapng/pcapng/master/draft-tuexen-opsawg-pcapng.xml&modeAsFormat=html/ascii&type=ascii#rfc.section.4.6
+ *
+ * which would let us add new statistics straightforwardly and indicate which
+ * statistics we are and are *not* providing, rather than having to provide
+ * possibly-bogus values for statistics we can't provide.
+ */
+static struct pcap_stat *
+airpcap_stats_ex(pcap_t *p, int *pcap_stat_size)
+{
+ struct pcap_airpcap *pa = p->priv;
+ AirpcapStats tas;
+
+ *pcap_stat_size = sizeof (p->stat);
+
+ /*
+ * Try to get statistics.
+ */
+ if (!p_AirpcapGetStats(pa->adapter, &tas)) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "AirpcapGetStats() failed: %s",
+ p_AirpcapGetLastError(pa->adapter));
+ return (NULL);
+ }
+
+ p->stat.ps_recv = tas.Recvs;
+ p->stat.ps_drop = tas.Drops;
+ p->stat.ps_ifdrop = tas.IfDrops;
+ /*
+ * Just in case this is ever compiled for a target other than
+ * Windows, which is extremely unlikely at best.
+ */
+#ifdef _WIN32
+ p->stat.ps_capt = tas.Capt;
+#endif
+ return (&p->stat);
+}
+
+/* Set the dimension of the kernel-level capture buffer */
+static int
+airpcap_setbuff(pcap_t *p, int dim)
+{
+ struct pcap_airpcap *pa = p->priv;
+
+ if (!p_AirpcapSetKernelBuffer(pa->adapter, dim)) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "AirpcapSetKernelBuffer() failed: %s",
+ p_AirpcapGetLastError(pa->adapter));
+ return (-1);
+ }
+ return (0);
+}
+
+/* Set the driver working mode */
+static int
+airpcap_setmode(pcap_t *p, int mode)
+{
+ if (mode != MODE_CAPT) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Only MODE_CAPT is supported on an AirPcap adapter");
+ return (-1);
+ }
+ return (0);
+}
+
+/*set the minimum amount of data that will release a read call*/
+static int
+airpcap_setmintocopy(pcap_t *p, int size)
+{
+ struct pcap_airpcap *pa = p->priv;
+
+ if (!p_AirpcapSetMinToCopy(pa->adapter, size)) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "AirpcapSetMinToCopy() failed: %s",
+ p_AirpcapGetLastError(pa->adapter));
+ return (-1);
+ }
+ return (0);
+}
+
+static HANDLE
+airpcap_getevent(pcap_t *p)
+{
+ struct pcap_airpcap *pa = p->priv;
+
+ return (pa->read_event);
+}
+
+static int
+airpcap_oid_get_request(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_,
+ size_t *lenp _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Getting OID values is not supported on an AirPcap adapter");
+ return (PCAP_ERROR);
+}
+
+static int
+airpcap_oid_set_request(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
+ size_t *lenp _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Setting OID values is not supported on an AirPcap adapter");
+ return (PCAP_ERROR);
+}
+
+static u_int
+airpcap_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue _U_, int sync _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Cannot queue packets for transmission on an AirPcap adapter");
+ return (0);
+}
+
+static int
+airpcap_setuserbuffer(pcap_t *p, int size)
+{
+ unsigned char *new_buff;
+
+ if (size <= 0) {
+ /* Bogus parameter */
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Error: invalid size %d",size);
+ return (-1);
+ }
+
+ /* Allocate the buffer */
+ new_buff = (unsigned char *)malloc(sizeof(char)*size);
+
+ if (!new_buff) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Error: not enough memory");
+ return (-1);
+ }
+
+ free(p->buffer);
+
+ p->buffer = new_buff;
+ p->bufsize = size;
+
+ return (0);
+}
+
+static int
+airpcap_live_dump(pcap_t *p, char *filename _U_, int maxsize _U_,
+ int maxpacks _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "AirPcap adapters don't support live dump");
+ return (-1);
+}
+
+static int
+airpcap_live_dump_ended(pcap_t *p, int sync _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "AirPcap adapters don't support live dump");
+ return (-1);
+}
+
+static PAirpcapHandle
+airpcap_get_airpcap_handle(pcap_t *p)
+{
+ struct pcap_airpcap *pa = p->priv;
+
+ return (pa->adapter);
+}
+
+static int
+airpcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
+ struct pcap_airpcap *pa = p->priv;
+ int cc;
+ int n;
+ register u_char *bp, *ep;
+ UINT bytes_read;
+ u_char *datap;
+
+ cc = p->cc;
+ if (cc == 0) {
+ /*
+ * Has "pcap_breakloop()" been called?
+ */
+ if (p->break_loop) {
+ /*
+ * Yes - clear the flag that indicates that it
+ * has, and return PCAP_ERROR_BREAK to indicate
+ * that we were told to break out of the loop.
+ */
+ p->break_loop = 0;
+ return (PCAP_ERROR_BREAK);
+ }
+
+ //
+ // If we're not in non-blocking mode, wait for data to
+ // arrive.
+ //
+ if (pa->read_timeout != -1) {
+ WaitForSingleObject(pa->read_event,
+ (pa->read_timeout ==0 )? INFINITE: pa->read_timeout);
+ }
+
+ //
+ // Read the data.
+ // p_AirpcapRead doesn't block.
+ //
+ if (!p_AirpcapRead(pa->adapter, (PBYTE)p->buffer,
+ p->bufsize, &bytes_read)) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "AirpcapRead() failed: %s",
+ p_AirpcapGetLastError(pa->adapter));
+ return (-1);
+ }
+ cc = bytes_read;
+ bp = (u_char *)p->buffer;
+ } else
+ bp = p->bp;
+
+ /*
+ * Loop through each packet.
+ */
+#define bhp ((AirpcapBpfHeader *)bp)
+ n = 0;
+ ep = bp + cc;
+ for (;;) {
+ register u_int caplen, hdrlen;
+
+ /*
+ * Has "pcap_breakloop()" been called?
+ * If so, return immediately - if we haven't read any
+ * packets, clear the flag and return PCAP_ERROR_BREAK
+ * to indicate that we were told to break out of the loop,
+ * otherwise leave the flag set, so that the *next* call
+ * will break out of the loop without having read any
+ * packets, and return the number of packets we've
+ * processed so far.
+ */
+ if (p->break_loop) {
+ if (n == 0) {
+ p->break_loop = 0;
+ return (PCAP_ERROR_BREAK);
+ } else {
+ p->bp = bp;
+ p->cc = (int) (ep - bp);
+ return (n);
+ }
+ }
+ if (bp >= ep)
+ break;
+
+ caplen = bhp->Caplen;
+ hdrlen = bhp->Hdrlen;
+ datap = bp + hdrlen;
+ /*
+ * Short-circuit evaluation: if using BPF filter
+ * in the AirPcap adapter, no need to do it now -
+ * we already know the packet passed the filter.
+ */
+ if (pa->filtering_in_kernel ||
+ p->fcode.bf_insns == NULL ||
+ pcap_filter(p->fcode.bf_insns, datap, bhp->Originallen, caplen)) {
+ struct pcap_pkthdr pkthdr;
+
+ pkthdr.ts.tv_sec = bhp->TsSec;
+ pkthdr.ts.tv_usec = bhp->TsUsec;
+ pkthdr.caplen = caplen;
+ pkthdr.len = bhp->Originallen;
+ (*callback)(user, &pkthdr, datap);
+ bp += AIRPCAP_WORDALIGN(caplen + hdrlen);
+ if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) {
+ p->bp = bp;
+ p->cc = (int)(ep - bp);
+ return (n);
+ }
+ } else {
+ /*
+ * Skip this packet.
+ */
+ bp += AIRPCAP_WORDALIGN(caplen + hdrlen);
+ }
+ }
+#undef bhp
+ p->cc = 0;
+ return (n);
+}
+
+static int
+airpcap_inject(pcap_t *p, const void *buf, int size)
+{
+ struct pcap_airpcap *pa = p->priv;
+
+ /*
+ * XXX - the second argument to AirpcapWrite() *should* have
+ * been declared as a const pointer - a write function that
+ * stomps on what it writes is *extremely* rude - but such
+ * is life. We assume it is, in fact, not going to write on
+ * our buffer.
+ */
+ if (!p_AirpcapWrite(pa->adapter, (void *)buf, size)) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "AirpcapWrite() failed: %s",
+ p_AirpcapGetLastError(pa->adapter));
+ return (-1);
+ }
+
+ /*
+ * We assume it all got sent if "AirpcapWrite()" succeeded.
+ * "pcap_inject()" is expected to return the number of bytes
+ * sent.
+ */
+ return (size);
+}
+
+static void
+airpcap_cleanup(pcap_t *p)
+{
+ struct pcap_airpcap *pa = p->priv;
+
+ if (pa->adapter != NULL) {
+ p_AirpcapClose(pa->adapter);
+ pa->adapter = NULL;
+ }
+ pcap_cleanup_live_common(p);
+}
+
+static void
+airpcap_breakloop(pcap_t *p)
+{
+ HANDLE read_event;
+
+ pcap_breakloop_common(p);
+ struct pcap_airpcap *pa = p->priv;
+
+ /* XXX - what if either of these fail? */
+ /*
+ * XXX - will SetEvent() force a wakeup and, if so, will
+ * the AirPcap read code handle that sanely?
+ */
+ if (!p_AirpcapGetReadEvent(pa->adapter, &read_event))
+ return;
+ SetEvent(read_event);
+}
+
+static int
+airpcap_activate(pcap_t *p)
+{
+ struct pcap_airpcap *pa = p->priv;
+ char *device = p->opt.device;
+ char airpcap_errbuf[AIRPCAP_ERRBUF_SIZE];
+ BOOL status;
+ AirpcapLinkType link_type;
+
+ pa->adapter = p_AirpcapOpen(device, airpcap_errbuf);
+ if (pa->adapter == NULL) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s", airpcap_errbuf);
+ return (PCAP_ERROR);
+ }
+
+ /*
+ * Set monitor mode appropriately.
+ * Always turn off the "ACK frames sent to the card" mode.
+ */
+ if (p->opt.rfmon) {
+ status = p_AirpcapSetDeviceMacFlags(pa->adapter,
+ AIRPCAP_MF_MONITOR_MODE_ON);
+ } else
+ status = p_AirpcapSetDeviceMacFlags(pa->adapter,
+ AIRPCAP_MF_ACK_FRAMES_ON);
+ if (!status) {
+ p_AirpcapClose(pa->adapter);
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "AirpcapSetDeviceMacFlags() failed: %s",
+ p_AirpcapGetLastError(pa->adapter));
+ return (PCAP_ERROR);
+ }
+
+ /*
+ * Turn a negative snapshot value (invalid), a snapshot value of
+ * 0 (unspecified), or a value bigger than the normal maximum
+ * value, into the maximum allowed value.
+ *
+ * If some application really *needs* a bigger snapshot
+ * length, we should just increase MAXIMUM_SNAPLEN.
+ */
+ if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN)
+ p->snapshot = MAXIMUM_SNAPLEN;
+
+ /*
+ * If the buffer size wasn't explicitly set, default to
+ * AIRPCAP_DEFAULT_KERNEL_BUFFER_SIZE.
+ */
+ if (p->opt.buffer_size == 0)
+ p->opt.buffer_size = AIRPCAP_DEFAULT_KERNEL_BUFFER_SIZE;
+
+ if (!p_AirpcapSetKernelBuffer(pa->adapter, p->opt.buffer_size)) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "AirpcapSetKernelBuffer() failed: %s",
+ p_AirpcapGetLastError(pa->adapter));
+ goto bad;
+ }
+
+ if(!p_AirpcapGetReadEvent(pa->adapter, &pa->read_event)) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "AirpcapGetReadEvent() failed: %s",
+ p_AirpcapGetLastError(pa->adapter));
+ goto bad;
+ }
+
+ /* Set the buffer size */
+ p->bufsize = AIRPCAP_DEFAULT_USER_BUFFER_SIZE;
+ p->buffer = malloc(p->bufsize);
+ if (p->buffer == NULL) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ goto bad;
+ }
+
+ if (p->opt.immediate) {
+ /* Tell the driver to copy the buffer as soon as data arrives. */
+ if (!p_AirpcapSetMinToCopy(pa->adapter, 0)) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "AirpcapSetMinToCopy() failed: %s",
+ p_AirpcapGetLastError(pa->adapter));
+ goto bad;
+ }
+ } else {
+ /*
+ * Tell the driver to copy the buffer only if it contains
+ * at least 16K.
+ */
+ if (!p_AirpcapSetMinToCopy(pa->adapter, 16000)) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "AirpcapSetMinToCopy() failed: %s",
+ p_AirpcapGetLastError(pa->adapter));
+ goto bad;
+ }
+ }
+
+ /*
+ * Find out what the default link-layer header type is,
+ * and set p->datalink to that.
+ *
+ * We don't force it to another value because there
+ * might be some programs using WinPcap/Npcap that,
+ * when capturing on AirPcap devices, assume the
+ * default value set with the AirPcap configuration
+ * program is what you get.
+ *
+ * The out-of-the-box default appears to be radiotap.
+ */
+ if (!p_AirpcapGetLinkType(pa->adapter, &link_type)) {
+ /* That failed. */
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "AirpcapGetLinkType() failed: %s",
+ p_AirpcapGetLastError(pa->adapter));
+ goto bad;
+ }
+ switch (link_type) {
+
+ case AIRPCAP_LT_802_11_PLUS_RADIO:
+ p->linktype = DLT_IEEE802_11_RADIO;
+ break;
+
+ case AIRPCAP_LT_802_11_PLUS_PPI:
+ p->linktype = DLT_PPI;
+ break;
+
+ case AIRPCAP_LT_802_11:
+ p->linktype = DLT_IEEE802_11;
+ break;
+
+ case AIRPCAP_LT_UNKNOWN:
+ default:
+ /* OK, what? */
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "AirpcapGetLinkType() returned unknown link type %u",
+ link_type);
+ goto bad;
+ }
+
+ /*
+ * Now provide a list of all the supported types; we
+ * assume they all work. We put radiotap at the top,
+ * followed by PPI, followed by "no radio metadata".
+ */
+ p->dlt_list = (u_int *) malloc(sizeof(u_int) * 3);
+ if (p->dlt_list == NULL)
+ goto bad;
+ p->dlt_list[0] = DLT_IEEE802_11_RADIO;
+ p->dlt_list[1] = DLT_PPI;
+ p->dlt_list[2] = DLT_IEEE802_11;
+ p->dlt_count = 3;
+
+ p->read_op = airpcap_read;
+ p->inject_op = airpcap_inject;
+ p->setfilter_op = airpcap_setfilter;
+ p->setdirection_op = NULL; /* Not implemented. */
+ p->set_datalink_op = airpcap_set_datalink;
+ p->getnonblock_op = airpcap_getnonblock;
+ p->setnonblock_op = airpcap_setnonblock;
+ p->breakloop_op = airpcap_breakloop;
+ p->stats_op = airpcap_stats;
+ p->stats_ex_op = airpcap_stats_ex;
+ p->setbuff_op = airpcap_setbuff;
+ p->setmode_op = airpcap_setmode;
+ p->setmintocopy_op = airpcap_setmintocopy;
+ p->getevent_op = airpcap_getevent;
+ p->oid_get_request_op = airpcap_oid_get_request;
+ p->oid_set_request_op = airpcap_oid_set_request;
+ p->sendqueue_transmit_op = airpcap_sendqueue_transmit;
+ p->setuserbuffer_op = airpcap_setuserbuffer;
+ p->live_dump_op = airpcap_live_dump;
+ p->live_dump_ended_op = airpcap_live_dump_ended;
+ p->get_airpcap_handle_op = airpcap_get_airpcap_handle;
+ p->cleanup_op = airpcap_cleanup;
+
+ return (0);
+ bad:
+ airpcap_cleanup(p);
+ return (PCAP_ERROR);
+}
+
+/*
+ * Monitor mode is supported.
+ */
+static int
+airpcap_can_set_rfmon(pcap_t *p)
+{
+ return (1);
+}
+
+int
+device_is_airpcap(const char *device, char *ebuf)
+{
+ static const char airpcap_prefix[] = "\\\\.\\airpcap";
+
+ /*
+ * We don't determine this by calling AirpcapGetDeviceList()
+ * and looking at the list, as that appears to be a costly
+ * operation.
+ *
+ * Instead, we just check whether it begins with "\\.\airpcap".
+ */
+ if (strncmp(device, airpcap_prefix, sizeof airpcap_prefix - 1) == 0) {
+ /*
+ * Yes, it's an AirPcap device.
+ */
+ return (1);
+ }
+
+ /*
+ * No, it's not an AirPcap device.
+ */
+ return (0);
+}
+
+pcap_t *
+airpcap_create(const char *device, char *ebuf, int *is_ours)
+{
+ int ret;
+ pcap_t *p;
+
+ /*
+ * This can be called before we've tried loading the library,
+ * so do so if we haven't already tried to do so.
+ */
+ if (load_airpcap_functions() != AIRPCAP_API_LOADED) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "Couldn't load AirPcap DLL\n");
+ return (NULL);
+ }
+
+ /*
+ * Is this an AirPcap device?
+ */
+ ret = device_is_airpcap(device, ebuf);
+ if (ret == 0) {
+ /* No. */
+ *is_ours = 0;
+ return (NULL);
+ }
+
+ /*
+ * Yes.
+ */
+ *is_ours = 1;
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_airpcap);
+ if (p == NULL)
+ return (NULL);
+
+ p->activate_op = airpcap_activate;
+ p->can_set_rfmon_op = airpcap_can_set_rfmon;
+ return (p);
+}
+
+/*
+ * Add all AirPcap devices.
+ */
+int
+airpcap_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
+{
+ AirpcapDeviceDescription *airpcap_devices, *airpcap_device;
+ char airpcap_errbuf[AIRPCAP_ERRBUF_SIZE];
+
+ /*
+ * This can be called before we've tried loading the library,
+ * so do so if we haven't already tried to do so.
+ */
+ if (load_airpcap_functions() != AIRPCAP_API_LOADED) {
+ /*
+ * XXX - unless the error is "no such DLL", report this
+ * as an error rather than as "no AirPcap devices"?
+ */
+ return (0);
+ }
+
+ if (!p_AirpcapGetDeviceList(&airpcap_devices, airpcap_errbuf)) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "AirpcapGetDeviceList() failed: %s", airpcap_errbuf);
+ return (-1);
+ }
+
+ for (airpcap_device = airpcap_devices; airpcap_device != NULL;
+ airpcap_device = airpcap_device->next) {
+ if (add_dev(devlistp, airpcap_device->Name, 0,
+ airpcap_device->Description, errbuf) == NULL) {
+ /*
+ * Failure.
+ */
+ p_AirpcapFreeDeviceList(airpcap_devices);
+ return (-1);
+ }
+ }
+ p_AirpcapFreeDeviceList(airpcap_devices);
+ return (0);
+}
diff --git a/pcap-airpcap.h b/pcap-airpcap.h
new file mode 100644
index 00000000..aa1164ed
--- /dev/null
+++ b/pcap-airpcap.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
+ * Copyright (c) 2005 - 2010 CACE Technologies, Davis (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. Neither the name of the Politecnico di Torino, CACE Technologies
+ * nor the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+pcap_t *airpcap_create(const char *, char *, int *);
+int airpcap_findalldevs(pcap_if_list_t *devlistp, char *errbuf);
+int device_is_airpcap(const char *device, char *ebuf);
diff --git a/pcap-bpf.c b/pcap-bpf.c
index 4f1a0afb..f0ccb965 100644
--- a/pcap-bpf.c
+++ b/pcap-bpf.c
@@ -115,7 +115,6 @@ static int bpf_load(char *errbuf);
#endif /* _AIX */
-#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
@@ -153,7 +152,7 @@ struct pcap_bpf {
* As there is a header on the front size of the mmap'd buffer, only
* some of the buffer is exposed to libpcap as a whole via bufsize;
* zbufsize is the true size. zbuffer tracks the current zbuf
- * assocated with buffer so that it can be used to decide which the
+ * associated with buffer so that it can be used to decide which the
* next buffer to read will be.
*/
u_char *zbuf1, *zbuf2, *zbuffer;
@@ -313,7 +312,7 @@ pcap_next_zbuf_shm(pcap_t *p, int *cc)
atomic_load_acq_int(&bzh->bzh_kernel_gen)) {
pb->bzh = bzh;
pb->zbuffer = (u_char *)pb->zbuf2;
- p->buffer = pb->zbuffer + sizeof(*bzh);
+ p->buffer = pb->zbuffer + sizeof(*bzh);
*cc = bzh->bzh_kernel_len;
return (1);
}
@@ -445,7 +444,7 @@ pcap_create_interface(const char *device _U_, char *ebuf)
{
pcap_t *p;
- p = pcap_create_common(ebuf, sizeof (struct pcap_bpf));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_bpf);
if (p == NULL)
return (NULL);
@@ -456,7 +455,6 @@ pcap_create_interface(const char *device _U_, char *ebuf)
* We claim that we support microsecond and nanosecond time
* stamps.
*/
- p->tstamp_precision_count = 2;
p->tstamp_precision_list = malloc(2 * sizeof(u_int));
if (p->tstamp_precision_list == NULL) {
pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno,
@@ -466,6 +464,7 @@ pcap_create_interface(const char *device _U_, char *ebuf)
}
p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO;
p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO;
+ p->tstamp_precision_count = 2;
#endif /* BIOCSTSTAMP */
return (p);
}
@@ -522,7 +521,7 @@ bpf_open(char *errbuf)
* that isn't in use.
*/
do {
- (void)pcap_snprintf(device, sizeof(device), "/dev/bpf%d", n++);
+ (void)snprintf(device, sizeof(device), "/dev/bpf%d", n++);
/*
* Initially try a read/write open (to allow the inject
* method to work). If that fails due to permission
@@ -557,7 +556,7 @@ bpf_open(char *errbuf)
* means we probably have no BPF
* devices.
*/
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"(there are no BPF devices)");
} else {
/*
@@ -566,7 +565,7 @@ bpf_open(char *errbuf)
* devices, but all the ones
* that exist are busy.
*/
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"(all BPF devices are busy)");
}
break;
@@ -597,38 +596,66 @@ bpf_open(char *errbuf)
}
/*
- * Open and bind to a device; used if we're not actually going to use
- * the device, but are just testing whether it can be opened, or opening
- * it to get information about it.
+ * Bind a network adapter to a BPF device, given a descriptor for the
+ * BPF device and the name of the network adapter.
*
- * Returns an error code on failure (always negative), and an FD for
- * the now-bound BPF device on success (always non-negative).
+ * Use BIOCSETLIF if available (meaning "on Solaris"), as it supports
+ * longer device names.
+ *
+ * If the name is longer than will fit, return PCAP_ERROR_NO_SUCH_DEVICE
+ * before trying to bind the interface, as there cannot be such a device.
+ *
+ * If the attempt succeeds, return BPF_BIND_SUCCEEDED.
+ *
+ * If the attempt fails:
+ *
+ * if it fails with ENXIO, return PCAP_ERROR_NO_SUCH_DEVICE, as
+ * the device doesn't exist;
+ *
+ * if it fails with ENETDOWN, return PCAP_ERROR_IFACE_NOT_UP, as
+ * the interface exists but isn't up and the OS doesn't allow
+ * binding to an interface that isn't up;
+ *
+ * if it fails with ENOBUFS, return BPF_BIND_BUFFER_TOO_BIG, and
+ * fill in an error message, as the buffer being requested is too
+ * large;
+ *
+ * otherwise, return PCAP_ERROR and fill in an error message.
*/
+#define BPF_BIND_SUCCEEDED 0
+#define BPF_BIND_BUFFER_TOO_BIG 1
+
static int
-bpf_open_and_bind(const char *name, char *errbuf)
+bpf_bind(int fd, const char *name, char *errbuf)
{
- int fd;
+ int status;
+#ifdef LIFNAMSIZ
+ struct lifreq ifr;
+
+ if (strlen(name) >= sizeof(ifr.lifr_name)) {
+ /* The name is too long, so it can't possibly exist. */
+ return (PCAP_ERROR_NO_SUCH_DEVICE);
+ }
+ (void)pcap_strlcpy(ifr.lifr_name, name, sizeof(ifr.lifr_name));
+ status = ioctl(fd, BIOCSETLIF, (caddr_t)&ifr);
+#else
struct ifreq ifr;
- /*
- * First, open a BPF device.
- */
- fd = bpf_open(errbuf);
- if (fd < 0)
- return (fd); /* fd is the appropriate error code */
+ if (strlen(name) >= sizeof(ifr.ifr_name)) {
+ /* The name is too long, so it can't possibly exist. */
+ return (PCAP_ERROR_NO_SUCH_DEVICE);
+ }
+ (void)pcap_strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ status = ioctl(fd, BIOCSETIF, (caddr_t)&ifr);
+#endif
- /*
- * Now bind to the device.
- */
- (void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
- if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
+ if (status < 0) {
switch (errno) {
case ENXIO:
/*
* There's no such device.
*/
- close(fd);
return (PCAP_ERROR_NO_SUCH_DEVICE);
case ENETDOWN:
@@ -639,16 +666,68 @@ bpf_open_and_bind(const char *name, char *errbuf)
* suggest that they report a problem to the
* libpcap developers.
*/
- close(fd);
return (PCAP_ERROR_IFACE_NOT_UP);
+ case ENOBUFS:
+ /*
+ * The buffer size is too big.
+ * Return a special indication so that, if we're
+ * trying to crank the buffer size down, we know
+ * we have to continue; add an error message that
+ * tells the user what needs to be fixed.
+ */
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
+ errno, "The requested buffer size for %s is too large",
+ name);
+ return (BPF_BIND_BUFFER_TOO_BIG);
+
default:
pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
- errno, "BIOCSETIF: %s", name);
- close(fd);
+ errno, "Binding interface %s to BPF device failed",
+ name);
return (PCAP_ERROR);
}
}
+ return (BPF_BIND_SUCCEEDED);
+}
+
+/*
+ * Open and bind to a device; used if we're not actually going to use
+ * the device, but are just testing whether it can be opened, or opening
+ * it to get information about it.
+ *
+ * Returns an error code on failure (always negative), and an FD for
+ * the now-bound BPF device on success (always non-negative).
+ */
+static int
+bpf_open_and_bind(const char *name, char *errbuf)
+{
+ int fd;
+ int status;
+
+ /*
+ * First, open a BPF device.
+ */
+ fd = bpf_open(errbuf);
+ if (fd < 0)
+ return (fd); /* fd is the appropriate error code */
+
+ /*
+ * Now bind to the device.
+ */
+ status = bpf_bind(fd, name, errbuf);
+ if (status != BPF_BIND_SUCCEEDED) {
+ close(fd);
+ if (status == BPF_BIND_BUFFER_TOO_BIG) {
+ /*
+ * We didn't specify a buffer size, so
+ * this *really* shouldn't fail because
+ * there's no buffer space. Fail.
+ */
+ return (PCAP_ERROR);
+ }
+ return (status);
+ }
/*
* Success.
@@ -656,6 +735,47 @@ bpf_open_and_bind(const char *name, char *errbuf)
return (fd);
}
+#ifdef __APPLE__
+static int
+device_exists(int fd, const char *name, char *errbuf)
+{
+ int status;
+ struct ifreq ifr;
+
+ if (strlen(name) >= sizeof(ifr.ifr_name)) {
+ /* The name is too long, so it can't possibly exist. */
+ return (PCAP_ERROR_NO_SUCH_DEVICE);
+ }
+ (void)pcap_strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ status = ioctl(fd, SIOCGIFFLAGS, (caddr_t)&ifr);
+
+ if (status < 0) {
+ if (errno == ENXIO || errno == EINVAL) {
+ /*
+ * macOS and *BSD return one of those two
+ * errors if the device doesn't exist.
+ * Don't fill in an error, as this is
+ * an "expected" condition.
+ */
+ return (PCAP_ERROR_NO_SUCH_DEVICE);
+ }
+
+ /*
+ * Some other error - provide a message for it, as
+ * it's "unexpected".
+ */
+ pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno,
+ "Can't get interface flags on %s", name);
+ return (PCAP_ERROR);
+ }
+
+ /*
+ * The device exists.
+ */
+ return (0);
+}
+#endif
+
#ifdef BIOCGDLTLIST
static int
get_dlt_list(int fd, int v, struct bpf_dltlist *bdlp, char *ebuf)
@@ -742,10 +862,10 @@ static int
pcap_can_set_rfmon_bpf(pcap_t *p)
{
struct utsname osinfo;
- struct ifreq ifr;
int fd;
#ifdef BIOCGDLTLIST
struct bpf_dltlist bdl;
+ int err;
#endif
/*
@@ -783,6 +903,9 @@ pcap_can_set_rfmon_bpf(pcap_t *p)
return (0);
}
if (osinfo.release[0] == '8' && osinfo.release[1] == '.') {
+ char *wlt_name;
+ int status;
+
/*
* 10.4 (Darwin 8.x). s/en/wlt/, and check
* whether the device exists.
@@ -799,16 +922,24 @@ pcap_can_set_rfmon_bpf(pcap_t *p)
errno, "socket");
return (PCAP_ERROR);
}
- pcap_strlcpy(ifr.ifr_name, "wlt", sizeof(ifr.ifr_name));
- pcap_strlcat(ifr.ifr_name, p->opt.device + 2, sizeof(ifr.ifr_name));
- if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
- /*
- * No such device?
- */
+ if (pcap_asprintf(&wlt_name, "wlt%s", p->opt.device + 2) == -1) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
close(fd);
- return (0);
+ return (PCAP_ERROR);
}
+ status = device_exists(fd, wlt_name, p->errbuf);
+ free(wlt_name);
close(fd);
+ if (status != 0) {
+ if (status == PCAP_ERROR_NO_SUCH_DEVICE)
+ return (0);
+
+ /*
+ * Error.
+ */
+ return (status);
+ }
return (1);
}
@@ -827,34 +958,18 @@ pcap_can_set_rfmon_bpf(pcap_t *p)
/*
* Now bind to the device.
*/
- (void)strncpy(ifr.ifr_name, p->opt.device, sizeof(ifr.ifr_name));
- if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
- switch (errno) {
-
- case ENXIO:
- /*
- * There's no such device.
- */
- close(fd);
- return (PCAP_ERROR_NO_SUCH_DEVICE);
-
- case ENETDOWN:
+ err = bpf_bind(fd, p->opt.device, p->errbuf);
+ if (err != BPF_BIND_SUCCEEDED) {
+ close(fd);
+ if (err == BPF_BIND_BUFFER_TOO_BIG) {
/*
- * Return a "network down" indication, so that
- * the application can report that rather than
- * saying we had a mysterious failure and
- * suggest that they report a problem to the
- * libpcap developers.
+ * We didn't specify a buffer size, so
+ * this *really* shouldn't fail because
+ * there's no buffer space. Fail.
*/
- close(fd);
- return (PCAP_ERROR_IFACE_NOT_UP);
-
- default:
- pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
- errno, "BIOCSETIF: %s", p->opt.device);
- close(fd);
return (PCAP_ERROR);
}
+ return (err);
}
/*
@@ -982,7 +1097,7 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
} else
#endif
{
- cc = read(p->fd, p->buffer, p->bufsize);
+ cc = (int)read(p->fd, p->buffer, p->bufsize);
}
if (cc < 0) {
/* Don't choke when we get ptraced */
@@ -1033,7 +1148,7 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
* documented as having error returns
* other than PCAP_ERROR or PCAP_ERROR_BREAK.
*/
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The interface disappeared");
return (PCAP_ERROR);
@@ -1087,7 +1202,7 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
*/
if (p->break_loop) {
p->bp = bp;
- p->cc = ep - bp;
+ p->cc = (int)(ep - bp);
/*
* ep is set based on the return value of read(),
* but read() from a BPF device doesn't necessarily
@@ -1127,7 +1242,7 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
#endif
*/
if (pb->filtering_in_kernel ||
- bpf_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) {
+ pcap_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) {
struct pcap_pkthdr pkthdr;
#ifdef BIOCSTSTAMP
struct bintime bt;
@@ -1177,7 +1292,7 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
bp += BPF_WORDALIGN(caplen + hdrlen);
if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) {
p->bp = bp;
- p->cc = ep - bp;
+ p->cc = (int)(ep - bp);
/*
* See comment above about p->cc < 0.
*/
@@ -1198,11 +1313,11 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
}
static int
-pcap_inject_bpf(pcap_t *p, const void *buf, size_t size)
+pcap_inject_bpf(pcap_t *p, const void *buf, int size)
{
int ret;
- ret = write(p->fd, buf, size);
+ ret = (int)write(p->fd, buf, size);
#ifdef __APPLE__
if (ret == -1 && errno == EAFNOSUPPORT) {
/*
@@ -1234,7 +1349,7 @@ pcap_inject_bpf(pcap_t *p, const void *buf, size_t size)
/*
* Now try the write again.
*/
- ret = write(p->fd, buf, size);
+ ret = (int)write(p->fd, buf, size);
}
#endif /* __APPLE__ */
if (ret == -1) {
@@ -1254,7 +1369,7 @@ bpf_odminit(char *errbuf)
if (odm_initialize() == -1) {
if (odm_err_msg(odmerrno, &errstr) == -1)
errstr = "Unknown error";
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"bpf_load: odm_initialize failed: %s",
errstr);
return (PCAP_ERROR);
@@ -1263,7 +1378,7 @@ bpf_odminit(char *errbuf)
if ((odmlockid = odm_lock("/etc/objrepos/config_lock", ODM_WAIT)) == -1) {
if (odm_err_msg(odmerrno, &errstr) == -1)
errstr = "Unknown error";
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"bpf_load: odm_lock of /etc/objrepos/config_lock failed: %s",
errstr);
(void)odm_terminate();
@@ -1282,7 +1397,7 @@ bpf_odmcleanup(char *errbuf)
if (errbuf != NULL) {
if (odm_err_msg(odmerrno, &errstr) == -1)
errstr = "Unknown error";
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"bpf_load: odm_unlock failed: %s",
errstr);
}
@@ -1293,7 +1408,7 @@ bpf_odmcleanup(char *errbuf)
if (errbuf != NULL) {
if (odm_err_msg(odmerrno, &errstr) == -1)
errstr = "Unknown error";
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"bpf_load: odm_terminate failed: %s",
errstr);
}
@@ -1356,7 +1471,7 @@ bpf_load(char *errbuf)
if (rc == -1 || getmajor(sbuf.st_rdev) != major) {
for (i = 0; i < BPF_MINORS; i++) {
- pcap_snprintf(buf, sizeof(buf), "%s%d", BPF_NODE, i);
+ snprintf(buf, sizeof(buf), "%s%d", BPF_NODE, i);
unlink(buf);
if (mknod(buf, S_IRUSR | S_IFCHR, domakedev(major, i)) == -1) {
pcap_fmt_errmsg_for_errno(errbuf,
@@ -1369,7 +1484,7 @@ bpf_load(char *errbuf)
/* Check if the driver is loaded */
memset(&cfg_ld, 0x0, sizeof(cfg_ld));
- pcap_snprintf(buf, sizeof(buf), "%s/%s", DRIVER_PATH, BPF_NAME);
+ snprintf(buf, sizeof(buf), "%s/%s", DRIVER_PATH, BPF_NAME);
cfg_ld.path = buf;
if ((sysconfig(SYS_QUERYLOAD, (void *)&cfg_ld, sizeof(cfg_ld)) == -1) ||
(cfg_ld.kmid == 0)) {
@@ -1437,7 +1552,7 @@ pcap_cleanup_bpf(pcap_t *p)
strerror(errno));
} else {
memset(&req, 0, sizeof(req));
- strncpy(req.ifm_name, pb->device,
+ pcap_strlcpy(req.ifm_name, pb->device,
sizeof(req.ifm_name));
if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) {
fprintf(stderr,
@@ -1451,7 +1566,7 @@ pcap_cleanup_bpf(pcap_t *p)
* turn it off.
*/
memset(&ifr, 0, sizeof(ifr));
- (void)strncpy(ifr.ifr_name,
+ (void)pcap_strlcpy(ifr.ifr_name,
pb->device,
sizeof(ifr.ifr_name));
ifr.ifr_media =
@@ -1519,20 +1634,17 @@ pcap_cleanup_bpf(pcap_t *p)
pcap_cleanup_live_common(p);
}
+#ifdef __APPLE__
static int
check_setif_failure(pcap_t *p, int error)
{
-#ifdef __APPLE__
int fd;
- struct ifreq ifr;
int err;
-#endif
- if (error == ENXIO) {
+ if (error == PCAP_ERROR_NO_SUCH_DEVICE) {
/*
* No such device exists.
*/
-#ifdef __APPLE__
if (p->opt.rfmon && strncmp(p->opt.device, "wlt", 3) == 0) {
/*
* Monitor mode was requested, and we're trying
@@ -1543,33 +1655,38 @@ check_setif_failure(pcap_t *p, int error)
*/
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd != -1) {
- pcap_strlcpy(ifr.ifr_name, "en",
- sizeof(ifr.ifr_name));
- pcap_strlcat(ifr.ifr_name, p->opt.device + 3,
- sizeof(ifr.ifr_name));
- if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
+ char *en_name;
+
+ if (pcap_asprintf(&en_name, "en%s",
+ p->opt.device + 3) == -1) {
/*
- * We assume this failed because
- * the underlying device doesn't
- * exist.
+ * We can't find out whether there's
+ * an underlying "enN" device, so
+ * just report "no such device".
*/
- err = PCAP_ERROR_NO_SUCH_DEVICE;
pcap_fmt_errmsg_for_errno(p->errbuf,
PCAP_ERRBUF_SIZE, errno,
- "SIOCGIFFLAGS on %s failed",
- ifr.ifr_name);
- } else {
- /*
- * The underlying "enN" device
- * exists, but there's no
- * corresponding "wltN" device;
- * that means that the "enN"
- * device doesn't support
- * monitor mode, probably because
- * it's an Ethernet device rather
- * than a wireless device.
- */
- err = PCAP_ERROR_RFMON_NOTSUP;
+ "malloc");
+ close(fd);
+ return (PCAP_ERROR_NO_SUCH_DEVICE);
+ }
+ err = device_exists(fd, en_name, p->errbuf);
+ free(en_name);
+ if (err != 0) {
+ if (err == PCAP_ERROR_NO_SUCH_DEVICE) {
+ /*
+ * The underlying "enN" device
+ * exists, but there's no
+ * corresponding "wltN" device;
+ * that means that the "enN"
+ * device doesn't support
+ * monitor mode, probably
+ * because it's an Ethernet
+ * device rather than a
+ * wireless device.
+ */
+ err = PCAP_ERROR_RFMON_NOTSUP;
+ }
}
close(fd);
} else {
@@ -1585,32 +1702,30 @@ check_setif_failure(pcap_t *p, int error)
}
return (err);
}
-#endif
+
/*
* No such device.
*/
- pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
- errno, "BIOCSETIF failed");
return (PCAP_ERROR_NO_SUCH_DEVICE);
- } else if (errno == ENETDOWN) {
- /*
- * Return a "network down" indication, so that
- * the application can report that rather than
- * saying we had a mysterious failure and
- * suggest that they report a problem to the
- * libpcap developers.
- */
- return (PCAP_ERROR_IFACE_NOT_UP);
- } else {
- /*
- * Some other error; fill in the error string, and
- * return PCAP_ERROR.
- */
- pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
- errno, "BIOCSETIF: %s", p->opt.device);
- return (PCAP_ERROR);
}
+
+ /*
+ * Just return the error status; it's what we want, and, if it's
+ * PCAP_ERROR, the error string has been filled in.
+ */
+ return (error);
+}
+#else
+static int
+check_setif_failure(pcap_t *p _U_, int error)
+{
+ /*
+ * Just return the error status; it's what we want, and, if it's
+ * PCAP_ERROR, the error string has been filled in.
+ */
+ return (error);
}
+#endif
/*
* Default capture buffer size.
@@ -1636,15 +1751,9 @@ pcap_activate_bpf(pcap_t *p)
int retv;
#endif
int fd;
-#ifdef LIFNAMSIZ
- char *zonesep;
+#if defined(LIFNAMSIZ) && defined(ZONENAME_MAX) && defined(lifr_zoneid)
struct lifreq ifr;
- char *ifrname = ifr.lifr_name;
- const size_t ifnamsiz = sizeof(ifr.lifr_name);
-#else
- struct ifreq ifr;
- char *ifrname = ifr.ifr_name;
- const size_t ifnamsiz = sizeof(ifr.ifr_name);
+ char *zonesep;
#endif
struct bpf_version bv;
#ifdef __APPLE__
@@ -1686,7 +1795,7 @@ pcap_activate_bpf(pcap_t *p)
}
if (bv.bv_major != BPF_MAJOR_VERSION ||
bv.bv_minor < BPF_MINOR_VERSION) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"kernel bpf filter out of date");
status = PCAP_ERROR;
goto bad;
@@ -1726,7 +1835,7 @@ pcap_activate_bpf(pcap_t *p)
char *lnamep;
if (ifr.lifr_zoneid != GLOBAL_ZONEID) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"zonename/linkname only valid in global zone.");
status = PCAP_ERROR;
goto bad;
@@ -1797,24 +1906,19 @@ pcap_activate_bpf(pcap_t *p)
*/
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd != -1) {
- pcap_strlcpy(ifrname,
- p->opt.device, ifnamsiz);
- if (ioctl(sockfd, SIOCGIFFLAGS,
- (char *)&ifr) < 0) {
+ status = device_exists(sockfd,
+ p->opt.device, p->errbuf);
+ if (status == 0) {
/*
- * We assume this
- * failed because
- * the underlying
- * device doesn't
- * exist.
+ * The device exists,
+ * but it's not an
+ * enN device; that
+ * means it doesn't
+ * support monitor
+ * mode.
*/
- status = PCAP_ERROR_NO_SUCH_DEVICE;
- pcap_fmt_errmsg_for_errno(p->errbuf,
- PCAP_ERRBUF_SIZE,
- errno,
- "SIOCGIFFLAGS failed");
- } else
status = PCAP_ERROR_RFMON_NOTSUP;
+ }
close(sockfd);
} else {
/*
@@ -1866,6 +1970,7 @@ pcap_activate_bpf(pcap_t *p)
* it when the pcap_t is closed.
*/
int s;
+ struct ifreq ifr;
/*
* Open a socket to use for ioctls to
@@ -1889,7 +1994,7 @@ pcap_activate_bpf(pcap_t *p)
* "atexit()" failed; don't create the
* interface, just give up.
*/
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"atexit failed");
close(s);
status = PCAP_ERROR;
@@ -1902,7 +2007,7 @@ pcap_activate_bpf(pcap_t *p)
pcap_strlcpy(ifr.ifr_name, p->opt.device, sizeof(ifr.ifr_name));
if (ioctl(s, SIOCIFCREATE2, &ifr) < 0) {
if (errno == EINVAL) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Invalid USB bus interface %s",
p->opt.device);
} else {
@@ -1994,11 +2099,19 @@ pcap_activate_bpf(pcap_t *p)
status = PCAP_ERROR;
goto bad;
}
- (void)strncpy(ifrname, p->opt.device, ifnamsiz);
- if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
- pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
- errno, "BIOCSETIF: %s", p->opt.device);
- status = PCAP_ERROR;
+ status = bpf_bind(fd, p->opt.device, ifnamsiz, p->errbuf);
+ if (status != BPF_BIND_SUCCEEDED) {
+ if (status == BPF_BIND_BUFFER_TOO_BIG) {
+ /*
+ * The requested buffer size
+ * is too big. Fail.
+ *
+ * XXX - should we do the "keep cutting
+ * the buffer size in half" loop here if
+ * we're using the default buffer size?
+ */
+ status = PCAP_ERROR;
+ }
goto bad;
}
v = pb->zbufsize - sizeof(struct bpf_zbuf_header);
@@ -2025,14 +2138,23 @@ pcap_activate_bpf(pcap_t *p)
/*
* Now bind to the device.
*/
- (void)strncpy(ifrname, p->opt.device, ifnamsiz);
-#ifdef BIOCSETLIF
- if (ioctl(fd, BIOCSETLIF, (caddr_t)&ifr) < 0)
-#else
- if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0)
-#endif
- {
- status = check_setif_failure(p, errno);
+ status = bpf_bind(fd, p->opt.device, p->errbuf);
+ if (status != BPF_BIND_SUCCEEDED) {
+ if (status == BPF_BIND_BUFFER_TOO_BIG) {
+ /*
+ * The requested buffer size
+ * is too big. Fail.
+ */
+ status = PCAP_ERROR;
+ goto bad;
+ }
+
+ /*
+ * Special checks on macOS to deal with
+ * the way monitor mode was done on
+ * 10.4 Tiger.
+ */
+ status = check_setif_failure(p, status);
goto bad;
}
} else {
@@ -2058,22 +2180,30 @@ pcap_activate_bpf(pcap_t *p)
*/
(void) ioctl(fd, BIOCSBLEN, (caddr_t)&v);
- (void)strncpy(ifrname, p->opt.device, ifnamsiz);
-#ifdef BIOCSETLIF
- if (ioctl(fd, BIOCSETLIF, (caddr_t)&ifr) >= 0)
-#else
- if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0)
-#endif
+ status = bpf_bind(fd, p->opt.device, p->errbuf);
+ if (status == BPF_BIND_SUCCEEDED)
break; /* that size worked; we're done */
- if (errno != ENOBUFS) {
- status = check_setif_failure(p, errno);
+ /*
+ * If the attempt failed because the
+ * buffer was too big, cut the buffer
+ * size in half and try again.
+ *
+ * Otherwise, fail.
+ */
+ if (errno != BPF_BIND_BUFFER_TOO_BIG) {
+ /*
+ * Special checks on macOS to deal
+ * with the way monitor mode was
+ * done on 10.4 Tiger.
+ */
+ status = check_setif_failure(p, status);
goto bad;
}
}
if (v == 0) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"BIOCSBLEN: %s: No buffer size worked",
p->opt.device);
status = PCAP_ERROR;
@@ -2117,7 +2247,7 @@ pcap_activate_bpf(pcap_t *p)
/*
* We don't know what to map this to yet.
*/
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown interface type %u",
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown interface type %u",
v);
status = PCAP_ERROR;
goto bad;
@@ -2177,9 +2307,9 @@ pcap_activate_bpf(pcap_t *p)
* we try to select DLT_IEEE802_11.
*/
if (have_osinfo) {
- if (isdigit((unsigned)osinfo.release[0]) &&
+ if (PCAP_ISDIGIT((unsigned)osinfo.release[0]) &&
(osinfo.release[0] == '9' ||
- isdigit((unsigned)osinfo.release[1]))) {
+ PCAP_ISDIGIT((unsigned)osinfo.release[1]))) {
/*
* 10.5 (Darwin 9.x), or later.
*/
@@ -2429,7 +2559,7 @@ pcap_activate_bpf(pcap_t *p)
/*
* We don't support immediate mode. Fail.
*/
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Immediate mode not supported");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Immediate mode not supported");
status = PCAP_ERROR;
goto bad;
}
@@ -2756,10 +2886,14 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
return (-1);
}
memset(&req, 0, sizeof(req));
- strncpy(req.ifm_name, name, sizeof(req.ifm_name));
+ pcap_strlcpy(req.ifm_name, name, sizeof(req.ifm_name));
if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) {
if (errno == EOPNOTSUPP || errno == EINVAL || errno == ENOTTY ||
- errno == ENODEV || errno == EPERM) {
+ errno == ENODEV || errno == EPERM
+#ifdef EPWROFF
+ || errno == EPWROFF
+#endif
+ ) {
/*
* Not supported, so we can't provide any
* additional information. Assume that
@@ -2774,6 +2908,18 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
* So, just as we do for some ethtool ioctls
* on Linux, which makes the same mistake, we
* also treat EPERM as meaning "not supported".
+ *
+ * And it appears that Apple's llw0 device, which
+ * appears to be part of the Skywalk subsystem:
+ *
+ * http://newosxbook.com/bonus/vol1ch16.html
+ *
+ * can sometimes return EPWROFF ("Device power
+ * is off") for that ioctl, so we treat *that*
+ * as another indication that we can't get a
+ * connection status. (If it *isn't* "powered
+ * off", it's reported as a wireless device,
+ * complete with an active/inactive state.)
*/
*flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE;
close(sock);
@@ -2883,7 +3029,7 @@ monitor_mode(pcap_t *p, int set)
}
memset(&req, 0, sizeof req);
- strncpy(req.ifm_name, p->opt.device, sizeof req.ifm_name);
+ pcap_strlcpy(req.ifm_name, p->opt.device, sizeof req.ifm_name);
/*
* Find out how many media types we have.
@@ -2993,7 +3139,7 @@ monitor_mode(pcap_t *p, int set)
return (PCAP_ERROR);
}
memset(&ifr, 0, sizeof(ifr));
- (void)strncpy(ifr.ifr_name, p->opt.device,
+ (void)pcap_strlcpy(ifr.ifr_name, p->opt.device,
sizeof(ifr.ifr_name));
ifr.ifr_media = req.ifm_current | IFM_IEEE80211_MONITOR;
if (ioctl(sock, SIOCSIFMEDIA, &ifr) == -1) {
@@ -3259,14 +3405,101 @@ static int
pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d)
{
u_int direction;
+ const char *direction_name;
+
+ /*
+ * FreeBSD and NetBSD.
+ */
+ switch (d) {
+
+ case PCAP_D_IN:
+ /*
+ * Incoming, but not outgoing, so accept only
+ * incoming packets.
+ */
+ direction = BPF_D_IN;
+ direction_name = "\"incoming only\"";
+ break;
+
+ case PCAP_D_OUT:
+ /*
+ * Outgoing, but not incoming, so accept only
+ * outgoing packets.
+ */
+ direction = BPF_D_OUT;
+ direction_name = "\"outgoing only\"";
+ break;
+
+ default:
+ /*
+ * Incoming and outgoing, so accept both
+ * incoming and outgoing packets.
+ *
+ * It's guaranteed, at this point, that d is a valid
+ * direction value, so we know that this is PCAP_D_INOUT
+ * if it's not PCAP_D_IN or PCAP_D_OUT.
+ */
+ direction = BPF_D_INOUT;
+ direction_name = "\"incoming and outgoing\"";
+ break;
+ }
- direction = (d == PCAP_D_IN) ? BPF_D_IN :
- ((d == PCAP_D_OUT) ? BPF_D_OUT : BPF_D_INOUT);
if (ioctl(p->fd, BIOCSDIRECTION, &direction) == -1) {
pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
- errno, "Cannot set direction to %s",
- (d == PCAP_D_IN) ? "PCAP_D_IN" :
- ((d == PCAP_D_OUT) ? "PCAP_D_OUT" : "PCAP_D_INOUT"));
+ errno, "Cannot set direction to %s", direction_name);
+ return (-1);
+ }
+ return (0);
+}
+#elif defined(BIOCSDIRFILT)
+static int
+pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d)
+{
+ u_int dirfilt;
+ const char *direction_name;
+
+ /*
+ * OpenBSD; same functionality, different names, different
+ * semantics (the flags mean "*don't* capture packets in
+ * that direction", not "*capture only* packets in that
+ * direction").
+ */
+ switch (d) {
+
+ case PCAP_D_IN:
+ /*
+ * Incoming, but not outgoing, so filter out
+ * outgoing packets.
+ */
+ dirfilt = BPF_DIRECTION_OUT;
+ direction_name = "\"incoming only\"";
+ break;
+
+ case PCAP_D_OUT:
+ /*
+ * Outgoing, but not incoming, so filter out
+ * incoming packets.
+ */
+ dirfilt = BPF_DIRECTION_IN;
+ direction_name = "\"outgoing only\"";
+ break;
+
+ default:
+ /*
+ * Incoming and outgoing, so don't filter out
+ * any packets based on direction.
+ *
+ * It's guaranteed, at this point, that d is a valid
+ * direction value, so we know that this is PCAP_D_INOUT
+ * if it's not PCAP_D_IN or PCAP_D_OUT.
+ */
+ dirfilt = 0;
+ direction_name = "\"incoming and outgoing\"";
+ break;
+ }
+ if (ioctl(p->fd, BIOCSDIRFILT, &dirfilt) == -1) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
+ errno, "Cannot set direction to %s", direction_name);
return (-1);
}
return (0);
@@ -3276,21 +3509,47 @@ static int
pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d)
{
u_int seesent;
+ const char *direction_name;
/*
- * We don't support PCAP_D_OUT.
+ * OS with just BIOCSSEESENT.
*/
- if (d == PCAP_D_OUT) {
- pcap_snprintf(p->errbuf, sizeof(p->errbuf),
- "Setting direction to PCAP_D_OUT is not supported on BPF");
- return -1;
+ switch (d) {
+
+ case PCAP_D_IN:
+ /*
+ * Incoming, but not outgoing, so we don't want to
+ * see transmitted packets.
+ */
+ seesent = 0;
+ direction_name = "\"incoming only\"";
+ break;
+
+ case PCAP_D_OUT:
+ /*
+ * Outgoing, but not incoming; we can't specify that.
+ */
+ snprintf(p->errbuf, sizeof(p->errbuf),
+ "Setting direction to \"outgoing only\" is not supported on this device");
+ return (-1);
+
+ default:
+ /*
+ * Incoming and outgoing, so we want to see transmitted
+ * packets.
+ *
+ * It's guaranteed, at this point, that d is a valid
+ * direction value, so we know that this is PCAP_D_INOUT
+ * if it's not PCAP_D_IN or PCAP_D_OUT.
+ */
+ seesent = 1;
+ direction_name = "\"incoming and outgoing\"";
+ break;
}
- seesent = (d == PCAP_D_INOUT);
if (ioctl(p->fd, BIOCSSEESENT, &seesent) == -1) {
pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
- errno, "Cannot set direction to %s",
- (d == PCAP_D_INOUT) ? "PCAP_D_INOUT" : "PCAP_D_IN");
+ errno, "Cannot set direction to %s", direction_name);
return (-1);
}
return (0);
@@ -3299,8 +3558,8 @@ pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d)
static int
pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d _U_)
{
- (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf),
- "This system doesn't support BIOCSSEESENT, so the direction can't be set");
+ (void) snprintf(p->errbuf, sizeof(p->errbuf),
+ "Setting direction is not supported on this device");
return (-1);
}
#endif
diff --git a/pcap-bt-linux.c b/pcap-bt-linux.c
index 9c8712e9..2969ff8d 100644
--- a/pcap-bt-linux.c
+++ b/pcap-bt-linux.c
@@ -58,7 +58,7 @@
/* forward declaration */
static int bt_activate(pcap_t *);
static int bt_read_linux(pcap_t *, int , pcap_handler , u_char *);
-static int bt_inject_linux(pcap_t *, const void *, size_t);
+static int bt_inject_linux(pcap_t *, const void *, int);
static int bt_setdirection_linux(pcap_t *, pcap_direction_t);
static int bt_stats_linux(pcap_t *, struct pcap_stat *);
@@ -92,7 +92,7 @@ bt_findalldevs(pcap_if_list_t *devlistp, char *err_str)
dev_list = malloc(HCI_MAX_DEV * sizeof(*dev_req) + sizeof(*dev_list));
if (!dev_list)
{
- pcap_snprintf(err_str, PCAP_ERRBUF_SIZE, "Can't allocate %zu bytes for Bluetooth device list",
+ snprintf(err_str, PCAP_ERRBUF_SIZE, "Can't allocate %zu bytes for Bluetooth device list",
HCI_MAX_DEV * sizeof(*dev_req) + sizeof(*dev_list));
ret = -1;
goto done;
@@ -112,8 +112,8 @@ bt_findalldevs(pcap_if_list_t *devlistp, char *err_str)
for (i = 0; i < dev_list->dev_num; i++, dev_req++) {
char dev_name[20], dev_descr[40];
- pcap_snprintf(dev_name, sizeof(dev_name), BT_IFACE"%u", dev_req->dev_id);
- pcap_snprintf(dev_descr, sizeof(dev_descr), "Bluetooth adapter number %u", i);
+ snprintf(dev_name, sizeof(dev_name), BT_IFACE"%u", dev_req->dev_id);
+ snprintf(dev_descr, sizeof(dev_descr), "Bluetooth adapter number %u", i);
/*
* Bluetooth is a wireless technology.
@@ -173,7 +173,7 @@ bt_create(const char *device, char *ebuf, int *is_ours)
/* OK, it's probably ours. */
*is_ours = 1;
- p = pcap_create_common(ebuf, sizeof (struct pcap_bt));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_bt);
if (p == NULL)
return (NULL);
@@ -194,7 +194,7 @@ bt_activate(pcap_t* handle)
/* get bt interface id */
if (sscanf(handle->opt.device, BT_IFACE"%d", &dev_id) != 1)
{
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Can't get Bluetooth device index from %s",
handle->opt.device);
return PCAP_ERROR;
@@ -346,7 +346,7 @@ bt_read_linux(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char
return -1;
}
- pkth.caplen = ret;
+ pkth.caplen = (bpf_u_int32)ret;
/* get direction and timestamp*/
cmsg = CMSG_FIRSTHDR(&msg);
@@ -362,15 +362,27 @@ bt_read_linux(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char
}
cmsg = CMSG_NXTHDR(&msg, cmsg);
}
- if ((in && (handle->direction == PCAP_D_OUT)) ||
- ((!in) && (handle->direction == PCAP_D_IN)))
- return 0;
+ switch (handle->direction) {
+
+ case PCAP_D_IN:
+ if (!in)
+ return 0;
+ break;
+
+ case PCAP_D_OUT:
+ if (in)
+ return 0;
+ break;
+
+ default:
+ break;
+ }
bthdr->direction = htonl(in != 0);
pkth.caplen+=sizeof(pcap_bluetooth_h4_header);
pkth.len = pkth.caplen;
if (handle->fcode.bf_insns == NULL ||
- bpf_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) {
+ pcap_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) {
callback(user, &pkth, pktd);
return 1;
}
@@ -378,9 +390,9 @@ bt_read_linux(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char
}
static int
-bt_inject_linux(pcap_t *handle, const void *buf _U_, size_t size _U_)
+bt_inject_linux(pcap_t *handle, const void *buf _U_, int size _U_)
{
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Packet injection is not supported on Bluetooth devices");
return (-1);
}
@@ -418,6 +430,10 @@ bt_stats_linux(pcap_t *handle, struct pcap_stat *stats)
static int
bt_setdirection_linux(pcap_t *p, pcap_direction_t d)
{
+ /*
+ * It's guaranteed, at this point, that d is a valid
+ * direction value.
+ */
p->direction = d;
return 0;
}
diff --git a/pcap-bt-monitor-linux.c b/pcap-bt-monitor-linux.c
index a693949d..ad4fc375 100644
--- a/pcap-bt-monitor-linux.c
+++ b/pcap-bt-monitor-linux.c
@@ -50,6 +50,14 @@
#define INTERFACE_NAME "bluetooth-monitor"
/*
+ * Private data.
+ * Currently contains nothing.
+ */
+struct pcap_bt_monitor {
+ int dummy;
+};
+
+/*
* Fields and alignment must match the declaration in the Linux kernel 3.4+.
* See struct hci_mon_hdr in include/net/bluetooth/hci_mon.h.
*/
@@ -124,7 +132,7 @@ bt_monitor_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_ch
return -1;
}
- pkth.caplen = ret - sizeof(hdr) + sizeof(pcap_bluetooth_linux_monitor_header);
+ pkth.caplen = (bpf_u_int32)(ret - sizeof(hdr) + sizeof(pcap_bluetooth_linux_monitor_header));
pkth.len = pkth.caplen;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
@@ -139,7 +147,7 @@ bt_monitor_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_ch
bthdr->opcode = htons(hdr.opcode);
if (handle->fcode.bf_insns == NULL ||
- bpf_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) {
+ pcap_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) {
callback(user, &pkth, pktd);
return 1;
}
@@ -147,21 +155,14 @@ bt_monitor_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_ch
}
static int
-bt_monitor_inject(pcap_t *handle, const void *buf _U_, size_t size _U_)
+bt_monitor_inject(pcap_t *handle, const void *buf _U_, int size _U_)
{
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Packet injection is not supported yet on Bluetooth monitor devices");
return -1;
}
static int
-bt_monitor_setdirection(pcap_t *p, pcap_direction_t d)
-{
- p->direction = d;
- return 0;
-}
-
-static int
bt_monitor_stats(pcap_t *handle _U_, struct pcap_stat *stats)
{
stats->ps_recv = 0;
@@ -200,7 +201,7 @@ bt_monitor_activate(pcap_t* handle)
handle->read_op = bt_monitor_read;
handle->inject_op = bt_monitor_inject;
handle->setfilter_op = install_bpf_program; /* no kernel filtering */
- handle->setdirection_op = bt_monitor_setdirection;
+ handle->setdirection_op = NULL; /* Not implemented */
handle->set_datalink_op = NULL; /* can't change data link type */
handle->getnonblock_op = pcap_getnonblock_fd;
handle->setnonblock_op = pcap_setnonblock_fd;
@@ -263,7 +264,7 @@ bt_monitor_create(const char *device, char *ebuf, int *is_ours)
}
*is_ours = 1;
- p = pcap_create_common(ebuf, 0);
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_bt_monitor);
if (p == NULL)
return NULL;
diff --git a/pcap-common.c b/pcap-common.c
index 2a745f0b..51d0666f 100644
--- a/pcap-common.c
+++ b/pcap-common.c
@@ -326,7 +326,7 @@
* input packets such as port scans, packets from old lost connections,
* etc. to force the connection to stay up).
*
- * The first byte of the PPP header (0xff03) is modified to accomodate
+ * The first byte of the PPP header (0xff03) is modified to accommodate
* the direction - 0x00 = IN, 0x01 = OUT.
*/
#define LINKTYPE_PPP_PPPD 166
@@ -361,7 +361,7 @@
/*
* Link types requested by Gregor Maier <gregor@endace.com> of Endace
* Measurement Systems. They add an ERF header (see
- * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of
+ * https://www.endace.com/support/EndaceRecordFormat.pdf) in front of
* the link-layer header.
*/
#define LINKTYPE_ERF_ETH 175 /* Ethernet */
@@ -495,7 +495,7 @@
/*
* Various link-layer types, with a pseudo-header, for SITA
- * (http://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com).
+ * (https://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com).
*/
#define LINKTYPE_SITA 196
@@ -558,7 +558,6 @@
*/
#define LINKTYPE_LAPD 203
-
/*
* PPP, with a one-byte direction pseudo-header prepended - zero means
* "received by this host", non-zero (any non-zero value) means "sent by
@@ -608,7 +607,7 @@
/*
* Media Oriented Systems Transport (MOST) bus for multimedia
- * transport - http://www.mostcooperation.com/ - as requested
+ * transport - https://www.mostcooperation.com/ - as requested
* by Hannes Kaelber <hannes.kaelber@x2e.de>.
*/
#define LINKTYPE_MOST 211
@@ -794,16 +793,16 @@
/*
* Raw D-Bus:
*
- * http://www.freedesktop.org/wiki/Software/dbus
+ * https://www.freedesktop.org/wiki/Software/dbus
*
* messages:
*
- * http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages
+ * https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages
*
* starting with the endianness flag, followed by the message type, etc.,
* but without the authentication handshake before the message sequence:
*
- * http://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol
+ * https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol
*
* Requested by Martin Vidner <martin@vidner.net>.
*/
@@ -821,7 +820,7 @@
* DVB-CI (DVB Common Interface for communication between a PC Card
* module and a DVB receiver). See
*
- * http://www.kaiser.cx/pcap-dvbci.html
+ * https://www.kaiser.cx/pcap-dvbci.html
*
* for the specification.
*
@@ -945,7 +944,7 @@
*
* Requested by Chris Bontje <chris_bontje@selinc.com>.
*/
-#define DLT_RTAC_SERIAL 250
+#define LINKTYPE_RTAC_SERIAL 250
/*
* Bluetooth Low Energy air interface link-layer packets.
@@ -1079,9 +1078,9 @@
/*
* per: Stefanha at gmail.com for
- * http://lists.sandelman.ca/pipermail/tcpdump-workers/2017-May/000772.html
+ * https://lists.sandelman.ca/pipermail/tcpdump-workers/2017-May/000772.html
* and: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/vsockmon.h
- * for: http://qemu-project.org/Features/VirtioVsock
+ * for: https://qemu-project.org/Features/VirtioVsock
*/
#define LINKTYPE_VSOCK 271
@@ -1093,7 +1092,7 @@
/*
* Excentis DOCSIS 3.1 RF sniffer (XRA-31)
* per: bruno.verstuyft at excentis.com
- * http://www.xra31.com/xra-header
+ * https://www.xra31.com/xra-header
*/
#define LINKTYPE_DOCSIS31_XRA31 273
@@ -1105,7 +1104,7 @@
/*
* DisplayPort AUX channel monitoring data as specified by VESA
- * DisplayPort(DP) Standard preceeded by a pseudo-header.
+ * DisplayPort(DP) Standard preceded by a pseudo-header.
* per dirk.eibach at gdsys.cc
*/
#define LINKTYPE_DISPLAYPORT_AUX 275
@@ -1115,7 +1114,84 @@
*/
#define LINKTYPE_LINUX_SLL2 276
-#define LINKTYPE_MATCHING_MAX 276 /* highest value in the "matching" range */
+/*
+ * Sercos Monitor, per Manuel Jacob <manuel.jacob at steinbeis-stg.de>
+ */
+#define LINKTYPE_SERCOS_MONITOR 277
+
+/*
+ * OpenVizsla http://openvizsla.org is open source USB analyzer hardware.
+ * It consists of FPGA with attached USB phy and FTDI chip for streaming
+ * the data to the host PC.
+ *
+ * Current OpenVizsla data encapsulation format is described here:
+ * https://github.com/matwey/libopenvizsla/wiki/OpenVizsla-protocol-description
+ *
+ */
+#define LINKTYPE_OPENVIZSLA 278
+
+/*
+ * The Elektrobit High Speed Capture and Replay (EBHSCR) protocol is produced
+ * by a PCIe Card for interfacing high speed automotive interfaces.
+ *
+ * The specification for this frame format can be found at:
+ * https://www.elektrobit.com/ebhscr
+ *
+ * for Guenter.Ebermann at elektrobit.com
+ *
+ */
+#define LINKTYPE_EBHSCR 279
+
+/*
+ * The https://fd.io vpp graph dispatch tracer produces pcap trace files
+ * in the format documented here:
+ * https://fdio-vpp.readthedocs.io/en/latest/gettingstarted/developers/vnet.html#graph-dispatcher-pcap-tracing
+ */
+#define LINKTYPE_VPP_DISPATCH 280
+
+/*
+ * Broadcom Ethernet switches (ROBO switch) 4 bytes proprietary tagging format.
+ */
+#define LINKTYPE_DSA_TAG_BRCM 281
+#define LINKTYPE_DSA_TAG_BRCM_PREPEND 282
+
+/*
+ * IEEE 802.15.4 with pseudo-header and optional meta-data TLVs, PHY payload
+ * exactly as it appears in the spec (no padding, no nothing), and FCS if
+ * specified by FCS Type TLV; requested by James Ko <jck@exegin.com>.
+ * Specification at https://github.com/jkcko/ieee802.15.4-tap
+ */
+#define LINKTYPE_IEEE802_15_4_TAP 283
+
+/*
+ * Marvell (Ethertype) Distributed Switch Architecture proprietary tagging format.
+ */
+#define LINKTYPE_DSA_TAG_DSA 284
+#define LINKTYPE_DSA_TAG_EDSA 285
+
+/*
+ * Payload of lawful intercept packets using the ELEE protocol;
+ * https://socket.hr/draft-dfranusic-opsawg-elee-00.xml
+ * https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://socket.hr/draft-dfranusic-opsawg-elee-00.xml&modeAsFormat=html/ascii
+ */
+#define LINKTYPE_ELEE 286
+
+/*
+ * Serial frames transmitted between a host and a Z-Wave chip.
+ */
+#define LINKTYPE_Z_WAVE_SERIAL 287
+
+/*
+ * USB 2.0, 1.1, and 1.0 packets as transmitted over the cable.
+ */
+#define LINKTYPE_USB_2_0 288
+
+/*
+ * ATSC Link-Layer Protocol (A/330) packets.
+ */
+#define LINKTYPE_ATSC_ALP 289
+
+#define LINKTYPE_MATCHING_MAX 289 /* highest value in the "matching" range */
/*
* The DLT_ and LINKTYPE_ values in the "matching" range should be the
@@ -1144,7 +1220,7 @@ static struct linktype_map {
{ DLT_ARCNET, LINKTYPE_ARCNET_BSD },
{ DLT_SLIP, LINKTYPE_SLIP },
{ DLT_PPP, LINKTYPE_PPP },
- { DLT_FDDI, LINKTYPE_FDDI },
+ { DLT_FDDI, LINKTYPE_FDDI },
{ DLT_SYMANTEC_FIREWALL, LINKTYPE_SYMANTEC_FIREWALL },
/*
@@ -1248,11 +1324,20 @@ linktype_to_dlt(int linktype)
return (DLT_PKTAP);
/*
- * For all other values in the matching range, the LINKTYPE
- * value is the same as the DLT value.
+ * For all other values in the matching range, except for
+ * LINKTYPE_ATM_CLIP, the LINKTYPE value is the same as
+ * the DLT value.
+ *
+ * LINKTYPE_ATM_CLIP is a special case. DLT_ATM_CLIP is
+ * not on all platforms, but, so far, there don't appear
+ * to be any platforms that define it as anything other
+ * than 19; we define LINKTYPE_ATM_CLIP as something
+ * other than 19, just in case. That value is in the
+ * matching range, so we have to check for it.
*/
if (linktype >= LINKTYPE_MATCHING_MIN &&
- linktype <= LINKTYPE_MATCHING_MAX)
+ linktype <= LINKTYPE_MATCHING_MAX &&
+ linktype != LINKTYPE_ATM_CLIP)
return (linktype);
/*
@@ -1265,7 +1350,7 @@ linktype_to_dlt(int linktype)
/*
* If we don't have an entry for this LINKTYPE, return
- * the link type value; it may be a DLT from an older
+ * the link type value; it may be a DLT from an newer
* version of libpcap.
*/
return linktype;
@@ -1280,6 +1365,10 @@ linktype_to_dlt(int linktype)
*
* https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages
*
+ * For DLT_EBHSCR, the maximum is 8MiB, as per
+ *
+ * https://www.elektrobit.com/ebhscr
+ *
* For DLT_USBPCAP, the maximum is 1MiB, as per
*
* https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=15985
@@ -1292,6 +1381,9 @@ max_snaplen_for_dlt(int dlt)
case DLT_DBUS:
return 128*1024*1024;
+ case DLT_EBHSCR:
+ return 8*1024*1024;
+
case DLT_USBPCAP:
return 1024*1024;
@@ -1324,7 +1416,7 @@ swap_linux_sll_header(const struct pcap_pkthdr *hdr, u_char *buf)
return;
}
- protocol = EXTRACT_16BITS(&shdr->sll_protocol);
+ protocol = EXTRACT_BE_U_2(&shdr->sll_protocol);
if (protocol != LINUX_SLL_P_CAN && protocol != LINUX_SLL_P_CANFD)
return;
diff --git a/pcap-config.1 b/pcap-config.1
index 0388d0f1..fe8d799c 100644
--- a/pcap-config.1
+++ b/pcap-config.1
@@ -69,4 +69,4 @@ dynamically-linked version of libpcap; the
flag causes it to write flags appropriate for compiling with a
statically-linked version of libpcap.
.SH "SEE ALSO"
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap-dag.c b/pcap-dag.c
index e076676c..b207dd84 100644
--- a/pcap-dag.c
+++ b/pcap-dag.c
@@ -19,7 +19,6 @@
#include "pcap-int.h"
-#include <ctype.h>
#include <netinet/in.h>
#include <sys/mman.h>
#include <sys/socket.h>
@@ -208,7 +207,6 @@ static unsigned char TempPkt[MAX_DAG_PACKET];
#define dag_size_t uint32_t
#endif
-static int dag_setfilter(pcap_t *p, struct bpf_program *fp);
static int dag_stats(pcap_t *p, struct pcap_stat *ps);
static int dag_set_datalink(pcap_t *p, int dlt);
static int dag_get_datalink(pcap_t *p);
@@ -335,7 +333,7 @@ dag_erf_ext_header_count(uint8_t * erf, size_t len)
/*
* Read at most max_packets from the capture stream and call the callback
* for each of them. Returns the number of packets handled, -1 if an
- * error occured, or -2 if we were told to break out of the loop.
+ * error occurred, or -2 if we were told to break out of the loop.
*/
static int
dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
@@ -421,7 +419,8 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
rlen = ntohs(header->rlen);
if (rlen < dag_record_size)
{
- strncpy(p->errbuf, "dag_read: record too small", PCAP_ERRBUF_SIZE);
+ pcap_strlcpy(p->errbuf, "dag_read: record too small",
+ PCAP_ERRBUF_SIZE);
return -1;
}
pd->dag_mem_bottom += rlen;
@@ -664,7 +663,7 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
caplen = p->snapshot;
/* Run the packet filter if there is one. */
- if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) {
+ if ((p->fcode.bf_insns == NULL) || pcap_filter(p->fcode.bf_insns, dp, packet_len, caplen)) {
/* convert between timestamp formats */
register unsigned long long ts;
@@ -718,7 +717,7 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
}
static int
-dag_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
+dag_inject(pcap_t *p, const void *buf _U_, int size _U_)
{
pcap_strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards",
PCAP_ERRBUF_SIZE);
@@ -750,7 +749,7 @@ static int dag_activate(pcap_t* p)
struct timeval poll;
if (device == NULL) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL");
return PCAP_ERROR;
}
@@ -780,7 +779,7 @@ static int dag_activate(pcap_t* p)
if (pd->dag_stream%2) {
ret = PCAP_ERROR;
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: tx (even numbered) streams not supported for capture");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: tx (even numbered) streams not supported for capture");
goto fail;
}
@@ -936,7 +935,7 @@ static int dag_activate(pcap_t* p)
pd->dag_fcs_bits = n;
} else {
ret = PCAP_ERROR;
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"pcap_activate %s: bad ERF_FCS_BITS value (%d) in environment", device, n);
goto failstop;
}
@@ -983,7 +982,7 @@ static int dag_activate(pcap_t* p)
p->read_op = dag_read;
p->inject_op = dag_inject;
- p->setfilter_op = dag_setfilter;
+ p->setfilter_op = install_bpf_program;
p->setdirection_op = NULL; /* Not implemented.*/
p->set_datalink_op = dag_set_datalink;
p->getnonblock_op = pcap_getnonblock_fd;
@@ -1072,7 +1071,7 @@ pcap_t *dag_create(const char *device, char *ebuf, int *is_ours)
/* OK, it's probably ours. */
*is_ours = 1;
- p = pcap_create_common(ebuf, sizeof (struct pcap_dag));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_dag);
if (p == NULL)
return NULL;
@@ -1085,7 +1084,6 @@ pcap_t *dag_create(const char *device, char *ebuf, int *is_ours)
* XXX Our native precision is 2^-32s, but libpcap doesn't support
* power of two precisions yet. We can convert to either MICRO or NANO.
*/
- p->tstamp_precision_count = 2;
p->tstamp_precision_list = malloc(2 * sizeof(u_int));
if (p->tstamp_precision_list == NULL) {
pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
@@ -1095,6 +1093,7 @@ pcap_t *dag_create(const char *device, char *ebuf, int *is_ours)
}
p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO;
p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO;
+ p->tstamp_precision_count = 2;
return p;
}
@@ -1115,10 +1114,10 @@ dag_stats(pcap_t *p, struct pcap_stat *ps) {
/* Note this counter is cleared at start of capture and will wrap at UINT_MAX.
* The application is responsible for polling ps_drop frequently enough
* to detect each wrap and integrate total drop with a wider counter */
- if ((dag_error = dag_config_get_uint32_attribute_ex(pd->dag_ref, pd->drop_attr, &stream_drop) == kDagErrNone)) {
+ if ((dag_error = dag_config_get_uint32_attribute_ex(pd->dag_ref, pd->drop_attr, &stream_drop)) == kDagErrNone) {
pd->stat.ps_drop = stream_drop;
} else {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "reading stream drop attribute: %s",
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "reading stream drop attribute: %s",
dag_config_strerror(dag_error));
return -1;
}
@@ -1146,10 +1145,10 @@ dag_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
/* Try all the DAGs 0-DAG_MAX_BOARDS */
for (c = 0; c < DAG_MAX_BOARDS; c++) {
- pcap_snprintf(name, 12, "dag%d", c);
+ snprintf(name, 12, "dag%d", c);
if (-1 == dag_parse_name(name, dagname, DAGNAME_BUFSIZE, &dagstream))
{
- (void) pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ (void) snprintf(errbuf, PCAP_ERRBUF_SIZE,
"dag: device name %s can't be parsed", name);
return (-1);
}
@@ -1177,7 +1176,7 @@ dag_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
if (0 == dag_attach_stream64(dagfd, stream, 0, 0)) {
dag_detach_stream(dagfd, stream);
- pcap_snprintf(name, 10, "dag%d:%d", c, stream);
+ snprintf(name, 10, "dag%d:%d", c, stream);
if (add_dev(devlistp, name, 0, description, errbuf) == NULL) {
/*
* Failure.
@@ -1198,30 +1197,6 @@ dag_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
return (0);
}
-/*
- * Installs the given bpf filter program in the given pcap structure. There is
- * no attempt to store the filter in kernel memory as that is not supported
- * with DAG cards.
- */
-static int
-dag_setfilter(pcap_t *p, struct bpf_program *fp)
-{
- if (!p)
- return -1;
- if (!fp) {
- strncpy(p->errbuf, "setfilter: No filter specified",
- sizeof(p->errbuf));
- return -1;
- }
-
- /* Make our private copy of the filter */
-
- if (install_bpf_program(p, fp) < 0)
- return -1;
-
- return (0);
-}
-
static int
dag_set_datalink(pcap_t *p, int dlt)
{
@@ -1451,7 +1426,7 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp _U_, char *errbuf)
pcap_t *
pcap_create_interface(const char *device, char *errbuf)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"This version of libpcap only supports DAG cards");
return NULL;
}
diff --git a/pcap-dbus.c b/pcap-dbus.c
index 1252975e..506f150f 100644
--- a/pcap-dbus.c
+++ b/pcap-dbus.c
@@ -68,7 +68,7 @@ dbus_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *us
while (!message) {
/* XXX handle->opt.timeout = timeout_ms; */
if (!dbus_connection_read_write(handlep->conn, 100)) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Connection closed");
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Connection closed");
return -1;
}
@@ -81,7 +81,7 @@ dbus_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *us
}
if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Disconnected");
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Disconnected");
return -1;
}
@@ -91,7 +91,7 @@ dbus_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *us
gettimeofday(&pkth.ts, NULL);
if (handle->fcode.bf_insns == NULL ||
- bpf_filter(handle->fcode.bf_insns, (u_char *)raw_msg, pkth.len, pkth.caplen)) {
+ pcap_filter(handle->fcode.bf_insns, (u_char *)raw_msg, pkth.len, pkth.caplen)) {
handlep->packets_read++;
callback(user, &pkth, (u_char *)raw_msg);
count++;
@@ -103,7 +103,7 @@ dbus_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *us
}
static int
-dbus_write(pcap_t *handle, const void *buf, size_t size)
+dbus_write(pcap_t *handle, const void *buf, int size)
{
/* XXX, not tested */
struct pcap_dbus *handlep = handle->priv;
@@ -112,7 +112,7 @@ dbus_write(pcap_t *handle, const void *buf, size_t size)
DBusMessage *msg;
if (!(msg = dbus_message_demarshal(buf, size, &error))) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dbus_message_demarshal() failed: %s", error.message);
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dbus_message_demarshal() failed: %s", error.message);
dbus_error_free(&error);
return -1;
}
@@ -154,7 +154,7 @@ dbus_cleanup(pcap_t *handle)
static int
dbus_getnonblock(pcap_t *p)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Non-blocking mode isn't supported for capturing on D-Bus");
return (-1);
}
@@ -162,7 +162,7 @@ dbus_getnonblock(pcap_t *p)
static int
dbus_setnonblock(pcap_t *p, int nonblock _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Non-blocking mode isn't supported for capturing on D-Bus");
return (-1);
}
@@ -189,14 +189,14 @@ dbus_activate(pcap_t *handle)
if (strcmp(dev, "dbus-system") == 0) {
if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get system bus: %s", error.message);
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get system bus: %s", error.message);
dbus_error_free(&error);
return PCAP_ERROR;
}
} else if (strcmp(dev, "dbus-session") == 0) {
if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SESSION, &error))) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get session bus: %s", error.message);
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get session bus: %s", error.message);
dbus_error_free(&error);
return PCAP_ERROR;
}
@@ -205,19 +205,19 @@ dbus_activate(pcap_t *handle)
const char *addr = dev + 7;
if (!(handlep->conn = dbus_connection_open(addr, &error))) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to open connection to: %s: %s", addr, error.message);
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to open connection to: %s: %s", addr, error.message);
dbus_error_free(&error);
return PCAP_ERROR;
}
if (!dbus_bus_register(handlep->conn, &error)) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to register bus %s: %s\n", addr, error.message);
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to register bus %s: %s\n", addr, error.message);
dbus_error_free(&error);
return PCAP_ERROR;
}
} else {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get bus address from %s", handle->opt.device);
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get bus address from %s", handle->opt.device);
return PCAP_ERROR;
}
@@ -289,7 +289,7 @@ dbus_activate(pcap_t *handle)
/* try without eavesdrop */
dbus_bus_add_match(handlep->conn, rules[i] + strlen(EAVESDROPPING_RULE), &error);
if (dbus_error_is_set(&error)) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to add bus match: %s\n", error.message);
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to add bus match: %s\n", error.message);
dbus_error_free(&error);
dbus_cleanup(handle);
return PCAP_ERROR;
@@ -314,7 +314,7 @@ dbus_create(const char *device, char *ebuf, int *is_ours)
}
*is_ours = 1;
- p = pcap_create_common(ebuf, sizeof (struct pcap_dbus));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_dbus);
if (p == NULL)
return (NULL);
diff --git a/pcap-dlpi.c b/pcap-dlpi.c
index 3ed8fa7a..208a63bc 100644
--- a/pcap-dlpi.c
+++ b/pcap-dlpi.c
@@ -96,7 +96,6 @@
#include <net/if.h>
#endif
-#include <ctype.h>
#ifdef HAVE_HPUX9
#include <nlist.h>
#endif
@@ -108,12 +107,7 @@
#include <string.h>
#include <stropts.h>
#include <unistd.h>
-
-#ifdef HAVE_LIMITS_H
#include <limits.h>
-#else
-#define INT_MAX 2147483647
-#endif
#include "pcap-int.h"
#include "dlpisubs.h"
@@ -252,7 +246,7 @@ pcap_read_dlpi(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
}
static int
-pcap_inject_dlpi(pcap_t *p, const void *buf, size_t size)
+pcap_inject_dlpi(pcap_t *p, const void *buf, int size)
{
#ifdef DL_HP_RAWDLS
struct pcap_dlpi *pd = p->priv;
@@ -268,7 +262,7 @@ pcap_inject_dlpi(pcap_t *p, const void *buf, size_t size)
}
#elif defined(DL_HP_RAWDLS)
if (pd->send_fd < 0) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"send: Output FD couldn't be opened");
return (-1);
}
@@ -417,7 +411,7 @@ open_dlpi_device(const char *name, u_int *ppa, char *errbuf)
if (*name == '/')
pcap_strlcpy(dname, name, sizeof(dname));
else
- pcap_snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX,
+ snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX,
name);
/*
@@ -475,7 +469,7 @@ open_dlpi_device(const char *name, u_int *ppa, char *errbuf)
* interface is just a symptom of that
* inability.
*/
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"%s: No DLPI device found", name);
} else {
if (errno == EPERM || errno == EACCES)
@@ -639,7 +633,7 @@ pcap_activate_dlpi(pcap_t *p)
**/
if (dlbindreq(p->fd, 0, p->errbuf) < 0 ||
dlbindack(p->fd, (char *)buf, p->errbuf, NULL) < 0) {
- status = PCAP_ERROR;
+ status = PCAP_ERROR;
goto bad;
}
#endif /* AIX vs. HP-UX vs. other */
@@ -767,7 +761,7 @@ pcap_activate_dlpi(pcap_t *p)
*/
if (dlinforeq(p->fd, p->errbuf) < 0 ||
dlinfoack(p->fd, (char *)buf, p->errbuf) < 0) {
- status = PCAP_ERROR;
+ status = PCAP_ERROR;
goto bad;
}
@@ -805,7 +799,7 @@ pcap_activate_dlpi(pcap_t *p)
get_release(release, sizeof (release), &osmajor, &osminor, &osmicro);
if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) &&
getenv("BUFMOD_FIXED") == NULL) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"WARNING: bufmod is broken in SunOS %s; ignoring snaplen.",
release);
ss = 0;
@@ -880,7 +874,7 @@ split_dname(char *device, u_int *unitp, char *ebuf)
*/
cp = device + strlen(device) - 1;
if (*cp < '0' || *cp > '9') {
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s missing unit number",
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s missing unit number",
device);
return (NULL);
}
@@ -892,16 +886,16 @@ split_dname(char *device, u_int *unitp, char *ebuf)
errno = 0;
unit = strtol(cp, &eos, 10);
if (*eos != '\0') {
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device);
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device);
return (NULL);
}
if (errno == ERANGE || unit > INT_MAX) {
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number too large",
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number too large",
device);
return (NULL);
}
if (unit < 0) {
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number is negative",
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number is negative",
device);
return (NULL);
}
@@ -1115,7 +1109,7 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
return (-1);
}
for (i = 0; i < buf.nunits; i++) {
- pcap_snprintf(baname, sizeof baname, "ba%u", i);
+ snprintf(baname, sizeof baname, "ba%u", i);
/*
* XXX - is there a notion of "up" and "running"?
* And is there a way to determine whether the
@@ -1202,7 +1196,7 @@ recv_ack(int fd, int size, const char *what, char *bufp, char *ebuf, int *uerror
break;
default:
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
"recv_ack: %s: %s", what,
dlstrerror(errmsgbuf, sizeof (errmsgbuf), dlp->error_ack.dl_errno));
if (dlp->error_ack.dl_errno == DL_BADPPA)
@@ -1214,14 +1208,14 @@ recv_ack(int fd, int size, const char *what, char *bufp, char *ebuf, int *uerror
return (PCAP_ERROR);
default:
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
"recv_ack: %s: Unexpected primitive ack %s",
what, dlprim(dlprimbuf, sizeof (dlprimbuf), dlp->dl_primitive));
return (PCAP_ERROR);
}
if (ctl.len < size) {
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
"recv_ack: %s: Ack too small (%d < %d)",
what, ctl.len, size);
return (PCAP_ERROR);
@@ -1332,7 +1326,7 @@ dlstrerror(char *errbuf, size_t errbufsize, bpf_u_int32 dl_errno)
return ("Pending outstanding connect indications");
default:
- pcap_snprintf(errbuf, errbufsize, "Error %02x", dl_errno);
+ snprintf(errbuf, errbufsize, "Error %02x", dl_errno);
return (errbuf);
}
}
@@ -1424,7 +1418,7 @@ dlprim(char *primbuf, size_t primbufsize, bpf_u_int32 prim)
return ("DL_RESET_CON");
default:
- pcap_snprintf(primbuf, primbufsize, "unknown primitive 0x%x",
+ snprintf(primbuf, primbufsize, "unknown primitive 0x%x",
prim);
return (primbuf);
}
@@ -1551,7 +1545,7 @@ get_release(char *buf, size_t bufsize, bpf_u_int32 *majorp,
return;
}
cp = buf;
- if (!isdigit((unsigned char)*cp))
+ if (!PCAP_ISDIGIT((unsigned char)*cp))
return;
*majorp = strtol(cp, &cp, 10);
if (*cp++ != '.')
@@ -1651,21 +1645,21 @@ get_dlpi_ppa(register int fd, register const char *device, register u_int unit,
return (PCAP_ERROR);
}
if (ctl.len == -1) {
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
"get_dlpi_ppa: hpppa getmsg: control buffer has no data");
return (PCAP_ERROR);
}
dlp = (dl_hp_ppa_ack_t *)ctl.buf;
if (dlp->dl_primitive != DL_HP_PPA_ACK) {
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
"get_dlpi_ppa: hpppa unexpected primitive ack 0x%x",
(bpf_u_int32)dlp->dl_primitive);
return (PCAP_ERROR);
}
if ((size_t)ctl.len < DL_HP_PPA_ACK_SIZE) {
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
"get_dlpi_ppa: hpppa ack too small (%d < %lu)",
ctl.len, (unsigned long)DL_HP_PPA_ACK_SIZE);
return (PCAP_ERROR);
@@ -1688,12 +1682,12 @@ get_dlpi_ppa(register int fd, register const char *device, register u_int unit,
return (PCAP_ERROR);
}
if (ctl.len == -1) {
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
"get_dlpi_ppa: hpppa getmsg: control buffer has no data");
return (PCAP_ERROR);
}
if ((u_int)ctl.len < dlp->dl_length) {
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
"get_dlpi_ppa: hpppa ack too small (%d < %lu)",
ctl.len, (unsigned long)dlp->dl_length);
free(ppa_data_buf);
@@ -1750,7 +1744,7 @@ get_dlpi_ppa(register int fd, register const char *device, register u_int unit,
* device number of a device with the name "/dev/<dev><unit>",
* if such a device exists, as the old code did.
*/
- pcap_snprintf(dname, sizeof(dname), "/dev/%s%u", device, unit);
+ snprintf(dname, sizeof(dname), "/dev/%s%u", device, unit);
if (stat(dname, &statbuf) < 0) {
pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
errno, "stat: %s", dname);
@@ -1769,12 +1763,12 @@ get_dlpi_ppa(register int fd, register const char *device, register u_int unit,
}
}
if (i == ap->dl_count) {
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
"can't find /dev/dlpi PPA for %s%u", device, unit);
return (PCAP_ERROR_NO_SUCH_DEVICE);
}
if (ip->dl_hdw_state == HDW_DEAD) {
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
"%s%d: hardware state: DOWN\n", device, unit);
free(ppa_data_buf);
return (PCAP_ERROR);
@@ -1813,13 +1807,13 @@ get_dlpi_ppa(register int fd, register const char *ifname, register u_int unit,
if (cp != NULL)
ifname = cp + 1;
if (nlist(path_vmunix, &nl) < 0) {
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "nlist %s failed",
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "nlist %s failed",
path_vmunix);
return (PCAP_ERROR);
}
if (nl[NL_IFNET].n_value == 0) {
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
- "could't find %s kernel symbol",
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "couldn't find %s kernel symbol",
nl[NL_IFNET].n_name);
return (PCAP_ERROR);
}
@@ -1849,7 +1843,7 @@ get_dlpi_ppa(register int fd, register const char *ifname, register u_int unit,
}
}
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't find %s", ifname);
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't find %s", ifname);
return (PCAP_ERROR_NO_SUCH_DEVICE);
}
@@ -1870,7 +1864,7 @@ dlpi_kread(register int fd, register off_t addr,
errno, "read");
return (-1);
} else if (cc != len) {
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "short read (%d != %d)", cc,
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "short read (%d != %d)", cc,
len);
return (-1);
}
@@ -1886,7 +1880,7 @@ pcap_create_interface(const char *device _U_, char *ebuf)
struct pcap_dlpi *pd;
#endif
- p = pcap_create_common(ebuf, sizeof (struct pcap_dlpi));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_dlpi);
if (p == NULL)
return (NULL);
diff --git a/pcap-dos.c b/pcap-dos.c
index c159b552..cdd60ea4 100644
--- a/pcap-dos.c
+++ b/pcap-dos.c
@@ -153,7 +153,7 @@ pcap_t *pcap_create_interface (const char *device _U_, char *ebuf)
{
pcap_t *p;
- p = pcap_create_common(ebuf, sizeof (struct pcap_dos));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_dos);
if (p == NULL)
return (NULL);
@@ -215,7 +215,7 @@ static int pcap_activate_dos (pcap_t *pcap)
}
else if (stricmp(active_dev->name,pcap->opt.device))
{
- pcap_snprintf (pcap->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf (pcap->errbuf, PCAP_ERRBUF_SIZE,
"Cannot use different devices simultaneously "
"(`%s' vs. `%s')", active_dev->name, pcap->opt.device);
/* XXX - free pcap->buffer? */
@@ -283,7 +283,7 @@ pcap_read_one (pcap_t *p, pcap_handler callback, u_char *data)
pcap.len = rx_len;
if (callback &&
- (!p->fcode.bf_insns || bpf_filter(p->fcode.bf_insns, p->buffer, pcap.len, pcap.caplen)))
+ (!p->fcode.bf_insns || pcap_filter(p->fcode.bf_insns, p->buffer, pcap.len, pcap.caplen)))
{
filter_count++;
@@ -539,7 +539,7 @@ int pcap_lookupnet (const char *device, bpf_u_int32 *localnet,
net = IN_CLASSC_NET;
else
{
- pcap_snprintf (errbuf, PCAP_ERRBUF_SIZE, "inet class for 0x%lx unknown", mask);
+ snprintf (errbuf, PCAP_ERRBUF_SIZE, "inet class for 0x%lx unknown", mask);
return (-1);
}
}
@@ -667,7 +667,7 @@ open_driver (const char *dev_name, char *ebuf, int promisc)
if (!(*dev->probe)(dev)) /* call the xx_probe() function */
{
- pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to detect device `%s'", dev_name);
+ snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to detect device `%s'", dev_name);
return (NULL);
}
probed_dev = dev; /* device is probed okay and may be used */
@@ -689,7 +689,7 @@ open_driver (const char *dev_name, char *ebuf, int promisc)
if (!(*dev->open)(dev))
{
- pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to activate device `%s'", dev_name);
+ snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to activate device `%s'", dev_name);
if (pktInfo.error && !strncmp(dev->name,"pkt",3))
{
strcat (ebuf, ": ");
@@ -698,7 +698,7 @@ open_driver (const char *dev_name, char *ebuf, int promisc)
return (NULL);
}
- /* Some devices need this to operate in promiscous mode
+ /* Some devices need this to operate in promiscuous mode
*/
if (promisc && dev->set_multicast_list)
(*dev->set_multicast_list) (dev);
@@ -711,14 +711,14 @@ open_driver (const char *dev_name, char *ebuf, int promisc)
*/
if (!dev)
{
- pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not supported", dev_name);
+ snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not supported", dev_name);
return (NULL);
}
not_probed:
if (!probed_dev)
{
- pcap_snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not probed", dev_name);
+ snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not probed", dev_name);
return (NULL);
}
return (dev);
@@ -943,7 +943,7 @@ static void pcap_init_hook (void)
}
/*
- * Supress PRINT message from Watt-32's sock_init()
+ * Suppress PRINT message from Watt-32's sock_init()
*/
static void null_print (void) {}
@@ -1005,7 +1005,7 @@ static int init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf)
}
else if (rc && using_pktdrv)
{
- pcap_snprintf (err_buf, PCAP_ERRBUF_SIZE, "sock_init() failed, code %d", rc);
+ snprintf (err_buf, PCAP_ERRBUF_SIZE, "sock_init() failed, code %d", rc);
return (0);
}
@@ -1031,11 +1031,9 @@ static int init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf)
pcap_save.linktype = _eth_get_hwtype (NULL, NULL);
pcap_save.snapshot = MTU > 0 ? MTU : ETH_MAX; /* assume 1514 */
-#if 1
/* prevent use of resolve() and resolve_ip()
*/
last_nameserver = 0;
-#endif
return (1);
}
diff --git a/pcap-dpdk.c b/pcap-dpdk.c
new file mode 100644
index 00000000..765abe59
--- /dev/null
+++ b/pcap-dpdk.c
@@ -0,0 +1,1070 @@
+/*
+ * Copyright (C) 2018 jingle YANG. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+Date: Dec 16, 2018
+
+Description:
+1. Pcap-dpdk provides libpcap the ability to use DPDK with the device name as dpdk:{portid}, such as dpdk:0.
+2. DPDK is a set of libraries and drivers for fast packet processing. (https://www.dpdk.org/)
+3. The testprogs/capturetest provides 6.4Gbps/800,000 pps on Intel 10-Gigabit X540-AT2 with DPDK 18.11.
+
+Limitations:
+1. DPDK support will be on if DPDK is available. Please set DIR for --with-dpdk[=DIR] with ./configure or -DDPDK_DIR[=DIR] with cmake if DPDK is installed manually.
+2. Only support link libdpdk.so dynamically, because the libdpdk.a will not work correctly.
+3. Only support read operation, and packet injection has not been supported yet.
+
+Usage:
+1. Compile DPDK as shared library and install.(https://github.com/DPDK/dpdk.git)
+
+You shall modify the file $RTE_SDK/$RTE_TARGET/.config and set:
+CONFIG_RTE_BUILD_SHARED_LIB=y
+By the following command:
+sed -i 's/CONFIG_RTE_BUILD_SHARED_LIB=n/CONFIG_RTE_BUILD_SHARED_LIB=y/' $RTE_SDK/$RTE_TARGET/.config
+
+2. Launch l2fwd that is one of DPDK examples correctly, and get device information.
+
+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:
+$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.
+
+If DPDK has not been found automatically, you shall export DPDK environment variable which are used for compiling DPDK. And then pass $RTE_SDK/$RTE_TARGET to --with-dpdk or -DDPDK_DIR
+
+export RTE_SDK={your DPDK base directory}
+export RTE_TARGET={your target name}
+
+3.1 With configure
+
+./configure --with-dpdk=$RTE_SDK/$RTE_TARGET && make -s all && make -s testprogs && make install
+
+3.2 With cmake
+
+mkdir -p build && cd build && cmake -DDPDK_DIR=$RTE_SDK/$RTE_TARGET ../ && make -s all && make -s testprogs && make install
+
+4. Link your own program with libpcap, and use DPDK with the device name as dpdk:{portid}, such as dpdk:0.
+And you shall set DPDK configure options by environment variable DPDK_CFG
+For example, the testprogs/capturetest could be lanched by:
+
+env DPDK_CFG="--log-level=debug -l0 -dlibrte_pmd_e1000.so -dlibrte_pmd_ixgbe.so -dlibrte_mempool_ring.so" ./capturetest -i dpdk:0
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <sys/time.h>
+
+//header for calling dpdk
+#include <rte_config.h>
+#include <rte_common.h>
+#include <rte_errno.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_memory.h>
+#include <rte_eal.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_bus.h>
+
+#include "pcap-int.h"
+#include "pcap-dpdk.h"
+
+/*
+ * Deal with API changes that break source compatibility.
+ */
+
+#ifdef HAVE_STRUCT_RTE_ETHER_ADDR
+#define ETHER_ADDR_TYPE struct rte_ether_addr
+#else
+#define ETHER_ADDR_TYPE struct ether_addr
+#endif
+
+#define DPDK_DEF_LOG_LEV RTE_LOG_ERR
+//
+// This is set to 0 if we haven't initialized DPDK yet, 1 if we've
+// successfully initialized it, a negative value, which is the negative
+// of the rte_errno from rte_eal_init(), if we tried to initialize it
+// and got an error.
+//
+static int is_dpdk_pre_inited=0;
+#define DPDK_LIB_NAME "libpcap_dpdk"
+#define DPDK_DESC "Data Plane Development Kit (DPDK) Interface"
+#define DPDK_ERR_PERM_MSG "permission denied, DPDK needs root permission"
+#define DPDK_ARGC_MAX 64
+#define DPDK_CFG_MAX_LEN 1024
+#define DPDK_DEV_NAME_MAX 32
+#define DPDK_DEV_DESC_MAX 512
+#define DPDK_CFG_ENV_NAME "DPDK_CFG"
+#define DPDK_DEF_MIN_SLEEP_MS 1
+static char dpdk_cfg_buf[DPDK_CFG_MAX_LEN];
+#define DPDK_MAC_ADDR_SIZE 32
+#define DPDK_DEF_MAC_ADDR "00:00:00:00:00:00"
+#define DPDK_PCI_ADDR_SIZE 16
+#define DPDK_DEF_CFG "--log-level=error -l0 -dlibrte_pmd_e1000.so -dlibrte_pmd_ixgbe.so -dlibrte_mempool_ring.so"
+#define DPDK_PREFIX "dpdk:"
+#define DPDK_PORTID_MAX 65535U
+#define MBUF_POOL_NAME "mbuf_pool"
+#define DPDK_TX_BUF_NAME "tx_buffer"
+//The number of elements in the mbuf pool.
+#define DPDK_NB_MBUFS 8192U
+#define MEMPOOL_CACHE_SIZE 256
+#define MAX_PKT_BURST 32
+// Configurable number of RX/TX ring descriptors
+#define RTE_TEST_RX_DESC_DEFAULT 1024
+#define RTE_TEST_TX_DESC_DEFAULT 1024
+
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+#ifdef RTE_ETHER_MAX_JUMBO_FRAME_LEN
+#define RTE_ETH_PCAP_SNAPLEN RTE_ETHER_MAX_JUMBO_FRAME_LEN
+#else
+#define RTE_ETH_PCAP_SNAPLEN ETHER_MAX_JUMBO_FRAME_LEN
+#endif
+
+static struct rte_eth_dev_tx_buffer *tx_buffer;
+
+struct dpdk_ts_helper{
+ struct timeval start_time;
+ uint64_t start_cycles;
+ uint64_t hz;
+};
+struct pcap_dpdk{
+ pcap_t * orig;
+ uint16_t portid; // portid of DPDK
+ int must_clear_promisc;
+ uint64_t bpf_drop;
+ int nonblock;
+ struct timeval required_select_timeout;
+ struct timeval prev_ts;
+ struct rte_eth_stats prev_stats;
+ struct timeval curr_ts;
+ struct rte_eth_stats curr_stats;
+ uint64_t pps;
+ uint64_t bps;
+ struct rte_mempool * pktmbuf_pool;
+ struct dpdk_ts_helper ts_helper;
+ ETHER_ADDR_TYPE eth_addr;
+ char mac_addr[DPDK_MAC_ADDR_SIZE];
+ char pci_addr[DPDK_PCI_ADDR_SIZE];
+ unsigned char pcap_tmp_buf[RTE_ETH_PCAP_SNAPLEN];
+};
+
+static struct rte_eth_conf port_conf = {
+ .rxmode = {
+ .split_hdr_size = 0,
+ },
+ .txmode = {
+ .mq_mode = ETH_MQ_TX_NONE,
+ },
+};
+
+static void dpdk_fmt_errmsg_for_rte_errno(char *, size_t, int,
+ PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(4, 5);
+
+/*
+ * Generate an error message based on a format, arguments, and an
+ * rte_errno, with a message for the rte_errno after the formatted output.
+ */
+static void dpdk_fmt_errmsg_for_rte_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);
+ msglen = strlen(errbuf);
+
+ /*
+ * Do we have enough space to append ": "?
+ * Including the terminating '\0', that's 3 bytes.
+ */
+ if (msglen + 3 > errbuflen) {
+ /* No - just give them what we've produced. */
+ return;
+ }
+ p = errbuf + msglen;
+ errbuflen_remaining = errbuflen - msglen;
+ *p++ = ':';
+ *p++ = ' ';
+ *p = '\0';
+ msglen += 2;
+ errbuflen_remaining -= 2;
+
+ /*
+ * Now append the string for the error code.
+ * rte_strerror() is thread-safe, at least as of dpdk 18.11,
+ * unlike strerror() - it uses strerror_r() rather than strerror()
+ * for UN*X errno values, and prints to what I assume is a per-thread
+ * buffer (based on the "PER_LCORE" in "RTE_DEFINE_PER_LCORE" used
+ * to declare the buffers statically) for DPDK errors.
+ */
+ snprintf(p, errbuflen_remaining, "%s", rte_strerror(errnum));
+}
+
+static int dpdk_init_timer(struct pcap_dpdk *pd){
+ gettimeofday(&(pd->ts_helper.start_time),NULL);
+ pd->ts_helper.start_cycles = rte_get_timer_cycles();
+ pd->ts_helper.hz = rte_get_timer_hz();
+ if (pd->ts_helper.hz == 0){
+ return -1;
+ }
+ return 0;
+}
+static inline void calculate_timestamp(struct dpdk_ts_helper *helper,struct timeval *ts)
+{
+ uint64_t cycles;
+ // delta
+ struct timeval cur_time;
+ cycles = rte_get_timer_cycles() - helper->start_cycles;
+ cur_time.tv_sec = (time_t)(cycles/helper->hz);
+ cur_time.tv_usec = (suseconds_t)((cycles%helper->hz)*1e6/helper->hz);
+ timeradd(&(helper->start_time), &cur_time, ts);
+}
+
+static uint32_t dpdk_gather_data(unsigned char *data, uint32_t len, struct rte_mbuf *mbuf)
+{
+ uint32_t total_len = 0;
+ while (mbuf && (total_len+mbuf->data_len) < len ){
+ rte_memcpy(data+total_len, rte_pktmbuf_mtod(mbuf,void *),mbuf->data_len);
+ total_len+=mbuf->data_len;
+ mbuf=mbuf->next;
+ }
+ return total_len;
+}
+
+
+static int dpdk_read_with_timeout(pcap_t *p, struct rte_mbuf **pkts_burst, const uint16_t burst_cnt){
+ struct pcap_dpdk *pd = (struct pcap_dpdk*)(p->priv);
+ int nb_rx = 0;
+ int timeout_ms = p->opt.timeout;
+ int sleep_ms = 0;
+ if (pd->nonblock){
+ // In non-blocking mode, just read once, no matter how many packets are captured.
+ nb_rx = (int)rte_eth_rx_burst(pd->portid, 0, pkts_burst, burst_cnt);
+ }else{
+ // In blocking mode, read many times until packets are captured or timeout or break_loop is set.
+ // if timeout_ms == 0, it may be blocked forever.
+ while (timeout_ms == 0 || sleep_ms < timeout_ms){
+ nb_rx = (int)rte_eth_rx_burst(pd->portid, 0, pkts_burst, burst_cnt);
+ if (nb_rx){ // got packets within timeout_ms
+ break;
+ }else{ // no packet arrives at this round.
+ if (p->break_loop){
+ break;
+ }
+ // sleep for a very short while.
+ // block sleep is the only choice, since usleep() will impact performance dramatically.
+ rte_delay_us_block(DPDK_DEF_MIN_SLEEP_MS*1000);
+ sleep_ms += DPDK_DEF_MIN_SLEEP_MS;
+ }
+ }
+ }
+ return nb_rx;
+}
+
+static int pcap_dpdk_dispatch(pcap_t *p, int max_cnt, pcap_handler cb, u_char *cb_arg)
+{
+ struct pcap_dpdk *pd = (struct pcap_dpdk*)(p->priv);
+ int burst_cnt = 0;
+ int nb_rx = 0;
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ struct rte_mbuf *m;
+ struct pcap_pkthdr pcap_header;
+ // In DPDK, pkt_len is sum of lengths for all segments. And data_len is for one segment
+ uint32_t pkt_len = 0;
+ uint32_t caplen = 0;
+ u_char *bp = NULL;
+ int i=0;
+ unsigned int gather_len =0;
+ int pkt_cnt = 0;
+ u_char *large_buffer=NULL;
+ int timeout_ms = p->opt.timeout;
+
+ if ( !PACKET_COUNT_IS_UNLIMITED(max_cnt) && max_cnt < MAX_PKT_BURST){
+ burst_cnt = max_cnt;
+ }else{
+ burst_cnt = MAX_PKT_BURST;
+ }
+
+ while( PACKET_COUNT_IS_UNLIMITED(max_cnt) || pkt_cnt < max_cnt){
+ if (p->break_loop){
+ p->break_loop = 0;
+ return PCAP_ERROR_BREAK;
+ }
+ // read once in non-blocking mode, or try many times waiting for timeout_ms.
+ // if timeout_ms == 0, it will be blocked until one packet arrives or break_loop is set.
+ nb_rx = dpdk_read_with_timeout(p, pkts_burst, burst_cnt);
+ if (nb_rx == 0){
+ if (pd->nonblock){
+ RTE_LOG(DEBUG, USER1, "dpdk: no packets available in non-blocking mode.\n");
+ }else{
+ if (p->break_loop){
+ RTE_LOG(DEBUG, USER1, "dpdk: no packets available and break_loop is set in blocking mode.\n");
+ p->break_loop = 0;
+ return PCAP_ERROR_BREAK;
+
+ }
+ RTE_LOG(DEBUG, USER1, "dpdk: no packets available for timeout %d ms in blocking mode.\n", timeout_ms);
+ }
+ // break if dpdk reads 0 packet, no matter in blocking(timeout) or non-blocking mode.
+ break;
+ }
+ pkt_cnt += nb_rx;
+ for ( i = 0; i < nb_rx; i++) {
+ m = pkts_burst[i];
+ calculate_timestamp(&(pd->ts_helper),&(pcap_header.ts));
+ pkt_len = rte_pktmbuf_pkt_len(m);
+ // caplen = min(pkt_len, p->snapshot);
+ // caplen will not be changed, no matter how long the rte_pktmbuf
+ caplen = pkt_len < (uint32_t)p->snapshot ? pkt_len: (uint32_t)p->snapshot;
+ pcap_header.caplen = caplen;
+ pcap_header.len = pkt_len;
+ // volatile prefetch
+ rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+ bp = NULL;
+ if (m->nb_segs == 1)
+ {
+ bp = rte_pktmbuf_mtod(m, u_char *);
+ }else{
+ // use fast buffer pcap_tmp_buf if pkt_len is small, no need to call malloc and free
+ if ( pkt_len <= RTE_ETH_PCAP_SNAPLEN)
+ {
+ gather_len = dpdk_gather_data(pd->pcap_tmp_buf, RTE_ETH_PCAP_SNAPLEN, m);
+ bp = pd->pcap_tmp_buf;
+ }else{
+ // need call free later
+ large_buffer = (u_char *)malloc(caplen*sizeof(u_char));
+ gather_len = dpdk_gather_data(large_buffer, caplen, m);
+ bp = large_buffer;
+ }
+
+ }
+ if (bp){
+ if (p->fcode.bf_insns==NULL || pcap_filter(p->fcode.bf_insns, bp, pcap_header.len, pcap_header.caplen)){
+ cb(cb_arg, &pcap_header, bp);
+ }else{
+ pd->bpf_drop++;
+ }
+ }
+ //free all pktmbuf
+ rte_pktmbuf_free(m);
+ if (large_buffer){
+ free(large_buffer);
+ large_buffer=NULL;
+ }
+ }
+ }
+ return pkt_cnt;
+}
+
+static int pcap_dpdk_inject(pcap_t *p, const void *buf _U_, int size _U_)
+{
+ //not implemented yet
+ pcap_strlcpy(p->errbuf,
+ "dpdk error: Inject function has not been implemented yet",
+ PCAP_ERRBUF_SIZE);
+ return PCAP_ERROR;
+}
+
+static void pcap_dpdk_close(pcap_t *p)
+{
+ struct pcap_dpdk *pd = p->priv;
+ if (pd==NULL)
+ {
+ return;
+ }
+ if (pd->must_clear_promisc)
+ {
+ rte_eth_promiscuous_disable(pd->portid);
+ }
+ rte_eth_dev_stop(pd->portid);
+ rte_eth_dev_close(pd->portid);
+ pcap_cleanup_live_common(p);
+}
+
+static void nic_stats_display(struct pcap_dpdk *pd)
+{
+ uint16_t portid = pd->portid;
+ struct rte_eth_stats stats;
+ rte_eth_stats_get(portid, &stats);
+ RTE_LOG(INFO,USER1, "portid:%d, RX-packets: %-10"PRIu64" RX-errors: %-10"PRIu64
+ " RX-bytes: %-10"PRIu64" RX-Imissed: %-10"PRIu64"\n", portid, stats.ipackets, stats.ierrors,
+ stats.ibytes,stats.imissed);
+ RTE_LOG(INFO,USER1, "portid:%d, RX-PPS: %-10"PRIu64" RX-Mbps: %.2lf\n", portid, pd->pps, pd->bps/1e6f );
+}
+
+static int pcap_dpdk_stats(pcap_t *p, struct pcap_stat *ps)
+{
+ struct pcap_dpdk *pd = p->priv;
+ calculate_timestamp(&(pd->ts_helper), &(pd->curr_ts));
+ rte_eth_stats_get(pd->portid,&(pd->curr_stats));
+ if (ps){
+ ps->ps_recv = pd->curr_stats.ipackets;
+ ps->ps_drop = pd->curr_stats.ierrors;
+ ps->ps_drop += pd->bpf_drop;
+ ps->ps_ifdrop = pd->curr_stats.imissed;
+ }
+ uint64_t delta_pkt = pd->curr_stats.ipackets - pd->prev_stats.ipackets;
+ struct timeval delta_tm;
+ timersub(&(pd->curr_ts),&(pd->prev_ts), &delta_tm);
+ uint64_t delta_usec = delta_tm.tv_sec*1e6+delta_tm.tv_usec;
+ uint64_t delta_bit = (pd->curr_stats.ibytes-pd->prev_stats.ibytes)*8;
+ RTE_LOG(DEBUG, USER1, "delta_usec: %-10"PRIu64" delta_pkt: %-10"PRIu64" delta_bit: %-10"PRIu64"\n", delta_usec, delta_pkt, delta_bit);
+ pd->pps = (uint64_t)(delta_pkt*1e6f/delta_usec);
+ pd->bps = (uint64_t)(delta_bit*1e6f/delta_usec);
+ nic_stats_display(pd);
+ pd->prev_stats = pd->curr_stats;
+ pd->prev_ts = pd->curr_ts;
+ return 0;
+}
+
+static int pcap_dpdk_setnonblock(pcap_t *p, int nonblock){
+ struct pcap_dpdk *pd = (struct pcap_dpdk*)(p->priv);
+ pd->nonblock = nonblock;
+ return 0;
+}
+
+static int pcap_dpdk_getnonblock(pcap_t *p){
+ struct pcap_dpdk *pd = (struct pcap_dpdk*)(p->priv);
+ return pd->nonblock;
+}
+static int check_link_status(uint16_t portid, struct rte_eth_link *plink)
+{
+ // wait up to 9 seconds to get link status
+ rte_eth_link_get(portid, plink);
+ return plink->link_status == ETH_LINK_UP;
+}
+static void eth_addr_str(ETHER_ADDR_TYPE *addrp, char* mac_str, int len)
+{
+ int offset=0;
+ if (addrp == NULL){
+ snprintf(mac_str, len-1, DPDK_DEF_MAC_ADDR);
+ return;
+ }
+ for (int i=0; i<6; i++)
+ {
+ if (offset >= len)
+ { // buffer overflow
+ return;
+ }
+ if (i==0)
+ {
+ snprintf(mac_str+offset, len-1-offset, "%02X",addrp->addr_bytes[i]);
+ offset+=2; // FF
+ }else{
+ snprintf(mac_str+offset, len-1-offset, ":%02X", addrp->addr_bytes[i]);
+ offset+=3; // :FF
+ }
+ }
+ return;
+}
+// return portid by device name, otherwise return -1
+static uint16_t portid_by_device(char * device)
+{
+ uint16_t ret = DPDK_PORTID_MAX;
+ int len = strlen(device);
+ int 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:
+ {
+ return ret;
+ }
+ //check all chars are digital
+ for (int i=prefix_len; device[i]; i++){
+ if (device[i]<'0' || device[i]>'9'){
+ return ret;
+ }
+ }
+ ret_ul = strtoul(&(device[prefix_len]), &pEnd, 10);
+ if (pEnd == &(device[prefix_len]) || *pEnd != '\0'){
+ return ret;
+ }
+ // too large for portid
+ if (ret_ul >= DPDK_PORTID_MAX){
+ return ret;
+ }
+ ret = (uint16_t)ret_ul;
+ return ret;
+}
+
+static int parse_dpdk_cfg(char* dpdk_cfg,char** dargv)
+{
+ int cnt=0;
+ memset(dargv,0,sizeof(dargv[0])*DPDK_ARGC_MAX);
+ //current process name
+ int skip_space = 1;
+ int i=0;
+ RTE_LOG(INFO, USER1,"dpdk cfg: %s\n",dpdk_cfg);
+ // find first non space char
+ // The last opt is NULL
+ for (i=0;dpdk_cfg[i] && cnt<DPDK_ARGC_MAX-1;i++){
+ if (skip_space && dpdk_cfg[i]!=' '){ // not space
+ skip_space=!skip_space; // skip normal char
+ dargv[cnt++] = dpdk_cfg+i;
+ }
+ if (!skip_space && dpdk_cfg[i]==' '){ // fint a space
+ dpdk_cfg[i]=0x00; // end of this opt
+ skip_space=!skip_space; // skip space char
+ }
+ }
+ dargv[cnt]=NULL;
+ return cnt;
+}
+
+// only called once
+// Returns:
+//
+// 1 on success;
+//
+// 0 if "the EAL cannot initialize on this system", which we treat as
+// meaning "DPDK isn't available";
+//
+// a PCAP_ERROR_ code for other errors.
+//
+// If eaccess_not_fatal is non-zero, treat "a permissions issue" the way
+// we treat "the EAL cannot initialize on this system". We use that
+// when trying to find DPDK devices, as we don't want to fail to return
+// *any* devices just because we can't support DPDK; when we're trying
+// to open a device, we need to return a permissions error in that case.
+static int dpdk_pre_init(char * ebuf, int eaccess_not_fatal)
+{
+ int dargv_cnt=0;
+ char *dargv[DPDK_ARGC_MAX];
+ char *ptr_dpdk_cfg = NULL;
+ int ret;
+ // globale var
+ if (is_dpdk_pre_inited != 0)
+ {
+ // already inited; did that succeed?
+ if (is_dpdk_pre_inited < 0)
+ {
+ // failed
+ goto error;
+ }
+ else
+ {
+ // succeeded
+ return 1;
+ }
+ }
+ // init EAL
+ ptr_dpdk_cfg = getenv(DPDK_CFG_ENV_NAME);
+ // set default log level to debug
+ rte_log_set_global_level(DPDK_DEF_LOG_LEV);
+ if (ptr_dpdk_cfg == NULL)
+ {
+ RTE_LOG(INFO,USER1,"env $DPDK_CFG is unset, so using default: %s\n",DPDK_DEF_CFG);
+ ptr_dpdk_cfg = DPDK_DEF_CFG;
+ }
+ memset(dpdk_cfg_buf,0,sizeof(dpdk_cfg_buf));
+ snprintf(dpdk_cfg_buf,DPDK_CFG_MAX_LEN-1,"%s %s",DPDK_LIB_NAME,ptr_dpdk_cfg);
+ dargv_cnt = parse_dpdk_cfg(dpdk_cfg_buf,dargv);
+ ret = rte_eal_init(dargv_cnt,dargv);
+ if (ret == -1)
+ {
+ // Indicate that we've called rte_eal_init() by setting
+ // is_dpdk_pre_inited to the negative of the error code,
+ // and process the error.
+ is_dpdk_pre_inited = -rte_errno;
+ goto error;
+ }
+ // init succeeded, so we do not need to do it again later.
+ is_dpdk_pre_inited = 1;
+ return 1;
+
+error:
+ switch (-is_dpdk_pre_inited)
+ {
+ case EACCES:
+ // This "indicates a permissions issue.".
+ RTE_LOG(ERR, USER1, "%s\n", DPDK_ERR_PERM_MSG);
+ // If we were told to treat this as just meaning
+ // DPDK isn't available, do so.
+ if (eaccess_not_fatal)
+ return 0;
+ // Otherwise report a fatal error.
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "DPDK requires that it run as root");
+ return PCAP_ERROR_PERM_DENIED;
+
+ case EAGAIN:
+ // This "indicates either a bus or system
+ // resource was not available, setup may
+ // be attempted again."
+ // There's no such error in pcap, so I'm
+ // not sure what we should do here.
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "Bus or system resource was not available");
+ break;
+
+ case EALREADY:
+ // This "indicates that the rte_eal_init
+ // function has already been called, and
+ // cannot be called again."
+ // That's not an error; set the "we've
+ // been here before" flag and return
+ // success.
+ is_dpdk_pre_inited = 1;
+ return 1;
+
+ case EFAULT:
+ // This "indicates the tailq configuration
+ // name was not found in memory configuration."
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "The tailq configuration name was not found in the memory configuration");
+ return PCAP_ERROR;
+
+ case EINVAL:
+ // This "indicates invalid parameters were
+ // passed as argv/argc." Those came from
+ // the configuration file.
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "The configuration file has invalid parameters");
+ break;
+
+ case ENOMEM:
+ // This "indicates failure likely caused by
+ // an out-of-memory condition."
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "Out of memory");
+ break;
+
+ case ENODEV:
+ // This "indicates memory setup issues."
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "An error occurred setting up memory");
+ break;
+
+ case ENOTSUP:
+ // This "indicates that the EAL cannot
+ // initialize on this system." We treat
+ // that as meaning DPDK isn't available
+ // on this machine, rather than as a
+ // fatal error, and let our caller decide
+ // whether that's a fatal error (if trying
+ // to activate a DPDK device) or not (if
+ // trying to enumerate devices).
+ return 0;
+
+ case EPROTO:
+ // This "indicates that the PCI bus is
+ // either not present, or is not readable
+ // by the eal." Does "the PCI bus is not
+ // present" mean "this machine has no PCI
+ // bus", which strikes me as a "not available"
+ // case? If so, should "is not readable by
+ // the EAL" also something we should treat
+ // as a "not available" case? If not, we
+ // can't distinguish between the two, so
+ // we're stuck.
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "PCI bus is not present or not readable by the EAL");
+ break;
+
+ case ENOEXEC:
+ // This "indicates that a service core
+ // failed to launch successfully."
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "A service core failed to launch successfully");
+ break;
+
+ default:
+ //
+ // That's not in the list of errors in
+ // the documentation; let it be reported
+ // as an error.
+ //
+ dpdk_fmt_errmsg_for_rte_errno(ebuf,
+ PCAP_ERRBUF_SIZE, -is_dpdk_pre_inited,
+ "dpdk error: dpdk_pre_init failed");
+ break;
+ }
+ // Error.
+ return PCAP_ERROR;
+}
+
+static int pcap_dpdk_activate(pcap_t *p)
+{
+ struct pcap_dpdk *pd = p->priv;
+ pd->orig = p;
+ int ret = PCAP_ERROR;
+ uint16_t nb_ports=0;
+ uint16_t portid= DPDK_PORTID_MAX;
+ unsigned nb_mbufs = DPDK_NB_MBUFS;
+ struct rte_eth_rxconf rxq_conf;
+ struct rte_eth_txconf txq_conf;
+ struct rte_eth_conf local_port_conf = port_conf;
+ struct rte_eth_dev_info dev_info;
+ int is_port_up = 0;
+ struct rte_eth_link link;
+ do{
+ //init EAL; fail if we have insufficient permission
+ char dpdk_pre_init_errbuf[PCAP_ERRBUF_SIZE];
+ ret = dpdk_pre_init(dpdk_pre_init_errbuf, 0);
+ if (ret < 0)
+ {
+ // This returns a negative value on an error.
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Can't open device %s: %s",
+ p->opt.device, dpdk_pre_init_errbuf);
+ // ret is set to the correct error
+ break;
+ }
+ if (ret == 0)
+ {
+ // This means DPDK isn't available on this machine.
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Can't open device %s: DPDK is not available on this machine",
+ p->opt.device);
+ return PCAP_ERROR_NO_SUCH_DEVICE;
+ }
+
+ ret = dpdk_init_timer(pd);
+ if (ret<0)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "dpdk error: Init timer is zero with device %s",
+ p->opt.device);
+ ret = PCAP_ERROR;
+ break;
+ }
+
+ nb_ports = rte_eth_dev_count_avail();
+ if (nb_ports == 0)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "dpdk error: No Ethernet ports");
+ ret = PCAP_ERROR;
+ break;
+ }
+
+ portid = portid_by_device(p->opt.device);
+ if (portid == DPDK_PORTID_MAX){
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "dpdk error: portid is invalid. device %s",
+ p->opt.device);
+ ret = PCAP_ERROR_NO_SUCH_DEVICE;
+ break;
+ }
+
+ pd->portid = portid;
+
+ if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN)
+ {
+ p->snapshot = MAXIMUM_SNAPLEN;
+ }
+ // create the mbuf pool
+ pd->pktmbuf_pool = rte_pktmbuf_pool_create(MBUF_POOL_NAME, nb_mbufs,
+ MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
+ rte_socket_id());
+ if (pd->pktmbuf_pool == NULL)
+ {
+ dpdk_fmt_errmsg_for_rte_errno(p->errbuf,
+ PCAP_ERRBUF_SIZE, rte_errno,
+ "dpdk error: Cannot init mbuf pool");
+ ret = PCAP_ERROR;
+ break;
+ }
+ // config dev
+ rte_eth_dev_info_get(portid, &dev_info);
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
+ {
+ local_port_conf.txmode.offloads |=DEV_TX_OFFLOAD_MBUF_FAST_FREE;
+ }
+ // only support 1 queue
+ ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);
+ if (ret < 0)
+ {
+ dpdk_fmt_errmsg_for_rte_errno(p->errbuf,
+ PCAP_ERRBUF_SIZE, -ret,
+ "dpdk error: Cannot configure device: port=%u",
+ portid);
+ ret = PCAP_ERROR;
+ break;
+ }
+ // adjust rx tx
+ ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, &nb_txd);
+ if (ret < 0)
+ {
+ dpdk_fmt_errmsg_for_rte_errno(p->errbuf,
+ PCAP_ERRBUF_SIZE, -ret,
+ "dpdk error: Cannot adjust number of descriptors: port=%u",
+ portid);
+ ret = PCAP_ERROR;
+ break;
+ }
+ // get MAC addr
+ rte_eth_macaddr_get(portid, &(pd->eth_addr));
+ eth_addr_str(&(pd->eth_addr), pd->mac_addr, DPDK_MAC_ADDR_SIZE-1);
+
+ // init one RX queue
+ rxq_conf = dev_info.default_rxconf;
+ rxq_conf.offloads = local_port_conf.rxmode.offloads;
+ ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+ rte_eth_dev_socket_id(portid),
+ &rxq_conf,
+ pd->pktmbuf_pool);
+ if (ret < 0)
+ {
+ dpdk_fmt_errmsg_for_rte_errno(p->errbuf,
+ PCAP_ERRBUF_SIZE, -ret,
+ "dpdk error: rte_eth_rx_queue_setup:port=%u",
+ portid);
+ ret = PCAP_ERROR;
+ break;
+ }
+
+ // init one TX queue
+ txq_conf = dev_info.default_txconf;
+ txq_conf.offloads = local_port_conf.txmode.offloads;
+ ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+ rte_eth_dev_socket_id(portid),
+ &txq_conf);
+ if (ret < 0)
+ {
+ dpdk_fmt_errmsg_for_rte_errno(p->errbuf,
+ PCAP_ERRBUF_SIZE, -ret,
+ "dpdk error: rte_eth_tx_queue_setup:port=%u",
+ portid);
+ ret = PCAP_ERROR;
+ break;
+ }
+ // Initialize TX buffers
+ tx_buffer = rte_zmalloc_socket(DPDK_TX_BUF_NAME,
+ RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
+ rte_eth_dev_socket_id(portid));
+ if (tx_buffer == NULL)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "dpdk error: Cannot allocate buffer for tx on port %u", portid);
+ ret = PCAP_ERROR;
+ break;
+ }
+ rte_eth_tx_buffer_init(tx_buffer, MAX_PKT_BURST);
+ // Start device
+ ret = rte_eth_dev_start(portid);
+ if (ret < 0)
+ {
+ dpdk_fmt_errmsg_for_rte_errno(p->errbuf,
+ PCAP_ERRBUF_SIZE, -ret,
+ "dpdk error: rte_eth_dev_start:port=%u",
+ portid);
+ ret = PCAP_ERROR;
+ break;
+ }
+ // set promiscuous mode
+ if (p->opt.promisc){
+ pd->must_clear_promisc=1;
+ rte_eth_promiscuous_enable(portid);
+ }
+ // check link status
+ is_port_up = check_link_status(portid, &link);
+ if (!is_port_up){
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "dpdk error: link is down, port=%u",portid);
+ ret = PCAP_ERROR_IFACE_NOT_UP;
+ break;
+ }
+ // reset statistics
+ rte_eth_stats_reset(pd->portid);
+ calculate_timestamp(&(pd->ts_helper), &(pd->prev_ts));
+ rte_eth_stats_get(pd->portid,&(pd->prev_stats));
+ // format pcap_t
+ pd->portid = portid;
+ p->fd = pd->portid;
+ if (p->snapshot <=0 || p->snapshot> MAXIMUM_SNAPLEN)
+ {
+ p->snapshot = MAXIMUM_SNAPLEN;
+ }
+ p->linktype = DLT_EN10MB; // Ethernet, the 10MB is historical.
+ p->selectable_fd = p->fd;
+ p->read_op = pcap_dpdk_dispatch;
+ p->inject_op = pcap_dpdk_inject;
+ // using pcap_filter currently, though DPDK provides their own BPF function. Because DPDK BPF needs load a ELF file as a filter.
+ p->setfilter_op = install_bpf_program;
+ p->setdirection_op = NULL;
+ p->set_datalink_op = NULL;
+ p->getnonblock_op = pcap_dpdk_getnonblock;
+ p->setnonblock_op = pcap_dpdk_setnonblock;
+ p->stats_op = pcap_dpdk_stats;
+ p->cleanup_op = pcap_dpdk_close;
+ p->breakloop_op = pcap_breakloop_common;
+ // set default timeout
+ pd->required_select_timeout.tv_sec = 0;
+ pd->required_select_timeout.tv_usec = DPDK_DEF_MIN_SLEEP_MS*1000;
+ p->required_select_timeout = &pd->required_select_timeout;
+ ret = 0; // OK
+ }while(0);
+
+ if (ret <= PCAP_ERROR) // all kinds of error code
+ {
+ pcap_cleanup_live_common(p);
+ }else{
+ rte_eth_dev_get_name_by_port(portid,pd->pci_addr);
+ RTE_LOG(INFO, USER1,"Port %d device: %s, MAC:%s, PCI:%s\n", portid, p->opt.device, pd->mac_addr, pd->pci_addr);
+ RTE_LOG(INFO, USER1,"Port %d Link Up. Speed %u Mbps - %s\n",
+ portid, link.link_speed,
+ (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
+ ("full-duplex") : ("half-duplex\n"));
+ }
+ return ret;
+}
+
+// device name for dpdk should be in the form as dpdk:number, such as dpdk:0
+pcap_t * pcap_dpdk_create(const char *device, char *ebuf, int *is_ours)
+{
+ pcap_t *p=NULL;
+ *is_ours = 0;
+
+ *is_ours = !strncmp(device, "dpdk:", 5);
+ if (! *is_ours)
+ return NULL;
+ //memset will happen
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_dpdk);
+
+ if (p == NULL)
+ return NULL;
+ p->activate_op = pcap_dpdk_activate;
+ return p;
+}
+
+int pcap_dpdk_findalldevs(pcap_if_list_t *devlistp, char *ebuf)
+{
+ int ret=0;
+ unsigned int nb_ports = 0;
+ char dpdk_name[DPDK_DEV_NAME_MAX];
+ char dpdk_desc[DPDK_DEV_DESC_MAX];
+ ETHER_ADDR_TYPE eth_addr;
+ char mac_addr[DPDK_MAC_ADDR_SIZE];
+ char pci_addr[DPDK_PCI_ADDR_SIZE];
+ do{
+ // init EAL; return "DPDK not available" if we
+ // have insufficient permission
+ char dpdk_pre_init_errbuf[PCAP_ERRBUF_SIZE];
+ ret = dpdk_pre_init(dpdk_pre_init_errbuf, 1);
+ if (ret < 0)
+ {
+ // This returns a negative value on an error.
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "Can't look for DPDK devices: %s",
+ dpdk_pre_init_errbuf);
+ ret = PCAP_ERROR;
+ break;
+ }
+ if (ret == 0)
+ {
+ // This means DPDK isn't available on this machine.
+ // That just means "don't return any devices".
+ break;
+ }
+ nb_ports = rte_eth_dev_count_avail();
+ if (nb_ports == 0)
+ {
+ // That just means "don't return any devices".
+ ret = 0;
+ break;
+ }
+ for (unsigned int i=0; i<nb_ports; i++){
+ snprintf(dpdk_name, DPDK_DEV_NAME_MAX-1,
+ "%s%u", DPDK_PREFIX, i);
+ // mac addr
+ rte_eth_macaddr_get(i, &eth_addr);
+ eth_addr_str(&eth_addr,mac_addr,DPDK_MAC_ADDR_SIZE);
+ // PCI addr
+ rte_eth_dev_get_name_by_port(i,pci_addr);
+ snprintf(dpdk_desc,DPDK_DEV_DESC_MAX-1,"%s %s, MAC:%s, PCI:%s", DPDK_DESC, dpdk_name, mac_addr, pci_addr);
+ if (add_dev(devlistp, dpdk_name, 0, dpdk_desc, ebuf)==NULL){
+ ret = PCAP_ERROR;
+ break;
+ }
+ }
+ }while(0);
+ return ret;
+}
+
+#ifdef DPDK_ONLY
+/*
+ * This libpcap build supports only DPDK, not regular network interfaces.
+ */
+
+/*
+ * There are no regular interfaces, just DPDK interfaces.
+ */
+int
+pcap_platform_finddevs(pcap_if_list_t *devlistp _U_, char *errbuf)
+{
+ return (0);
+}
+
+/*
+ * Attempts to open a regular interface fail.
+ */
+pcap_t *
+pcap_create_interface(const char *device, char *errbuf)
+{
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "This version of libpcap only supports DPDK");
+ return NULL;
+}
+
+/*
+ * Libpcap version string.
+ */
+const char *
+pcap_lib_version(void)
+{
+ return (PCAP_VERSION_STRING " (DPDK-only)");
+}
+#endif
diff --git a/pcap-dpdk.h b/pcap-dpdk.h
new file mode 100644
index 00000000..b759b7f4
--- /dev/null
+++ b/pcap-dpdk.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 jingle YANG. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+pcap_t *pcap_dpdk_create(const char *, char *, int *);
+int pcap_dpdk_findalldevs(pcap_if_list_t *devlistp, char *errbuf);
diff --git a/pcap-enet.c b/pcap-enet.c
index cd8cdbbb..6f0512f3 100644
--- a/pcap-enet.c
+++ b/pcap-enet.c
@@ -75,7 +75,7 @@ readloop(int cnt, int if_fd, struct bpf_program *fp, printfunc printit)
ph = (struct packet_header *)bp;
caplen = ph->tap.th_wirelen > snaplen ? snaplen : ph->tap
.th_wirelen ;
- if (bpf_filter(fcode, (char *)ph->packet,
+ if (pcap_filter(fcode, (char *)ph->packet,
ph->tap.th_wirelen, caplen)) {
if (cnt >= 0 && --cnt < 0)
goto out;
@@ -89,7 +89,7 @@ readloop(int cnt, int if_fd, struct bpf_program *fp, printfunc printit)
}
#else /* !IBMRTPC */
caplen = cc > snaplen ? snaplen : cc ;
- if (bpf_filter(fcode, buf.hdr.packet, cc, caplen)) {
+ if (pcap_filter(fcode, buf.hdr.packet, cc, caplen)) {
if (cnt >= 0 && --cnt < 0)
goto out;
(*printit)(buf.hdr.packet, &tv, cc, caplen);
diff --git a/pcap-filter.manmisc.in b/pcap-filter.manmisc.in
index 777e7350..e0f883d5 100644
--- a/pcap-filter.manmisc.in
+++ b/pcap-filter.manmisc.in
@@ -18,22 +18,22 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP-FILTER @MAN_MISC_INFO@ "5 November 2017"
+.TH PCAP-FILTER @MAN_MISC_INFO@ "2 September 2020"
.SH NAME
pcap-filter \- packet filter syntax
.br
.ad
.SH DESCRIPTION
.LP
-.B pcap_compile()
+.BR pcap_compile ()
is used to compile a string into a filter program.
The resulting filter program can then be applied to
some stream of packets to determine which packets will be supplied to
-.BR pcap_loop(3PCAP) ,
-.BR pcap_dispatch(3PCAP) ,
-.BR pcap_next(3PCAP) ,
+.BR pcap_loop (3PCAP),
+.BR pcap_dispatch (3PCAP),
+.BR pcap_next (3PCAP),
or
-.BR pcap_next_ex(3PCAP) .
+.BR pcap_next_ex (3PCAP).
.LP
The \fIfilter expression\fP consists of one or more
.IR primitives .
@@ -47,11 +47,11 @@ different kinds of qualifier:
qualifiers say what kind of thing the id name or number refers to.
Possible types are
.BR host ,
-.B net ,
+.BR net ,
.B port
and
.BR portrange .
-E.g., `host foo', `net 128.3', `port 20', `portrange 6000-6008'.
+E.g., `\fBhost\fP foo', `\fBnet\fP 128.3', `\fBport\fP 20', `\fBportrange\fP 6000-6008'.
If there is no type
qualifier,
.B host
@@ -72,11 +72,9 @@ Possible directions are
.BR addr3 ,
and
.BR addr4 .
-E.g., `src foo', `dst net 128.3', `src or dst port ftp-data'.
+E.g., `\fBsrc\fP foo', `\fBdst net\fP 128.3', `\fBsrc or dst port\fP ftp-data'.
If
-there is no dir qualifier,
-.B "src or dst"
-is assumed.
+there is no dir qualifier, `\fBsrc or dst\fP' is assumed.
The
.BR ra ,
.BR ta ,
@@ -103,25 +101,26 @@ protos are:
.B tcp
and
.BR udp .
-E.g., `ether src foo', `arp net 128.3', `tcp port 21', `udp portrange
-7000-7009', `wlan addr2 0:2:3:4:5:6'.
+E.g., `\fBether src\fP foo', `\fBarp net\fP 128.3', `\fBtcp port\fP 21',
+`\fBudp portrange\fP 7000-7009', `\fBwlan addr2\fP 0:2:3:4:5:6'.
If there is
no proto qualifier, all protocols consistent with the type are
assumed.
-E.g., `src foo' means `(ip or arp or rarp) src foo'
-(except the latter is not legal syntax), `net bar' means `(ip or
-arp or rarp) net bar' and `port 53' means `(tcp or udp) port 53'.
+E.g., `\fBsrc\fP foo' means `\fB(ip or arp or rarp) src\fP foo'
+(except the latter is not legal syntax), `\fBnet\fP bar' means `\fB(ip or
+arp or rarp) net\fP bar' and `\fBport\fP 53' means `\fB(tcp or udp)
+port\fP 53'.
.LP
-[`fddi' is actually an alias for `ether'; the parser treats them
+[\fBfddi\fP is actually an alias for \fBether\fP; the parser treats them
identically as meaning ``the data link level used on the specified
-network interface.'' FDDI headers contain Ethernet-like source
+network interface''. FDDI headers contain Ethernet-like source
and destination addresses, and often contain Ethernet-like packet
types, so you can filter on these FDDI fields just as with the
analogous Ethernet fields.
FDDI headers also contain other fields,
but you cannot name them explicitly in a filter expression.
.LP
-Similarly, `tr' and `wlan' are aliases for `ether'; the previous
+Similarly, \fBtr\fP and \fBwlan\fP are aliases for \fBether\fP; the previous
paragraph's statements about FDDI headers also apply to Token Ring
and 802.11 wireless LAN headers. For 802.11 headers, the destination
address is the DA field and the source address is the SA field; the
@@ -141,12 +140,13 @@ More complex filter expressions are built up by using the words
.B or
and
.B not
+(or equivalently: `\fB&&\fP', `\fB||\fP' and `\fB!\fP' respectively)
to combine primitives.
-E.g., `host foo and not port ftp and not port ftp-data'.
+E.g., `\fBhost\fP foo \fBand not port\fP ftp \fBand not port\fP ftp-data'.
To save typing, identical qualifier lists can be omitted.
E.g.,
-`tcp dst port ftp or ftp-data or domain' is exactly the same as
-`tcp dst port ftp or tcp dst port ftp-data or tcp dst port domain'.
+`\fBtcp dst port\fP ftp \fBor\fP ftp-data \fBor\fP domain' is exactly the same as
+`\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"
@@ -167,10 +167,10 @@ Any of the above host expressions can be prepended with the keywords,
which is equivalent to:
.in +.5i
.nf
-\fBether proto \fI\\ip\fB and host \fIhost\fR
+\fBether proto \\ip and host \fIhost\fR
.fi
.in -.5i
-If \fIhost\fR is a name with multiple IP addresses, each address will
+If \fIhost\fR is a name with multiple IPv4 addresses, each address will
be checked for a match.
.IP "\fBether dst \fIehost\fP"
True if the Ethernet destination address is \fIehost\fP.
@@ -228,24 +228,24 @@ True if the IPv4/v6 address matches \fInet\fR with a netmask \fIlen\fR
bits wide.
May be qualified with \fBsrc\fR or \fBdst\fR.
.IP "\fBdst port \fIport\fR"
-True if the packet is ip/tcp, ip/udp, ip6/tcp or ip6/udp and has a
+True if the packet is IPv4 TCP, IPv4 UDP, IPv6 TCP or IPv6 UDP and has a
destination port value of \fIport\fP.
The \fIport\fP can be a number or a name used in /etc/services (see
-.IR tcp (4P)
+.BR tcp (4P)
and
-.IR udp (4P)).
+.BR udp (4P)).
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 513\fR will print both
-tcp/login traffic and udp/who traffic, and \fBport domain\fR will print
+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
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\fB-\fIport2\fR"
-True if the packet is ip/tcp, ip/udp, ip6/tcp or ip6/udp and has a
+.IP "\fBdst portrange \fIport1-port2\fR"
+True if the packet is IPv4 TCP, IPv4 UDP, IPv6 TCP or IPv6 UDP and has a
destination port value between \fIport1\fP and \fIport2\fP.
.I port1
and
@@ -254,10 +254,10 @@ are interpreted in the same fashion as the
.I port
parameter for
.BR port .
-.IP "\fBsrc portrange \fIport1\fB-\fIport2\fR"
+.IP "\fBsrc portrange \fIport1-port2\fR"
True if the packet has a source port value between \fIport1\fP and
\fIport2\fP.
-.IP "\fBportrange \fIport1\fB-\fIport2\fR"
+.IP "\fBportrange \fIport1-port2\fR"
True if either the source or destination port of the packet is between
\fIport1\fP and \fIport2\fP.
.IP
@@ -268,13 +268,13 @@ the keywords, \fBtcp\fP or \fBudp\fP, as in:
\fBtcp src port \fIport\fR
.fi
.in -.5i
-which matches only tcp packets whose source port is \fIport\fP.
+which matches only TCP packets whose source port is \fIport\fP.
.IP "\fBless \fIlength\fR"
True if the packet has a length less than or equal to \fIlength\fP.
This is equivalent to:
.in +.5i
.nf
-\fBlen <= \fIlength\fP.
+\fBlen <= \fIlength\fP
.fi
.in -.5i
.IP "\fBgreater \fIlength\fR"
@@ -282,12 +282,12 @@ True if the packet has a length greater than or equal to \fIlength\fP.
This is equivalent to:
.in +.5i
.nf
-\fBlen >= \fIlength\fP.
+\fBlen >= \fIlength\fP
.fi
.in -.5i
.IP "\fBip proto \fIprotocol\fR"
True if the packet is an IPv4 packet (see
-.IR ip (4P))
+.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,
@@ -306,10 +306,10 @@ header chain.
Abbreviations for:
.in +.5i
.nf
-\fBproto \fIp\fR\fB
+\fBproto \\\fIprotocol\fR\fB
.fi
.in -.5i
-where \fIp\fR is one of the above protocols.
+where \fIprotocol\fR is one of the above protocols.
.IP "\fBip6 protochain \fIprotocol\fR"
True if the packet is IPv6 packet,
and contains protocol header with type \fIprotocol\fR
@@ -317,7 +317,7 @@ in its protocol header chain.
For example,
.in +.5i
.nf
-\fBip6 protochain 6\fR
+\fBip6 protochain\fR 6
.fi
.in -.5i
matches any IPv6 packet with TCP protocol header in the protocol header chain.
@@ -336,7 +336,7 @@ True if the packet is an IPv4 or IPv6 packet of protocol type
header chain.
.IP "\fBether broadcast\fR"
True if the packet is an Ethernet broadcast packet.
-The \fIether\fP
+The \fBether\fP
keyword is optional.
.IP "\fBip broadcast\fR"
True if the packet is an IPv4 broadcast packet.
@@ -353,7 +353,7 @@ check will not work correctly.
True if the packet is an Ethernet multicast packet.
The \fBether\fP
keyword is optional.
-This is shorthand for `\fBether[0] & 1 != 0\fP'.
+This is shorthand for `\fBether[\fP0\fB] & \fP1\fB != \fP0'.
.IP "\fBip multicast\fR"
True if the packet is an IPv4 multicast packet.
.IP "\fBip6 multicast\fR"
@@ -361,15 +361,15 @@ True if the packet is an IPv6 multicast packet.
.IP "\fBether proto \fIprotocol\fR"
True if the packet is of ether type \fIprotocol\fR.
\fIProtocol\fP can be a number or one of the names
-\fBip\fP, \fBip6\fP, \fBarp\fP, \fBrarp\fP, \fBatalk\fP, \fBaarp\fP,
-\fBdecnet\fP, \fBsca\fP, \fBlat\fP, \fBmopdl\fP, \fBmoprc\fP,
-\fBiso\fP, \fBstp\fP, \fBipx\fP, or \fBnetbeui\fP.
-Note these identifiers are also keywords
+\fBaarp\fP, \fBarp\fP, \fBatalk\fP, \fBdecnet\fP, \fBip\fP, \fBip6\fP,
+\fBipx\fP, \fBiso\fP, \fBlat\fP, \fBloopback\fP, \fBmopdl\fP, \fBmoprc\fP, \fBnetbeui\fP,
+\fBrarp\fP, \fBsca\fP or \fBstp\fP.
+Note these identifiers (except \fBloopback\fP) are also keywords
and must be escaped via backslash (\\).
.IP
-[In the case of FDDI (e.g., `\fBfddi proto arp\fR'), Token Ring
-(e.g., `\fBtr proto arp\fR'), and IEEE 802.11 wireless LANS (e.g.,
-`\fBwlan proto arp\fR'), for most of those protocols, the
+[In the case of FDDI (e.g., `\fBfddi proto \\arp\fR'), Token Ring
+(e.g., `\fBtr proto \\arp\fR'), and IEEE 802.11 wireless LANs (e.g.,
+`\fBwlan proto \\arp\fR'), for most of those protocols, the
protocol identification comes from the 802.2 Logical Link Control (LLC)
header, which is usually layered on top of the FDDI, Token Ring, or
802.11 header.
@@ -419,33 +419,33 @@ IPX, and the IPX etype in a SNAP frame.
Abbreviations for:
.in +.5i
.nf
-\fBether proto \fIp\fR
+\fBether proto \\\fIprotocol\fR
.fi
.in -.5i
-where \fIp\fR is one of the above protocols.
+where \fIprotocol\fR is one of the above protocols.
.IP "\fBlat\fR, \fBmoprc\fR, \fBmopdl\fR"
Abbreviations for:
.in +.5i
.nf
-\fBether proto \fIp\fR
+\fBether proto \\\fIprotocol\fR
.fi
.in -.5i
-where \fIp\fR is one of the above protocols.
+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"
-True if the DECNET source address is
+True if the DECnet source address is
.IR host ,
-which may be an address of the form ``10.123'', or a DECNET host
+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.]
+[DECnet host name support is only available on ULTRIX systems
+that are configured to run DECnet.]
.IP "\fBdecnet dst \fIhost\fR"
-True if the DECNET destination address is
+True if the DECnet destination address is
.IR host .
.IP "\fBdecnet host \fIhost\fR"
-True if either the DECNET source or destination address is
+True if either the DECnet source or destination address is
.IR host .
.IP \fBllc\fP
True if the packet has an 802.2 LLC header. This includes:
@@ -460,7 +460,7 @@ Token Ring packets (no check is done for LLC frames);
FDDI packets (no check is done for LLC frames);
.IP
LLC-encapsulated ATM packets, for SunATM on Solaris.
-.IP "\fBllc\fP \Fitype\fR"
+.IP "\fBllc\fP \fItype\fR"
True if the packet has an 802.2 LLC header and has the specified
.IR type .
.I type
@@ -668,51 +668,51 @@ Valid directions are:
or a numeric value.
.IP "\fBvlan \fI[vlan_id]\fR"
True if the packet is an IEEE 802.1Q VLAN packet.
-If \fI[vlan_id]\fR is specified, only true if the packet has the specified
+If the optional \fIvlan_id\fR is specified, only true if the packet has the specified
\fIvlan_id\fR.
-Note that the first \fBvlan\fR keyword encountered in \fIexpression\fR
-changes the decoding offsets for the remainder of \fIexpression\fR on
-the assumption that the packet is a VLAN packet. The \fBvlan
-\fI[vlan_id]\fR expression may be used more than once, to filter on VLAN
-hierarchies. Each use of that expression increments the filter offsets
+Note that the first \fBvlan\fR keyword encountered in an expression
+changes the decoding offsets for the remainder of the expression on
+the assumption that the packet is a VLAN packet. The `\fBvlan
+\fI[vlan_id]\fR` keyword may be used more than once, to filter on VLAN
+hierarchies. Each use of that keyword increments the filter offsets
by 4.
.IP
For example:
.in +.5i
.nf
-\fBvlan 100 && vlan 200\fR
+\fBvlan\fP 100 \fB&& vlan\fR 200
.fi
.in -.5i
filters on VLAN 200 encapsulated within VLAN 100, and
.in +.5i
.nf
-\fBvlan && vlan 300 && ip\fR
+\fBvlan && vlan \fP300 \fB&& ip\fR
.fi
.in -.5i
-filters IPv4 protocols encapsulated in VLAN 300 encapsulated within any
+filters IPv4 protocol encapsulated in VLAN 300 encapsulated within any
higher order VLAN.
.IP "\fBmpls \fI[label_num]\fR"
True if the packet is an MPLS packet.
-If \fI[label_num]\fR is specified, only true is the packet has the specified
+If the optional \fIlabel_num\fR is specified, only true if the packet has the specified
\fIlabel_num\fR.
-Note that the first \fBmpls\fR keyword encountered in \fIexpression\fR
-changes the decoding offsets for the remainder of \fIexpression\fR on
+Note that the first \fBmpls\fR keyword encountered in an expression
+changes the decoding offsets for the remainder of the expression on
the assumption that the packet is a MPLS-encapsulated IP packet. The
-\fBmpls \fI[label_num]\fR expression may be used more than once, to
-filter on MPLS hierarchies. Each use of that expression increments the
+`\fBmpls \fI[label_num]\fR` keyword may be used more than once, to
+filter on MPLS hierarchies. Each use of that keyword increments the
filter offsets by 4.
.IP
For example:
.in +.5i
.nf
-\fBmpls 100000 && mpls 1024\fR
+\fBmpls\fP 100000 \fB&& mpls\fR 1024
.fi
.in -.5i
filters packets with an outer label of 100000 and an inner label of
1024, and
.in +.5i
.nf
-\fBmpls && mpls 1024 && host 192.9.200.1\fR
+\fBmpls && mpls\fP 1024 \fB&& host\fR 192.9.200.1
.fi
.in -.5i
filters packets to or from 192.9.200.1 with an inner label of 1024 and
@@ -723,34 +723,34 @@ type 0x8863).
.IP "\fBpppoes \fI[session_id]\fR"
True if the packet is a PPP-over-Ethernet Session packet (Ethernet
type 0x8864).
-If \fI[session_id]\fR is specified, only true if the packet has the specified
+If the optional \fIsession_id\fR is specified, only true if the packet has the specified
\fIsession_id\fR.
-Note that the first \fBpppoes\fR keyword encountered in \fIexpression\fR
-changes the decoding offsets for the remainder of \fIexpression\fR on
+Note that the first \fBpppoes\fR keyword encountered in an expression
+changes the decoding offsets for the remainder of the expression on
the assumption that the packet is a PPPoE session packet.
.IP
For example:
.in +.5i
.nf
-\fBpppoes 0x27 && ip\fR
+\fBpppoes\fP 0x27 \fB&& ip\fR
.fi
.in -.5i
-filters IPv4 protocols encapsulated in PPPoE session id 0x27.
+filters IPv4 protocol encapsulated in PPPoE session id 0x27.
.IP "\fBgeneve \fI[vni]\fR"
-True if the packet is a Geneve packet (UDP port 6081). If \fI[vni]\fR
+True if the packet is a Geneve packet (UDP port 6081). If the optional \fIvni\fR
is specified, only true if the packet has the specified \fIvni\fR.
Note that when the \fBgeneve\fR keyword is encountered in
-\fIexpression\fR, it changes the decoding offsets for the remainder of
-\fIexpression\fR on the assumption that the packet is a Geneve packet.
+an expression, it changes the decoding offsets for the remainder of
+the expression on the assumption that the packet is a Geneve packet.
.IP
For example:
.in +.5i
.nf
-\fBgeneve 0xb && ip\fR
+\fBgeneve\fP 0xb \fB&& ip\fR
.fi
.in -.5i
-filters IPv4 protocols encapsulated in Geneve with VNI 0xb. This will
-match both IP directly encapsulated in Geneve as well as IP contained
+filters IPv4 protocol encapsulated in Geneve with VNI 0xb. This will
+match both IPv4 directly encapsulated in Geneve as well as IPv4 contained
inside an Ethernet frame.
.IP "\fBiso proto \fIprotocol\fR"
True if the packet is an OSI packet of protocol type \fIprotocol\fP.
@@ -760,10 +760,10 @@ True if the packet is an OSI packet of protocol type \fIprotocol\fP.
Abbreviations for:
.in +.5i
.nf
-\fBiso proto \fIp\fR
+\fBiso proto \\\fIprotocol\fR
.fi
.in -.5i
-where \fIp\fR is one of the above protocols.
+where \fIprotocol\fR is one of the above protocols.
.IP "\fBl1\fR, \fBl2\fR, \fBiih\fR, \fBlsp\fR, \fBsnp\fR, \fBcsnp\fR, \fBpsnp\fR"
Abbreviations for IS-IS PDU types.
.IP "\fBvpi\fP \fIn\fR"
@@ -777,8 +777,8 @@ virtual channel identifier of
.IP \fBlane\fP
True if the packet is an ATM packet, for SunATM on Solaris, and is
an ATM LANE packet.
-Note that the first \fBlane\fR keyword encountered in \fIexpression\fR
-changes the tests done in the remainder of \fIexpression\fR
+Note that the first \fBlane\fR keyword encountered in an expression
+changes the tests done in the remainder of the expression
on the assumption that the packet is either a LANE emulated Ethernet
packet or a LANE LE Control packet. If \fBlane\fR isn't specified, the
tests are done under the assumption that the packet is an
@@ -841,7 +841,7 @@ indicates the protocol layer for the index operation.
(\fBether, fddi, wlan, tr, ppp, slip\fR and \fBlink\fR all refer to the
link layer. \fBradio\fR refers to the "radio header" added to some
802.11 captures.)
-Note that \fItcp, udp\fR and other upper-layer protocol types only
+Note that \fBtcp\fR, \fBudp\fR and other upper-layer protocol types only
apply to IPv4, not IPv6 (this will be fixed in the future).
The byte offset, relative to the indicated protocol layer, is
given by \fIexpr\fR.
@@ -850,24 +850,24 @@ 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[0] & 1 != 0\fP' catches all multicast traffic.
-The expression `\fBip[0] & 0xf != 5\fP'
+For example, `\fBether[\fP0\fB] &\fP 1 \fB!=\fP 0' catches all multicast traffic.
+The expression `\fBip[\fP0\fB] &\fP 0xf \fB!=\fP 5'
catches all IPv4 packets with options.
The expression
-`\fBip[6:2] & 0x1fff = 0\fP'
+`\fBip[\fP6:2\fB] &\fP 0x1fff \fB=\fP 0'
catches only unfragmented IPv4 datagrams and frag zero of fragmented
IPv4 datagrams.
This check is implicitly applied to the \fBtcp\fP and \fBudp\fP
index operations.
-For instance, \fBtcp[0]\fP always means the first
+For instance, \fBtcp[\fP0\fB]\fP always means the first
byte of the TCP \fIheader\fP, and never means the first byte of an
intervening fragment.
Some offsets and field values may be expressed as names rather than
as numeric values.
The following protocol header field offsets are
-available: \fBicmptype\fP (ICMP type field), \fBicmp6type (ICMP v6 type field)
-\fBicmpcode\fP (ICMP code field), \fBicmp6code\fP (ICMP v6 code field), and
+available: \fBicmptype\fP (ICMP type field), \fBicmp6type\fP (ICMPv6 type field),
+\fBicmpcode\fP (ICMP code field), \fBicmp6code\fP (ICMPv6 code field) and
\fBtcpflags\fP (TCP flags field).
The following ICMP type field values are available: \fBicmp-echoreply\fP,
@@ -877,7 +877,9 @@ The following ICMP type field values are available: \fBicmp-echoreply\fP,
\fBicmp-tstampreply\fP, \fBicmp-ireq\fP, \fBicmp-ireqreply\fP,
\fBicmp-maskreq\fP, \fBicmp-maskreply\fP.
-The following ICMPv6 type fields are available: \fBicmp6-echo\fP,
+The following ICMPv6 type fields are available: \fBicmp6-destinationrunreach\fP,
+\fBicmp6-packettoobig\fP, \fBicmp6-timeexceeded\fP,
+\fBicmp6-parameterproblem\fP, \fBicmp6-echo\fP,
\fBicmp6-echoreply\fP, \fBicmp6-multicastlistenerquery\fP,
\fBicmp6-multicastlistenerreportv1\fP, \fBicmp6-multicastlistenerdone\fP,
\fBicmp6-routersolicit\fP, \fBicmp6-routeradvert\fP,
@@ -906,7 +908,7 @@ Concatenation (`\fB&&\fP' or `\fBand\fP').
.IP
Alternation (`\fB||\fP' or `\fBor\fP').
.LP
-Negation has highest precedence.
+Negation has the highest precedence.
Alternation and concatenation have equal precedence and associate
left to right.
Note that explicit \fBand\fR tokens, not juxtaposition,
@@ -917,67 +919,64 @@ is assumed.
For example,
.in +.5i
.nf
-\fBnot host vs and ace\fR
+\fBnot host\fP vs \fBand\fR ace
.fi
.in -.5i
is short for
.in +.5i
.nf
-\fBnot host vs and host ace\fR
+\fBnot host\fP vs \fBand host\fR ace
.fi
.in -.5i
which should not be confused with
.in +.5i
.nf
-\fBnot ( host vs or ace )\fR
+\fBnot (host \fPvs\fB or \fPace\fB)\fR
.fi
.in -.5i
.SH EXAMPLES
.LP
-To select all packets arriving at or departing from \fIsundown\fP:
+To select all packets arriving at or departing from `sundown':
.RS
.nf
-\fBhost sundown\fP
+\fBhost\fP sundown
.fi
.RE
.LP
-To select traffic between \fIhelios\fR and either \fIhot\fR or \fIace\fR:
+To select traffic between `helios' and either `hot' or `ace':
.RS
.nf
-\fBhost helios and \\( hot or ace \\)\fP
+\fBhost\fP helios \fBand (\fPhot \fBor\fP ace\fB)\fP
.fi
.RE
.LP
-To select all IP packets between \fIace\fR and any host except \fIhelios\fR:
+To select all IPv4 packets between `ace' and any host except `helios':
.RS
.nf
-\fBip host ace and not helios\fP
+\fBip host\fP ace \fBand not\fP helios
.fi
.RE
.LP
To select all traffic between local hosts and hosts at Berkeley:
.RS
.nf
-.B
-net ucb-ether
+\fBnet\fP ucb-ether
.fi
.RE
.LP
-To select all ftp traffic through internet gateway \fIsnup\fP:
+To select all FTP traffic through Internet gateway `snup':
.RS
.nf
-.B
-gateway snup and (port ftp or ftp-data)
+\fBgateway\fP snup \fBand (port\fP ftp \fBor\fP ftp-data\fB)\fP
.fi
.RE
.LP
-To select traffic neither sourced from nor destined for local hosts
+To select IPv4 traffic neither sourced from nor destined for local hosts
(if you gateway to one other net, this stuff should never make it
onto your local net).
.RS
.nf
-.B
-ip and not net \fIlocalnet\fP
+\fBip and not net \fPlocalnet
.fi
.RE
.LP
@@ -985,8 +984,17 @@ To select the start and end packets (the SYN and FIN packets) of each
TCP conversation that involves a non-local host.
.RS
.nf
+\fBtcp[tcpflags] & (tcp-syn|tcp-fin) !=\fP 0 \fBand not src and dst net\fP localnet
+.fi
+.RE
+.LP
+To select the TCP packets with flags RST and ACK both set.
+(i.e. select only the RST and ACK flags in the flags field, and if the result
+is "RST and ACK both set", match)
+.RS
+.nf
.B
-tcp[tcpflags] & (tcp-syn|tcp-fin) != 0 and not src and dst net \fIlocalnet\fP
+tcp[tcpflags] & (tcp-rst|tcp-ack) == (tcp-rst|tcp-ack)
.fi
.RE
.LP
@@ -995,26 +1003,23 @@ packets that contain data, not, for example, SYN and FIN packets and
ACK-only packets. (IPv6 is left as an exercise for the reader.)
.RS
.nf
-.B
-tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)
+\fBtcp port\fP 80 \fBand (((ip[\fP2:2\fB] - ((ip[\fP0\fB]&\fP0xf\fB)<<\fP2\fB)) - ((tcp[\fP12\fB]&\fP0xf0\fB)>>\fP2\fB)) != \fP0\fB)
.fi
.RE
.LP
-To select IP packets longer than 576 bytes sent through gateway \fIsnup\fP:
+To select IPv4 packets longer than 576 bytes sent through gateway `snup':
.RS
.nf
-.B
-gateway snup and ip[2:2] > 576
+\fBgateway\fP snup \fBand ip[\fP2:2\fB] >\fP 576
.fi
.RE
.LP
-To select IP broadcast or multicast packets that were
+To select IPv4 broadcast or multicast packets that were
.I not
sent via Ethernet broadcast or multicast:
.RS
.nf
-.B
-ether[0] & 1 = 0 and ip[16] >= 224
+\fBether[\fP0\fB] &\fP 1 \fB=\fP 0 \fBand ip[\fP16\fB] >=\fP 224
.fi
.RE
.LP
@@ -1024,16 +1029,18 @@ ping packets):
.nf
.B
icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply
+.B
+icmp6[icmp6type] != icmp6-echo and icmp6[icmp6type] != icmp6-echoreply
.fi
.RE
.SH "SEE ALSO"
-pcap(3PCAP)
+.BR pcap (3PCAP)
.SH BUGS
To report a security issue please send an e-mail to security@tcpdump.org.
.LP
To report bugs and other problems, contribute patches, request a
feature, provide generic feedback etc please see the file
-.I CONTRIBUTING
+.I CONTRIBUTING.md
in the libpcap source tree root.
.LP
Filter expressions on fields other than those in Token Ring headers will
@@ -1042,10 +1049,11 @@ not correctly handle source-routed Token Ring packets.
Filter expressions on fields other than those in 802.11 headers will not
correctly handle 802.11 data packets with both To DS and From DS set.
.LP
-.BR "ip6 proto"
+`\fBip6 proto\fP'
should chase header chain, but at this moment it does not.
-.BR "ip6 protochain"
-is supplied for this behavior.
+`\fBip6 protochain\fP'
+is supplied for this behavior. For example, to match IPv6 fragments:
+`\fBip6 protochain\fP 44'
.LP
Arithmetic expression against transport layer headers, like \fBtcp[0]\fP,
does not work against IPv6 packets.
diff --git a/pcap-haiku.cpp b/pcap-haiku.cpp
new file mode 100644
index 00000000..701cac38
--- /dev/null
+++ b/pcap-haiku.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ * Axel Dörfler, axeld@pinc-software.de
+ * James Woodcock
+ */
+
+
+#include "config.h"
+#include "pcap-int.h"
+
+#include <OS.h>
+
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/*
+ * Private data for capturing on Haiku sockets.
+ */
+struct pcap_haiku {
+ struct pcap_stat stat;
+ char *device; /* device name */
+};
+
+
+bool
+prepare_request(struct ifreq& request, const char* name)
+{
+ if (strlen(name) >= IF_NAMESIZE)
+ return false;
+
+ strcpy(request.ifr_name, name);
+ return true;
+}
+
+
+static int
+pcap_read_haiku(pcap_t* handle, int maxPackets, 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;
+ do {
+ if (handle->break_loop) {
+ // Clear the break loop flag, and return -2 to indicate our
+ // reasoning
+ handle->break_loop = 0;
+ return -2;
+ }
+
+ socklen_t fromLength = sizeof(from);
+ bytesReceived = recvfrom(handle->fd, buffer, handle->bufsize, MSG_TRUNC,
+ (struct sockaddr*)&from, &fromLength);
+ } while (bytesReceived < 0 && errno == B_INTERRUPTED);
+
+ if (bytesReceived < 0) {
+ if (errno == B_WOULD_BLOCK) {
+ // there is no packet for us
+ return 0;
+ }
+
+ snprintf(handle->errbuf, sizeof(handle->errbuf),
+ "recvfrom: %s", strerror(errno));
+ return -1;
+ }
+
+ int32 captureLength = bytesReceived;
+ if (captureLength > handle->snapshot)
+ captureLength = handle->snapshot;
+
+ // run the packet filter
+ if (handle->fcode.bf_insns) {
+ if (pcap_filter(handle->fcode.bf_insns, buffer, bytesReceived,
+ captureLength) == 0) {
+ // packet got rejected
+ return 0;
+ }
+ }
+
+ // fill in pcap_header
+ pcap_pkthdr header;
+ header.caplen = captureLength;
+ header.len = bytesReceived;
+ header.ts.tv_usec = system_time() % 1000000;
+ header.ts.tv_sec = system_time() / 1000000;
+ // TODO: get timing from packet!!!
+
+ /* Call the user supplied callback function */
+ callback(userdata, &header, buffer);
+ return 1;
+}
+
+
+static int
+pcap_inject_haiku(pcap_t *handle, const void *buffer, int size)
+{
+ // we don't support injecting packets yet
+ // TODO: use the AF_LINK protocol (we need another socket for this) to
+ // inject the packets
+ strlcpy(handle->errbuf, "Sending packets isn't supported yet",
+ PCAP_ERRBUF_SIZE);
+ return -1;
+}
+
+
+static int
+pcap_stats_haiku(pcap_t *handle, struct pcap_stat *stats)
+{
+ struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv;
+ ifreq request;
+ int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
+ if (socket < 0) {
+ return -1;
+ }
+ prepare_request(request, handlep->device);
+ if (ioctl(socket, SIOCGIFSTATS, &request, sizeof(struct ifreq)) < 0) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "pcap_stats: %s",
+ strerror(errno));
+ close(socket);
+ return -1;
+ }
+
+ close(socket);
+ handlep->stat.ps_recv += request.ifr_stats.receive.packets;
+ handlep->stat.ps_drop += request.ifr_stats.receive.dropped;
+ *stats = handlep->stat;
+ return 0;
+}
+
+
+static int
+pcap_activate_haiku(pcap_t *handle)
+{
+ struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv;
+
+ const char* device = handle->opt.device;
+
+ handle->read_op = pcap_read_haiku;
+ handle->setfilter_op = install_bpf_program; /* no kernel filtering */
+ handle->inject_op = pcap_inject_haiku;
+ handle->stats_op = pcap_stats_haiku;
+
+ // use default hooks where possible
+ handle->getnonblock_op = pcap_getnonblock_fd;
+ handle->setnonblock_op = pcap_setnonblock_fd;
+
+ handlep->device = strdup(device);
+ if (handlep->device == NULL) {
+ pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "strdup");
+ return PCAP_ERROR;
+ }
+
+ handle->bufsize = 65536;
+ // TODO: should be determined by interface MTU
+
+ // allocate buffer for monitoring the device
+ handle->buffer = (u_char*)malloc(handle->bufsize);
+ if (handle->buffer == NULL) {
+ pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "buffer malloc");
+ return PCAP_ERROR;
+ }
+
+ handle->offset = 0;
+ handle->linktype = DLT_EN10MB;
+ // TODO: check interface type!
+
+ return 0;
+}
+
+
+// #pragma mark - pcap API
+
+
+extern "C" pcap_t *
+pcap_create_interface(const char *device, char *errorBuffer)
+{
+ // TODO: handle promiscuous mode!
+
+ // we need a socket to talk to the networking stack
+ int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
+ if (socket < 0) {
+ snprintf(errorBuffer, PCAP_ERRBUF_SIZE,
+ "The networking stack doesn't seem to be available.\n");
+ return NULL;
+ }
+
+ struct ifreq request;
+ if (!prepare_request(request, device)) {
+ snprintf(errorBuffer, PCAP_ERRBUF_SIZE,
+ "Interface name \"%s\" is too long.", device);
+ close(socket);
+ return NULL;
+ }
+
+ // check if the interface exist
+ if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) < 0) {
+ snprintf(errorBuffer, PCAP_ERRBUF_SIZE,
+ "Interface \"%s\" does not exist.\n", device);
+ close(socket);
+ return NULL;
+ }
+
+ close(socket);
+ // no longer needed after this point
+
+ // get link level interface for this interface
+
+ socket = ::socket(AF_LINK, SOCK_DGRAM, 0);
+ if (socket < 0) {
+ snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "No link level: %s\n",
+ strerror(errno));
+ return NULL;
+ }
+
+ // start monitoring
+ if (ioctl(socket, SIOCSPACKETCAP, &request, sizeof(struct ifreq)) < 0) {
+ snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "Cannot start monitoring: %s\n",
+ strerror(errno));
+ close(socket);
+ return NULL;
+ }
+
+ pcap_t* handle = PCAP_CREATE_COMMON(errorBuffer, struct pcap_haiku);
+ if (handle == NULL) {
+ snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "malloc: %s", strerror(errno));
+ close(socket);
+ return NULL;
+ }
+
+ handle->selectable_fd = socket;
+ handle->fd = socket;
+
+ handle->activate_op = pcap_activate_haiku;
+
+ return handle;
+}
+
+static int
+can_be_bound(const char *name)
+{
+ return 1;
+}
+
+static int
+get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
+{
+ /* TODO */
+ if (*flags & PCAP_IF_LOOPBACK) {
+ /*
+ * Loopback devices aren't wireless, and "connected"/
+ * "disconnected" doesn't apply to them.
+ */
+ *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE;
+ return (0);
+ }
+ return (0);
+}
+
+extern "C" int
+pcap_platform_finddevs(pcap_if_list_t* _allDevices, char* errorBuffer)
+{
+ return pcap_findalldevs_interfaces(_allDevices, errorBuffer, can_be_bound,
+ get_if_flags);
+}
diff --git a/pcap-int.h b/pcap-int.h
index 5295f8fb..3c18dae8 100644
--- a/pcap-int.h
+++ b/pcap-int.h
@@ -34,6 +34,8 @@
#ifndef pcap_int_h
#define pcap_int_h
+#include <stddef.h>
+
#include <signal.h>
#include <pcap/pcap.h>
@@ -51,6 +53,33 @@
extern "C" {
#endif
+/*
+ * If pcap_new_api is set, we disable pcap_lookupdev(), because:
+ *
+ * it's not thread-safe, and is marked as deprecated, on all
+ * platforms;
+ *
+ * on Windows, it may return UTF-16LE strings, which the program
+ * might then pass to pcap_create() (or to pcap_open_live(), which
+ * then passes them to pcap_create()), requiring pcap_create() to
+ * check for UTF-16LE strings using a hack, and that hack 1)
+ * *cannot* be 100% reliable and 2) runs the risk of going past the
+ * end of the string.
+ *
+ * We keep it around in legacy mode for compatibility.
+ *
+ * We also disable the aforementioned hack in pcap_create().
+ */
+extern int pcap_new_api;
+
+/*
+ * If pcap_utf_8_mode is set, on Windows we treat strings as UTF-8.
+ *
+ * On UN*Xes, we assume all strings are and should be in UTF-8, regardless
+ * of the setting of this flag.
+ */
+extern int pcap_utf_8_mode;
+
#ifdef MSDOS
#include <fcntl.h>
#include <io.h>
@@ -77,7 +106,7 @@ extern "C" {
* 1) big enough for maximum-size Linux loopback packets (65549)
* and some USB packets captured with USBPcap:
*
- * http://desowin.org/usbpcap/
+ * https://desowin.org/usbpcap/
*
* (> 131072, < 262144)
*
@@ -97,6 +126,18 @@ extern "C" {
*/
#define MAXIMUM_SNAPLEN 262144
+/*
+ * Locale-independent macros for testing character types.
+ * These can be passed any integral value, without worrying about, for
+ * example, sign-extending char values, unlike the C macros.
+ */
+#define PCAP_ISDIGIT(c) \
+ ((c) >= '0' && (c) <= '9')
+#define PCAP_ISXDIGIT(c) \
+ (((c) >= '0' && (c) <= '9') || \
+ ((c) >= 'A' && (c) <= 'F') || \
+ ((c) >= 'a' && (c) <= 'f'))
+
struct pcap_opt {
char *device;
int timeout; /* timeout for buffering */
@@ -123,7 +164,7 @@ typedef int (*activate_op_t)(pcap_t *);
typedef int (*can_set_rfmon_op_t)(pcap_t *);
typedef int (*read_op_t)(pcap_t *, int cnt, pcap_handler, u_char *);
typedef int (*next_packet_op_t)(pcap_t *, struct pcap_pkthdr *, u_char **);
-typedef int (*inject_op_t)(pcap_t *, const void *, size_t);
+typedef int (*inject_op_t)(pcap_t *, const void *, int);
typedef void (*save_current_filter_op_t)(pcap_t *, const char *);
typedef int (*setfilter_op_t)(pcap_t *, struct bpf_program *);
typedef int (*setdirection_op_t)(pcap_t *, pcap_direction_t);
@@ -131,6 +172,7 @@ typedef int (*set_datalink_op_t)(pcap_t *, int);
typedef int (*getnonblock_op_t)(pcap_t *);
typedef int (*setnonblock_op_t)(pcap_t *, int);
typedef int (*stats_op_t)(pcap_t *, struct pcap_stat *);
+typedef void (*breakloop_op_t)(pcap_t *);
#ifdef _WIN32
typedef struct pcap_stat *(*stats_ex_op_t)(pcap_t *, int *);
typedef int (*setbuff_op_t)(pcap_t *, int);
@@ -200,8 +242,7 @@ struct pcap {
int snapshot;
int linktype; /* Network linktype */
- int linktype_ext; /* Extended information stored in the linktype field of a file */
- int tzoff; /* timezone offset */
+ int linktype_ext; /* Extended information stored in the linktype field of a file */
int offset; /* offset for proper alignment */
int activated; /* true if the capture is really started */
int oldstyle; /* if we're opening with pcap_open_live() */
@@ -239,7 +280,7 @@ struct pcap {
* pcap_t's with a required timeout, and the code must be
* prepared not to see any packets from the attempt.
*/
- struct timeval *required_select_timeout;
+ const struct timeval *required_select_timeout;
#endif
/*
@@ -248,6 +289,9 @@ struct pcap {
struct bpf_program fcode;
char errbuf[PCAP_ERRBUF_SIZE + 1];
+#ifdef _WIN32
+ char acp_errbuf[PCAP_ERRBUF_SIZE + 1]; /* buffer for local code page error strings */
+#endif
int dlt_count;
u_int *dlt_list;
int tstamp_type_count;
@@ -270,6 +314,7 @@ struct pcap {
getnonblock_op_t getnonblock_op;
setnonblock_op_t setnonblock_op;
stats_op_t stats_op;
+ breakloop_op_t breakloop_op;
/*
* Routine to use as callback for pcap_next()/pcap_next_ex().
@@ -340,7 +385,7 @@ struct pcap_timeval {
*
* Then supply the changes by forking the branch at
*
- * https://github.com/the-tcpdump-group/libpcap/issues
+ * https://github.com/the-tcpdump-group/libpcap/tree/master
*
* and issuing a pull request, so that future versions of libpcap and
* programs that use it (such as tcpdump) will be able to read your new
@@ -350,7 +395,7 @@ struct pcap_timeval {
struct pcap_sf_pkthdr {
struct pcap_timeval ts; /* time stamp */
bpf_u_int32 caplen; /* length of portion present */
- bpf_u_int32 len; /* length this packet (off wire) */
+ bpf_u_int32 len; /* length of this packet (off wire) */
};
/*
@@ -366,7 +411,7 @@ struct pcap_sf_pkthdr {
struct pcap_sf_patched_pkthdr {
struct pcap_timeval ts; /* time stamp */
bpf_u_int32 caplen; /* length of portion present */
- bpf_u_int32 len; /* length this packet (off wire) */
+ bpf_u_int32 len; /* length of this packet (off wire) */
int index;
unsigned short protocol;
unsigned char pkt_type;
@@ -418,12 +463,25 @@ int pcap_setnonblock_fd(pcap_t *p, int);
* by pcap_create routines.
*/
pcap_t *pcap_create_interface(const char *, char *);
-pcap_t *pcap_create_common(char *, size_t);
+
+/*
+ * 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
+ * offset of the private data from the beginning of the structure, in
+ * bytes.
+ */
+#define PCAP_CREATE_COMMON(ebuf, type) \
+ pcap_create_common(ebuf, \
+ sizeof (struct { pcap_t __common; type __private; }), \
+ offsetof (struct { pcap_t __common; type __private; }, __private))
+pcap_t *pcap_create_common(char *, size_t, size_t);
int pcap_do_addexit(pcap_t *);
void pcap_add_to_pcaps_to_close(pcap_t *);
void pcap_remove_from_pcaps_to_close(pcap_t *);
void pcap_cleanup_live_common(pcap_t *);
int pcap_check_activated(pcap_t *);
+void pcap_breakloop_common(pcap_t *);
/*
* Internal interfaces for "pcap_findalldevs()".
@@ -472,7 +530,8 @@ int add_addr_to_if(pcap_if_list_t *, const char *, bpf_u_int32,
#endif
/*
- * Internal interfaces for "pcap_open_offline()".
+ * Internal interfaces for "pcap_open_offline()" and other savefile
+ * I/O routines.
*
* "pcap_open_offline_common()" allocates and fills in a pcap_t, for use
* by pcap_open_offline routines.
@@ -483,10 +542,46 @@ int add_addr_to_if(pcap_if_list_t *, const char *, bpf_u_int32,
* "sf_cleanup()" closes the file handle associated with a pcap_t, if
* appropriate, and frees all data common to all modules for handling
* savefile types.
+ *
+ * "charset_fopen()", in UTF-8 mode on Windows, does an fopen() that
+ * treats the pathname as being in UTF-8, rather than the local
+ * code page, on Windows.
+ */
+
+/*
+ * 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
+ * offset of the private data from the beginning of the structure, in
+ * bytes.
*/
-pcap_t *pcap_open_offline_common(char *ebuf, size_t size);
+#define PCAP_OPEN_OFFLINE_COMMON(ebuf, type) \
+ pcap_open_offline_common(ebuf, \
+ sizeof (struct { pcap_t __common; type __private; }), \
+ offsetof (struct { pcap_t __common; type __private; }, __private))
+pcap_t *pcap_open_offline_common(char *ebuf, size_t total_size,
+ size_t private_data);
bpf_u_int32 pcap_adjust_snapshot(bpf_u_int32 linktype, bpf_u_int32 snaplen);
void sf_cleanup(pcap_t *p);
+#ifdef _WIN32
+FILE *charset_fopen(const char *path, const char *mode);
+#else
+/*
+ * On other OSes, just use Boring Old fopen().
+ */
+#define charset_fopen(path, mode) fopen((path), (mode))
+#endif
+
+/*
+ * Internal interfaces for loading code at run time.
+ */
+#ifdef _WIN32
+#define pcap_code_handle_t HMODULE
+#define pcap_funcptr_t FARPROC
+
+pcap_code_handle_t pcap_load_code(const char *);
+pcap_funcptr_t pcap_find_function(pcap_code_handle_t, const char *);
+#endif
/*
* Internal interfaces for doing user-mode filtering of packets and
@@ -506,10 +601,20 @@ struct bpf_aux_data {
* Filtering routine that takes the auxiliary data as an additional
* argument.
*/
-u_int bpf_filter_with_aux_data(const struct bpf_insn *,
+u_int pcap_filter_with_aux_data(const struct bpf_insn *,
const u_char *, u_int, u_int, const struct bpf_aux_data *);
/*
+ * Filtering routine that doesn't.
+ */
+u_int pcap_filter(const struct bpf_insn *, const u_char *, u_int, u_int);
+
+/*
+ * Routine to validate a BPF program.
+ */
+int pcap_validate_filter(const struct bpf_insn *, int);
+
+/*
* Internal interfaces for both "pcap_create()" and routines that
* open savefiles.
*
@@ -522,6 +627,16 @@ int install_bpf_program(pcap_t *, struct bpf_program *);
int pcap_strcasecmp(const char *, const char *);
+/*
+ * Internal interfaces for pcap_createsrcstr and pcap_parsesrcstr with
+ * the additional bit of information regarding SSL support (rpcap:// vs.
+ * rpcaps://).
+ */
+int pcap_createsrcstr_ex(char *, int, const char *, const char *,
+ const char *, unsigned char, char *);
+int pcap_parsesrcstr_ex(const char *, int *, char *, char *,
+ char *, unsigned char *, char *);
+
#ifdef YYDEBUG
extern int pcap_debug;
#endif
diff --git a/pcap-libdlpi.c b/pcap-libdlpi.c
index a38da8b6..ef3fdac3 100644
--- a/pcap-libdlpi.c
+++ b/pcap-libdlpi.c
@@ -46,7 +46,7 @@
/* Forwards. */
static int dlpromiscon(pcap_t *, bpf_u_int32);
static int pcap_read_libdlpi(pcap_t *, int, pcap_handler, u_char *);
-static int pcap_inject_libdlpi(pcap_t *, const void *, size_t);
+static int pcap_inject_libdlpi(pcap_t *, const void *, int);
static void pcap_libdlpi_err(const char *, const char *, int, char *);
static void pcap_cleanup_libdlpi(pcap_t *);
@@ -427,7 +427,7 @@ process_pkts:
}
static int
-pcap_inject_libdlpi(pcap_t *p, const void *buf, size_t size)
+pcap_inject_libdlpi(pcap_t *p, const void *buf, int size)
{
struct pcap_dlpi *pd = p->priv;
int retv;
@@ -468,7 +468,7 @@ pcap_cleanup_libdlpi(pcap_t *p)
static void
pcap_libdlpi_err(const char *linkname, const char *func, int err, char *errbuf)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "libpcap: %s failed on %s: %s",
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "libpcap: %s failed on %s: %s",
func, linkname, dlpi_strerror(err));
}
@@ -477,7 +477,7 @@ pcap_create_interface(const char *device _U_, char *ebuf)
{
pcap_t *p;
- p = pcap_create_common(ebuf, sizeof (struct pcap_dlpi));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_dlpi);
if (p == NULL)
return (NULL);
diff --git a/pcap-linktype.manmisc.in b/pcap-linktype.manmisc.in
index 777e9dc7..736a91c7 100644
--- a/pcap-linktype.manmisc.in
+++ b/pcap-linktype.manmisc.in
@@ -18,7 +18,7 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP-LINKTYPE @MAN_MISC_INFO@ "7 April 2014"
+.TH PCAP-LINKTYPE @MAN_MISC_INFO@ "6 April 2020"
.SH NAME
pcap-linktype \- link-layer header types supported by libpcap
.SH DESCRIPTION
@@ -38,11 +38,11 @@ so they are sometimes called "DLT_ values".
The values stored in the link-layer header type field in the savefile
header are, in most but not all cases, the same as the values returned
by
-.BR pcap_datalink() .
+.BR pcap_datalink ().
The names for those values begin with
.BR LINKTYPE_ .
.PP
The link-layer header types supported by libpcap are described at
-https://www.tcpdump.org/linktypes.html.
+https://www.tcpdump.org/linktypes.html .
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap-linux.c b/pcap-linux.c
index 70334b3c..74816892 100644
--- a/pcap-linux.c
+++ b/pcap-linux.c
@@ -67,48 +67,6 @@
* SUCH DAMAGE.
*/
-/*
- * Known problems with 2.0[.x] kernels:
- *
- * - The loopback device gives every packet twice; on 2.2[.x] kernels,
- * if we use PF_PACKET, we can filter out the transmitted version
- * of the packet by using data in the "sockaddr_ll" returned by
- * "recvfrom()", but, on 2.0[.x] kernels, we have to use
- * PF_INET/SOCK_PACKET, which means "recvfrom()" supplies a
- * "sockaddr_pkt" which doesn't give us enough information to let
- * us do that.
- *
- * - We have to set the interface's IFF_PROMISC flag ourselves, if
- * we're to run in promiscuous mode, which means we have to turn
- * it off ourselves when we're done; the kernel doesn't keep track
- * of how many sockets are listening promiscuously, which means
- * it won't get turned off automatically when no sockets are
- * listening promiscuously. We catch "pcap_close()" and, for
- * interfaces we put into promiscuous mode, take them out of
- * promiscuous mode - which isn't necessarily the right thing to
- * do, if another socket also requested promiscuous mode between
- * the time when we opened the socket and the time when we close
- * the socket.
- *
- * - MSG_TRUNC isn't supported, so you can't specify that "recvfrom()"
- * return the amount of data that you could have read, rather than
- * the amount that was returned, so we can't just allocate a buffer
- * whose size is the snapshot length and pass the snapshot length
- * as the byte count, and also pass MSG_TRUNC, so that the return
- * value tells us how long the packet was on the wire.
- *
- * This means that, if we want to get the actual size of the packet,
- * so we can return it in the "len" field of the packet header,
- * we have to read the entire packet, not just the part that fits
- * within the snapshot length, and thus waste CPU time copying data
- * from the kernel that our caller won't see.
- *
- * We have to get the actual size, and supply it in "len", because
- * otherwise, the IP dissector in tcpdump, for example, will complain
- * about "truncated-ip", as the packet will appear to have been
- * shorter, on the wire, than the IP header said it should have been.
- */
-
#define _GNU_SOURCE
@@ -119,7 +77,6 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
-#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
@@ -132,112 +89,54 @@
#include <linux/if.h>
#include <linux/if_packet.h>
#include <linux/sockios.h>
+#include <linux/ethtool.h>
#include <netinet/in.h>
#include <linux/if_ether.h>
-#include <net/if_arp.h>
+#include <linux/if_arp.h>
#include <poll.h>
#include <dirent.h>
+#include <sys/eventfd.h>
#include "pcap-int.h"
#include "pcap/sll.h"
#include "pcap/vlan.h"
+#include "diag-control.h"
+
/*
- * If PF_PACKET is defined, we can use {SOCK_RAW,SOCK_DGRAM}/PF_PACKET
- * sockets rather than SOCK_PACKET sockets.
- *
- * To use them, we include <linux/if_packet.h> rather than
- * <netpacket/packet.h>; we do so because
- *
- * some Linux distributions (e.g., Slackware 4.0) have 2.2 or
- * later kernels and libc5, and don't provide a <netpacket/packet.h>
- * file;
- *
- * not all versions of glibc2 have a <netpacket/packet.h> file
- * that defines stuff needed for some of the 2.4-or-later-kernel
- * features, so if the system has a 2.4 or later kernel, we
- * still can't use those features.
- *
- * We're already including a number of other <linux/XXX.h> headers, and
- * this code is Linux-specific (no other OS has PF_PACKET sockets as
- * a raw packet capture mechanism), so it's not as if you gain any
- * useful portability by using <netpacket/packet.h>
- *
- * XXX - should we just include <linux/if_packet.h> even if PF_PACKET
- * isn't defined? It only defines one data structure in 2.0.x, so
- * it shouldn't cause any problems.
+ * We require TPACKET_V2 support.
*/
-#ifdef PF_PACKET
-# include <linux/if_packet.h>
-
- /*
- * On at least some Linux distributions (for example, Red Hat 5.2),
- * there's no <netpacket/packet.h> file, but PF_PACKET is defined if
- * you include <sys/socket.h>, but <linux/if_packet.h> doesn't define
- * any of the PF_PACKET stuff such as "struct sockaddr_ll" or any of
- * the PACKET_xxx stuff.
- *
- * So we check whether PACKET_HOST is defined, and assume that we have
- * PF_PACKET sockets only if it is defined.
- */
-# ifdef PACKET_HOST
-# define HAVE_PF_PACKET_SOCKETS
-# ifdef PACKET_AUXDATA
-# define HAVE_PACKET_AUXDATA
-# endif /* PACKET_AUXDATA */
-# endif /* PACKET_HOST */
-
-
- /* check for memory mapped access avaibility. We assume every needed
- * struct is defined if the macro TPACKET_HDRLEN is defined, because it
- * uses many ring related structs and macros */
-# ifdef PCAP_SUPPORT_PACKET_RING
-# ifdef TPACKET_HDRLEN
-# define HAVE_PACKET_RING
-# ifdef TPACKET3_HDRLEN
-# define HAVE_TPACKET3
-# endif /* TPACKET3_HDRLEN */
-# ifdef TPACKET2_HDRLEN
-# define HAVE_TPACKET2
-# else /* TPACKET2_HDRLEN */
-# define TPACKET_V1 0 /* Old kernel with only V1, so no TPACKET_Vn defined */
-# endif /* TPACKET2_HDRLEN */
-# endif /* TPACKET_HDRLEN */
-# endif /* PCAP_SUPPORT_PACKET_RING */
-#endif /* PF_PACKET */
-
-#ifdef SO_ATTACH_FILTER
+#ifndef TPACKET2_HDRLEN
+#error "Libpcap will only work if TPACKET_V2 is supported; you must build for a 2.6.27 or later kernel"
+#endif
+
+/* check for memory mapped access avaibility. We assume every needed
+ * struct is defined if the macro TPACKET_HDRLEN is defined, because it
+ * uses many ring related structs and macros */
+#ifdef TPACKET3_HDRLEN
+# define HAVE_TPACKET3
+#endif /* TPACKET3_HDRLEN */
+
+#define packet_mmap_acquire(pkt) \
+ (__atomic_load_n(&pkt->tp_status, __ATOMIC_ACQUIRE) != TP_STATUS_KERNEL)
+#define packet_mmap_release(pkt) \
+ (__atomic_store_n(&pkt->tp_status, TP_STATUS_KERNEL, __ATOMIC_RELEASE))
+#define packet_mmap_v3_acquire(pkt) \
+ (__atomic_load_n(&pkt->hdr.bh1.block_status, __ATOMIC_ACQUIRE) != TP_STATUS_KERNEL)
+#define packet_mmap_v3_release(pkt) \
+ (__atomic_store_n(&pkt->hdr.bh1.block_status, TP_STATUS_KERNEL, __ATOMIC_RELEASE))
+
#include <linux/types.h>
#include <linux/filter.h>
-#endif
#ifdef HAVE_LINUX_NET_TSTAMP_H
#include <linux/net_tstamp.h>
#endif
-#ifdef HAVE_LINUX_SOCKIOS_H
-#include <linux/sockios.h>
-#endif
-
-#ifdef HAVE_LINUX_IF_BONDING_H
-#include <linux/if_bonding.h>
-
-/*
- * The ioctl code to use to check whether a device is a bonding device.
- */
-#if defined(SIOCBONDINFOQUERY)
- #define BOND_INFO_QUERY_IOCTL SIOCBONDINFOQUERY
-#elif defined(BOND_INFO_QUERY_OLD)
- #define BOND_INFO_QUERY_IOCTL BOND_INFO_QUERY_OLD
-#endif
-#endif /* HAVE_LINUX_IF_BONDING_H */
-
/*
- * Got Wireless Extensions?
+ * For checking whether a device is a bonding device.
*/
-#ifdef HAVE_LINUX_WIRELESS_H
-#include <linux/wireless.h>
-#endif /* HAVE_LINUX_WIRELESS_H */
+#include <linux/if_bonding.h>
/*
* Got libnl?
@@ -252,39 +151,10 @@
#include <netlink/attr.h>
#endif /* HAVE_LIBNL */
-/*
- * Got ethtool support?
- */
-#ifdef HAVE_LINUX_ETHTOOL_H
-#include <linux/ethtool.h>
-#endif
-
#ifndef HAVE_SOCKLEN_T
typedef int socklen_t;
#endif
-#ifndef MSG_TRUNC
-/*
- * This is being compiled on a system that lacks MSG_TRUNC; define it
- * with the value it has in the 2.2 and later kernels, so that, on
- * those kernels, when we pass it in the flags argument to "recvfrom()"
- * we're passing the right value and thus get the MSG_TRUNC behavior
- * we want. (We don't get that behavior on 2.0[.x] kernels, because
- * they didn't support MSG_TRUNC.)
- */
-#define MSG_TRUNC 0x20
-#endif
-
-#ifndef SOL_PACKET
-/*
- * This is being compiled on a system that lacks SOL_PACKET; define it
- * with the value it has in the 2.2 and later kernels, so that we can
- * set promiscuous mode in the good modern way rather than the old
- * 2.0-kernel crappy way.
- */
-#define SOL_PACKET 263
-#endif
-
#define MAX_LINKHEADER_SIZE 256
/*
@@ -295,11 +165,10 @@ typedef int socklen_t;
#define BIGGER_THAN_ALL_MTUS (64*1024)
/*
- * Private data for capturing on Linux SOCK_PACKET or PF_PACKET sockets.
+ * Private data for capturing on Linux PF_PACKET sockets.
*/
struct pcap_linux {
- u_int packets_read; /* count of packets read with recvfrom() */
- long proc_dropped; /* packets reported dropped by /proc/net/dev */
+ long long sysfs_dropped; /* packets reported dropped by /sys/class/net/{if_name}/statistics/rx_{missed,fifo}_errors */
struct pcap_stat stat;
char *device; /* device name */
@@ -307,10 +176,10 @@ struct pcap_linux {
int blocks_to_filter_in_userland;
int must_do_on_close; /* stuff we must do when we close */
int timeout; /* timeout for buffering */
- int sock_packet; /* using Linux 2.0 compatible interface */
int cooked; /* using SOCK_DGRAM rather than SOCK_RAW */
int ifindex; /* interface index of device we're bound to */
int lo_ifindex; /* interface index of the loopback device */
+ int netdown; /* we got an ENETDOWN and haven't resolved it */
bpf_u_int32 oldmode; /* mode to restore when turning monitor mode off */
char *mondevice; /* mac80211 monitor device we created */
u_char *mmapbuf; /* memory-mapped region pointer */
@@ -324,90 +193,54 @@ struct pcap_linux {
unsigned char *current_packet; /* Current packet within the TPACKET_V3 block. Move to next block if NULL. */
int packets_left; /* Unhandled packets left within the block from previous call to pcap_read_linux_mmap_v3 in case of TPACKET_V3. */
#endif
+ int poll_breakloop_fd; /* fd to an eventfd to break from blocking operations */
};
/*
* Stuff to do when we close.
*/
-#define MUST_CLEAR_PROMISC 0x00000001 /* clear promiscuous mode */
-#define MUST_CLEAR_RFMON 0x00000002 /* clear rfmon (monitor) mode */
-#define MUST_DELETE_MONIF 0x00000004 /* delete monitor-mode interface */
+#define MUST_CLEAR_RFMON 0x00000001 /* clear rfmon (monitor) mode */
+#define MUST_DELETE_MONIF 0x00000002 /* delete monitor-mode interface */
/*
* Prototypes for internal functions and methods.
*/
static int get_if_flags(const char *, bpf_u_int32 *, char *);
-static int is_wifi(int, const char *);
-static void map_arphrd_to_dlt(pcap_t *, int, int, const char *, int);
+static int is_wifi(const char *);
+static void map_arphrd_to_dlt(pcap_t *, int, const char *, int);
static int pcap_activate_linux(pcap_t *);
-static int activate_old(pcap_t *);
-static int activate_new(pcap_t *);
-static int activate_mmap(pcap_t *, int *);
+static int activate_pf_packet(pcap_t *, int);
+static int setup_mmapped(pcap_t *, int *);
static int pcap_can_set_rfmon_linux(pcap_t *);
-static int pcap_read_linux(pcap_t *, int, pcap_handler, u_char *);
-static int pcap_read_packet(pcap_t *, pcap_handler, u_char *);
-static int pcap_inject_linux(pcap_t *, const void *, size_t);
+static int pcap_inject_linux(pcap_t *, const void *, int);
static int pcap_stats_linux(pcap_t *, struct pcap_stat *);
static int pcap_setfilter_linux(pcap_t *, struct bpf_program *);
static int pcap_setdirection_linux(pcap_t *, pcap_direction_t);
static int pcap_set_datalink_linux(pcap_t *, int);
static void pcap_cleanup_linux(pcap_t *);
-/*
- * This is what the header structure looks like in a 64-bit kernel;
- * we use this, rather than struct tpacket_hdr, if we're using
- * TPACKET_V1 in 32-bit code running on a 64-bit kernel.
- */
-struct tpacket_hdr_64 {
- uint64_t tp_status;
- unsigned int tp_len;
- unsigned int tp_snaplen;
- unsigned short tp_mac;
- unsigned short tp_net;
- unsigned int tp_sec;
- unsigned int tp_usec;
-};
-
-/*
- * We use this internally as the tpacket version for TPACKET_V1 in
- * 32-bit code on a 64-bit kernel.
- */
-#define TPACKET_V1_64 99
-
union thdr {
- struct tpacket_hdr *h1;
- struct tpacket_hdr_64 *h1_64;
-#ifdef HAVE_TPACKET2
struct tpacket2_hdr *h2;
-#endif
#ifdef HAVE_TPACKET3
struct tpacket_block_desc *h3;
#endif
- void *raw;
+ u_char *raw;
};
-#ifdef HAVE_PACKET_RING
-#define RING_GET_FRAME_AT(h, offset) (((union thdr **)h->buffer)[(offset)])
+#define RING_GET_FRAME_AT(h, offset) (((u_char **)h->buffer)[(offset)])
#define RING_GET_CURRENT_FRAME(h) RING_GET_FRAME_AT(h, h->offset)
static void destroy_ring(pcap_t *handle);
static int create_ring(pcap_t *handle, int *status);
static int prepare_tpacket_socket(pcap_t *handle);
-static void pcap_cleanup_linux_mmap(pcap_t *);
-static int pcap_read_linux_mmap_v1(pcap_t *, int, pcap_handler , u_char *);
-static int pcap_read_linux_mmap_v1_64(pcap_t *, int, pcap_handler , u_char *);
-#ifdef HAVE_TPACKET2
static int pcap_read_linux_mmap_v2(pcap_t *, int, pcap_handler , u_char *);
-#endif
#ifdef HAVE_TPACKET3
static int pcap_read_linux_mmap_v3(pcap_t *, int, pcap_handler , u_char *);
#endif
-static int pcap_setfilter_linux_mmap(pcap_t *, struct bpf_program *);
-static int pcap_setnonblock_mmap(pcap_t *p, int nonblock);
-static int pcap_getnonblock_mmap(pcap_t *p);
-static void pcap_oneshot_mmap(u_char *user, const struct pcap_pkthdr *h,
+static int pcap_setnonblock_linux(pcap_t *p, int nonblock);
+static int pcap_getnonblock_linux(pcap_t *p);
+static void pcap_oneshot_linux(u_char *user, const struct pcap_pkthdr *h,
const u_char *bytes);
-#endif
/*
* In pre-3.0 kernels, the tp_vlan_tci field is set to whatever the
@@ -456,33 +289,29 @@ static void pcap_oneshot_mmap(u_char *user, const struct pcap_pkthdr *h,
#endif
/*
+ * Required select timeout if we're polling for an "interface disappeared"
+ * indication - 1 millisecond.
+ */
+static const struct timeval netdown_timeout = {
+ 0, 1000 /* 1000 microseconds = 1 millisecond */
+};
+
+/*
* Wrap some ioctl calls
*/
-#ifdef HAVE_PF_PACKET_SOCKETS
static int iface_get_id(int fd, const char *device, char *ebuf);
-#endif /* HAVE_PF_PACKET_SOCKETS */
static int iface_get_mtu(int fd, const char *device, char *ebuf);
static int iface_get_arptype(int fd, const char *device, char *ebuf);
-#ifdef HAVE_PF_PACKET_SOCKETS
static int iface_bind(int fd, int ifindex, char *ebuf, int protocol);
-#ifdef IW_MODE_MONITOR
-static int has_wext(int sock_fd, const char *device, char *ebuf);
-#endif /* IW_MODE_MONITOR */
static int enter_rfmon_mode(pcap_t *handle, int sock_fd,
const char *device);
-#endif /* HAVE_PF_PACKET_SOCKETS */
#if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP)
static int iface_ethtool_get_ts_info(const char *device, pcap_t *handle,
char *ebuf);
#endif
-#ifdef HAVE_PACKET_RING
static int iface_get_offload(pcap_t *handle);
-#endif
-static int iface_bind_old(int fd, const char *device, char *ebuf);
-#ifdef SO_ATTACH_FILTER
-static int fix_program(pcap_t *handle, struct sock_fprog *fcode,
- int is_mapped);
+static int fix_program(pcap_t *handle, struct sock_fprog *fcode);
static int fix_offset(pcap_t *handle, struct bpf_insn *p);
static int set_kernel_filter(pcap_t *handle, struct sock_fprog *fcode);
static int reset_kernel_filter(pcap_t *handle);
@@ -491,14 +320,15 @@ static struct sock_filter total_insn
= BPF_STMT(BPF_RET | BPF_K, 0);
static struct sock_fprog total_fcode
= { 1, &total_insn };
-#endif /* SO_ATTACH_FILTER */
+
+static int iface_dsa_get_proto_info(const char *device, pcap_t *handle);
pcap_t *
pcap_create_interface(const char *device, char *ebuf)
{
pcap_t *handle;
- handle = pcap_create_common(ebuf, sizeof (struct pcap_linux));
+ handle = PCAP_CREATE_COMMON(ebuf, struct pcap_linux);
if (handle == NULL)
return NULL;
@@ -515,7 +345,6 @@ pcap_create_interface(const char *device, char *ebuf)
}
#endif
-#if defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS)
/*
* We claim that we support microsecond and nanosecond time
* stamps.
@@ -524,7 +353,6 @@ pcap_create_interface(const char *device, char *ebuf)
* microsecond or nanosecond time stamps on arbitrary
* adapters?
*/
- handle->tstamp_precision_count = 2;
handle->tstamp_precision_list = malloc(2 * sizeof(u_int));
if (handle->tstamp_precision_list == NULL) {
pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
@@ -534,16 +362,19 @@ pcap_create_interface(const char *device, char *ebuf)
}
handle->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO;
handle->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO;
-#endif /* defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS) */
+ handle->tstamp_precision_count = 2;
+
+ struct pcap_linux *handlep = handle->priv;
+ handlep->poll_breakloop_fd = eventfd(0, EFD_NONBLOCK);
return handle;
}
#ifdef HAVE_LIBNL
/*
- * If interface {if} is a mac80211 driver, the file
- * /sys/class/net/{if}/phy80211 is a symlink to
- * /sys/class/ieee80211/{phydev}, for some {phydev}.
+ * If interface {if_name} is a mac80211 driver, the file
+ * /sys/class/net/{if_name}/phy80211 is a symlink to
+ * /sys/class/ieee80211/{phydev_name}, for some {phydev_name}.
*
* On Fedora 9, with a 2.6.26.3-29 kernel, my Zydas stick, at
* least, has a "wmaster0" device and a "wlan0" device; the
@@ -554,24 +385,30 @@ pcap_create_interface(const char *device, char *ebuf)
* airmon-ng searches through /sys/class/net for devices named
* monN, starting with mon0; as soon as one *doesn't* exist,
* it chooses that as the monitor device name. If the "iw"
- * command exists, it does "iw dev {if} interface add {monif}
- * type monitor", where {monif} is the monitor device. It
- * then (sigh) sleeps .1 second, and then configures the
- * device up. Otherwise, if /sys/class/ieee80211/{phydev}/add_iface
- * is a file, it writes {mondev}, without a newline, to that file,
- * and again (sigh) sleeps .1 second, and then iwconfig's that
- * device into monitor mode and configures it up. Otherwise,
- * you can't do monitor mode.
+ * command exists, it does
+ *
+ * iw dev {if_name} interface add {monif_name} type monitor
+ *
+ * where {monif_name} is the monitor device. It then (sigh) sleeps
+ * .1 second, and then configures the device up. Otherwise, if
+ * /sys/class/ieee80211/{phydev_name}/add_iface is a file, it writes
+ * {mondev_name}, without a newline, to that file, and again (sigh)
+ * sleeps .1 second, and then iwconfig's that device into monitor
+ * mode and configures it up. Otherwise, you can't do monitor mode.
*
* All these devices are "glued" together by having the
- * /sys/class/net/{device}/phy80211 links pointing to the same
+ * /sys/class/net/{if_name}/phy80211 links pointing to the same
* place, so, given a wmaster, wlan, or mon device, you can
* find the other devices by looking for devices with
* the same phy80211 link.
*
* To turn monitor mode off, delete the monitor interface,
- * either with "iw dev {monif} interface del" or by sending
- * {monif}, with no NL, down /sys/class/ieee80211/{phydev}/remove_iface
+ * either with
+ *
+ * iw dev {monif_name} interface del
+ *
+ * or by sending {monif_name}, with no NL, down
+ * /sys/class/ieee80211/{phydev_name}/remove_iface
*
* Note: if you try to create a monitor device named "monN", and
* there's already a "monN" device, it fails, as least with
@@ -599,7 +436,7 @@ get_mac80211_phydev(pcap_t *handle, const char *device, char *phydev_path,
* Generate the path string for the symlink to the physical device.
*/
if (asprintf(&pathstr, "/sys/class/net/%s/phy80211", device) == -1) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: Can't generate path name string for /sys/class/net device",
device);
return PCAP_ERROR;
@@ -624,39 +461,6 @@ get_mac80211_phydev(pcap_t *handle, const char *device, char *phydev_path,
return 1;
}
-#ifdef HAVE_LIBNL_SOCKETS
-#define get_nl_errmsg nl_geterror
-#else
-/* libnl 2.x compatibility code */
-
-#define nl_sock nl_handle
-
-static inline struct nl_handle *
-nl_socket_alloc(void)
-{
- return nl_handle_alloc();
-}
-
-static inline void
-nl_socket_free(struct nl_handle *h)
-{
- nl_handle_destroy(h);
-}
-
-#define get_nl_errmsg strerror
-
-static inline int
-__genl_ctrl_alloc_cache(struct nl_handle *h, struct nl_cache **cache)
-{
- struct nl_cache *tmp = genl_ctrl_alloc_cache(h);
- if (!tmp)
- return -ENOMEM;
- *cache = tmp;
- return 0;
-}
-#define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache
-#endif /* !HAVE_LIBNL_SOCKETS */
-
struct nl80211_state {
struct nl_sock *nl_sock;
struct nl_cache *nl_cache;
@@ -670,28 +474,28 @@ nl80211_init(pcap_t *handle, struct nl80211_state *state, const char *device)
state->nl_sock = nl_socket_alloc();
if (!state->nl_sock) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: failed to allocate netlink handle", device);
return PCAP_ERROR;
}
if (genl_connect(state->nl_sock)) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: failed to connect to generic netlink", device);
goto out_handle_destroy;
}
err = genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache);
if (err < 0) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: failed to allocate generic netlink cache: %s",
- device, get_nl_errmsg(-err));
+ device, nl_geterror(-err));
goto out_handle_destroy;
}
state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211");
if (!state->nl80211) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: nl80211 not found", device);
goto out_cache_free;
}
@@ -732,7 +536,7 @@ add_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state,
msg = nlmsg_alloc();
if (!msg) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: failed to allocate netlink msg", device);
return PCAP_ERROR;
}
@@ -740,16 +544,14 @@ add_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state,
genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
0, NL80211_CMD_NEW_INTERFACE, 0);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+DIAG_OFF_NARROWING
NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, mondevice);
+DIAG_ON_NARROWING
NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
err = nl_send_auto_complete(state->nl_sock, msg);
if (err < 0) {
-#if defined HAVE_LIBNL_NLE
if (err == -NLE_FAILURE) {
-#else
- if (err == -ENFILE) {
-#endif
/*
* Device not available; our caller should just
* keep trying. (libnl 2.x maps ENFILE to
@@ -764,20 +566,16 @@ add_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state,
* Real failure, not just "that device is not
* available.
*/
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: nl_send_auto_complete failed adding %s interface: %s",
- device, mondevice, get_nl_errmsg(-err));
+ device, mondevice, nl_geterror(-err));
nlmsg_free(msg);
return PCAP_ERROR;
}
}
err = nl_wait_for_ack(state->nl_sock);
if (err < 0) {
-#if defined HAVE_LIBNL_NLE
if (err == -NLE_FAILURE) {
-#else
- if (err == -ENFILE) {
-#endif
/*
* Device not available; our caller should just
* keep trying. (libnl 2.x maps ENFILE to
@@ -792,9 +590,9 @@ add_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state,
* Real failure, not just "that device is not
* available.
*/
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: nl_wait_for_ack failed adding %s interface: %s",
- device, mondevice, get_nl_errmsg(-err));
+ device, mondevice, nl_geterror(-err));
nlmsg_free(msg);
return PCAP_ERROR;
}
@@ -821,7 +619,7 @@ add_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state,
return 1;
nla_put_failure:
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: nl_put failed adding %s interface",
device, mondevice);
nlmsg_free(msg);
@@ -842,7 +640,7 @@ del_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state,
msg = nlmsg_alloc();
if (!msg) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: failed to allocate netlink msg", device);
return PCAP_ERROR;
}
@@ -853,17 +651,17 @@ del_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state,
err = nl_send_auto_complete(state->nl_sock, msg);
if (err < 0) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: nl_send_auto_complete failed deleting %s interface: %s",
- device, mondevice, get_nl_errmsg(-err));
+ device, mondevice, nl_geterror(-err));
nlmsg_free(msg);
return PCAP_ERROR;
}
err = nl_wait_for_ack(state->nl_sock);
if (err < 0) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: nl_wait_for_ack failed adding %s interface: %s",
- device, mondevice, get_nl_errmsg(-err));
+ device, mondevice, nl_geterror(-err));
nlmsg_free(msg);
return PCAP_ERROR;
}
@@ -875,177 +673,14 @@ del_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state,
return 1;
nla_put_failure:
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: nl_put failed deleting %s interface",
device, mondevice);
nlmsg_free(msg);
return PCAP_ERROR;
}
-
-static int
-enter_rfmon_mode_mac80211(pcap_t *handle, int sock_fd, const char *device)
-{
- struct pcap_linux *handlep = handle->priv;
- int ret;
- char phydev_path[PATH_MAX+1];
- struct nl80211_state nlstate;
- struct ifreq ifr;
- u_int n;
-
- /*
- * Is this a mac80211 device?
- */
- ret = get_mac80211_phydev(handle, device, phydev_path, PATH_MAX);
- if (ret < 0)
- return ret; /* error */
- if (ret == 0)
- return 0; /* no error, but not mac80211 device */
-
- /*
- * XXX - is this already a monN device?
- * If so, we're done.
- * Is that determined by old Wireless Extensions ioctls?
- */
-
- /*
- * OK, it's apparently a mac80211 device.
- * Try to find an unused monN device for it.
- */
- ret = nl80211_init(handle, &nlstate, device);
- if (ret != 0)
- return ret;
- for (n = 0; n < UINT_MAX; n++) {
- /*
- * Try mon{n}.
- */
- char mondevice[3+10+1]; /* mon{UINT_MAX}\0 */
-
- pcap_snprintf(mondevice, sizeof mondevice, "mon%u", n);
- ret = add_mon_if(handle, sock_fd, &nlstate, device, mondevice);
- if (ret == 1) {
- /*
- * Success. We don't clean up the libnl state
- * yet, as we'll be using it later.
- */
- goto added;
- }
- if (ret < 0) {
- /*
- * Hard failure. Just return ret; handle->errbuf
- * has already been set.
- */
- nl80211_cleanup(&nlstate);
- return ret;
- }
- }
-
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
- "%s: No free monN interfaces", device);
- nl80211_cleanup(&nlstate);
- return PCAP_ERROR;
-
-added:
-
-#if 0
- /*
- * Sleep for .1 seconds.
- */
- delay.tv_sec = 0;
- delay.tv_nsec = 500000000;
- nanosleep(&delay, NULL);
-#endif
-
- /*
- * If we haven't already done so, arrange to have
- * "pcap_close_all()" called when we exit.
- */
- if (!pcap_do_addexit(handle)) {
- /*
- * "atexit()" failed; don't put the interface
- * in rfmon mode, just give up.
- */
- del_mon_if(handle, sock_fd, &nlstate, device,
- handlep->mondevice);
- nl80211_cleanup(&nlstate);
- return PCAP_ERROR;
- }
-
- /*
- * Now configure the monitor interface up.
- */
- memset(&ifr, 0, sizeof(ifr));
- pcap_strlcpy(ifr.ifr_name, handlep->mondevice, sizeof(ifr.ifr_name));
- if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) {
- pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
- errno, "%s: Can't get flags for %s", device,
- handlep->mondevice);
- del_mon_if(handle, sock_fd, &nlstate, device,
- handlep->mondevice);
- nl80211_cleanup(&nlstate);
- return PCAP_ERROR;
- }
- ifr.ifr_flags |= IFF_UP|IFF_RUNNING;
- if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) {
- pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
- errno, "%s: Can't set flags for %s", device,
- handlep->mondevice);
- del_mon_if(handle, sock_fd, &nlstate, device,
- handlep->mondevice);
- nl80211_cleanup(&nlstate);
- return PCAP_ERROR;
- }
-
- /*
- * Success. Clean up the libnl state.
- */
- nl80211_cleanup(&nlstate);
-
- /*
- * Note that we have to delete the monitor device when we close
- * the handle.
- */
- handlep->must_do_on_close |= MUST_DELETE_MONIF;
-
- /*
- * Add this to the list of pcaps to close when we exit.
- */
- pcap_add_to_pcaps_to_close(handle);
-
- return 1;
-}
#endif /* HAVE_LIBNL */
-#ifdef IW_MODE_MONITOR
-/*
- * Bonding devices mishandle unknown ioctls; they fail with ENODEV
- * rather than ENOTSUP, EOPNOTSUPP, or ENOTTY, so Wireless Extensions
- * will fail with ENODEV if we try to do them on a bonding device,
- * making us return a "no such device" indication rather than just
- * saying "no Wireless Extensions".
- *
- * So we check for bonding devices, if we can, before trying those
- * ioctls, by trying a bonding device information query ioctl to see
- * whether it succeeds.
- */
-static int
-is_bonding_device(int fd, const char *device)
-{
-#ifdef BOND_INFO_QUERY_IOCTL
- struct ifreq ifr;
- ifbond ifb;
-
- memset(&ifr, 0, sizeof ifr);
- pcap_strlcpy(ifr.ifr_name, device, sizeof ifr.ifr_name);
- memset(&ifb, 0, sizeof ifb);
- ifr.ifr_data = (caddr_t)&ifb;
- if (ioctl(fd, BOND_INFO_QUERY_IOCTL, &ifr) == 0)
- return 1; /* success, so it's a bonding device */
-#endif /* BOND_INFO_QUERY_IOCTL */
-
- return 0; /* no, it's not a bonding device */
-}
-#endif /* IW_MODE_MONITOR */
-
static int pcap_protocol(pcap_t *handle)
{
int protocol;
@@ -1064,10 +699,6 @@ pcap_can_set_rfmon_linux(pcap_t *handle)
char phydev_path[PATH_MAX+1];
int ret;
#endif
-#ifdef IW_MODE_MONITOR
- int sock_fd;
- struct iwreq ireq;
-#endif
if (strcmp(handle->opt.device, "any") == 0) {
/*
@@ -1083,11 +714,6 @@ pcap_can_set_rfmon_linux(pcap_t *handle)
* we'll just check whether the device appears to be a
* mac80211 device and, if so, assume the device supports
* monitor mode.
- *
- * wmaster devices don't appear to support the Wireless
- * Extensions, but we can create a mon device for a
- * wmaster device, so we don't bother checking whether
- * a mac80211 device supports the Wireless Extensions.
*/
ret = get_mac80211_phydev(handle, handle->opt.device, phydev_path,
PATH_MAX);
@@ -1097,229 +723,69 @@ pcap_can_set_rfmon_linux(pcap_t *handle)
return 1; /* mac80211 device */
#endif
-#ifdef IW_MODE_MONITOR
- /*
- * Bleah. There doesn't appear to be an ioctl to use to ask
- * whether a device supports monitor mode; we'll just do
- * SIOCGIWMODE and, if it succeeds, assume the device supports
- * monitor mode.
- *
- * Open a socket on which to attempt to get the mode.
- * (We assume that if we have Wireless Extensions support
- * we also have PF_PACKET support.)
- */
- sock_fd = socket(PF_PACKET, SOCK_RAW, pcap_protocol(handle));
- if (sock_fd == -1) {
- pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
- errno, "socket");
- return PCAP_ERROR;
- }
-
- if (is_bonding_device(sock_fd, handle->opt.device)) {
- /* It's a bonding device, so don't even try. */
- close(sock_fd);
- return 0;
- }
-
- /*
- * Attempt to get the current mode.
- */
- pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, handle->opt.device,
- sizeof ireq.ifr_ifrn.ifrn_name);
- if (ioctl(sock_fd, SIOCGIWMODE, &ireq) != -1) {
- /*
- * Well, we got the mode; assume we can set it.
- */
- close(sock_fd);
- return 1;
- }
- if (errno == ENODEV) {
- /* The device doesn't even exist. */
- pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
- errno, "SIOCGIWMODE failed");
- close(sock_fd);
- return PCAP_ERROR_NO_SUCH_DEVICE;
- }
- close(sock_fd);
-#endif
return 0;
}
/*
- * Grabs the number of dropped packets by the interface from /proc/net/dev.
+ * Grabs the number of missed packets by the interface from
+ * /sys/class/net/{if_name}/statistics/rx_{missed,fifo}_errors.
*
- * XXX - what about /sys/class/net/{interface name}/rx_*? There are
- * individual devices giving, in ASCII, various rx_ and tx_ statistics.
- *
- * Or can we get them in binary form from netlink?
+ * Compared to /proc/net/dev this avoids counting software drops,
+ * but may be unimplemented and just return 0.
+ * The author has found no straigthforward way to check for support.
*/
-static long int
-linux_if_drops(const char * if_name)
-{
- char buffer[512];
- FILE *file;
- char *bufptr, *nameptr, *colonptr;
- int field_to_convert = 3;
- long int dropped_pkts = 0;
-
- file = fopen("/proc/net/dev", "r");
- if (!file)
- return 0;
-
- while (fgets(buffer, sizeof(buffer), file) != NULL)
- {
- /* search for 'bytes' -- if its in there, then
- that means we need to grab the fourth field. otherwise
- grab the third field. */
- if (field_to_convert != 4 && strstr(buffer, "bytes"))
- {
- field_to_convert = 4;
- continue;
- }
-
- /*
- * See whether this line corresponds to this device.
- * The line should have zero or more leading blanks,
- * followed by a device name, followed by a colon,
- * followed by the statistics.
- */
- bufptr = buffer;
- /* Skip leading blanks */
- while (*bufptr == ' ')
- bufptr++;
- nameptr = bufptr;
- /* Look for the colon */
- colonptr = strchr(nameptr, ':');
- if (colonptr == NULL)
- {
- /*
- * Not found; this could, for example, be the
- * header line.
- */
- continue;
- }
- /* Null-terminate the interface name. */
- *colonptr = '\0';
- if (strcmp(if_name, nameptr) == 0)
- {
- /*
- * OK, this line has the statistics for the interface.
- * Skip past the interface name.
- */
- bufptr = colonptr + 1;
-
- /* grab the nth field from it */
- while (--field_to_convert && *bufptr != '\0')
- {
- /*
- * This isn't the field we want.
- * First, skip any leading blanks before
- * the field.
- */
- while (*bufptr == ' ')
- bufptr++;
+static long long int
+linux_get_stat(const char * if_name, const char * stat) {
+ ssize_t bytes_read;
+ int fd;
+ char buffer[PATH_MAX];
- /*
- * Now skip the non-blank characters of
- * the field.
- */
- while (*bufptr != '\0' && *bufptr != ' ')
- bufptr++;
- }
+ snprintf(buffer, sizeof(buffer), "/sys/class/net/%s/statistics/%s", if_name, stat);
+ fd = open(buffer, O_RDONLY);
+ if (fd == -1)
+ return 0;
- if (field_to_convert == 0)
- {
- /*
- * We've found the field we want.
- * Skip any leading blanks before it.
- */
- while (*bufptr == ' ')
- bufptr++;
+ bytes_read = read(fd, buffer, sizeof(buffer) - 1);
+ close(fd);
+ if (bytes_read == -1)
+ return 0;
+ buffer[bytes_read] = '\0';
- /*
- * Now extract the value, if we have one.
- */
- if (*bufptr != '\0')
- dropped_pkts = strtol(bufptr, NULL, 10);
- }
- break;
- }
- }
+ return strtoll(buffer, NULL, 10);
+}
- fclose(file);
- return dropped_pkts;
+static long long int
+linux_if_drops(const char * if_name)
+{
+ long long int missed = linux_get_stat(if_name, "rx_missed_errors");
+ long long int fifo = linux_get_stat(if_name, "rx_fifo_errors");
+ return missed + fifo;
}
/*
- * With older kernels promiscuous mode is kind of interesting because we
- * have to reset the interface before exiting. The problem can't really
- * be solved without some daemon taking care of managing usage counts.
- * If we put the interface into promiscuous mode, we set a flag indicating
- * that we must take it out of that mode when the interface is closed,
- * and, when closing the interface, if that flag is set we take it out
- * of promiscuous mode.
- *
- * Even with newer kernels, we have the same issue with rfmon mode.
+ * Monitor mode is kind of interesting because we have to reset the
+ * interface before exiting. The problem can't really be solved without
+ * some daemon taking care of managing usage counts. If we put the
+ * interface into monitor mode, we set a flag indicating that we must
+ * take it out of that mode when the interface is closed, and, when
+ * closing the interface, if that flag is set we take it out of monitor
+ * mode.
*/
static void pcap_cleanup_linux( pcap_t *handle )
{
struct pcap_linux *handlep = handle->priv;
- struct ifreq ifr;
#ifdef HAVE_LIBNL
struct nl80211_state nlstate;
int ret;
#endif /* HAVE_LIBNL */
-#ifdef IW_MODE_MONITOR
- int oldflags;
- struct iwreq ireq;
-#endif /* IW_MODE_MONITOR */
if (handlep->must_do_on_close != 0) {
/*
* There's something we have to do when closing this
* pcap_t.
*/
- if (handlep->must_do_on_close & MUST_CLEAR_PROMISC) {
- /*
- * We put the interface into promiscuous mode;
- * take it out of promiscuous mode.
- *
- * XXX - if somebody else wants it in promiscuous
- * mode, this code cannot know that, so it'll take
- * it out of promiscuous mode. That's not fixable
- * in 2.0[.x] kernels.
- */
- memset(&ifr, 0, sizeof(ifr));
- pcap_strlcpy(ifr.ifr_name, handlep->device,
- sizeof(ifr.ifr_name));
- if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) {
- fprintf(stderr,
- "Can't restore interface %s flags (SIOCGIFFLAGS failed: %s).\n"
- "Please adjust manually.\n"
- "Hint: This can't happen with Linux >= 2.2.0.\n",
- handlep->device, strerror(errno));
- } else {
- if (ifr.ifr_flags & IFF_PROMISC) {
- /*
- * Promiscuous mode is currently on;
- * turn it off.
- */
- ifr.ifr_flags &= ~IFF_PROMISC;
- if (ioctl(handle->fd, SIOCSIFFLAGS,
- &ifr) == -1) {
- fprintf(stderr,
- "Can't restore interface %s flags (SIOCSIFFLAGS failed: %s).\n"
- "Please adjust manually.\n"
- "Hint: This can't happen with Linux >= 2.2.0.\n",
- handlep->device,
- strerror(errno));
- }
- }
- }
- }
-
#ifdef HAVE_LIBNL
if (handlep->must_do_on_close & MUST_DELETE_MONIF) {
ret = nl80211_init(handle, &nlstate, handlep->device);
@@ -1337,68 +803,6 @@ static void pcap_cleanup_linux( pcap_t *handle )
}
#endif /* HAVE_LIBNL */
-#ifdef IW_MODE_MONITOR
- if (handlep->must_do_on_close & MUST_CLEAR_RFMON) {
- /*
- * We put the interface into rfmon mode;
- * take it out of rfmon mode.
- *
- * XXX - if somebody else wants it in rfmon
- * mode, this code cannot know that, so it'll take
- * it out of rfmon mode.
- */
-
- /*
- * First, take the interface down if it's up;
- * otherwise, we might get EBUSY.
- * If we get errors, just drive on and print
- * a warning if we can't restore the mode.
- */
- oldflags = 0;
- memset(&ifr, 0, sizeof(ifr));
- pcap_strlcpy(ifr.ifr_name, handlep->device,
- sizeof(ifr.ifr_name));
- if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) != -1) {
- if (ifr.ifr_flags & IFF_UP) {
- oldflags = ifr.ifr_flags;
- ifr.ifr_flags &= ~IFF_UP;
- if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1)
- oldflags = 0; /* didn't set, don't restore */
- }
- }
-
- /*
- * Now restore the mode.
- */
- pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, handlep->device,
- sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.u.mode = handlep->oldmode;
- if (ioctl(handle->fd, SIOCSIWMODE, &ireq) == -1) {
- /*
- * Scientist, you've failed.
- */
- fprintf(stderr,
- "Can't restore interface %s wireless mode (SIOCSIWMODE failed: %s).\n"
- "Please adjust manually.\n",
- handlep->device, strerror(errno));
- }
-
- /*
- * Now bring the interface back up if we brought
- * it down.
- */
- if (oldflags != 0) {
- ifr.ifr_flags = oldflags;
- if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1) {
- fprintf(stderr,
- "Can't bring interface %s back up (SIOCSIFFLAGS failed: %s).\n"
- "Please adjust manually.\n",
- handlep->device, strerror(errno));
- }
- }
- }
-#endif /* IW_MODE_MONITOR */
-
/*
* Take this pcap out of the list of pcaps for which we
* have to take the interface out of some mode.
@@ -1406,6 +810,19 @@ static void pcap_cleanup_linux( pcap_t *handle )
pcap_remove_from_pcaps_to_close(handle);
}
+ if (handle->fd != -1) {
+ /*
+ * Destroy the ring buffer (assuming we've set it up),
+ * and unmap it if it's mapped.
+ */
+ destroy_ring(handle);
+ }
+
+ if (handlep->oneshot_buffer != NULL) {
+ free(handlep->oneshot_buffer);
+ handlep->oneshot_buffer = NULL;
+ }
+
if (handlep->mondevice != NULL) {
free(handlep->mondevice);
handlep->mondevice = NULL;
@@ -1414,9 +831,49 @@ static void pcap_cleanup_linux( pcap_t *handle )
free(handlep->device);
handlep->device = NULL;
}
+
+ close(handlep->poll_breakloop_fd);
pcap_cleanup_live_common(handle);
}
+#ifdef HAVE_TPACKET3
+/*
+ * Some versions of TPACKET_V3 have annoying bugs/misfeatures
+ * around which we have to work. Determine if we have those
+ * problems or not.
+ * 3.19 is the first release with a fixed version of
+ * TPACKET_V3. We treat anything before that as
+ * not having a fixed version; that may really mean
+ * it has *no* version.
+ */
+static int has_broken_tpacket_v3(void)
+{
+ struct utsname utsname;
+ const char *release;
+ long major, minor;
+ int matches, verlen;
+
+ /* No version information, assume broken. */
+ if (uname(&utsname) == -1)
+ return 1;
+ release = utsname.release;
+
+ /* A malformed version, ditto. */
+ matches = sscanf(release, "%ld.%ld%n", &major, &minor, &verlen);
+ if (matches != 2)
+ return 1;
+ if (release[verlen] != '.' && release[verlen] != '\0')
+ return 1;
+
+ /* OK, a fixed version. */
+ if (major > 3 || (major == 3 && minor >= 19))
+ return 0;
+
+ /* Too old :( */
+ return 1;
+}
+#endif
+
/*
* Set the timeout to be used in poll() with memory-mapped packet capture.
*/
@@ -1424,45 +881,7 @@ static void
set_poll_timeout(struct pcap_linux *handlep)
{
#ifdef HAVE_TPACKET3
- struct utsname utsname;
- char *version_component, *endp;
- int major, minor;
- int broken_tpacket_v3 = 1;
-
- /*
- * Some versions of TPACKET_V3 have annoying bugs/misfeatures
- * around which we have to work. Determine if we have those
- * problems or not.
- */
- if (uname(&utsname) == 0) {
- /*
- * 3.19 is the first release with a fixed version of
- * TPACKET_V3. We treat anything before that as
- * not haveing a fixed version; that may really mean
- * it has *no* version.
- */
- version_component = utsname.release;
- major = strtol(version_component, &endp, 10);
- if (endp != version_component && *endp == '.') {
- /*
- * OK, that was a valid major version.
- * Get the minor version.
- */
- version_component = endp + 1;
- minor = strtol(version_component, &endp, 10);
- if (endp != version_component &&
- (*endp == '.' || *endp == '\0')) {
- /*
- * OK, that was a valid minor version.
- * Is this 3.19 or newer?
- */
- if (major >= 4 || (major == 3 && minor >= 19)) {
- /* Yes. TPACKET_V3 works correctly. */
- broken_tpacket_v3 = 0;
- }
- }
- }
- }
+ int broken_tpacket_v3 = has_broken_tpacket_v3();
#endif
if (handlep->timeout == 0) {
#ifdef HAVE_TPACKET3
@@ -1505,11 +924,21 @@ set_poll_timeout(struct pcap_linux *handlep)
}
}
+static void pcap_breakloop_linux(pcap_t *handle)
+{
+ pcap_breakloop_common(handle);
+ struct pcap_linux *handlep = handle->priv;
+
+ uint64_t value = 1;
+ /* XXX - what if this fails? */
+ (void)write(handlep->poll_breakloop_fd, &value, sizeof(value));
+}
+
/*
* Get a handle for a live capture from the given device. You can
* pass NULL as device to get all packages (without link level
* information of course). If you pass 1 as promisc the interface
- * will be set to promiscous mode (XXX: I think this usage should
+ * will be set to promiscuous mode (XXX: I think this usage should
* be deprecated and functions be added to select that later allow
* modification of that values -- Torsten).
*/
@@ -1518,8 +947,10 @@ pcap_activate_linux(pcap_t *handle)
{
struct pcap_linux *handlep = handle->priv;
const char *device;
+ int is_any_device;
struct ifreq ifr;
int status = 0;
+ int status2 = 0;
int ret;
device = handle->opt.device;
@@ -1551,151 +982,109 @@ pcap_activate_linux(pcap_t *handle)
if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN)
handle->snapshot = MAXIMUM_SNAPLEN;
- handle->inject_op = pcap_inject_linux;
- handle->setfilter_op = pcap_setfilter_linux;
- handle->setdirection_op = pcap_setdirection_linux;
- handle->set_datalink_op = pcap_set_datalink_linux;
- handle->getnonblock_op = pcap_getnonblock_fd;
- handle->setnonblock_op = pcap_setnonblock_fd;
- handle->cleanup_op = pcap_cleanup_linux;
- handle->read_op = pcap_read_linux;
- handle->stats_op = pcap_stats_linux;
+ handlep->device = strdup(device);
+ if (handlep->device == NULL) {
+ pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "strdup");
+ status = PCAP_ERROR;
+ goto fail;
+ }
/*
* The "any" device is a special device which causes us not
* to bind to a particular device and thus to look at all
* devices.
*/
- if (strcmp(device, "any") == 0) {
+ is_any_device = (strcmp(device, "any") == 0);
+ if (is_any_device) {
if (handle->opt.promisc) {
handle->opt.promisc = 0;
/* Just a warning. */
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Promiscuous mode not supported on the \"any\" device");
status = PCAP_WARNING_PROMISC_NOTSUP;
}
}
- handlep->device = strdup(device);
- if (handlep->device == NULL) {
- pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
- errno, "strdup");
- status = PCAP_ERROR;
- goto fail;
- }
-
/* copy timeout value */
handlep->timeout = handle->opt.timeout;
/*
* If we're in promiscuous mode, then we probably want
* to see when the interface drops packets too, so get an
- * initial count from /proc/net/dev
+ * initial count from
+ * /sys/class/net/{if_name}/statistics/rx_{missed,fifo}_errors
*/
if (handle->opt.promisc)
- handlep->proc_dropped = linux_if_drops(handlep->device);
+ handlep->sysfs_dropped = linux_if_drops(handlep->device);
/*
- * Current Linux kernels use the protocol family PF_PACKET to
- * allow direct access to all packets on the network while
- * older kernels had a special socket type SOCK_PACKET to
- * implement this feature.
- * While this old implementation is kind of obsolete we need
- * to be compatible with older kernels for a while so we are
- * trying both methods with the newer method preferred.
+ * If the "any" device is specified, try to open a SOCK_DGRAM.
+ * Otherwise, open a SOCK_RAW.
*/
- ret = activate_new(handle);
+ ret = activate_pf_packet(handle, is_any_device);
if (ret < 0) {
/*
- * Fatal error with the new way; just fail.
- * ret has the error return; if it's PCAP_ERROR,
- * handle->errbuf has been set appropriately.
+ * Fatal error; the return value is the error code,
+ * and handle->errbuf has been set to an appropriate
+ * error message.
*/
status = ret;
goto fail;
}
- if (ret == 1) {
+ /*
+ * Success.
+ * Try to set up memory-mapped access.
+ */
+ ret = setup_mmapped(handle, &status);
+ if (ret == -1) {
/*
- * Success.
- * Try to use memory-mapped access.
+ * We failed to set up to use it, or the
+ * kernel supports it, but we failed to
+ * enable it. status has been set to the
+ * error status to return and, if it's
+ * PCAP_ERROR, handle->errbuf contains
+ * the error message.
*/
- switch (activate_mmap(handle, &status)) {
-
- case 1:
- /*
- * We succeeded. status has been
- * set to the status to return,
- * which might be 0, or might be
- * a PCAP_WARNING_ value.
- *
- * Set the timeout to use in poll() before
- * returning.
- */
- set_poll_timeout(handlep);
- return status;
-
- case 0:
- /*
- * Kernel doesn't support it - just continue
- * with non-memory-mapped access.
- */
- break;
-
- case -1:
- /*
- * We failed to set up to use it, or the kernel
- * supports it, but we failed to enable it.
- * status has been set to the error status to
- * return and, if it's PCAP_ERROR, handle->errbuf
- * contains the error message.
- */
- goto fail;
- }
- }
- else if (ret == 0) {
- /* Non-fatal error; try old way */
- if ((ret = activate_old(handle)) != 1) {
- /*
- * Both methods to open the packet socket failed.
- * Tidy up and report our failure (handle->errbuf
- * is expected to be set by the functions above).
- */
- status = ret;
- goto fail;
- }
+ goto fail;
}
/*
- * We set up the socket, but not with memory-mapped access.
+ * We succeeded. status has been set to the status to return,
+ * which might be 0, or might be a PCAP_WARNING_ value.
*/
- if (handle->opt.buffer_size != 0) {
- /*
- * Set the socket buffer size to the specified value.
- */
- if (setsockopt(handle->fd, SOL_SOCKET, SO_RCVBUF,
- &handle->opt.buffer_size,
- sizeof(handle->opt.buffer_size)) == -1) {
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno, "SO_RCVBUF");
- status = PCAP_ERROR;
- goto fail;
- }
+ /*
+ * Now that we have activated the mmap ring, we can
+ * set the correct protocol.
+ */
+ if ((status2 = iface_bind(handle->fd, handlep->ifindex,
+ handle->errbuf, pcap_protocol(handle))) != 0) {
+ status = status2;
+ goto fail;
}
- /* Allocate the buffer */
+ handle->inject_op = pcap_inject_linux;
+ handle->setfilter_op = pcap_setfilter_linux;
+ handle->setdirection_op = pcap_setdirection_linux;
+ handle->set_datalink_op = pcap_set_datalink_linux;
+ handle->setnonblock_op = pcap_setnonblock_linux;
+ handle->getnonblock_op = pcap_getnonblock_linux;
+ handle->cleanup_op = pcap_cleanup_linux;
+ handle->stats_op = pcap_stats_linux;
+ handle->breakloop_op = pcap_breakloop_linux;
- handle->buffer = malloc(handle->bufsize + handle->offset);
- if (!handle->buffer) {
- pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
- errno, "malloc");
- status = PCAP_ERROR;
- goto fail;
- }
+ switch (handlep->tp_version) {
- /*
- * "handle->fd" is a socket, so "select()" and "poll()"
- * should work on it.
- */
+ case TPACKET_V2:
+ handle->read_op = pcap_read_linux_mmap_v2;
+ break;
+#ifdef HAVE_TPACKET3
+ case TPACKET_V3:
+ handle->read_op = pcap_read_linux_mmap_v3;
+ break;
+#endif
+ }
+ handle->oneshot_callback = pcap_oneshot_linux;
handle->selectable_fd = handle->fd;
return status;
@@ -1705,21 +1094,6 @@ fail:
return status;
}
-/*
- * Read at most max_packets from the capture stream and call the callback
- * for each of them. Returns the number of packets handled or -1 if an
- * error occured.
- */
-static int
-pcap_read_linux(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *user)
-{
- /*
- * Currently, on Linux only one packet is delivered per read,
- * so we don't loop.
- */
- return pcap_read_packet(handle, callback, user);
-}
-
static int
pcap_set_datalink_linux(pcap_t *handle, int dlt)
{
@@ -1780,434 +1154,83 @@ linux_check_direction(const pcap_t *handle, const struct sockaddr_ll *sll)
}
/*
- * Read a packet from the socket calling the handler provided by
- * the user. Returns the number of packets received or -1 if an
- * error occured.
+ * Check whether the device to which the pcap_t is bound still exists.
+ * We do so by asking what address the socket is bound to, and checking
+ * whether the ifindex in the address is -1, meaning "that device is gone",
+ * or some other value, meaning "that device still exists".
*/
static int
-pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
+device_still_exists(pcap_t *handle)
{
- struct pcap_linux *handlep = handle->priv;
- u_char *bp;
- int offset;
-#ifdef HAVE_PF_PACKET_SOCKETS
- struct sockaddr_ll from;
-#else
- struct sockaddr from;
-#endif
-#if defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI)
- struct iovec iov;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- union {
- struct cmsghdr cmsg;
- char buf[CMSG_SPACE(sizeof(struct tpacket_auxdata))];
- } cmsg_buf;
-#else /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI) */
- socklen_t fromlen;
-#endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI) */
- int packet_len, caplen;
- struct pcap_pkthdr pcap_header;
-
- struct bpf_aux_data aux_data;
-#ifdef HAVE_PF_PACKET_SOCKETS
- /*
- * If this is a cooked device, leave extra room for a
- * fake packet header.
- */
- if (handlep->cooked) {
- if (handle->linktype == DLT_LINUX_SLL2)
- offset = SLL2_HDR_LEN;
- else
- offset = SLL_HDR_LEN;
- } else
- offset = 0;
-#else
+ struct pcap_linux *handlep = handle->priv;
+ struct sockaddr_ll addr;
+ socklen_t addr_len;
+
/*
- * This system doesn't have PF_PACKET sockets, so it doesn't
- * support cooked devices.
+ * If handlep->ifindex is -1, the socket isn't bound, meaning
+ * we're capturing on the "any" device; that device never
+ * disappears. (It should also never be configured down, so
+ * we shouldn't even get here, but let's make sure.)
*/
- offset = 0;
-#endif
+ if (handlep->ifindex == -1)
+ return (1); /* it's still here */
/*
- * Receive a single packet from the kernel.
- * We ignore EINTR, as that might just be due to a signal
- * being delivered - if the signal should interrupt the
- * loop, the signal handler should call pcap_breakloop()
- * to set handle->break_loop (we ignore it on other
- * platforms as well).
- * We also ignore ENETDOWN, so that we can continue to
- * capture traffic if the interface goes down and comes
- * back up again; comments in the kernel indicate that
- * we'll just block waiting for packets if we try to
- * receive from a socket that delivered ENETDOWN, and,
- * if we're using a memory-mapped buffer, we won't even
- * get notified of "network down" events.
+ * OK, now try to get the address for the socket.
*/
- bp = (u_char *)handle->buffer + handle->offset;
-
-#if defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI)
- msg.msg_name = &from;
- msg.msg_namelen = sizeof(from);
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = &cmsg_buf;
- msg.msg_controllen = sizeof(cmsg_buf);
- msg.msg_flags = 0;
-
- iov.iov_len = handle->bufsize - offset;
- iov.iov_base = bp + offset;
-#endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI) */
-
- do {
+ addr_len = sizeof (addr);
+ if (getsockname(handle->fd, (struct sockaddr *) &addr, &addr_len) == -1) {
/*
- * Has "pcap_breakloop()" been called?
+ * Error - report an error and return -1.
*/
- if (handle->break_loop) {
- /*
- * Yes - clear the flag that indicates that it has,
- * and return PCAP_ERROR_BREAK as an indication that
- * we were told to break out of the loop.
- */
- handle->break_loop = 0;
- return PCAP_ERROR_BREAK;
- }
-
-#if defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI)
- packet_len = recvmsg(handle->fd, &msg, MSG_TRUNC);
-#else /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI) */
- fromlen = sizeof(from);
- packet_len = recvfrom(
- handle->fd, bp + offset,
- handle->bufsize - offset, MSG_TRUNC,
- (struct sockaddr *) &from, &fromlen);
-#endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI) */
- } while (packet_len == -1 && errno == EINTR);
-
- /* Check if an error occured */
-
- if (packet_len == -1) {
- switch (errno) {
-
- case EAGAIN:
- return 0; /* no packet there */
-
- case ENETDOWN:
- /*
- * The device on which we're capturing went away.
- *
- * XXX - we should really return
- * PCAP_ERROR_IFACE_NOT_UP, but pcap_dispatch()
- * etc. aren't defined to return that.
- */
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
- "The interface went down");
- return PCAP_ERROR;
-
- default:
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno, "recvfrom");
- return PCAP_ERROR;
- }
+ pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "getsockname failed");
+ return (-1);
}
-
-#ifdef HAVE_PF_PACKET_SOCKETS
- if (!handlep->sock_packet) {
- /*
- * Unfortunately, there is a window between socket() and
- * bind() where the kernel may queue packets from any
- * interface. If we're bound to a particular interface,
- * discard packets not from that interface.
- *
- * (If socket filters are supported, we could do the
- * same thing we do when changing the filter; however,
- * that won't handle packet sockets without socket
- * filter support, and it's a bit more complicated.
- * It would save some instructions per packet, however.)
- */
- if (handlep->ifindex != -1 &&
- from.sll_ifindex != handlep->ifindex)
- return 0;
-
+ if (addr.sll_ifindex == -1) {
/*
- * Do checks based on packet direction.
- * We can only do this if we're using PF_PACKET; the
- * address returned for SOCK_PACKET is a "sockaddr_pkt"
- * which lacks the relevant packet type information.
+ * This means the device went away.
*/
- if (!linux_check_direction(handle, &from))
- return 0;
+ return (0);
}
-#endif
-#ifdef HAVE_PF_PACKET_SOCKETS
/*
- * If this is a cooked device, fill in the fake packet header.
+ * The device presumably just went down.
*/
- if (handlep->cooked) {
- /*
- * Add the length of the fake header to the length
- * of packet data we read.
- */
- if (handle->linktype == DLT_LINUX_SLL2) {
- struct sll2_header *hdrp;
-
- packet_len += SLL2_HDR_LEN;
-
- hdrp = (struct sll2_header *)bp;
- hdrp->sll2_protocol = from.sll_protocol;
- hdrp->sll2_reserved_mbz = 0;
- hdrp->sll2_if_index = htonl(from.sll_ifindex);
- hdrp->sll2_hatype = htons(from.sll_hatype);
- hdrp->sll2_pkttype = from.sll_pkttype;
- hdrp->sll2_halen = from.sll_halen;
- memcpy(hdrp->sll2_addr, from.sll_addr,
- (from.sll_halen > SLL_ADDRLEN) ?
- SLL_ADDRLEN :
- from.sll_halen);
- } else {
- struct sll_header *hdrp;
-
- packet_len += SLL_HDR_LEN;
-
- hdrp = (struct sll_header *)bp;
- hdrp->sll_pkttype = htons(from.sll_pkttype);
- hdrp->sll_hatype = htons(from.sll_hatype);
- hdrp->sll_halen = htons(from.sll_halen);
- memcpy(hdrp->sll_addr, from.sll_addr,
- (from.sll_halen > SLL_ADDRLEN) ?
- SLL_ADDRLEN :
- from.sll_halen);
- hdrp->sll_protocol = from.sll_protocol;
- }
- }
-
- /*
- * Start out with no VLAN information.
- */
- aux_data.vlan_tag_present = 0;
- aux_data.vlan_tag = 0;
-#if defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI)
- if (handlep->vlan_offset != -1) {
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- struct tpacket_auxdata *aux;
- unsigned int len;
- struct vlan_tag *tag;
-
- if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct tpacket_auxdata)) ||
- cmsg->cmsg_level != SOL_PACKET ||
- cmsg->cmsg_type != PACKET_AUXDATA) {
- /*
- * This isn't a PACKET_AUXDATA auxiliary
- * data item.
- */
- continue;
- }
-
- aux = (struct tpacket_auxdata *)CMSG_DATA(cmsg);
- if (!VLAN_VALID(aux, aux)) {
- /*
- * There is no VLAN information in the
- * auxiliary data.
- */
- continue;
- }
-
- len = (u_int)packet_len > iov.iov_len ? iov.iov_len : (u_int)packet_len;
- if (len < (u_int)handlep->vlan_offset)
- break;
-
- /*
- * Move everything in the header, except the
- * type field, down VLAN_TAG_LEN bytes, to
- * allow us to insert the VLAN tag between
- * that stuff and the type field.
- */
- bp -= VLAN_TAG_LEN;
- memmove(bp, bp + VLAN_TAG_LEN, handlep->vlan_offset);
-
- /*
- * Now insert the tag.
- */
- tag = (struct vlan_tag *)(bp + handlep->vlan_offset);
- tag->vlan_tpid = htons(VLAN_TPID(aux, aux));
- tag->vlan_tci = htons(aux->tp_vlan_tci);
-
- /*
- * Save a flag indicating that we have a VLAN tag,
- * and the VLAN TCI, to bpf_aux_data struct for
- * use by the BPF filter if we're doing the
- * filtering in userland.
- */
- aux_data.vlan_tag_present = 1;
- aux_data.vlan_tag = htons(aux->tp_vlan_tci) & 0x0fff;
-
- /*
- * Add the tag to the packet lengths.
- */
- packet_len += VLAN_TAG_LEN;
- }
- }
-#endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI) */
-#endif /* HAVE_PF_PACKET_SOCKETS */
-
- /*
- * XXX: According to the kernel source we should get the real
- * packet len if calling recvfrom with MSG_TRUNC set. It does
- * not seem to work here :(, but it is supported by this code
- * anyway.
- * To be honest the code RELIES on that feature so this is really
- * broken with 2.2.x kernels.
- * I spend a day to figure out what's going on and I found out
- * that the following is happening:
- *
- * The packet comes from a random interface and the packet_rcv
- * hook is called with a clone of the packet. That code inserts
- * the packet into the receive queue of the packet socket.
- * If a filter is attached to that socket that filter is run
- * first - and there lies the problem. The default filter always
- * cuts the packet at the snaplen:
- *
- * # tcpdump -d
- * (000) ret #68
- *
- * So the packet filter cuts down the packet. The recvfrom call
- * says "hey, it's only 68 bytes, it fits into the buffer" with
- * the result that we don't get the real packet length. This
- * is valid at least until kernel 2.2.17pre6.
- *
- * We currently handle this by making a copy of the filter
- * program, fixing all "ret" instructions with non-zero
- * operands to have an operand of MAXIMUM_SNAPLEN so that the
- * filter doesn't truncate the packet, and supplying that modified
- * filter to the kernel.
- */
-
- caplen = packet_len;
- if (caplen > handle->snapshot)
- caplen = handle->snapshot;
-
- /* Run the packet filter if not using kernel filter */
- if (handlep->filter_in_userland && handle->fcode.bf_insns) {
- if (bpf_filter_with_aux_data(handle->fcode.bf_insns, bp,
- packet_len, caplen, &aux_data) == 0) {
- /* rejected by filter */
- return 0;
- }
- }
-
- /* Fill in our own header data */
-
- /* get timestamp for this packet */
-#if defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS)
- if (handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) {
- if (ioctl(handle->fd, SIOCGSTAMPNS, &pcap_header.ts) == -1) {
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno, "SIOCGSTAMPNS");
- return PCAP_ERROR;
- }
- } else
-#endif
- {
- if (ioctl(handle->fd, SIOCGSTAMP, &pcap_header.ts) == -1) {
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno, "SIOCGSTAMP");
- return PCAP_ERROR;
- }
- }
-
- pcap_header.caplen = caplen;
- pcap_header.len = packet_len;
-
- /*
- * Count the packet.
- *
- * Arguably, we should count them before we check the filter,
- * as on many other platforms "ps_recv" counts packets
- * handed to the filter rather than packets that passed
- * the filter, but if filtering is done in the kernel, we
- * can't get a count of packets that passed the filter,
- * and that would mean the meaning of "ps_recv" wouldn't
- * be the same on all Linux systems.
- *
- * XXX - it's not the same on all systems in any case;
- * ideally, we should have a "get the statistics" call
- * that supplies more counts and indicates which of them
- * it supplies, so that we supply a count of packets
- * handed to the filter only on platforms where that
- * information is available.
- *
- * We count them here even if we can get the packet count
- * from the kernel, as we can only determine at run time
- * whether we'll be able to get it from the kernel (if
- * HAVE_STRUCT_TPACKET_STATS isn't defined, we can't get it from
- * the kernel, but if it is defined, the library might
- * have been built with a 2.4 or later kernel, but we
- * might be running on a 2.2[.x] kernel without Alexey
- * Kuznetzov's turbopacket patches, and thus the kernel
- * might not be able to supply those statistics). We
- * could, I guess, try, when opening the socket, to get
- * the statistics, and if we can not increment the count
- * here, but it's not clear that always incrementing
- * the count is more expensive than always testing a flag
- * in memory.
- *
- * We keep the count in "handlep->packets_read", and use that
- * for "ps_recv" if we can't get the statistics from the kernel.
- * We do that because, if we *can* get the statistics from
- * the kernel, we use "handlep->stat.ps_recv" and
- * "handlep->stat.ps_drop" as running counts, as reading the
- * statistics from the kernel resets the kernel statistics,
- * and if we directly increment "handlep->stat.ps_recv" here,
- * that means it will count packets *twice* on systems where
- * we can get kernel statistics - once here, and once in
- * pcap_stats_linux().
- */
- handlep->packets_read++;
-
- /* Call the user supplied callback function */
- callback(userdata, &pcap_header, bp);
-
- return 1;
+ return (1);
}
static int
-pcap_inject_linux(pcap_t *handle, const void *buf, size_t size)
+pcap_inject_linux(pcap_t *handle, const void *buf, int size)
{
struct pcap_linux *handlep = handle->priv;
int ret;
-#ifdef HAVE_PF_PACKET_SOCKETS
- if (!handlep->sock_packet) {
- /* PF_PACKET socket */
- if (handlep->ifindex == -1) {
- /*
- * We don't support sending on the "any" device.
- */
- pcap_strlcpy(handle->errbuf,
- "Sending packets isn't supported on the \"any\" device",
- PCAP_ERRBUF_SIZE);
- return (-1);
- }
+ if (handlep->ifindex == -1) {
+ /*
+ * We don't support sending on the "any" device.
+ */
+ pcap_strlcpy(handle->errbuf,
+ "Sending packets isn't supported on the \"any\" device",
+ PCAP_ERRBUF_SIZE);
+ return (-1);
+ }
- if (handlep->cooked) {
- /*
- * We don't support sending on cooked-mode sockets.
- *
- * XXX - how do you send on a bound cooked-mode
- * socket?
- * Is a "sendto()" required there?
- */
- pcap_strlcpy(handle->errbuf,
- "Sending packets isn't supported in cooked mode",
- PCAP_ERRBUF_SIZE);
- return (-1);
- }
+ if (handlep->cooked) {
+ /*
+ * We don't support sending on cooked-mode sockets.
+ *
+ * XXX - how do you send on a bound cooked-mode
+ * socket?
+ * Is a "sendto()" required there?
+ */
+ pcap_strlcpy(handle->errbuf,
+ "Sending packets isn't supported in cooked mode",
+ PCAP_ERRBUF_SIZE);
+ return (-1);
}
-#endif
- ret = send(handle->fd, buf, size, 0);
+ ret = (int)send(handle->fd, buf, size, 0);
if (ret == -1) {
pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
errno, "send");
@@ -2218,27 +1241,20 @@ pcap_inject_linux(pcap_t *handle, const void *buf, size_t size)
/*
* Get the statistics for the given packet capture handle.
- * Reports the number of dropped packets iff the kernel supports
- * the PACKET_STATISTICS "getsockopt()" argument (2.4 and later
- * kernels, and 2.2[.x] kernels with Alexey Kuznetzov's turbopacket
- * patches); otherwise, that information isn't available, and we lie
- * and report 0 as the count of dropped packets.
*/
static int
pcap_stats_linux(pcap_t *handle, struct pcap_stat *stats)
{
struct pcap_linux *handlep = handle->priv;
-#ifdef HAVE_STRUCT_TPACKET_STATS
#ifdef HAVE_TPACKET3
/*
- * For sockets using TPACKET_V1 or TPACKET_V2, the extra
- * stuff at the end of a struct tpacket_stats_v3 will not
- * be filled in, and we don't look at it so this is OK even
- * for those sockets. In addition, the PF_PACKET socket
- * code in the kernel only uses the length parameter to
- * compute how much data to copy out and to indicate how
- * much data was copied out, so it's OK to base it on the
- * size of a struct tpacket_stats.
+ * For sockets using TPACKET_V2, the extra stuff at the end
+ * of a struct tpacket_stats_v3 will not be filled in, and
+ * we don't look at it so this is OK even for those sockets.
+ * In addition, the PF_PACKET socket code in the kernel only
+ * uses the length parameter to compute how much data to
+ * copy out and to indicate how much data was copied out, so
+ * it's OK to base it on the size of a struct tpacket_stats.
*
* XXX - it's probably OK, in fact, to just use a
* struct tpacket_stats for V3 sockets, as we don't
@@ -2249,52 +1265,77 @@ pcap_stats_linux(pcap_t *handle, struct pcap_stat *stats)
struct tpacket_stats kstats;
#endif /* HAVE_TPACKET3 */
socklen_t len = sizeof (struct tpacket_stats);
-#endif /* HAVE_STRUCT_TPACKET_STATS */
- long if_dropped = 0;
+ long long if_dropped = 0;
/*
- * To fill in ps_ifdrop, we parse /proc/net/dev for the number
+ * To fill in ps_ifdrop, we parse
+ * /sys/class/net/{if_name}/statistics/rx_{missed,fifo}_errors
+ * for the numbers
*/
if (handle->opt.promisc)
{
- if_dropped = handlep->proc_dropped;
- handlep->proc_dropped = linux_if_drops(handlep->device);
- handlep->stat.ps_ifdrop += (handlep->proc_dropped - if_dropped);
+ /*
+ * XXX - is there any reason to do this by remembering
+ * the last counts value, subtracting it from the
+ * current counts value, and adding that to stat.ps_ifdrop,
+ * maintaining stat.ps_ifdrop as a count, rather than just
+ * saving the *initial* counts value and setting
+ * stat.ps_ifdrop to the difference between the current
+ * value and the initial value?
+ *
+ * One reason might be to handle the count wrapping
+ * around, on platforms where the count is 32 bits
+ * and where you might get more than 2^32 dropped
+ * packets; is there any other reason?
+ *
+ * (We maintain the count as a long long int so that,
+ * if the kernel maintains the counts as 64-bit even
+ * on 32-bit platforms, we can handle the real count.
+ *
+ * Unfortunately, we can't report 64-bit counts; we
+ * need a better API for reporting statistics, such as
+ * one that reports them in a style similar to the
+ * pcapng Interface Statistics Block, so that 1) the
+ * counts are 64-bit, 2) it's easier to add new statistics
+ * without breaking the ABI, and 3) it's easier to
+ * indicate to a caller that wants one particular
+ * statistic that it's not available by just not supplying
+ * it.)
+ */
+ if_dropped = handlep->sysfs_dropped;
+ handlep->sysfs_dropped = linux_if_drops(handlep->device);
+ handlep->stat.ps_ifdrop += (u_int)(handlep->sysfs_dropped - if_dropped);
}
-#ifdef HAVE_STRUCT_TPACKET_STATS
/*
* Try to get the packet counts from the kernel.
*/
if (getsockopt(handle->fd, SOL_PACKET, PACKET_STATISTICS,
&kstats, &len) > -1) {
/*
- * On systems where the PACKET_STATISTICS "getsockopt()"
- * argument is supported on PF_PACKET sockets:
- *
- * "ps_recv" counts only packets that *passed* the
- * filter, not packets that didn't pass the filter.
- * This includes packets later dropped because we
- * ran out of buffer space.
+ * "ps_recv" counts only packets that *passed* the
+ * filter, not packets that didn't pass the filter.
+ * This includes packets later dropped because we
+ * ran out of buffer space.
*
- * "ps_drop" counts packets dropped because we ran
- * out of buffer space. It doesn't count packets
- * dropped by the interface driver. It counts only
- * packets that passed the filter.
+ * "ps_drop" counts packets dropped because we ran
+ * out of buffer space. It doesn't count packets
+ * dropped by the interface driver. It counts only
+ * packets that passed the filter.
*
- * See above for ps_ifdrop.
+ * See above for ps_ifdrop.
*
- * Both statistics include packets not yet read from
- * the kernel by libpcap, and thus not yet seen by
- * the application.
+ * Both statistics include packets not yet read from
+ * the kernel by libpcap, and thus not yet seen by
+ * the application.
*
- * In "linux/net/packet/af_packet.c", at least in the
- * 2.4.9 kernel, "tp_packets" is incremented for every
- * packet that passes the packet filter *and* is
- * successfully queued on the socket; "tp_drops" is
+ * In "linux/net/packet/af_packet.c", at least in 2.6.27
+ * through 5.6 kernels, "tp_packets" is incremented for
+ * every packet that passes the packet filter *and* is
+ * successfully copied to the ring buffer; "tp_drops" is
* incremented for every packet dropped because there's
- * not enough free space in the socket buffer.
+ * not enough free space in the ring buffer.
*
* When the statistics are returned for a PACKET_STATISTICS
* "getsockopt()" call, "tp_drops" is added to "tp_packets",
@@ -2321,350 +1362,144 @@ pcap_stats_linux(pcap_t *handle, struct pcap_stat *stats)
*stats = handlep->stat;
return 0;
}
- else
- {
- /*
- * If the error was EOPNOTSUPP, fall through, so that
- * if you build the library on a system with
- * "struct tpacket_stats" and run it on a system
- * that doesn't, it works as it does if the library
- * is built on a system without "struct tpacket_stats".
- */
- if (errno != EOPNOTSUPP) {
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno, "pcap_stats");
- return -1;
- }
- }
-#endif
- /*
- * On systems where the PACKET_STATISTICS "getsockopt()" argument
- * is not supported on PF_PACKET sockets:
- *
- * "ps_recv" counts only packets that *passed* the filter,
- * not packets that didn't pass the filter. It does not
- * count packets dropped because we ran out of buffer
- * space.
- *
- * "ps_drop" is not supported.
- *
- * "ps_ifdrop" is supported. It will return the number
- * of drops the interface reports in /proc/net/dev,
- * if that is available.
- *
- * "ps_recv" doesn't include packets not yet read from
- * the kernel by libpcap.
- *
- * We maintain the count of packets processed by libpcap in
- * "handlep->packets_read", for reasons described in the comment
- * at the end of pcap_read_packet(). We have no idea how many
- * packets were dropped by the kernel buffers -- but we know
- * how many the interface dropped, so we can return that.
- */
- stats->ps_recv = handlep->packets_read;
- stats->ps_drop = 0;
- stats->ps_ifdrop = handlep->stat.ps_ifdrop;
- return 0;
+ pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno,
+ "failed to get statistics from socket");
+ return -1;
}
+/*
+ * Description string for the "any" device.
+ */
+static const char any_descr[] = "Pseudo-device that captures on all interfaces";
+
+/*
+ * A PF_PACKET socket can be bound to any network interface.
+ */
static int
-add_linux_if(pcap_if_list_t *devlistp, const char *ifname, int fd, char *errbuf)
+can_be_bound(const char *name _U_)
{
- const char *p;
- char name[512]; /* XXX - pick a size */
- char *q, *saveq;
- struct ifreq ifrflags;
-
- /*
- * Get the interface name.
- */
- p = ifname;
- q = &name[0];
- while (*p != '\0' && isascii(*p) && !isspace(*p)) {
- if (*p == ':') {
- /*
- * This could be the separator between a
- * name and an alias number, or it could be
- * the separator between a name with no
- * alias number and the next field.
- *
- * If there's a colon after digits, it
- * separates the name and the alias number,
- * otherwise it separates the name and the
- * next field.
- */
- saveq = q;
- while (isascii(*p) && isdigit(*p))
- *q++ = *p++;
- if (*p != ':') {
- /*
- * That was the next field,
- * not the alias number.
- */
- q = saveq;
- }
- break;
- } else
- *q++ = *p++;
- }
- *q = '\0';
-
- /*
- * Get the flags for this interface.
- */
- pcap_strlcpy(ifrflags.ifr_name, name, sizeof(ifrflags.ifr_name));
- if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifrflags) < 0) {
- if (errno == ENXIO || errno == ENODEV)
- return (0); /* device doesn't actually exist - ignore it */
- pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
- errno, "SIOCGIFFLAGS: %.*s",
- (int)sizeof(ifrflags.ifr_name),
- ifrflags.ifr_name);
- return (-1);
- }
-
- /*
- * Add an entry for this interface, with no addresses, if it's
- * not already in the list.
- */
- if (find_or_add_if(devlistp, name, ifrflags.ifr_flags,
- get_if_flags, errbuf) == NULL) {
- /*
- * Failure.
- */
- return (-1);
- }
-
- return (0);
+ return (1);
}
/*
- * Get from "/sys/class/net" all interfaces listed there; if they're
- * already in the list of interfaces we have, that won't add another
- * instance, but if they're not, that'll add them.
- *
- * We don't bother getting any addresses for them; it appears you can't
- * use SIOCGIFADDR on Linux to get IPv6 addresses for interfaces, and,
- * although some other types of addresses can be fetched with SIOCGIFADDR,
- * we don't bother with them for now.
- *
- * We also don't fail if we couldn't open "/sys/class/net"; we just leave
- * the list of interfaces as is, and return 0, so that we can try
- * scanning /proc/net/dev.
- *
- * Otherwise, we return 1 if we don't get an error and -1 if we do.
+ * Get a socket to use with various interface ioctls.
*/
static int
-scan_sys_class_net(pcap_if_list_t *devlistp, char *errbuf)
+get_if_ioctl_socket(void)
{
- DIR *sys_class_net_d;
int fd;
- struct dirent *ent;
- char subsystem_path[PATH_MAX+1];
- struct stat statb;
- int ret = 1;
-
- sys_class_net_d = opendir("/sys/class/net");
- if (sys_class_net_d == NULL) {
- /*
- * Don't fail if it doesn't exist at all.
- */
- if (errno == ENOENT)
- return (0);
-
- /*
- * Fail if we got some other error.
- */
- pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
- errno, "Can't open /sys/class/net");
- return (-1);
- }
/*
- * Create a socket from which to fetch interface information.
+ * This is a bit ugly.
+ *
+ * There isn't a socket type that's guaranteed to work.
+ *
+ * AF_NETLINK will work *if* you have Netlink configured into the
+ * kernel (can it be configured out if you have any networking
+ * support at all?) *and* if you're running a sufficiently recent
+ * kernel, but not all the kernels we support are sufficiently
+ * recent - that feature was introduced in Linux 4.6.
+ *
+ * AF_UNIX will work *if* you have UNIX-domain sockets configured
+ * into the kernel and *if* you're not on a system that doesn't
+ * allow them - some SELinux systems don't allow you create them.
+ * Most systems probably have them configured in, but not all systems
+ * have them configured in and allow them to be created.
+ *
+ * AF_INET will work *if* you have IPv4 configured into the kernel,
+ * but, apparently, some systems have network adapters but have
+ * kernels without IPv4 support.
+ *
+ * AF_INET6 will work *if* you have IPv6 configured into the
+ * kernel, but if you don't have AF_INET, you might not have
+ * AF_INET6, either (that is, independently on its own grounds).
+ *
+ * AF_PACKET would work, except that some of these calls should
+ * work even if you *don't* have capture permission (you should be
+ * able to enumerate interfaces and get information about them
+ * without capture permission; you shouldn't get a failure until
+ * you try pcap_activate()). (If you don't allow programs to
+ * get as much information as possible about interfaces if you
+ * don't have permission to capture, you run the risk of users
+ * asking "why isn't it showing XXX" - or, worse, if you don't
+ * show interfaces *at all* if you don't have permission to
+ * 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.)
+ *
+ * So:
+ *
+ * we first try an AF_NETLINK socket, where "try" includes
+ * "try to do a device ioctl on it", as, in the future, once
+ * pre-4.6 kernels are sufficiently rare, that will probably
+ * be the mechanism most likely to work;
+ *
+ * if that fails, we try an AF_UNIX socket, as that's less
+ * likely to be configured out on a networking-capable system
+ * than is IP;
+ *
+ * if that fails, we try an AF_INET6 socket;
+ *
+ * if that fails, we try an AF_INET socket.
*/
- fd = socket(PF_UNIX, SOCK_RAW, 0);
- if (fd < 0) {
- pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
- errno, "socket");
- (void)closedir(sys_class_net_d);
- return (-1);
- }
-
- for (;;) {
- errno = 0;
- ent = readdir(sys_class_net_d);
- if (ent == NULL) {
- /*
- * Error or EOF; if errno != 0, it's an error.
- */
- break;
- }
-
- /*
- * Ignore "." and "..".
- */
- if (strcmp(ent->d_name, ".") == 0 ||
- strcmp(ent->d_name, "..") == 0)
- continue;
-
+ fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (fd != -1) {
/*
- * Ignore plain files; they do not have subdirectories
- * and thus have no attributes.
+ * OK, let's make sure we can do an SIOCGIFNAME
+ * ioctl.
*/
- if (ent->d_type == DT_REG)
- continue;
+ struct ifreq ifr;
- /*
- * Is there an "ifindex" file under that name?
- * (We don't care whether it's a directory or
- * a symlink; older kernels have directories
- * for devices, newer kernels have symlinks to
- * directories.)
- */
- pcap_snprintf(subsystem_path, sizeof subsystem_path,
- "/sys/class/net/%s/ifindex", ent->d_name);
- if (lstat(subsystem_path, &statb) != 0) {
+ memset(&ifr, 0, sizeof(ifr));
+ if (ioctl(fd, SIOCGIFNAME, &ifr) == 0 ||
+ errno != EOPNOTSUPP) {
/*
- * Stat failed. Either there was an error
- * other than ENOENT, and we don't know if
- * this is an interface, or it's ENOENT,
- * and either some part of "/sys/class/net/{if}"
- * disappeared, in which case it probably means
- * the interface disappeared, or there's no
- * "ifindex" file, which means it's not a
- * network interface.
+ * It succeeded, or failed for some reason
+ * other than "netlink sockets don't support
+ * device ioctls". Go with the AF_NETLINK
+ * socket.
*/
- continue;
+ return (fd);
}
/*
- * Attempt to add the interface.
- */
- if (add_linux_if(devlistp, &ent->d_name[0], fd, errbuf) == -1) {
- /* Fail. */
- ret = -1;
- break;
- }
- }
- if (ret != -1) {
- /*
- * Well, we didn't fail for any other reason; did we
- * fail due to an error reading the directory?
+ * OK, that didn't work, so it's as bad as "netlink
+ * sockets aren't available". Close the socket and
+ * drive on.
*/
- if (errno != 0) {
- pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
- errno, "Error reading /sys/class/net");
- ret = -1;
- }
+ close(fd);
}
- (void)close(fd);
- (void)closedir(sys_class_net_d);
- return (ret);
-}
-
-/*
- * Get from "/proc/net/dev" all interfaces listed there; if they're
- * already in the list of interfaces we have, that won't add another
- * instance, but if they're not, that'll add them.
- *
- * See comments from scan_sys_class_net().
- */
-static int
-scan_proc_net_dev(pcap_if_list_t *devlistp, char *errbuf)
-{
- FILE *proc_net_f;
- int fd;
- char linebuf[512];
- int linenum;
- char *p;
- int ret = 0;
-
- proc_net_f = fopen("/proc/net/dev", "r");
- if (proc_net_f == NULL) {
- /*
- * Don't fail if it doesn't exist at all.
- */
- if (errno == ENOENT)
- return (0);
-
+ /*
+ * Now try an AF_UNIX socket.
+ */
+ fd = socket(AF_UNIX, SOCK_RAW, 0);
+ if (fd != -1) {
/*
- * Fail if we got some other error.
+ * OK, we got it!
*/
- pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
- errno, "Can't open /proc/net/dev");
- return (-1);
+ return (fd);
}
/*
- * Create a socket from which to fetch interface information.
+ * Now try an AF_INET6 socket.
*/
- fd = socket(PF_UNIX, SOCK_RAW, 0);
- if (fd < 0) {
- pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
- errno, "socket");
- (void)fclose(proc_net_f);
- return (-1);
+ fd = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (fd != -1) {
+ return (fd);
}
- for (linenum = 1;
- fgets(linebuf, sizeof linebuf, proc_net_f) != NULL; linenum++) {
- /*
- * Skip the first two lines - they're headers.
- */
- if (linenum <= 2)
- continue;
-
- p = &linebuf[0];
-
- /*
- * Skip leading white space.
- */
- while (*p != '\0' && isascii(*p) && isspace(*p))
- p++;
- if (*p == '\0' || *p == '\n')
- continue; /* blank line */
-
- /*
- * Attempt to add the interface.
- */
- if (add_linux_if(devlistp, p, fd, errbuf) == -1) {
- /* Fail. */
- ret = -1;
- break;
- }
- }
- if (ret != -1) {
- /*
- * Well, we didn't fail for any other reason; did we
- * fail due to an error reading the file?
- */
- if (ferror(proc_net_f)) {
- pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
- errno, "Error reading /proc/net/dev");
- ret = -1;
- }
- }
-
- (void)close(fd);
- (void)fclose(proc_net_f);
- return (ret);
-}
-
-/*
- * Description string for the "any" device.
- */
-static const char any_descr[] = "Pseudo-device that captures on all interfaces";
-
-/*
- * A SOCK_PACKET or PF_PACKET socket can be bound to any network interface.
- */
-static int
-can_be_bound(const char *name _U_)
-{
- return (1);
+ /*
+ * Now try an AF_INET socket.
+ *
+ * XXX - if that fails, is there anything else we should try?
+ * AF_CAN, for embedded systems in vehicles, in case they're
+ * built without Internet protocol support? Any other socket
+ * types popular in non-Internet embedded systems?
+ */
+ return (socket(AF_INET, SOCK_DGRAM, 0));
}
/*
@@ -2688,7 +1523,7 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
return 0;
}
- sock = socket(AF_INET, SOCK_DGRAM, 0);
+ sock = get_if_ioctl_socket();
if (sock == -1) {
pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno,
"Can't create socket to get ethtool information for %s",
@@ -2700,14 +1535,14 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
* OK, what type of network is this?
* In particular, is it wired or wireless?
*/
- if (is_wifi(sock, name)) {
+ if (is_wifi(name)) {
/*
* Wi-Fi, hence wireless.
*/
*flags |= PCAP_IF_WIRELESS;
} else {
/*
- * OK, what does /sys/class/net/{if}/type contain?
+ * OK, what does /sys/class/net/{if_name}/type contain?
* (We don't use that for Wi-Fi, as it'll report
* "Ethernet", i.e. ARPHRD_ETHER, for non-monitor-
* mode devices.)
@@ -2715,7 +1550,7 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
char *pathstr;
if (asprintf(&pathstr, "/sys/class/net/%s/type", name) == -1) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"%s: Can't generate path name string for /sys/class/net device",
name);
close(sock);
@@ -2729,7 +1564,6 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
*/
switch (arptype) {
-#ifdef ARPHRD_LOOPBACK
case ARPHRD_LOOPBACK:
/*
* These are types to which
@@ -2743,7 +1577,6 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
fclose(fh);
free(pathstr);
return 0;
-#endif
case ARPHRD_IRDA:
case ARPHRD_IEEE80211:
@@ -2774,6 +1607,17 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
memset(&ifr, 0, sizeof(ifr));
pcap_strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
info.cmd = ETHTOOL_GLINK;
+ /*
+ * XXX - while Valgrind handles SIOCETHTOOL and knows that
+ * the ETHTOOL_GLINK command sets the .data member of the
+ * structure, Memory Sanitizer doesn't yet do so:
+ *
+ * https://bugs.llvm.org/show_bug.cgi?id=45814
+ *
+ * For now, we zero it out to squelch warnings; if the bug
+ * in question is fixed, we can remove this.
+ */
+ info.data = 0;
ifr.ifr_data = (caddr_t)&info;
if (ioctl(sock, SIOCETHTOOL, &ifr) == -1) {
int save_errno = errno;
@@ -2841,8 +1685,6 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
int
pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
{
- int ret;
-
/*
* Get the list of regular interfaces first.
*/
@@ -2851,25 +1693,6 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
return (-1); /* failure */
/*
- * Read "/sys/class/net", and add to the list of interfaces all
- * interfaces listed there that we don't already have, because,
- * on Linux, SIOCGIFCONF reports only interfaces with IPv4 addresses,
- * and even getifaddrs() won't return information about
- * interfaces with no addresses, so you need to read "/sys/class/net"
- * to get the names of the rest of the interfaces.
- */
- ret = scan_sys_class_net(devlistp, errbuf);
- if (ret == -1)
- return (-1); /* failed */
- if (ret == 0) {
- /*
- * No /sys/class/net; try reading /proc/net/dev instead.
- */
- if (scan_proc_net_dev(devlistp, errbuf) == -1)
- return (-1);
- }
-
- /*
* Add the "any" device.
* As it refers to all network devices, not to any particular
* network device, the notion of "connected" vs. "disconnected"
@@ -2884,223 +1707,25 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
}
/*
- * Attach the given BPF code to the packet capture device.
- */
-static int
-pcap_setfilter_linux_common(pcap_t *handle, struct bpf_program *filter,
- int is_mmapped)
-{
- struct pcap_linux *handlep;
-#ifdef SO_ATTACH_FILTER
- struct sock_fprog fcode;
- int can_filter_in_kernel;
- int err = 0;
-#endif
-
- if (!handle)
- return -1;
- if (!filter) {
- pcap_strlcpy(handle->errbuf, "setfilter: No filter specified",
- PCAP_ERRBUF_SIZE);
- return -1;
- }
-
- handlep = handle->priv;
-
- /* Make our private copy of the filter */
-
- if (install_bpf_program(handle, filter) < 0)
- /* install_bpf_program() filled in errbuf */
- return -1;
-
- /*
- * Run user level packet filter by default. Will be overriden if
- * installing a kernel filter succeeds.
- */
- handlep->filter_in_userland = 1;
-
- /* Install kernel level filter if possible */
-
-#ifdef SO_ATTACH_FILTER
-#ifdef USHRT_MAX
- if (handle->fcode.bf_len > USHRT_MAX) {
- /*
- * fcode.len is an unsigned short for current kernel.
- * I have yet to see BPF-Code with that much
- * instructions but still it is possible. So for the
- * sake of correctness I added this check.
- */
- fprintf(stderr, "Warning: Filter too complex for kernel\n");
- fcode.len = 0;
- fcode.filter = NULL;
- can_filter_in_kernel = 0;
- } else
-#endif /* USHRT_MAX */
- {
- /*
- * Oh joy, the Linux kernel uses struct sock_fprog instead
- * of struct bpf_program and of course the length field is
- * of different size. Pointed out by Sebastian
- *
- * Oh, and we also need to fix it up so that all "ret"
- * instructions with non-zero operands have MAXIMUM_SNAPLEN
- * as the operand if we're not capturing in memory-mapped
- * mode, and so that, if we're in cooked mode, all memory-
- * reference instructions use special magic offsets in
- * references to the link-layer header and assume that the
- * link-layer payload begins at 0; "fix_program()" will do
- * that.
- */
- switch (fix_program(handle, &fcode, is_mmapped)) {
-
- case -1:
- default:
- /*
- * Fatal error; just quit.
- * (The "default" case shouldn't happen; we
- * return -1 for that reason.)
- */
- return -1;
-
- case 0:
- /*
- * The program performed checks that we can't make
- * work in the kernel.
- */
- can_filter_in_kernel = 0;
- break;
-
- case 1:
- /*
- * We have a filter that'll work in the kernel.
- */
- can_filter_in_kernel = 1;
- break;
- }
- }
-
- /*
- * NOTE: at this point, we've set both the "len" and "filter"
- * fields of "fcode". As of the 2.6.32.4 kernel, at least,
- * those are the only members of the "sock_fprog" structure,
- * so we initialize every member of that structure.
- *
- * If there is anything in "fcode" that is not initialized,
- * it is either a field added in a later kernel, or it's
- * padding.
- *
- * If a new field is added, this code needs to be updated
- * to set it correctly.
- *
- * If there are no other fields, then:
- *
- * if the Linux kernel looks at the padding, it's
- * buggy;
- *
- * if the Linux kernel doesn't look at the padding,
- * then if some tool complains that we're passing
- * uninitialized data to the kernel, then the tool
- * is buggy and needs to understand that it's just
- * padding.
- */
- if (can_filter_in_kernel) {
- if ((err = set_kernel_filter(handle, &fcode)) == 0)
- {
- /*
- * Installation succeded - using kernel filter,
- * so userland filtering not needed.
- */
- handlep->filter_in_userland = 0;
- }
- else if (err == -1) /* Non-fatal error */
- {
- /*
- * Print a warning if we weren't able to install
- * the filter for a reason other than "this kernel
- * isn't configured to support socket filters.
- */
- if (errno != ENOPROTOOPT && errno != EOPNOTSUPP) {
- fprintf(stderr,
- "Warning: Kernel filter failed: %s\n",
- pcap_strerror(errno));
- }
- }
- }
-
- /*
- * If we're not using the kernel filter, get rid of any kernel
- * filter that might've been there before, e.g. because the
- * previous filter could work in the kernel, or because some other
- * code attached a filter to the socket by some means other than
- * calling "pcap_setfilter()". Otherwise, the kernel filter may
- * filter out packets that would pass the new userland filter.
- */
- if (handlep->filter_in_userland) {
- if (reset_kernel_filter(handle) == -1) {
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno,
- "can't remove kernel filter");
- err = -2; /* fatal error */
- }
- }
-
- /*
- * Free up the copy of the filter that was made by "fix_program()".
- */
- if (fcode.filter != NULL)
- free(fcode.filter);
-
- if (err == -2)
- /* Fatal error */
- return -1;
-#endif /* SO_ATTACH_FILTER */
-
- return 0;
-}
-
-static int
-pcap_setfilter_linux(pcap_t *handle, struct bpf_program *filter)
-{
- return pcap_setfilter_linux_common(handle, filter, 0);
-}
-
-
-/*
* Set direction flag: Which packets do we accept on a forwarding
* single device? IN, OUT or both?
*/
static int
pcap_setdirection_linux(pcap_t *handle, pcap_direction_t d)
{
-#ifdef HAVE_PF_PACKET_SOCKETS
- struct pcap_linux *handlep = handle->priv;
-
- if (!handlep->sock_packet) {
- handle->direction = d;
- return 0;
- }
-#endif
/*
- * We're not using PF_PACKET sockets, so we can't determine
- * the direction of the packet.
+ * It's guaranteed, at this point, that d is a valid
+ * direction value.
*/
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
- "Setting direction is not supported on SOCK_PACKET sockets");
- return -1;
+ handle->direction = d;
+ return 0;
}
static int
-is_wifi(int sock_fd
-#ifndef IW_MODE_MONITOR
-_U_
-#endif
-, const char *device)
+is_wifi(const char *device)
{
char *pathstr;
struct stat statb;
-#ifdef IW_MODE_MONITOR
- char errbuf[PCAP_ERRBUF_SIZE];
-#endif
/*
* See if there's a sysfs wireless directory for it.
@@ -3118,19 +1743,6 @@ _U_
}
free(pathstr);
-#ifdef IW_MODE_MONITOR
- /*
- * OK, maybe it's not wireless, or maybe this kernel doesn't
- * support sysfs. Try the wireless extensions.
- */
- if (has_wext(sock_fd, device, errbuf) == 1) {
- /*
- * It supports the wireless extensions, so it's a Wi-Fi
- * device.
- */
- return 1;
- }
-#endif
return 0;
}
@@ -3152,7 +1764,7 @@ _U_
*
* Sets the link type to -1 if unable to map the type.
*/
-static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype,
+static void map_arphrd_to_dlt(pcap_t *handle, int arptype,
const char *device, int cooked_ok)
{
static const char cdma_rmnet[] = "cdma_rmnet";
@@ -3190,12 +1802,33 @@ static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype,
* XXX - are there any other sorts of "fake Ethernet" that
* have ARPHRD_ETHER but that shouldn't offer DLT_DOCSIS as
* a Cisco CMTS won't put traffic onto it or get traffic
- * bridged onto it? ISDN is handled in "activate_new()",
+ * bridged onto it? ISDN is handled in "activate_pf_packet()",
* as we fall back on cooked mode there, and we use
* is_wifi() to check for 802.11 devices; are there any
* others?
*/
- if (!is_wifi(sock_fd, device)) {
+ if (!is_wifi(device)) {
+ int ret;
+
+ /*
+ * This is not a Wi-Fi device but it could be
+ * a DSA master/management network device.
+ */
+ ret = iface_dsa_get_proto_info(device, handle);
+ if (ret < 0)
+ return;
+
+ if (ret == 1) {
+ /*
+ * This is a DSA master/management network
+ * device linktype is already set by
+ * iface_dsa_get_proto_info() set an
+ * appropriate offset here.
+ */
+ handle->offset = 2;
+ break;
+ }
+
/*
* It's not a Wi-Fi device; offer DOCSIS.
*/
@@ -3461,7 +2094,7 @@ static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype,
* Back in 2002, Donald Lee at Cray wanted a DLT_ for
* IP-over-FC:
*
- * http://www.mail-archive.com/tcpdump-workers@sandelman.ottawa.on.ca/msg01043.html
+ * https://www.mail-archive.com/tcpdump-workers@sandelman.ottawa.on.ca/msg01043.html
*
* and one was assigned.
*
@@ -3525,7 +2158,7 @@ static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype,
/* We need to save packet direction for IrDA decoding,
* so let's use "Linux-cooked" mode. Jean II
*
- * XXX - this is handled in activate_new(). */
+ * XXX - this is handled in activate_pf_packet(). */
/* handlep->cooked = 1; */
break;
@@ -3567,7 +2200,7 @@ static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype,
* pick up the netlink protocol type such as NETLINK_ROUTE,
* NETLINK_GENERIC, NETLINK_FIB_LOOKUP, etc.
*
- * XXX - this is handled in activate_new().
+ * XXX - this is handled in activate_pf_packet().
*/
/* handlep->cooked = 1; */
break;
@@ -3585,8 +2218,6 @@ static void map_arphrd_to_dlt(pcap_t *handle, int sock_fd, int arptype,
}
}
-/* ===== Functions to interface to the newer kernels ================== */
-
#ifdef PACKET_RESERVE
static void
set_dlt_list_cooked(pcap_t *handle, int sock_fd)
@@ -3601,9 +2232,9 @@ set_dlt_list_cooked(pcap_t *handle, int sock_fd)
len = sizeof(tp_reserve);
if (getsockopt(sock_fd, SOL_PACKET, PACKET_RESERVE, &tp_reserve,
&len) == 0) {
- /*
- * Yes, we can do DLL_LINUX_SLL2.
- */
+ /*
+ * Yes, we can do DLL_LINUX_SLL2.
+ */
handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
/*
* If that fails, just leave the list empty.
@@ -3615,7 +2246,7 @@ set_dlt_list_cooked(pcap_t *handle, int sock_fd)
}
}
}
-#else
+#else/* PACKET_RESERVE */
/*
* The build environment doesn't define PACKET_RESERVE, so we can't reserve
* extra space for a DLL_LINUX_SLL2 header, so we can't support DLT_LINUX_SLL2.
@@ -3624,24 +2255,19 @@ static void
set_dlt_list_cooked(pcap_t *handle _U_, int sock_fd _U_)
{
}
-#endif
+#endif /* PACKET_RESERVE */
/*
- * Try to open a packet socket using the new kernel PF_PACKET interface.
- * Returns 1 on success, 0 on an error that means the new interface isn't
- * present (so the old SOCK_PACKET interface should be tried), and a
- * PCAP_ERROR_ value on an error that means that the old mechanism won't
- * work either (so it shouldn't be tried).
+ * Try to set up a PF_PACKET socket.
+ * Returns 0 on success and a PCAP_ERROR_ value on failure.
*/
static int
-activate_new(pcap_t *handle)
+activate_pf_packet(pcap_t *handle, int is_any_device)
{
-#ifdef HAVE_PF_PACKET_SOCKETS
struct pcap_linux *handlep = handle->priv;
const char *device = handle->opt.device;
- int is_any_device = (strcmp(device, "any") == 0);
- int protocol = pcap_protocol(handle);
- int sock_fd = -1, arptype, ret;
+ int status = 0;
+ int sock_fd, arptype;
#ifdef HAVE_PACKET_AUXDATA
int val;
#endif
@@ -3653,43 +2279,37 @@ activate_new(pcap_t *handle)
#endif
/*
- * Open a socket with protocol family packet. If the
- * "any" device was specified, we open a SOCK_DGRAM
- * socket for the cooked interface, otherwise we first
- * try a SOCK_RAW socket for the raw interface.
+ * Open a socket with protocol family packet. If cooked is true,
+ * we open a SOCK_DGRAM socket for the cooked interface, otherwise
+ * we open a SOCK_RAW socket for the raw interface.
+ *
+ * The protocol is set to 0. This means we will receive no
+ * packets until we "bind" the socket with a non-zero
+ * protocol. This allows us to setup the ring buffers without
+ * dropping any packets.
*/
sock_fd = is_any_device ?
- socket(PF_PACKET, SOCK_DGRAM, protocol) :
- socket(PF_PACKET, SOCK_RAW, protocol);
+ socket(PF_PACKET, SOCK_DGRAM, 0) :
+ socket(PF_PACKET, SOCK_RAW, 0);
if (sock_fd == -1) {
- if (errno == EINVAL || errno == EAFNOSUPPORT) {
- /*
- * We don't support PF_PACKET/SOCK_whatever
- * sockets; try the old mechanism.
- */
- return 0;
- }
if (errno == EPERM || errno == EACCES) {
/*
* You don't have permission to open the
* socket.
*/
- ret = PCAP_ERROR_PERM_DENIED;
+ status = PCAP_ERROR_PERM_DENIED;
} else {
/*
* Other error.
*/
- ret = PCAP_ERROR;
+ status = PCAP_ERROR;
}
pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
errno, "socket");
- return ret;
+ return status;
}
- /* It seems the kernel supports the new interface. */
- handlep->sock_packet = 0;
-
/*
* Get the interface index of the loopback device.
* If the attempt fails, don't fail, just set the
@@ -3754,7 +2374,7 @@ activate_new(pcap_t *handle)
close(sock_fd);
return arptype;
}
- map_arphrd_to_dlt(handle, sock_fd, arptype, device, 1);
+ map_arphrd_to_dlt(handle, arptype, device, 1);
if (handle->linktype == -1 ||
handle->linktype == DLT_LINUX_SLL ||
handle->linktype == DLT_LINUX_IRDA ||
@@ -3771,29 +2391,29 @@ activate_new(pcap_t *handle)
* type we can only determine by using
* APIs that may be different on different
* kernels) - reopen in cooked mode.
+ *
+ * If the type is unknown, return a warning;
+ * map_arphrd_to_dlt() has already set the
+ * warning message.
*/
if (close(sock_fd) == -1) {
pcap_fmt_errmsg_for_errno(handle->errbuf,
PCAP_ERRBUF_SIZE, errno, "close");
return PCAP_ERROR;
}
- sock_fd = socket(PF_PACKET, SOCK_DGRAM, protocol);
- if (sock_fd == -1) {
- if (errno == EPERM || errno == EACCES) {
- /*
- * You don't have permission to
- * open the socket.
- */
- ret = PCAP_ERROR_PERM_DENIED;
- } else {
- /*
- * Other error.
- */
- ret = PCAP_ERROR;
- }
+ sock_fd = socket(PF_PACKET, SOCK_DGRAM, 0);
+ if (sock_fd < 0) {
+ /*
+ * Fatal error. We treat this as
+ * a generic error; we already know
+ * that we were able to open a
+ * PF_PACKET/SOCK_RAW socket, so
+ * any failure is a "this shouldn't
+ * happen" case.
+ */
pcap_fmt_errmsg_for_errno(handle->errbuf,
PCAP_ERRBUF_SIZE, errno, "socket");
- return ret;
+ return PCAP_ERROR;
}
handlep->cooked = 1;
@@ -3816,7 +2436,7 @@ activate_new(pcap_t *handle)
* update "map_arphrd_to_dlt()"
* to handle the new type.
*/
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"arptype %d not "
"supported by libpcap - "
"falling back to cooked "
@@ -3833,6 +2453,12 @@ activate_new(pcap_t *handle)
handle->linktype != DLT_LINUX_LAPD &&
handle->linktype != DLT_NETLINK)
handle->linktype = DLT_LINUX_SLL;
+ if (handle->linktype == -1) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "unknown arptype %d, defaulting to cooked mode",
+ arptype);
+ status = PCAP_WARNING;
+ }
}
handlep->ifindex = iface_get_id(sock_fd, device,
@@ -3843,12 +2469,9 @@ activate_new(pcap_t *handle)
}
if ((err = iface_bind(sock_fd, handlep->ifindex,
- handle->errbuf, protocol)) != 1) {
- close(sock_fd);
- if (err < 0)
- return err;
- else
- return 0; /* try old mechanism */
+ handle->errbuf, 0)) != 0) {
+ close(sock_fd);
+ return err;
}
} else {
/*
@@ -3916,7 +2539,7 @@ activate_new(pcap_t *handle)
}
}
- /* Enable auxillary data if supported and reserve room for
+ /* Enable auxiliary data if supported and reserve room for
* reconstructing VLAN headers. */
#ifdef HAVE_PACKET_AUXDATA
val = 1;
@@ -3931,14 +2554,6 @@ activate_new(pcap_t *handle)
#endif /* HAVE_PACKET_AUXDATA */
/*
- * This is a 2.2[.x] or later kernel (we know that
- * because we're not using a SOCK_PACKET socket -
- * PF_PACKET is supported only in 2.2 and later
- * kernels).
- *
- * We can safely pass "recvfrom()" a byte count
- * based on the snapshot length.
- *
* If we're in cooked mode, make the snapshot length
* large enough to hold a "cooked mode" header plus
* 1 byte of packet data (so we don't pass a byte
@@ -3981,17 +2596,15 @@ activate_new(pcap_t *handle)
break;
}
-#if defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS)
if (handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) {
int nsec_tstamps = 1;
if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPNS, &nsec_tstamps, sizeof(nsec_tstamps)) < 0) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "setsockopt: unable to set SO_TIMESTAMPNS");
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "setsockopt: unable to set SO_TIMESTAMPNS");
close(sock_fd);
return PCAP_ERROR;
}
}
-#endif /* defined(SIOCGSTAMPNS) && defined(SO_TIMESTAMPNS) */
/*
* We've succeeded. Save the socket FD in the pcap structure.
@@ -4015,30 +2628,20 @@ activate_new(pcap_t *handle)
}
#endif /* defined(SO_BPF_EXTENSIONS) && defined(SKF_AD_VLAN_TAG_PRESENT) */
- return 1;
-#else /* HAVE_PF_PACKET_SOCKETS */
- pcap_strlcpy(ebuf,
- "New packet capturing interface not supported by build "
- "environment", PCAP_ERRBUF_SIZE);
- return 0;
-#endif /* HAVE_PF_PACKET_SOCKETS */
+ return status;
}
-#ifdef HAVE_PACKET_RING
/*
- * Attempt to activate with memory-mapped access.
+ * Attempt to setup memory-mapped access.
*
* On success, returns 1, and sets *status to 0 if there are no warnings
* or to a PCAP_WARNING_ code if there is a warning.
*
- * On failure due to lack of support for memory-mapped capture, returns
- * 0.
- *
* On error, returns -1, and sets *status to the appropriate error code;
* if that is PCAP_ERROR, sets handle->errbuf to the appropriate message.
*/
static int
-activate_mmap(pcap_t *handle, int *status)
+setup_mmapped(pcap_t *handle, int *status)
{
struct pcap_linux *handlep = handle->priv;
int ret;
@@ -4066,14 +2669,6 @@ activate_mmap(pcap_t *handle, int *status)
return ret;
}
ret = create_ring(handle, status);
- if (ret == 0) {
- /*
- * We don't support memory-mapped capture; our caller
- * will fall back on reading from the socket.
- */
- free(handlep->oneshot_buffer);
- return 0;
- }
if (ret == -1) {
/*
* Error attempting to enable memory-mapped capture;
@@ -4087,49 +2682,18 @@ activate_mmap(pcap_t *handle, int *status)
* Success. *status has been set either to 0 if there are no
* warnings or to a PCAP_WARNING_ value if there is a warning.
*
- * Override some defaults and inherit the other fields from
- * activate_new.
* handle->offset is used to get the current position into the rx ring.
* handle->cc is used to store the ring size.
*/
- switch (handlep->tp_version) {
- case TPACKET_V1:
- handle->read_op = pcap_read_linux_mmap_v1;
- break;
- case TPACKET_V1_64:
- handle->read_op = pcap_read_linux_mmap_v1_64;
- break;
-#ifdef HAVE_TPACKET2
- case TPACKET_V2:
- handle->read_op = pcap_read_linux_mmap_v2;
- break;
-#endif
-#ifdef HAVE_TPACKET3
- case TPACKET_V3:
- handle->read_op = pcap_read_linux_mmap_v3;
- break;
-#endif
- }
- handle->cleanup_op = pcap_cleanup_linux_mmap;
- handle->setfilter_op = pcap_setfilter_linux_mmap;
- handle->setnonblock_op = pcap_setnonblock_mmap;
- handle->getnonblock_op = pcap_getnonblock_mmap;
- handle->oneshot_callback = pcap_oneshot_mmap;
- handle->selectable_fd = handle->fd;
+ /*
+ * Set the timeout to use in poll() before returning.
+ */
+ set_poll_timeout(handlep);
+
return 1;
}
-#else /* HAVE_PACKET_RING */
-static int
-activate_mmap(pcap_t *handle _U_, int *status _U_)
-{
- return 0;
-}
-#endif /* HAVE_PACKET_RING */
-#ifdef HAVE_PACKET_RING
-
-#if defined(HAVE_TPACKET2) || defined(HAVE_TPACKET3)
/*
* Attempt to set the socket to the specified version of the memory-mapped
* header.
@@ -4152,20 +2716,36 @@ init_tpacket(pcap_t *handle, int version, const char *version_str)
* also the first release with TPACKET_V2 support.
*/
if (getsockopt(handle->fd, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) {
- if (errno == ENOPROTOOPT || errno == EINVAL) {
+ if (errno == EINVAL) {
/*
- * ENOPROTOOPT means the kernel is too old to
- * support PACKET_HDRLEN at all, which means
- * it either doesn't support TPACKET at all
- * or supports only TPACKET_V1.
+ * EINVAL means this specific version of TPACKET
+ * is not supported. Tell the caller they can try
+ * with a different one; if they've run out of
+ * others to try, let them set the error message
+ * appropriately.
*/
- return 1; /* no */
+ return 1;
}
- /* Failed to even find out; this is a fatal error. */
- pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
- errno, "can't get %s header len on packet socket",
- version_str);
+ /*
+ * All other errors are fatal.
+ */
+ if (errno == ENOPROTOOPT) {
+ /*
+ * PACKET_HDRLEN isn't supported, which means
+ * that memory-mapped capture isn't supported.
+ * Indicate that in the message.
+ */
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "Kernel doesn't support memory-mapped capture; a 2.6.27 or later 2.x kernel is required, with CONFIG_PACKET_MMAP specified for 2.x kernels");
+ } else {
+ /*
+ * Some unexpected error.
+ */
+ pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "can't get %s header len on packet socket",
+ version_str);
+ }
return -1;
}
handlep->tp_hdrlen = val;
@@ -4179,68 +2759,20 @@ init_tpacket(pcap_t *handle, int version, const char *version_str)
}
handlep->tp_version = version;
- /*
- * Reserve space for VLAN tag reconstruction.
- * This option was also introduced in 2.6.27.
- */
- val = VLAN_TAG_LEN;
- if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE, &val,
- sizeof(val)) < 0) {
- pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
- errno, "can't set up reserve on packet socket");
- return -1;
- }
-
return 0;
}
-#endif /* defined HAVE_TPACKET2 || defined HAVE_TPACKET3 */
-
-/*
- * If the instruction set for which we're compiling has both 32-bit
- * and 64-bit versions, and Linux support for the 64-bit version
- * predates TPACKET_V2, define ISA_64_BIT as the .machine value
- * you get from uname() for the 64-bit version. Otherwise, leave
- * it undefined. (This includes ARM, which has a 64-bit version,
- * but Linux support for it appeared well after TPACKET_V2 support
- * did, so there should never be a case where 32-bit ARM code is
- * running o a 64-bit kernel that only supports TPACKET_V1.)
- *
- * If we've omitted your favorite such architecture, please contribute
- * a patch. (No patch is needed for architectures that are 32-bit-only
- * or for which Linux has no support for 32-bit userland - or for which,
- * as noted, 64-bit support appeared in Linux after TPACKET_V2 support
- * did.)
- */
-#if defined(__i386__)
-#define ISA_64_BIT "x86_64"
-#elif defined(__ppc__)
-#define ISA_64_BIT "ppc64"
-#elif defined(__sparc__)
-#define ISA_64_BIT "sparc64"
-#elif defined(__s390__)
-#define ISA_64_BIT "s390x"
-#elif defined(__mips__)
-#define ISA_64_BIT "mips64"
-#elif defined(__hppa__)
-#define ISA_64_BIT "parisc64"
-#endif
/*
* Attempt to set the socket to version 3 of the memory-mapped header and,
* if that fails because version 3 isn't supported, attempt to fall
- * back to version 2. If version 2 isn't supported, just leave it at
- * version 1.
+ * back to version 2. If version 2 isn't supported, just fail.
*
- * Return 1 if we succeed or if we fail because neither version 2 nor 3 is
- * supported; return -1 on any other error, and set handle->errbuf.
+ * Return 0 if we succeed and -1 on any other error, and set handle->errbuf.
*/
static int
prepare_tpacket_socket(pcap_t *handle)
{
- struct pcap_linux *handlep = handle->priv;
-#if defined(HAVE_TPACKET2) || defined(HAVE_TPACKET3)
int ret;
-#endif
#ifdef HAVE_TPACKET3
/*
@@ -4260,7 +2792,7 @@ prepare_tpacket_socket(pcap_t *handle)
/*
* Success.
*/
- return 1;
+ return 0;
}
if (ret == -1) {
/*
@@ -4269,10 +2801,14 @@ prepare_tpacket_socket(pcap_t *handle)
*/
return -1;
}
+
+ /*
+ * This means it returned 1, which means "the kernel
+ * doesn't support TPACKET_V3"; try TPACKET_V2.
+ */
}
#endif /* HAVE_TPACKET3 */
-#ifdef HAVE_TPACKET2
/*
* Try setting the version to TPACKET_V2.
*/
@@ -4281,65 +2817,22 @@ prepare_tpacket_socket(pcap_t *handle)
/*
* Success.
*/
- return 1;
+ return 0;
}
- if (ret == -1) {
+
+ if (ret == 1) {
/*
- * We failed for some reason other than "the
- * kernel doesn't support TPACKET_V2".
+ * OK, the kernel supports memory-mapped capture, but
+ * not TPACKET_V2. Set the error message appropriately.
*/
- return -1;
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "Kernel doesn't support TPACKET_V2; a 2.6.27 or later kernel is required");
}
-#endif /* HAVE_TPACKET2 */
-
- /*
- * OK, we're using TPACKET_V1, as either that's all the kernel
- * supports or it doesn't support TPACKET at all. In the latter
- * case, create_ring() will fail, and we'll fall back on non-
- * memory-mapped capture.
- */
- handlep->tp_version = TPACKET_V1;
- handlep->tp_hdrlen = sizeof(struct tpacket_hdr);
-#ifdef ISA_64_BIT
/*
- * 32-bit userspace + 64-bit kernel + TPACKET_V1 are not compatible with
- * each other due to platform-dependent data type size differences.
- *
- * If we have a 32-bit userland and a 64-bit kernel, use an
- * internally-defined TPACKET_V1_64, with which we use a 64-bit
- * version of the data structures.
+ * We failed.
*/
- if (sizeof(long) == 4) {
- /*
- * This is 32-bit code.
- */
- struct utsname utsname;
-
- if (uname(&utsname) == -1) {
- /*
- * Failed.
- */
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno, "uname failed");
- return -1;
- }
- if (strcmp(utsname.machine, ISA_64_BIT) == 0) {
- /*
- * uname() tells us the machine is 64-bit,
- * so we presumably have a 64-bit kernel.
- *
- * XXX - this presumes that uname() won't lie
- * in 32-bit code and claim that the machine
- * has the 32-bit version of the ISA.
- */
- handlep->tp_version = TPACKET_V1_64;
- handlep->tp_hdrlen = sizeof(struct tpacket_hdr_64);
- }
- }
-#endif
-
- return 1;
+ return -1;
}
#define MAX(a,b) ((a)>(b)?(a):(b))
@@ -4350,9 +2843,6 @@ prepare_tpacket_socket(pcap_t *handle)
* On success, returns 1, and sets *status to 0 if there are no warnings
* or to a PCAP_WARNING_ code if there is a warning.
*
- * On failure due to lack of support for memory-mapped capture, returns
- * 0.
- *
* On error, returns -1, and sets *status to the appropriate error code;
* if that is PCAP_ERROR, sets handle->errbuf to the appropriate message.
*/
@@ -4363,9 +2853,9 @@ create_ring(pcap_t *handle, int *status)
unsigned i, j, frames_per_block;
#ifdef HAVE_TPACKET3
/*
- * For sockets using TPACKET_V1 or TPACKET_V2, the extra
- * stuff at the end of a struct tpacket_req3 will be
- * ignored, so this is OK even for those sockets.
+ * For sockets using TPACKET_V2, the extra stuff at the end of a
+ * struct tpacket_req3 will be ignored, so this is OK even for
+ * those sockets.
*/
struct tpacket_req3 req;
#else
@@ -4380,13 +2870,56 @@ create_ring(pcap_t *handle, int *status)
*/
*status = 0;
+ /*
+ * Reserve space for VLAN tag reconstruction.
+ */
+ tp_reserve = VLAN_TAG_LEN;
+
+ /*
+ * If we're using DLT_LINUX_SLL2, reserve space for a
+ * DLT_LINUX_SLL2 header.
+ *
+ * XXX - we assume that the kernel is still adding
+ * 16 bytes of extra space; that happens to
+ * correspond to SLL_HDR_LEN (whether intentionally
+ * or not - the kernel code has a raw "16" in
+ * the expression), so we subtract SLL_HDR_LEN
+ * from SLL2_HDR_LEN to get the additional space
+ * needed. That also means we don't bother reserving
+ * any additional space if we're using DLT_LINUX_SLL.
+ *
+ * XXX - should we use TPACKET_ALIGN(SLL2_HDR_LEN - SLL_HDR_LEN)?
+ */
+ if (handle->linktype == DLT_LINUX_SLL2)
+ tp_reserve += SLL2_HDR_LEN - SLL_HDR_LEN;
+
+ /*
+ * Try to request that amount of reserve space.
+ * This must be done before creating the ring buffer.
+ * If PACKET_RESERVE is supported, creating the ring
+ * buffer should be, although if creating the ring
+ * buffer fails, the PACKET_RESERVE call has no effect,
+ * so falling back on read-from-the-socket capturing
+ * won't be affected.
+ */
+ len = sizeof(tp_reserve);
+ if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE,
+ &tp_reserve, len) < 0) {
+ /*
+ * We treat ENOPROTOOPT as an error, as we
+ * already determined that we support
+ * TPACKET_V2 and later; see above.
+ */
+ pcap_fmt_errmsg_for_errno(handle->errbuf,
+ PCAP_ERRBUF_SIZE, errno,
+ "setsockopt (PACKET_RESERVE)");
+ *status = PCAP_ERROR;
+ return -1;
+ }
+
switch (handlep->tp_version) {
- case TPACKET_V1:
- case TPACKET_V1_64:
-#ifdef HAVE_TPACKET2
case TPACKET_V2:
-#endif
/* Note that with large snapshot length (say 256K, which is
* the default for recent versions of tcpdump, Wireshark,
* TShark, dumpcap or 64K, the value that "-s 0" has given for
@@ -4456,62 +2989,6 @@ create_ring(pcap_t *handle, int *status)
*status = PCAP_ERROR;
return -1;
}
-#ifdef PACKET_RESERVE
- len = sizeof(tp_reserve);
- if (getsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE,
- &tp_reserve, &len) < 0) {
- if (errno != ENOPROTOOPT) {
- /*
- * ENOPROTOOPT means "kernel doesn't support
- * PACKET_RESERVE", in which case we fall back
- * as best we can.
- */
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno,
- "getsockopt (PACKET_RESERVE)");
- *status = PCAP_ERROR;
- return -1;
- }
- /*
- * Older kernel, so we can't use PACKET_RESERVE;
- * this means we can't reserver extra space
- * for a DLT_LINUX_SLL2 header.
- */
- tp_reserve = 0;
- } else {
- /*
- * We can reserve extra space for a DLT_LINUX_SLL2
- * header. Do so.
- *
- * XXX - we assume that the kernel is still adding
- * 16 bytes of extra space; that happens to
- * correspond to SLL_HDR_LEN (whether intentionally
- * or not - the kernel code has a raw "16" in
- * the expression), so we subtract SLL_HDR_LEN
- * from SLL2_HDR_LEN to get the additional space
- * needed.
- *
- * XXX - should we use TPACKET_ALIGN(SLL2_HDR_LEN - SLL_HDR_LEN)?
- */
- tp_reserve += SLL2_HDR_LEN - SLL_HDR_LEN;
- len = sizeof(tp_reserve);
- if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE,
- &tp_reserve, len) < 0) {
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno,
- "setsockopt (PACKET_RESERVE)");
- *status = PCAP_ERROR;
- return -1;
- }
- }
-#else
- /*
- * Build environment for an older kernel, so we can't
- * use PACKET_RESERVE; this means we can't reserve
- * extra space for a DLT_LINUX_SLL2 header.
- */
- tp_reserve = 0;
-#endif
maclen = (sk_type == SOCK_DGRAM) ? 0 : MAX_LINKHEADER_SIZE;
/* XXX: in the kernel maclen is calculated from
* LL_ALLOCATED_SPACE(dev) and vnet_hdr.hdr_len
@@ -4554,49 +3031,6 @@ create_ring(pcap_t *handle, int *status)
#ifdef HAVE_TPACKET3
case TPACKET_V3:
- /*
- * If we have TPACKET_V3, we have PACKET_RESERVE.
- */
- len = sizeof(tp_reserve);
- if (getsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE,
- &tp_reserve, &len) < 0) {
- /*
- * Even ENOPROTOOPT is an error - we wouldn't
- * be here if the kernel didn't support
- * TPACKET_V3, which means it supports
- * PACKET_RESERVE.
- */
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno,
- "getsockopt (PACKET_RESERVE)");
- *status = PCAP_ERROR;
- return -1;
- }
- /*
- * We can reserve extra space for a DLT_LINUX_SLL2
- * header. Do so.
- *
- * XXX - we assume that the kernel is still adding
- * 16 bytes of extra space; that happens to
- * correspond to SLL_HDR_LEN (whether intentionally
- * or not - the kernel code has a raw "16" in
- * the expression), so we subtract SLL_HDR_LEN
- * from SLL2_HDR_LEN to get the additional space
- * needed.
- *
- * XXX - should we use TPACKET_ALIGN(SLL2_HDR_LEN - SLL_HDR_LEN)?
- */
- tp_reserve += SLL2_HDR_LEN - SLL_HDR_LEN;
- len = sizeof(tp_reserve);
- if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE,
- &tp_reserve, len) < 0) {
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno,
- "setsockopt (PACKET_RESERVE)");
- *status = PCAP_ERROR;
- return -1;
- }
-
/* The "frames" for this are actually buffers that
* contain multiple variable-sized frames.
*
@@ -4615,14 +3049,14 @@ create_ring(pcap_t *handle, int *status)
break;
#endif
default:
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Internal error: unknown TPACKET_ value %u",
handlep->tp_version);
*status = PCAP_ERROR;
return -1;
}
- /* compute the minumum block size that will handle this frame.
+ /* compute the minimum block size that will handle this frame.
* The block has to be page size aligned.
* The max block size allowed by the kernel is arch-dependent and
* it's not explicitly checked here. */
@@ -4796,12 +3230,6 @@ retry:
req.tp_frame_nr -= req.tp_frame_nr/20;
goto retry;
}
- if (errno == ENOPROTOOPT) {
- /*
- * We don't have ring buffer support in this kernel.
- */
- return 0;
- }
pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
errno, "can't create rx ring on packet socket");
*status = PCAP_ERROR;
@@ -4837,7 +3265,7 @@ retry:
/* fill the header ring with proper frame ptr*/
handle->offset = 0;
for (i=0; i<req.tp_block_nr; ++i) {
- void *base = &handlep->mmapbuf[i*req.tp_block_size];
+ u_char *base = &handlep->mmapbuf[i*req.tp_block_size];
for (j=0; j<frames_per_block; ++j, ++handle->offset) {
RING_GET_CURRENT_FRAME(handle) = base;
base += req.tp_frame_size;
@@ -4855,10 +3283,14 @@ destroy_ring(pcap_t *handle)
{
struct pcap_linux *handlep = handle->priv;
- /* tell the kernel to destroy the ring*/
+ /*
+ * Tell the kernel to destroy the ring.
+ * We don't check for setsockopt failure, as 1) we can't recover
+ * from an error and 2) we might not yet have set it up in the
+ * first place.
+ */
struct tpacket_req req;
memset(&req, 0, sizeof(req));
- /* do not test for setsockopt failure, as we can't recover from any error */
(void)setsockopt(handle->fd, SOL_PACKET, PACKET_RX_RING,
(void *) &req, sizeof(req));
@@ -4888,7 +3320,7 @@ destroy_ring(pcap_t *handle)
* pcap_next() or pcap_next_ex().
*/
static void
-pcap_oneshot_mmap(u_char *user, const struct pcap_pkthdr *h,
+pcap_oneshot_linux(u_char *user, const struct pcap_pkthdr *h,
const u_char *bytes)
{
struct oneshot_userdata *sp = (struct oneshot_userdata *)user;
@@ -4900,22 +3332,8 @@ pcap_oneshot_mmap(u_char *user, const struct pcap_pkthdr *h,
*sp->pkt = handlep->oneshot_buffer;
}
-static void
-pcap_cleanup_linux_mmap( pcap_t *handle )
-{
- struct pcap_linux *handlep = handle->priv;
-
- destroy_ring(handle);
- if (handlep->oneshot_buffer != NULL) {
- free(handlep->oneshot_buffer);
- handlep->oneshot_buffer = NULL;
- }
- pcap_cleanup_linux(handle);
-}
-
-
static int
-pcap_getnonblock_mmap(pcap_t *handle)
+pcap_getnonblock_linux(pcap_t *handle)
{
struct pcap_linux *handlep = handle->priv;
@@ -4924,7 +3342,7 @@ pcap_getnonblock_mmap(pcap_t *handle)
}
static int
-pcap_setnonblock_mmap(pcap_t *handle, int nonblock)
+pcap_setnonblock_linux(pcap_t *handle, int nonblock)
{
struct pcap_linux *handlep = handle->priv;
@@ -4960,7 +3378,7 @@ pcap_setnonblock_mmap(pcap_t *handle, int nonblock)
/*
* Get the status field of the ring buffer frame at a specified offset.
*/
-static inline int
+static inline u_int
pcap_get_ring_frame_status(pcap_t *handle, int offset)
{
struct pcap_linux *handlep = handle->priv;
@@ -4968,20 +3386,12 @@ pcap_get_ring_frame_status(pcap_t *handle, int offset)
h.raw = RING_GET_FRAME_AT(handle, offset);
switch (handlep->tp_version) {
- case TPACKET_V1:
- return (h.h1->tp_status);
- break;
- case TPACKET_V1_64:
- return (h.h1_64->tp_status);
- break;
-#ifdef HAVE_TPACKET2
case TPACKET_V2:
- return (h.h2->tp_status);
+ return __atomic_load_n(&h.h2->tp_status, __ATOMIC_ACQUIRE);
break;
-#endif
#ifdef HAVE_TPACKET3
case TPACKET_V3:
- return (h.h3->hdr.bh1.block_status);
+ return __atomic_load_n(&h.h3->hdr.bh1.block_status, __ATOMIC_ACQUIRE);
break;
#endif
}
@@ -4989,25 +3399,62 @@ pcap_get_ring_frame_status(pcap_t *handle, int offset)
return 0;
}
-#ifndef POLLRDHUP
-#define POLLRDHUP 0
-#endif
-
/*
* Block waiting for frames to be available.
*/
static int pcap_wait_for_frames_mmap(pcap_t *handle)
{
struct pcap_linux *handlep = handle->priv;
- char c;
- struct pollfd pollinfo;
+ int timeout;
+ struct ifreq ifr;
int ret;
+ struct pollfd pollinfo[2];
+ pollinfo[0].fd = handle->fd;
+ pollinfo[0].events = POLLIN;
+ pollinfo[1].fd = handlep->poll_breakloop_fd;
+ pollinfo[1].events = POLLIN;
- pollinfo.fd = handle->fd;
- pollinfo.events = POLLIN;
-
- do {
- /*
+ /*
+ * Keep polling until we either get some packets to read, see
+ * that we got told to break out of the loop, get a fatal error,
+ * or discover that the device went away.
+ *
+ * In non-blocking mode, we must still do one poll() to catch
+ * any pending error indications, but the poll() has a timeout
+ * of 0, so that it doesn't block, and we quit after that one
+ * poll().
+ *
+ * If we've seen an ENETDOWN, it might be the first indication
+ * that the device went away, or it might just be that it was
+ * configured down. Unfortunately, there's no guarantee that
+ * the device has actually been removed as an interface, because:
+ *
+ * 1) if, as appears to be the case at least some of the time,
+ * the PF_PACKET socket code first gets a NETDEV_DOWN indication
+ * for the device and then gets a NETDEV_UNREGISTER indication
+ * for it, the first indication will cause a wakeup with ENETDOWN
+ * but won't set the packet socket's field for the interface index
+ * to -1, and the second indication won't cause a wakeup (because
+ * the first indication also caused the protocol hook to be
+ * unregistered) but will set the packet socket's field for the
+ * interface index to -1;
+ *
+ * 2) even if just a NETDEV_UNREGISTER indication is registered,
+ * the packet socket's field for the interface index only gets
+ * set to -1 after the wakeup, so there's a small but non-zero
+ * risk that a thread blocked waiting for the wakeup will get
+ * to the "fetch the socket name" code before the interface index
+ * gets set to -1, so it'll get the old interface index.
+ *
+ * Therefore, if we got an ENETDOWN and haven't seen a packet
+ * since then, we assume that we might be waiting for the interface
+ * to disappear, and poll with a timeout to try again in a short
+ * period of time. If we *do* see a packet, the interface has
+ * come back up again, and is *definitely* still there, so we
+ * don't need to poll.
+ */
+ for (;;) {
+ /*
* Yes, we do this even in non-blocking mode, as it's
* the only way to get error indications from a
* tpacket socket.
@@ -5015,67 +3462,281 @@ static int pcap_wait_for_frames_mmap(pcap_t *handle)
* The timeout is 0 in non-blocking mode, so poll()
* returns immediately.
*/
- ret = poll(&pollinfo, 1, handlep->poll_timeout);
- if (ret < 0 && errno != EINTR) {
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno,
- "can't poll on packet socket");
- return PCAP_ERROR;
- } else if (ret > 0 &&
- (pollinfo.revents & (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL))) {
+ timeout = handlep->poll_timeout;
+
+ /*
+ * If we got an ENETDOWN and haven't gotten an indication
+ * that the device has gone away or that the device is up,
+ * we don't yet know for certain whether the device has
+ * gone away or not, do a poll() with a 1-millisecond timeout,
+ * as we have to poll indefinitely for "device went away"
+ * indications until we either get one or see that the
+ * device is up.
+ */
+ if (handlep->netdown) {
+ if (timeout != 0)
+ timeout = 1;
+ }
+ ret = poll(pollinfo, 2, timeout);
+ if (ret < 0) {
/*
- * There's some indication other than
- * "you can read on this descriptor" on
- * the descriptor.
+ * Error. If it's not EINTR, report it.
*/
- if (pollinfo.revents & (POLLHUP | POLLRDHUP)) {
- pcap_snprintf(handle->errbuf,
- PCAP_ERRBUF_SIZE,
- "Hangup on packet socket");
+ if (errno != EINTR) {
+ pcap_fmt_errmsg_for_errno(handle->errbuf,
+ PCAP_ERRBUF_SIZE, errno,
+ "can't poll on packet socket");
return PCAP_ERROR;
}
- if (pollinfo.revents & POLLERR) {
+
+ /*
+ * It's EINTR; if we were told to break out of
+ * the loop, do so.
+ */
+ if (handle->break_loop) {
+ handle->break_loop = 0;
+ return PCAP_ERROR_BREAK;
+ }
+ } else if (ret > 0) {
+ /*
+ * OK, some descriptor is ready.
+ * Check the socket descriptor first.
+ *
+ * As I read the Linux man page, pollinfo[0].revents
+ * will either be POLLIN, POLLERR, POLLHUP, or POLLNVAL.
+ */
+ if (pollinfo[0].revents == POLLIN) {
+ /*
+ * OK, we may have packets to
+ * read.
+ */
+ break;
+ }
+ if (pollinfo[0].revents != 0) {
+ /*
+ * There's some indication other than
+ * "you can read on this descriptor" on
+ * the descriptor.
+ */
+ if (pollinfo[0].revents & POLLNVAL) {
+ snprintf(handle->errbuf,
+ PCAP_ERRBUF_SIZE,
+ "Invalid polling request on packet socket");
+ return PCAP_ERROR;
+ }
+ if (pollinfo[0].revents & (POLLHUP | POLLRDHUP)) {
+ snprintf(handle->errbuf,
+ PCAP_ERRBUF_SIZE,
+ "Hangup on packet socket");
+ return PCAP_ERROR;
+ }
+ if (pollinfo[0].revents & POLLERR) {
+ /*
+ * Get the error.
+ */
+ int err;
+ socklen_t errlen;
+
+ errlen = sizeof(err);
+ if (getsockopt(handle->fd, SOL_SOCKET,
+ SO_ERROR, &err, &errlen) == -1) {
+ /*
+ * The call *itself* returned
+ * an error; make *that*
+ * the error.
+ */
+ err = errno;
+ }
+
+ /*
+ * OK, we have the error.
+ */
+ if (err == ENETDOWN) {
+ /*
+ * The device on which we're
+ * capturing went away or the
+ * interface was taken down.
+ *
+ * We don't know for certain
+ * which happened, and the
+ * next poll() may indicate
+ * that there are packets
+ * to be read, so just set
+ * a flag to get us to do
+ * checks later, and set
+ * the required select
+ * timeout to 1 millisecond
+ * so that event loops that
+ * check our socket descriptor
+ * also time out so that
+ * they can call us and we
+ * can do the checks.
+ */
+ handlep->netdown = 1;
+ handle->required_select_timeout = &netdown_timeout;
+ } else if (err == 0) {
+ /*
+ * This shouldn't happen, so
+ * report a special indication
+ * that it did.
+ */
+ snprintf(handle->errbuf,
+ PCAP_ERRBUF_SIZE,
+ "Error condition on packet socket: Reported error was 0");
+ return PCAP_ERROR;
+ } else {
+ pcap_fmt_errmsg_for_errno(handle->errbuf,
+ PCAP_ERRBUF_SIZE,
+ err,
+ "Error condition on packet socket");
+ return PCAP_ERROR;
+ }
+ }
+ }
+ /*
+ * Now check the event device.
+ */
+ if (pollinfo[1].revents & POLLIN) {
+ ssize_t nread;
+ uint64_t value;
+
/*
- * A recv() will give us the actual error code.
+ * This should never fail, but, just
+ * in case....
+ */
+ nread = read(handlep->poll_breakloop_fd, &value,
+ sizeof(value));
+ if (nread == -1) {
+ pcap_fmt_errmsg_for_errno(handle->errbuf,
+ PCAP_ERRBUF_SIZE,
+ errno,
+ "Error reading from event FD");
+ return PCAP_ERROR;
+ }
+
+ /*
+ * According to the Linux read(2) man
+ * page, read() will transfer at most
+ * 2^31-1 bytes, so the return value is
+ * either -1 or a value between 0
+ * and 2^31-1, so it's non-negative.
*
- * XXX - make the socket non-blocking?
+ * Cast it to size_t to squelch
+ * warnings from the compiler; add this
+ * comment to squelch warnings from
+ * humans reading the code. :-)
+ *
+ * Don't treat an EOF as an error, but
+ * *do* treat a short read as an error;
+ * that "shouldn't happen", but....
+ */
+ if (nread != 0 &&
+ (size_t)nread < sizeof(value)) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "Short read from event FD: expected %zu, got %zd",
+ sizeof(value), nread);
+ return PCAP_ERROR;
+ }
+
+ /*
+ * This event gets signaled by a
+ * pcap_breakloop() call; if we were told
+ * to break out of the loop, do so.
*/
- if (recv(handle->fd, &c, sizeof c,
- MSG_PEEK) != -1)
- continue; /* what, no error? */
- if (errno == ENETDOWN) {
+ if (handle->break_loop) {
+ handle->break_loop = 0;
+ return PCAP_ERROR_BREAK;
+ }
+ }
+ }
+
+ /*
+ * Either:
+ *
+ * 1) we got neither an error from poll() nor any
+ * readable descriptors, in which case there
+ * are no packets waiting to read
+ *
+ * or
+ *
+ * 2) We got readable descriptors but the PF_PACKET
+ * socket wasn't one of them, in which case there
+ * are no packets waiting to read
+ *
+ * so, if we got an ENETDOWN, we've drained whatever
+ * packets were available to read at the point of the
+ * ENETDOWN.
+ *
+ * So, if we got an ENETDOWN and haven't gotten an indication
+ * that the device has gone away or that the device is up,
+ * we don't yet know for certain whether the device has
+ * gone away or not, check whether the device exists and is
+ * up.
+ */
+ if (handlep->netdown) {
+ if (!device_still_exists(handle)) {
+ /*
+ * The device doesn't exist any more;
+ * report that.
+ *
+ * XXX - we should really return an
+ * appropriate error for that, but
+ * pcap_dispatch() etc. aren't documented
+ * as having error returns other than
+ * PCAP_ERROR or PCAP_ERROR_BREAK.
+ */
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "The interface disappeared");
+ return PCAP_ERROR;
+ }
+
+ /*
+ * The device still exists; try to see if it's up.
+ */
+ memset(&ifr, 0, sizeof(ifr));
+ pcap_strlcpy(ifr.ifr_name, handlep->device,
+ sizeof(ifr.ifr_name));
+ if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) {
+ if (errno == ENXIO || errno == ENODEV) {
/*
- * The device on which we're
- * capturing went away.
+ * OK, *now* it's gone.
*
- * XXX - we should really return
- * PCAP_ERROR_IFACE_NOT_UP, but
- * pcap_dispatch() etc. aren't
- * defined to return that.
+ * XXX - see above comment.
*/
- pcap_snprintf(handle->errbuf,
- PCAP_ERRBUF_SIZE,
- "The interface went down");
+ snprintf(handle->errbuf,
+ PCAP_ERRBUF_SIZE,
+ "The interface disappeared");
+ return PCAP_ERROR;
} else {
pcap_fmt_errmsg_for_errno(handle->errbuf,
PCAP_ERRBUF_SIZE, errno,
- "Error condition on packet socket");
+ "%s: Can't get flags",
+ handlep->device);
+ return PCAP_ERROR;
}
- return PCAP_ERROR;
}
- if (pollinfo.revents & POLLNVAL) {
- pcap_snprintf(handle->errbuf,
- PCAP_ERRBUF_SIZE,
- "Invalid polling request on packet socket");
- return PCAP_ERROR;
+ if (ifr.ifr_flags & IFF_UP) {
+ /*
+ * It's up, so it definitely still exists.
+ * Cancel the ENETDOWN indication - we
+ * presumably got it due to the interface
+ * going down rather than the device going
+ * away - and revert to "no required select
+ * timeout.
+ */
+ handlep->netdown = 0;
+ handle->required_select_timeout = NULL;
}
}
- /* check for break loop condition on interrupted syscall*/
- if (handle->break_loop) {
- handle->break_loop = 0;
- return PCAP_ERROR_BREAK;
- }
- } while (ret < 0);
+
+ /*
+ * If we're in non-blocking mode, just quit now, rather
+ * than spinning in a loop doing poll()s that immediately
+ * time out if there's no indication on any descriptor.
+ */
+ if (handlep->poll_timeout == 0)
+ break;
+ }
return 0;
}
@@ -5107,7 +3768,7 @@ static int pcap_handle_packet_mmap(
* Report some system information as a debugging aid.
*/
if (uname(&utsname) != -1) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"corrupted frame on kernel ring mac "
"offset %u + caplen %u > frame len %d "
"(kernel %.32s version %s, machine %.16s)",
@@ -5115,7 +3776,7 @@ static int pcap_handle_packet_mmap(
utsname.release, utsname.version,
utsname.machine);
} else {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"corrupted frame on kernel ring mac "
"offset %u + caplen %u > frame len %d",
tp_mac, tp_snaplen, handle->bufsize);
@@ -5135,7 +3796,7 @@ static int pcap_handle_packet_mmap(
bp = frame + tp_mac;
/* if required build in place the sll header*/
- sll = (void *)frame + TPACKET_ALIGN(handlep->tp_hdrlen);
+ sll = (void *)(frame + TPACKET_ALIGN(handlep->tp_hdrlen));
if (handlep->cooked) {
if (handle->linktype == DLT_LINUX_SLL2) {
struct sll2_header *hdrp;
@@ -5159,7 +3820,7 @@ static int pcap_handle_packet_mmap(
if (bp < (u_char *)frame +
TPACKET_ALIGN(handlep->tp_hdrlen) +
sizeof(struct sockaddr_ll)) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"cooked-mode frame doesn't have room for sll header");
return -1;
}
@@ -5199,7 +3860,7 @@ static int pcap_handle_packet_mmap(
if (bp < (u_char *)frame +
TPACKET_ALIGN(handlep->tp_hdrlen) +
sizeof(struct sockaddr_ll)) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"cooked-mode frame doesn't have room for sll header");
return -1;
}
@@ -5224,11 +3885,11 @@ static int pcap_handle_packet_mmap(
aux_data.vlan_tag_present = tp_vlan_tci_valid;
aux_data.vlan_tag = tp_vlan_tci & 0x0fff;
- if (bpf_filter_with_aux_data(handle->fcode.bf_insns,
- bp,
- tp_len,
- snaplen,
- &aux_data) == 0)
+ if (pcap_filter_with_aux_data(handle->fcode.bf_insns,
+ bp,
+ tp_len,
+ snaplen,
+ &aux_data) == 0)
return 0;
}
@@ -5253,7 +3914,6 @@ static int pcap_handle_packet_mmap(
}
}
-#if defined(HAVE_TPACKET2) || defined(HAVE_TPACKET3)
if (tp_vlan_tci_valid &&
handlep->vlan_offset != -1 &&
tp_snaplen >= (unsigned int) handlep->vlan_offset)
@@ -5281,7 +3941,6 @@ static int pcap_handle_packet_mmap(
pcaphdr.caplen += VLAN_TAG_LEN;
pcaphdr.len += VLAN_TAG_LEN;
}
-#endif
/*
* The only way to tell the kernel to cut off the
@@ -5291,6 +3950,13 @@ static int pcap_handle_packet_mmap(
*
* Trim the snapshot length to be no longer than the
* specified snapshot length.
+ *
+ * XXX - an alternative is to put a filter, consisting
+ * of a "ret <snaplen>" instruction, on the socket
+ * in the activate routine, so that the truncation is
+ * done in the kernel even if nobody specified a filter;
+ * that means that less buffer space is consumed in
+ * the memory-mapped buffer.
*/
if (pcaphdr.caplen > (bpf_u_int32)handle->snapshot)
pcaphdr.caplen = handle->snapshot;
@@ -5302,175 +3968,6 @@ static int pcap_handle_packet_mmap(
}
static int
-pcap_read_linux_mmap_v1(pcap_t *handle, int max_packets, pcap_handler callback,
- u_char *user)
-{
- struct pcap_linux *handlep = handle->priv;
- union thdr h;
- int pkts = 0;
- int ret;
-
- /* wait for frames availability.*/
- h.raw = RING_GET_CURRENT_FRAME(handle);
- if (h.h1->tp_status == TP_STATUS_KERNEL) {
- /*
- * The current frame is owned by the kernel; wait for
- * a frame to be handed to us.
- */
- ret = pcap_wait_for_frames_mmap(handle);
- if (ret) {
- return ret;
- }
- }
-
- /* non-positive values of max_packets are used to require all
- * packets currently available in the ring */
- while ((pkts < max_packets) || PACKET_COUNT_IS_UNLIMITED(max_packets)) {
- /*
- * Get the current ring buffer frame, and break if
- * it's still owned by the kernel.
- */
- h.raw = RING_GET_CURRENT_FRAME(handle);
- if (h.h1->tp_status == TP_STATUS_KERNEL)
- break;
-
- ret = pcap_handle_packet_mmap(
- handle,
- callback,
- user,
- h.raw,
- h.h1->tp_len,
- h.h1->tp_mac,
- h.h1->tp_snaplen,
- h.h1->tp_sec,
- h.h1->tp_usec,
- 0,
- 0,
- 0);
- if (ret == 1) {
- pkts++;
- handlep->packets_read++;
- } else if (ret < 0) {
- return ret;
- }
-
- /*
- * Hand this block back to the kernel, and, if we're
- * counting blocks that need to be filtered in userland
- * after having been filtered by the kernel, count
- * the one we've just processed.
- */
- h.h1->tp_status = TP_STATUS_KERNEL;
- if (handlep->blocks_to_filter_in_userland > 0) {
- handlep->blocks_to_filter_in_userland--;
- if (handlep->blocks_to_filter_in_userland == 0) {
- /*
- * No more blocks need to be filtered
- * in userland.
- */
- handlep->filter_in_userland = 0;
- }
- }
-
- /* next block */
- if (++handle->offset >= handle->cc)
- handle->offset = 0;
-
- /* check for break loop condition*/
- if (handle->break_loop) {
- handle->break_loop = 0;
- return PCAP_ERROR_BREAK;
- }
- }
- return pkts;
-}
-
-static int
-pcap_read_linux_mmap_v1_64(pcap_t *handle, int max_packets, pcap_handler callback,
- u_char *user)
-{
- struct pcap_linux *handlep = handle->priv;
- union thdr h;
- int pkts = 0;
- int ret;
-
- /* wait for frames availability.*/
- h.raw = RING_GET_CURRENT_FRAME(handle);
- if (h.h1_64->tp_status == TP_STATUS_KERNEL) {
- /*
- * The current frame is owned by the kernel; wait for
- * a frame to be handed to us.
- */
- ret = pcap_wait_for_frames_mmap(handle);
- if (ret) {
- return ret;
- }
- }
-
- /* non-positive values of max_packets are used to require all
- * packets currently available in the ring */
- while ((pkts < max_packets) || PACKET_COUNT_IS_UNLIMITED(max_packets)) {
- /*
- * Get the current ring buffer frame, and break if
- * it's still owned by the kernel.
- */
- h.raw = RING_GET_CURRENT_FRAME(handle);
- if (h.h1_64->tp_status == TP_STATUS_KERNEL)
- break;
-
- ret = pcap_handle_packet_mmap(
- handle,
- callback,
- user,
- h.raw,
- h.h1_64->tp_len,
- h.h1_64->tp_mac,
- h.h1_64->tp_snaplen,
- h.h1_64->tp_sec,
- h.h1_64->tp_usec,
- 0,
- 0,
- 0);
- if (ret == 1) {
- pkts++;
- handlep->packets_read++;
- } else if (ret < 0) {
- return ret;
- }
-
- /*
- * Hand this block back to the kernel, and, if we're
- * counting blocks that need to be filtered in userland
- * after having been filtered by the kernel, count
- * the one we've just processed.
- */
- h.h1_64->tp_status = TP_STATUS_KERNEL;
- if (handlep->blocks_to_filter_in_userland > 0) {
- handlep->blocks_to_filter_in_userland--;
- if (handlep->blocks_to_filter_in_userland == 0) {
- /*
- * No more blocks need to be filtered
- * in userland.
- */
- handlep->filter_in_userland = 0;
- }
- }
-
- /* next block */
- if (++handle->offset >= handle->cc)
- handle->offset = 0;
-
- /* check for break loop condition*/
- if (handle->break_loop) {
- handle->break_loop = 0;
- return PCAP_ERROR_BREAK;
- }
- }
- return pkts;
-}
-
-#ifdef HAVE_TPACKET2
-static int
pcap_read_linux_mmap_v2(pcap_t *handle, int max_packets, pcap_handler callback,
u_char *user)
{
@@ -5481,7 +3978,7 @@ pcap_read_linux_mmap_v2(pcap_t *handle, int max_packets, pcap_handler callback,
/* wait for frames availability.*/
h.raw = RING_GET_CURRENT_FRAME(handle);
- if (h.h2->tp_status == TP_STATUS_KERNEL) {
+ if (!packet_mmap_acquire(h.h2)) {
/*
* The current frame is owned by the kernel; wait for
* a frame to be handed to us.
@@ -5500,7 +3997,7 @@ pcap_read_linux_mmap_v2(pcap_t *handle, int max_packets, pcap_handler callback,
* it's still owned by the kernel.
*/
h.raw = RING_GET_CURRENT_FRAME(handle);
- if (h.h2->tp_status == TP_STATUS_KERNEL)
+ if (!packet_mmap_acquire(h.h2))
break;
ret = pcap_handle_packet_mmap(
@@ -5518,7 +4015,6 @@ pcap_read_linux_mmap_v2(pcap_t *handle, int max_packets, pcap_handler callback,
VLAN_TPID(h.h2, h.h2));
if (ret == 1) {
pkts++;
- handlep->packets_read++;
} else if (ret < 0) {
return ret;
}
@@ -5529,7 +4025,7 @@ pcap_read_linux_mmap_v2(pcap_t *handle, int max_packets, pcap_handler callback,
* after having been filtered by the kernel, count
* the one we've just processed.
*/
- h.h2->tp_status = TP_STATUS_KERNEL;
+ packet_mmap_release(h.h2);
if (handlep->blocks_to_filter_in_userland > 0) {
handlep->blocks_to_filter_in_userland--;
if (handlep->blocks_to_filter_in_userland == 0) {
@@ -5553,7 +4049,6 @@ pcap_read_linux_mmap_v2(pcap_t *handle, int max_packets, pcap_handler callback,
}
return pkts;
}
-#endif /* HAVE_TPACKET2 */
#ifdef HAVE_TPACKET3
static int
@@ -5569,7 +4064,7 @@ again:
if (handlep->current_packet == NULL) {
/* wait for frames availability.*/
h.raw = RING_GET_CURRENT_FRAME(handle);
- if (h.h3->hdr.bh1.block_status == TP_STATUS_KERNEL) {
+ if (!packet_mmap_v3_acquire(h.h3)) {
/*
* The current frame is owned by the kernel; wait
* for a frame to be handed to us.
@@ -5581,7 +4076,7 @@ again:
}
}
h.raw = RING_GET_CURRENT_FRAME(handle);
- if (h.h3->hdr.bh1.block_status == TP_STATUS_KERNEL) {
+ if (!packet_mmap_v3_acquire(h.h3)) {
if (pkts == 0 && handlep->timeout == 0) {
/* Block until we see a packet. */
goto again;
@@ -5596,7 +4091,7 @@ again:
if (handlep->current_packet == NULL) {
h.raw = RING_GET_CURRENT_FRAME(handle);
- if (h.h3->hdr.bh1.block_status == TP_STATUS_KERNEL)
+ if (!packet_mmap_v3_acquire(h.h3))
break;
handlep->current_packet = h.raw + h.h3->hdr.bh1.offset_to_first_pkt;
@@ -5632,7 +4127,6 @@ again:
VLAN_TPID(tp3_hdr, &tp3_hdr->hv1));
if (ret == 1) {
pkts++;
- handlep->packets_read++;
} else if (ret < 0) {
handlep->current_packet = NULL;
return ret;
@@ -5649,7 +4143,7 @@ again:
* filtered by the kernel, count the one we've
* just processed.
*/
- h.h3->hdr.bh1.block_status = TP_STATUS_KERNEL;
+ packet_mmap_v3_release(h.h3);
if (handlep->blocks_to_filter_in_userland > 0) {
handlep->blocks_to_filter_in_userland--;
if (handlep->blocks_to_filter_in_userland == 0) {
@@ -5682,29 +4176,180 @@ again:
}
#endif /* HAVE_TPACKET3 */
+/*
+ * Attach the given BPF code to the packet capture device.
+ */
static int
-pcap_setfilter_linux_mmap(pcap_t *handle, struct bpf_program *filter)
+pcap_setfilter_linux(pcap_t *handle, struct bpf_program *filter)
{
- struct pcap_linux *handlep = handle->priv;
- int n, offset;
- int ret;
+ struct pcap_linux *handlep;
+ struct sock_fprog fcode;
+ int can_filter_in_kernel;
+ int err = 0;
+ int n, offset;
+
+ if (!handle)
+ return -1;
+ if (!filter) {
+ pcap_strlcpy(handle->errbuf, "setfilter: No filter specified",
+ PCAP_ERRBUF_SIZE);
+ return -1;
+ }
+
+ handlep = handle->priv;
+
+ /* Make our private copy of the filter */
+
+ if (install_bpf_program(handle, filter) < 0)
+ /* install_bpf_program() filled in errbuf */
+ return -1;
/*
- * Don't rewrite "ret" instructions; we don't need to, as
- * we're not reading packets with recvmsg(), and we don't
- * want to, as, by not rewriting them, the kernel can avoid
- * copying extra data.
+ * Run user level packet filter by default. Will be overridden if
+ * installing a kernel filter succeeds.
*/
- ret = pcap_setfilter_linux_common(handle, filter, 1);
- if (ret < 0)
- return ret;
+ handlep->filter_in_userland = 1;
+
+ /* Install kernel level filter if possible */
+
+#ifdef USHRT_MAX
+ if (handle->fcode.bf_len > USHRT_MAX) {
+ /*
+ * fcode.len is an unsigned short for current kernel.
+ * I have yet to see BPF-Code with that much
+ * instructions but still it is possible. So for the
+ * sake of correctness I added this check.
+ */
+ fprintf(stderr, "Warning: Filter too complex for kernel\n");
+ fcode.len = 0;
+ fcode.filter = NULL;
+ can_filter_in_kernel = 0;
+ } else
+#endif /* USHRT_MAX */
+ {
+ /*
+ * Oh joy, the Linux kernel uses struct sock_fprog instead
+ * of struct bpf_program and of course the length field is
+ * of different size. Pointed out by Sebastian
+ *
+ * Oh, and we also need to fix it up so that all "ret"
+ * instructions with non-zero operands have MAXIMUM_SNAPLEN
+ * as the operand if we're not capturing in memory-mapped
+ * mode, and so that, if we're in cooked mode, all memory-
+ * reference instructions use special magic offsets in
+ * references to the link-layer header and assume that the
+ * link-layer payload begins at 0; "fix_program()" will do
+ * that.
+ */
+ switch (fix_program(handle, &fcode)) {
+
+ case -1:
+ default:
+ /*
+ * Fatal error; just quit.
+ * (The "default" case shouldn't happen; we
+ * return -1 for that reason.)
+ */
+ return -1;
+
+ case 0:
+ /*
+ * The program performed checks that we can't make
+ * work in the kernel.
+ */
+ can_filter_in_kernel = 0;
+ break;
+
+ case 1:
+ /*
+ * We have a filter that'll work in the kernel.
+ */
+ can_filter_in_kernel = 1;
+ break;
+ }
+ }
+
+ /*
+ * NOTE: at this point, we've set both the "len" and "filter"
+ * fields of "fcode". As of the 2.6.32.4 kernel, at least,
+ * those are the only members of the "sock_fprog" structure,
+ * so we initialize every member of that structure.
+ *
+ * If there is anything in "fcode" that is not initialized,
+ * it is either a field added in a later kernel, or it's
+ * padding.
+ *
+ * If a new field is added, this code needs to be updated
+ * to set it correctly.
+ *
+ * If there are no other fields, then:
+ *
+ * if the Linux kernel looks at the padding, it's
+ * buggy;
+ *
+ * if the Linux kernel doesn't look at the padding,
+ * then if some tool complains that we're passing
+ * uninitialized data to the kernel, then the tool
+ * is buggy and needs to understand that it's just
+ * padding.
+ */
+ if (can_filter_in_kernel) {
+ if ((err = set_kernel_filter(handle, &fcode)) == 0)
+ {
+ /*
+ * Installation succeeded - using kernel filter,
+ * so userland filtering not needed.
+ */
+ handlep->filter_in_userland = 0;
+ }
+ else if (err == -1) /* Non-fatal error */
+ {
+ /*
+ * Print a warning if we weren't able to install
+ * the filter for a reason other than "this kernel
+ * isn't configured to support socket filters.
+ */
+ if (errno != ENOPROTOOPT && errno != EOPNOTSUPP) {
+ fprintf(stderr,
+ "Warning: Kernel filter failed: %s\n",
+ pcap_strerror(errno));
+ }
+ }
+ }
+
+ /*
+ * If we're not using the kernel filter, get rid of any kernel
+ * filter that might've been there before, e.g. because the
+ * previous filter could work in the kernel, or because some other
+ * code attached a filter to the socket by some means other than
+ * calling "pcap_setfilter()". Otherwise, the kernel filter may
+ * filter out packets that would pass the new userland filter.
+ */
+ if (handlep->filter_in_userland) {
+ if (reset_kernel_filter(handle) == -1) {
+ pcap_fmt_errmsg_for_errno(handle->errbuf,
+ PCAP_ERRBUF_SIZE, errno,
+ "can't remove kernel filter");
+ err = -2; /* fatal error */
+ }
+ }
+
+ /*
+ * Free up the copy of the filter that was made by "fix_program()".
+ */
+ if (fcode.filter != NULL)
+ free(fcode.filter);
+
+ if (err == -2)
+ /* Fatal error */
+ return -1;
/*
* If we're filtering in userland, there's nothing to do;
* the new filter will be used for the next packet.
*/
if (handlep->filter_in_userland)
- return ret;
+ return 0;
/*
* We're filtering in the kernel; the packets present in
@@ -5755,13 +4400,10 @@ pcap_setfilter_linux_mmap(pcap_t *handle, struct bpf_program *filter)
*/
handlep->blocks_to_filter_in_userland = handle->cc - n;
handlep->filter_in_userland = 1;
- return ret;
-}
-
-#endif /* HAVE_PACKET_RING */
+ return 0;
+}
-#ifdef HAVE_PF_PACKET_SOCKETS
/*
* Return the index of the given device name. Fill ebuf and return
* -1 on failure.
@@ -5785,19 +4427,18 @@ iface_get_id(int fd, const char *device, char *ebuf)
/*
* Bind the socket associated with FD to the given device.
- * Return 1 on success, 0 if we should try a SOCK_PACKET socket,
- * or a PCAP_ERROR_ value on a hard error.
+ * Return 0 on success or a PCAP_ERROR_ value on a hard error.
*/
static int
iface_bind(int fd, int ifindex, char *ebuf, int protocol)
{
struct sockaddr_ll sll;
- int err;
+ int ret, err;
socklen_t errlen = sizeof(err);
memset(&sll, 0, sizeof(sll));
sll.sll_family = AF_PACKET;
- sll.sll_ifindex = ifindex;
+ sll.sll_ifindex = ifindex < 0 ? 0 : ifindex;
sll.sll_protocol = protocol;
if (bind(fd, (struct sockaddr *) &sll, sizeof(sll)) == -1) {
@@ -5810,11 +4451,14 @@ iface_bind(int fd, int ifindex, char *ebuf, int protocol)
* libpcap developers.
*/
return PCAP_ERROR_IFACE_NOT_UP;
- } else {
- pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
- errno, "bind");
- return PCAP_ERROR;
}
+ if (errno == ENODEV)
+ ret = PCAP_ERROR_NO_SUCH_DEVICE;
+ else
+ ret = PCAP_ERROR;
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "bind");
+ return ret;
}
/* Any pending errors, e.g., network is down? */
@@ -5822,7 +4466,7 @@ iface_bind(int fd, int ifindex, char *ebuf, int protocol)
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
errno, "getsockopt (SO_ERROR)");
- return 0;
+ return PCAP_ERROR;
}
if (err == ENETDOWN) {
@@ -5837,391 +4481,89 @@ iface_bind(int fd, int ifindex, char *ebuf, int protocol)
} else if (err > 0) {
pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
err, "bind");
- return 0;
+ return PCAP_ERROR;
}
- return 1;
-}
-
-#ifdef IW_MODE_MONITOR
-/*
- * Check whether the device supports the Wireless Extensions.
- * Returns 1 if it does, 0 if it doesn't, PCAP_ERROR_NO_SUCH_DEVICE
- * if the device doesn't even exist.
- */
-static int
-has_wext(int sock_fd, const char *device, char *ebuf)
-{
- struct iwreq ireq;
- int ret;
-
- if (is_bonding_device(sock_fd, device))
- return 0; /* bonding device, so don't even try */
-
- pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
- sizeof ireq.ifr_ifrn.ifrn_name);
- if (ioctl(sock_fd, SIOCGIWNAME, &ireq) >= 0)
- return 1; /* yes */
- if (errno == ENODEV)
- ret = PCAP_ERROR_NO_SUCH_DEVICE;
- else
- ret = 0;
- pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno,
- "%s: SIOCGIWNAME", device);
- return ret;
+ return 0;
}
/*
- * Per me si va ne la citta dolente,
- * Per me si va ne l'etterno dolore,
- * ...
- * Lasciate ogne speranza, voi ch'intrate.
- *
- * XXX - airmon-ng does special stuff with the Orinoco driver and the
- * wlan-ng driver.
- */
-typedef enum {
- MONITOR_WEXT,
- MONITOR_HOSTAP,
- MONITOR_PRISM,
- MONITOR_PRISM54,
- MONITOR_ACX100,
- MONITOR_RT2500,
- MONITOR_RT2570,
- MONITOR_RT73,
- MONITOR_RTL8XXX
-} monitor_type;
-
-/*
- * Use the Wireless Extensions, if we have them, to try to turn monitor mode
- * on if it's not already on.
- *
- * Returns 1 on success, 0 if we don't support the Wireless Extensions
- * on this device, or a PCAP_ERROR_ value if we do support them but
- * we weren't able to turn monitor mode on.
+ * Try to enter monitor mode.
+ * If we have libnl, try to create a new monitor-mode device and
+ * capture on that; otherwise, just say "not supported".
*/
+#ifdef HAVE_LIBNL
static int
-enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device)
+enter_rfmon_mode(pcap_t *handle, int sock_fd, const char *device)
{
- /*
- * XXX - at least some adapters require non-Wireless Extensions
- * mechanisms to turn monitor mode on.
- *
- * Atheros cards might require that a separate "monitor virtual access
- * point" be created, with later versions of the madwifi driver.
- * airmon-ng does "wlanconfig ath create wlandev {if} wlanmode
- * monitor -bssid", which apparently spits out a line "athN"
- * where "athN" is the monitor mode device. To leave monitor
- * mode, it destroys the monitor mode device.
- *
- * Some Intel Centrino adapters might require private ioctls to get
- * radio headers; the ipw2200 and ipw3945 drivers allow you to
- * configure a separate "rtapN" interface to capture in monitor
- * mode without preventing the adapter from operating normally.
- * (airmon-ng doesn't appear to use that, though.)
- *
- * It would be Truly Wonderful if mac80211 and nl80211 cleaned this
- * up, and if all drivers were converted to mac80211 drivers.
- *
- * If interface {if} is a mac80211 driver, the file
- * /sys/class/net/{if}/phy80211 is a symlink to
- * /sys/class/ieee80211/{phydev}, for some {phydev}.
- *
- * On Fedora 9, with a 2.6.26.3-29 kernel, my Zydas stick, at
- * least, has a "wmaster0" device and a "wlan0" device; the
- * latter is the one with the IP address. Both show up in
- * "tcpdump -D" output. Capturing on the wmaster0 device
- * captures with 802.11 headers.
- *
- * airmon-ng searches through /sys/class/net for devices named
- * monN, starting with mon0; as soon as one *doesn't* exist,
- * it chooses that as the monitor device name. If the "iw"
- * command exists, it does "iw dev {if} interface add {monif}
- * type monitor", where {monif} is the monitor device. It
- * then (sigh) sleeps .1 second, and then configures the
- * device up. Otherwise, if /sys/class/ieee80211/{phydev}/add_iface
- * is a file, it writes {mondev}, without a newline, to that file,
- * and again (sigh) sleeps .1 second, and then iwconfig's that
- * device into monitor mode and configures it up. Otherwise,
- * you can't do monitor mode.
- *
- * All these devices are "glued" together by having the
- * /sys/class/net/{device}/phy80211 links pointing to the same
- * place, so, given a wmaster, wlan, or mon device, you can
- * find the other devices by looking for devices with
- * the same phy80211 link.
- *
- * To turn monitor mode off, delete the monitor interface,
- * either with "iw dev {monif} interface del" or by sending
- * {monif}, with no NL, down /sys/class/ieee80211/{phydev}/remove_iface
- *
- * Note: if you try to create a monitor device named "monN", and
- * there's already a "monN" device, it fails, as least with
- * the netlink interface (which is what iw uses), with a return
- * value of -ENFILE. (Return values are negative errnos.) We
- * could probably use that to find an unused device.
- */
struct pcap_linux *handlep = handle->priv;
- int err;
- struct iwreq ireq;
- struct iw_priv_args *priv;
- monitor_type montype;
- int i;
- __u32 cmd;
+ int ret;
+ char phydev_path[PATH_MAX+1];
+ struct nl80211_state nlstate;
struct ifreq ifr;
- int oldflags;
- int args[2];
- int channel;
+ u_int n;
/*
- * Does this device *support* the Wireless Extensions?
+ * Is this a mac80211 device?
*/
- err = has_wext(sock_fd, device, handle->errbuf);
- if (err <= 0)
- return err; /* either it doesn't or the device doesn't even exist */
+ ret = get_mac80211_phydev(handle, device, phydev_path, PATH_MAX);
+ if (ret < 0)
+ return ret; /* error */
+ if (ret == 0)
+ return 0; /* no error, but not mac80211 device */
+
/*
- * Start out assuming we have no private extensions to control
- * radio metadata.
+ * XXX - is this already a monN device?
+ * If so, we're done.
*/
- montype = MONITOR_WEXT;
- cmd = 0;
/*
- * Try to get all the Wireless Extensions private ioctls
- * supported by this device.
- *
- * First, get the size of the buffer we need, by supplying no
- * buffer and a length of 0. If the device supports private
- * ioctls, it should return E2BIG, with ireq.u.data.length set
- * to the length we need. If it doesn't support them, it should
- * return EOPNOTSUPP.
+ * OK, it's apparently a mac80211 device.
+ * Try to find an unused monN device for it.
*/
- memset(&ireq, 0, sizeof ireq);
- pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
- sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.u.data.pointer = (void *)args;
- ireq.u.data.length = 0;
- ireq.u.data.flags = 0;
- if (ioctl(sock_fd, SIOCGIWPRIV, &ireq) != -1) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
- "%s: SIOCGIWPRIV with a zero-length buffer didn't fail!",
- device);
- return PCAP_ERROR;
- }
- if (errno != EOPNOTSUPP) {
+ ret = nl80211_init(handle, &nlstate, device);
+ if (ret != 0)
+ return ret;
+ for (n = 0; n < UINT_MAX; n++) {
/*
- * OK, it's not as if there are no private ioctls.
+ * Try mon{n}.
*/
- if (errno != E2BIG) {
+ char mondevice[3+10+1]; /* mon{UINT_MAX}\0 */
+
+ snprintf(mondevice, sizeof mondevice, "mon%u", n);
+ ret = add_mon_if(handle, sock_fd, &nlstate, device, mondevice);
+ if (ret == 1) {
/*
- * Failed.
+ * Success. We don't clean up the libnl state
+ * yet, as we'll be using it later.
*/
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno, "%s: SIOCGIWPRIV", device);
- return PCAP_ERROR;
- }
-
- /*
- * OK, try to get the list of private ioctls.
- */
- priv = malloc(ireq.u.data.length * sizeof (struct iw_priv_args));
- if (priv == NULL) {
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno, "malloc");
- return PCAP_ERROR;
- }
- ireq.u.data.pointer = (void *)priv;
- if (ioctl(sock_fd, SIOCGIWPRIV, &ireq) == -1) {
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno, "%s: SIOCGIWPRIV", device);
- free(priv);
- return PCAP_ERROR;
+ goto added;
}
-
- /*
- * Look for private ioctls to turn monitor mode on or, if
- * monitor mode is on, to set the header type.
- */
- for (i = 0; i < ireq.u.data.length; i++) {
- if (strcmp(priv[i].name, "monitor_type") == 0) {
- /*
- * Hostap driver, use this one.
- * Set monitor mode first.
- * You can set it to 0 to get DLT_IEEE80211,
- * 1 to get DLT_PRISM, 2 to get
- * DLT_IEEE80211_RADIO_AVS, and, with more
- * recent versions of the driver, 3 to get
- * DLT_IEEE80211_RADIO.
- */
- if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
- break;
- if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
- break;
- if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1)
- break;
- montype = MONITOR_HOSTAP;
- cmd = priv[i].cmd;
- break;
- }
- if (strcmp(priv[i].name, "set_prismhdr") == 0) {
- /*
- * Prism54 driver, use this one.
- * Set monitor mode first.
- * You can set it to 2 to get DLT_IEEE80211
- * or 3 or get DLT_PRISM.
- */
- if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
- break;
- if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
- break;
- if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1)
- break;
- montype = MONITOR_PRISM54;
- cmd = priv[i].cmd;
- break;
- }
- if (strcmp(priv[i].name, "forceprismheader") == 0) {
- /*
- * RT2570 driver, use this one.
- * Do this after turning monitor mode on.
- * You can set it to 1 to get DLT_PRISM or 2
- * to get DLT_IEEE80211.
- */
- if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
- break;
- if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
- break;
- if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1)
- break;
- montype = MONITOR_RT2570;
- cmd = priv[i].cmd;
- break;
- }
- if (strcmp(priv[i].name, "forceprism") == 0) {
- /*
- * RT73 driver, use this one.
- * Do this after turning monitor mode on.
- * Its argument is a *string*; you can
- * set it to "1" to get DLT_PRISM or "2"
- * to get DLT_IEEE80211.
- */
- if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_CHAR)
- break;
- if (priv[i].set_args & IW_PRIV_SIZE_FIXED)
- break;
- montype = MONITOR_RT73;
- cmd = priv[i].cmd;
- break;
- }
- if (strcmp(priv[i].name, "prismhdr") == 0) {
- /*
- * One of the RTL8xxx drivers, use this one.
- * It can only be done after monitor mode
- * has been turned on. You can set it to 1
- * to get DLT_PRISM or 0 to get DLT_IEEE80211.
- */
- if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
- break;
- if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
- break;
- if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1)
- break;
- montype = MONITOR_RTL8XXX;
- cmd = priv[i].cmd;
- break;
- }
- if (strcmp(priv[i].name, "rfmontx") == 0) {
- /*
- * RT2500 or RT61 driver, use this one.
- * It has one one-byte parameter; set
- * u.data.length to 1 and u.data.pointer to
- * point to the parameter.
- * It doesn't itself turn monitor mode on.
- * You can set it to 1 to allow transmitting
- * in monitor mode(?) and get DLT_IEEE80211,
- * or set it to 0 to disallow transmitting in
- * monitor mode(?) and get DLT_PRISM.
- */
- if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
- break;
- if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 2)
- break;
- montype = MONITOR_RT2500;
- cmd = priv[i].cmd;
- break;
- }
- if (strcmp(priv[i].name, "monitor") == 0) {
- /*
- * Either ACX100 or hostap, use this one.
- * It turns monitor mode on.
- * If it takes two arguments, it's ACX100;
- * the first argument is 1 for DLT_PRISM
- * or 2 for DLT_IEEE80211, and the second
- * argument is the channel on which to
- * run. If it takes one argument, it's
- * HostAP, and the argument is 2 for
- * DLT_IEEE80211 and 3 for DLT_PRISM.
- *
- * If we see this, we don't quit, as this
- * might be a version of the hostap driver
- * that also supports "monitor_type".
- */
- if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
- break;
- if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
- break;
- switch (priv[i].set_args & IW_PRIV_SIZE_MASK) {
-
- case 1:
- montype = MONITOR_PRISM;
- cmd = priv[i].cmd;
- break;
-
- case 2:
- montype = MONITOR_ACX100;
- cmd = priv[i].cmd;
- break;
-
- default:
- break;
- }
- }
+ if (ret < 0) {
+ /*
+ * Hard failure. Just return ret; handle->errbuf
+ * has already been set.
+ */
+ nl80211_cleanup(&nlstate);
+ return ret;
}
- free(priv);
}
- /*
- * XXX - ipw3945? islism?
- */
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "%s: No free monN interfaces", device);
+ nl80211_cleanup(&nlstate);
+ return PCAP_ERROR;
- /*
- * Get the old mode.
- */
- pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
- sizeof ireq.ifr_ifrn.ifrn_name);
- if (ioctl(sock_fd, SIOCGIWMODE, &ireq) == -1) {
- /*
- * We probably won't be able to set the mode, either.
- */
- return PCAP_ERROR_RFMON_NOTSUP;
- }
+added:
+#if 0
/*
- * Is it currently in monitor mode?
- */
- if (ireq.u.mode == IW_MODE_MONITOR) {
- /*
- * Yes. Just leave things as they are.
- * We don't offer multiple link-layer types, as
- * changing the link-layer type out from under
- * somebody else capturing in monitor mode would
- * be considered rude.
- */
- return 1;
- }
- /*
- * No. We have to put the adapter into rfmon mode.
+ * Sleep for .1 seconds.
*/
+ delay.tv_sec = 0;
+ delay.tv_nsec = 500000000;
+ nanosleep(&delay, NULL);
+#endif
/*
* If we haven't already done so, arrange to have
@@ -6232,277 +4574,47 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device)
* "atexit()" failed; don't put the interface
* in rfmon mode, just give up.
*/
- return PCAP_ERROR_RFMON_NOTSUP;
- }
-
- /*
- * Save the old mode.
- */
- handlep->oldmode = ireq.u.mode;
-
- /*
- * Put the adapter in rfmon mode. How we do this depends
- * on whether we have a special private ioctl or not.
- */
- if (montype == MONITOR_PRISM) {
- /*
- * We have the "monitor" private ioctl, but none of
- * the other private ioctls. Use this, and select
- * the Prism header.
- *
- * If it fails, just fall back on SIOCSIWMODE.
- */
- memset(&ireq, 0, sizeof ireq);
- pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
- sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.u.data.length = 1; /* 1 argument */
- args[0] = 3; /* request Prism header */
- memcpy(ireq.u.name, args, sizeof (int));
- if (ioctl(sock_fd, cmd, &ireq) != -1) {
- /*
- * Success.
- * Note that we have to put the old mode back
- * when we close the device.
- */
- handlep->must_do_on_close |= MUST_CLEAR_RFMON;
-
- /*
- * Add this to the list of pcaps to close
- * when we exit.
- */
- pcap_add_to_pcaps_to_close(handle);
-
- return 1;
- }
-
- /*
- * Failure. Fall back on SIOCSIWMODE.
- */
+ del_mon_if(handle, sock_fd, &nlstate, device,
+ handlep->mondevice);
+ nl80211_cleanup(&nlstate);
+ return PCAP_ERROR;
}
/*
- * First, take the interface down if it's up; otherwise, we
- * might get EBUSY.
+ * Now configure the monitor interface up.
*/
memset(&ifr, 0, sizeof(ifr));
- pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ pcap_strlcpy(ifr.ifr_name, handlep->mondevice, sizeof(ifr.ifr_name));
if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) {
pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
- errno, "%s: Can't get flags", device);
+ errno, "%s: Can't get flags for %s", device,
+ handlep->mondevice);
+ del_mon_if(handle, sock_fd, &nlstate, device,
+ handlep->mondevice);
+ nl80211_cleanup(&nlstate);
return PCAP_ERROR;
}
- oldflags = 0;
- if (ifr.ifr_flags & IFF_UP) {
- oldflags = ifr.ifr_flags;
- ifr.ifr_flags &= ~IFF_UP;
- if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) {
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno, "%s: Can't set flags",
- device);
- return PCAP_ERROR;
- }
- }
-
- /*
- * Then turn monitor mode on.
- */
- pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
- sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.u.mode = IW_MODE_MONITOR;
- if (ioctl(sock_fd, SIOCSIWMODE, &ireq) == -1) {
- /*
- * Scientist, you've failed.
- * Bring the interface back up if we shut it down.
- */
- ifr.ifr_flags = oldflags;
- if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) {
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno, "%s: Can't set flags",
- device);
- return PCAP_ERROR;
- }
- return PCAP_ERROR_RFMON_NOTSUP;
- }
-
- /*
- * XXX - airmon-ng does "iwconfig {if} key off" after setting
- * monitor mode and setting the channel, and then does
- * "iwconfig up".
- */
-
- /*
- * Now select the appropriate radio header.
- */
- switch (montype) {
-
- case MONITOR_WEXT:
- /*
- * We don't have any private ioctl to set the header.
- */
- break;
-
- case MONITOR_HOSTAP:
- /*
- * Try to select the radiotap header.
- */
- memset(&ireq, 0, sizeof ireq);
- pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
- sizeof ireq.ifr_ifrn.ifrn_name);
- args[0] = 3; /* request radiotap header */
- memcpy(ireq.u.name, args, sizeof (int));
- if (ioctl(sock_fd, cmd, &ireq) != -1)
- break; /* success */
-
- /*
- * That failed. Try to select the AVS header.
- */
- memset(&ireq, 0, sizeof ireq);
- pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
- sizeof ireq.ifr_ifrn.ifrn_name);
- args[0] = 2; /* request AVS header */
- memcpy(ireq.u.name, args, sizeof (int));
- if (ioctl(sock_fd, cmd, &ireq) != -1)
- break; /* success */
-
- /*
- * That failed. Try to select the Prism header.
- */
- memset(&ireq, 0, sizeof ireq);
- pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
- sizeof ireq.ifr_ifrn.ifrn_name);
- args[0] = 1; /* request Prism header */
- memcpy(ireq.u.name, args, sizeof (int));
- ioctl(sock_fd, cmd, &ireq);
- break;
-
- case MONITOR_PRISM:
- /*
- * The private ioctl failed.
- */
- break;
-
- case MONITOR_PRISM54:
- /*
- * Select the Prism header.
- */
- memset(&ireq, 0, sizeof ireq);
- pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
- sizeof ireq.ifr_ifrn.ifrn_name);
- args[0] = 3; /* request Prism header */
- memcpy(ireq.u.name, args, sizeof (int));
- ioctl(sock_fd, cmd, &ireq);
- break;
-
- case MONITOR_ACX100:
- /*
- * Get the current channel.
- */
- memset(&ireq, 0, sizeof ireq);
- pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
- sizeof ireq.ifr_ifrn.ifrn_name);
- if (ioctl(sock_fd, SIOCGIWFREQ, &ireq) == -1) {
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno, "%s: SIOCGIWFREQ", device);
- return PCAP_ERROR;
- }
- channel = ireq.u.freq.m;
-
- /*
- * Select the Prism header, and set the channel to the
- * current value.
- */
- memset(&ireq, 0, sizeof ireq);
- pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
- sizeof ireq.ifr_ifrn.ifrn_name);
- args[0] = 1; /* request Prism header */
- args[1] = channel; /* set channel */
- memcpy(ireq.u.name, args, 2*sizeof (int));
- ioctl(sock_fd, cmd, &ireq);
- break;
-
- case MONITOR_RT2500:
- /*
- * Disallow transmission - that turns on the
- * Prism header.
- */
- memset(&ireq, 0, sizeof ireq);
- pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
- sizeof ireq.ifr_ifrn.ifrn_name);
- args[0] = 0; /* disallow transmitting */
- memcpy(ireq.u.name, args, sizeof (int));
- ioctl(sock_fd, cmd, &ireq);
- break;
-
- case MONITOR_RT2570:
- /*
- * Force the Prism header.
- */
- memset(&ireq, 0, sizeof ireq);
- pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
- sizeof ireq.ifr_ifrn.ifrn_name);
- args[0] = 1; /* request Prism header */
- memcpy(ireq.u.name, args, sizeof (int));
- ioctl(sock_fd, cmd, &ireq);
- break;
-
- case MONITOR_RT73:
- /*
- * Force the Prism header.
- */
- memset(&ireq, 0, sizeof ireq);
- pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
- sizeof ireq.ifr_ifrn.ifrn_name);
- ireq.u.data.length = 1; /* 1 argument */
- ireq.u.data.pointer = "1";
- ireq.u.data.flags = 0;
- ioctl(sock_fd, cmd, &ireq);
- break;
-
- case MONITOR_RTL8XXX:
- /*
- * Force the Prism header.
- */
- memset(&ireq, 0, sizeof ireq);
- pcap_strlcpy(ireq.ifr_ifrn.ifrn_name, device,
- sizeof ireq.ifr_ifrn.ifrn_name);
- args[0] = 1; /* request Prism header */
- memcpy(ireq.u.name, args, sizeof (int));
- ioctl(sock_fd, cmd, &ireq);
- break;
+ ifr.ifr_flags |= IFF_UP|IFF_RUNNING;
+ if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) {
+ pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "%s: Can't set flags for %s", device,
+ handlep->mondevice);
+ del_mon_if(handle, sock_fd, &nlstate, device,
+ handlep->mondevice);
+ nl80211_cleanup(&nlstate);
+ return PCAP_ERROR;
}
/*
- * Now bring the interface back up if we brought it down.
+ * Success. Clean up the libnl state.
*/
- if (oldflags != 0) {
- ifr.ifr_flags = oldflags;
- if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) {
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno, "%s: Can't set flags",
- device);
-
- /*
- * At least try to restore the old mode on the
- * interface.
- */
- if (ioctl(handle->fd, SIOCSIWMODE, &ireq) == -1) {
- /*
- * Scientist, you've failed.
- */
- fprintf(stderr,
- "Can't restore interface wireless mode (SIOCSIWMODE failed: %s).\n"
- "Please adjust manually.\n",
- strerror(errno));
- }
- return PCAP_ERROR;
- }
- }
+ nl80211_cleanup(&nlstate);
/*
- * Note that we have to put the old mode back when we
- * close the device.
+ * Note that we have to delete the monitor device when we close
+ * the handle.
*/
- handlep->must_do_on_close |= MUST_CLEAR_RFMON;
+ handlep->must_do_on_close |= MUST_DELETE_MONIF;
/*
* Add this to the list of pcaps to close when we exit.
@@ -6511,41 +4623,16 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device)
return 1;
}
-#endif /* IW_MODE_MONITOR */
-
-/*
- * Try various mechanisms to enter monitor mode.
- */
+#else /* HAVE_LIBNL */
static int
-enter_rfmon_mode(pcap_t *handle, int sock_fd, const char *device)
+enter_rfmon_mode(pcap_t *handle _U_, int sock_fd _U_, const char *device _U_)
{
-#if defined(HAVE_LIBNL) || defined(IW_MODE_MONITOR)
- int ret;
-#endif
-
-#ifdef HAVE_LIBNL
- ret = enter_rfmon_mode_mac80211(handle, sock_fd, device);
- if (ret < 0)
- return ret; /* error attempting to do so */
- if (ret == 1)
- return 1; /* success */
-#endif /* HAVE_LIBNL */
-
-#ifdef IW_MODE_MONITOR
- ret = enter_rfmon_mode_wext(handle, sock_fd, device);
- if (ret < 0)
- return ret; /* error attempting to do so */
- if (ret == 1)
- return 1; /* success */
-#endif /* IW_MODE_MONITOR */
-
/*
- * Either none of the mechanisms we know about work or none
- * of those mechanisms are available, so we can't do monitor
- * mode.
+ * We don't have libnl, so we can't do monitor mode.
*/
return 0;
}
+#endif /* HAVE_LIBNL */
#if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP)
/*
@@ -6564,15 +4651,21 @@ static const struct {
/*
* Set the list of time stamping types to include all types.
*/
-static void
-iface_set_all_ts_types(pcap_t *handle)
+static int
+iface_set_all_ts_types(pcap_t *handle, char *ebuf)
{
u_int i;
- handle->tstamp_type_count = NUM_SOF_TIMESTAMPING_TYPES;
handle->tstamp_type_list = malloc(NUM_SOF_TIMESTAMPING_TYPES * sizeof(u_int));
+ if (handle->tstamp_type_list == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return -1;
+ }
for (i = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++)
handle->tstamp_type_list[i] = sof_ts_type_map[i].pcap_tstamp_val;
+ handle->tstamp_type_count = NUM_SOF_TIMESTAMPING_TYPES;
+ return 0;
}
#ifdef ETHTOOL_GET_TS_INFO
@@ -6603,7 +4696,7 @@ iface_ethtool_get_ts_info(const char *device, pcap_t *handle, char *ebuf)
/*
* Create a socket from which to fetch time stamping capabilities.
*/
- fd = socket(PF_UNIX, SOCK_RAW, 0);
+ fd = get_if_ioctl_socket();
if (fd < 0) {
pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
errno, "socket for SIOCETHTOOL(ETHTOOL_GET_TS_INFO)");
@@ -6628,7 +4721,8 @@ iface_ethtool_get_ts_info(const char *device, pcap_t *handle, char *ebuf)
* asking for the time stamping types, so let's
* just return all the possible types.
*/
- iface_set_all_ts_types(handle);
+ if (iface_set_all_ts_types(handle, ebuf) == -1)
+ return -1;
return 0;
case ENODEV:
@@ -6676,15 +4770,20 @@ iface_ethtool_get_ts_info(const char *device, pcap_t *handle, char *ebuf)
if (info.so_timestamping & sof_ts_type_map[i].soft_timestamping_val)
num_ts_types++;
}
- handle->tstamp_type_count = num_ts_types;
if (num_ts_types != 0) {
handle->tstamp_type_list = malloc(num_ts_types * sizeof(u_int));
+ if (handle->tstamp_type_list == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
+ errno, "malloc");
+ return -1;
+ }
for (i = 0, j = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++) {
if (info.so_timestamping & sof_ts_type_map[i].soft_timestamping_val) {
handle->tstamp_type_list[j] = sof_ts_type_map[i].pcap_tstamp_val;
j++;
}
}
+ handle->tstamp_type_count = num_ts_types;
} else
handle->tstamp_type_list = NULL;
@@ -6692,7 +4791,7 @@ iface_ethtool_get_ts_info(const char *device, pcap_t *handle, char *ebuf)
}
#else /* ETHTOOL_GET_TS_INFO */
static int
-iface_ethtool_get_ts_info(const char *device, pcap_t *handle, char *ebuf _U_)
+iface_ethtool_get_ts_info(const char *device, pcap_t *handle, char *ebuf)
{
/*
* This doesn't apply to the "any" device; you can't say "turn on
@@ -6710,14 +4809,14 @@ iface_ethtool_get_ts_info(const char *device, pcap_t *handle, char *ebuf _U_)
* We don't have an ioctl to use to ask what's supported,
* so say we support everything.
*/
- iface_set_all_ts_types(handle);
+ if (iface_set_all_ts_types(handle, ebuf) == -1)
+ return -1;
return 0;
}
#endif /* ETHTOOL_GET_TS_INFO */
#endif /* defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) */
-#ifdef HAVE_PACKET_RING
/*
* Find out if we have any form of fragmentation/reassembly offloading.
*
@@ -6860,264 +4959,88 @@ iface_get_offload(pcap_t *handle _U_)
}
#endif /* SIOCETHTOOL */
-#endif /* HAVE_PACKET_RING */
-
-#endif /* HAVE_PF_PACKET_SOCKETS */
-
-/* ===== Functions to interface to the older kernels ================== */
+static struct dsa_proto {
+ const char *name;
+ bpf_u_int32 linktype;
+} dsa_protos[] = {
+ /*
+ * None is special and indicates that the interface does not have
+ * any tagging protocol configured, and is therefore a standard
+ * Ethernet interface.
+ */
+ { "none", DLT_EN10MB },
+ { "brcm", DLT_DSA_TAG_BRCM },
+ { "brcm-prepend", DLT_DSA_TAG_BRCM_PREPEND },
+ { "dsa", DLT_DSA_TAG_DSA },
+ { "edsa", DLT_DSA_TAG_EDSA },
+};
-/*
- * Try to open a packet socket using the old kernel interface.
- * Returns 1 on success and a PCAP_ERROR_ value on an error.
- */
static int
-activate_old(pcap_t *handle)
+iface_dsa_get_proto_info(const char *device, pcap_t *handle)
{
- struct pcap_linux *handlep = handle->priv;
- int err;
- int arptype;
- struct ifreq ifr;
- const char *device = handle->opt.device;
- struct utsname utsname;
- int mtu;
-
+ char *pathstr;
+ unsigned int i;
/*
- * PF_INET/SOCK_PACKET sockets must be bound to a device, so we
- * can't support the "any" device.
+ * Make this significantly smaller than PCAP_ERRBUF_SIZE;
+ * the tag *shouldn't* have some huge long name, and making
+ * it smaller keeps newer versions of GCC from whining that
+ * the error message if we don't support the tag could
+ * overflow the error message buffer.
*/
- if (strcmp(device, "any") == 0) {
- pcap_strlcpy(handle->errbuf, "pcap_activate: The \"any\" device isn't supported on 2.0[.x]-kernel systems",
- PCAP_ERRBUF_SIZE);
- return PCAP_ERROR;
- }
+ char buf[128];
+ ssize_t r;
+ int fd;
- /* Open the socket */
- handle->fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL));
- if (handle->fd == -1) {
- err = errno;
+ fd = asprintf(&pathstr, "/sys/class/net/%s/dsa/tagging", device);
+ if (fd < 0) {
pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
- err, "socket");
- if (err == EPERM || err == EACCES) {
- /*
- * You don't have permission to open the
- * socket.
- */
- return PCAP_ERROR_PERM_DENIED;
- } else {
- /*
- * Other error.
- */
- return PCAP_ERROR;
- }
- }
-
- /* It worked - we are using the old interface */
- handlep->sock_packet = 1;
-
- /* ...which means we get the link-layer header. */
- handlep->cooked = 0;
-
- /* Bind to the given device */
- if (iface_bind_old(handle->fd, device, handle->errbuf) == -1)
+ fd, "asprintf");
return PCAP_ERROR;
+ }
+ fd = open(pathstr, O_RDONLY);
+ free(pathstr);
/*
- * Try to get the link-layer type.
+ * This is not fatal, kernel >= 4.20 *might* expose this attribute
*/
- arptype = iface_get_arptype(handle->fd, device, handle->errbuf);
- if (arptype < 0)
- return PCAP_ERROR;
+ if (fd < 0)
+ return 0;
- /*
- * Try to find the DLT_ type corresponding to that
- * link-layer type.
- */
- map_arphrd_to_dlt(handle, handle->fd, arptype, device, 0);
- if (handle->linktype == -1) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
- "unknown arptype %d", arptype);
+ r = read(fd, buf, sizeof(buf) - 1);
+ if (r <= 0) {
+ pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "read");
+ close(fd);
return PCAP_ERROR;
}
-
- /* Go to promisc mode if requested */
-
- if (handle->opt.promisc) {
- memset(&ifr, 0, sizeof(ifr));
- pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
- if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) {
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno, "SIOCGIFFLAGS");
- return PCAP_ERROR;
- }
- if ((ifr.ifr_flags & IFF_PROMISC) == 0) {
- /*
- * Promiscuous mode isn't currently on,
- * so turn it on, and remember that
- * we should turn it off when the
- * pcap_t is closed.
- */
-
- /*
- * If we haven't already done so, arrange
- * to have "pcap_close_all()" called when
- * we exit.
- */
- if (!pcap_do_addexit(handle)) {
- /*
- * "atexit()" failed; don't put
- * the interface in promiscuous
- * mode, just give up.
- */
- return PCAP_ERROR;
- }
-
- ifr.ifr_flags |= IFF_PROMISC;
- if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1) {
- pcap_fmt_errmsg_for_errno(handle->errbuf,
- PCAP_ERRBUF_SIZE, errno, "SIOCSIFFLAGS");
- return PCAP_ERROR;
- }
- handlep->must_do_on_close |= MUST_CLEAR_PROMISC;
-
- /*
- * Add this to the list of pcaps
- * to close when we exit.
- */
- pcap_add_to_pcaps_to_close(handle);
- }
- }
-
- /*
- * Compute the buffer size.
- *
- * We're using SOCK_PACKET, so this might be a 2.0[.x]
- * kernel, and might require special handling - check.
- */
- if (uname(&utsname) < 0 ||
- strncmp(utsname.release, "2.0", 3) == 0) {
- /*
- * Either we couldn't find out what kernel release
- * this is, or it's a 2.0[.x] kernel.
- *
- * In the 2.0[.x] kernel, a "recvfrom()" on
- * a SOCK_PACKET socket, with MSG_TRUNC set, will
- * return the number of bytes read, so if we pass
- * a length based on the snapshot length, it'll
- * return the number of bytes from the packet
- * copied to userland, not the actual length
- * of the packet.
- *
- * This means that, for example, the IP dissector
- * in tcpdump will get handed a packet length less
- * than the length in the IP header, and will
- * complain about "truncated-ip".
- *
- * So we don't bother trying to copy from the
- * kernel only the bytes in which we're interested,
- * but instead copy them all, just as the older
- * versions of libpcap for Linux did.
- *
- * The buffer therefore needs to be big enough to
- * hold the largest packet we can get from this
- * device. Unfortunately, we can't get the MRU
- * of the network; we can only get the MTU. The
- * MTU may be too small, in which case a packet larger
- * than the buffer size will be truncated *and* we
- * won't get the actual packet size.
- *
- * However, if the snapshot length is larger than
- * the buffer size based on the MTU, we use the
- * snapshot length as the buffer size, instead;
- * this means that with a sufficiently large snapshot
- * length we won't artificially truncate packets
- * to the MTU-based size.
- *
- * This mess just one of many problems with packet
- * capture on 2.0[.x] kernels; you really want a
- * 2.2[.x] or later kernel if you want packet capture
- * to work well.
- */
- mtu = iface_get_mtu(handle->fd, device, handle->errbuf);
- if (mtu == -1)
- return PCAP_ERROR;
- handle->bufsize = MAX_LINKHEADER_SIZE + mtu;
- if (handle->bufsize < (u_int)handle->snapshot)
- handle->bufsize = (u_int)handle->snapshot;
- } else {
- /*
- * This is a 2.2[.x] or later kernel.
- *
- * We can safely pass "recvfrom()" a byte count
- * based on the snapshot length.
- *
- * XXX - this "should not happen", as 2.2[.x]
- * kernels all have PF_PACKET sockets, and there's
- * no configuration option to disable them without
- * disabling SOCK_PACKET sockets, because
- * SOCK_PACKET sockets are implemented in the same
- * source file, net/packet/af_packet.c. There *is*
- * an option to disable SOCK_PACKET sockets so that
- * you only have PF_PACKET sockets, and the kernel
- * will log warning messages for code that uses
- * "obsolete (PF_INET,SOCK_PACKET)".
- */
- handle->bufsize = (u_int)handle->snapshot;
- }
-
- /*
- * Default value for offset to align link-layer payload
- * on a 4-byte boundary.
- */
- handle->offset = 0;
+ close(fd);
/*
- * SOCK_PACKET sockets don't supply information from
- * stripped VLAN tags.
+ * Buffer should be LF terminated.
*/
- handlep->vlan_offset = -1; /* unknown */
-
- return 1;
-}
-
-/*
- * Bind the socket associated with FD to the given device using the
- * interface of the old kernels.
- */
-static int
-iface_bind_old(int fd, const char *device, char *ebuf)
-{
- struct sockaddr saddr;
- int err;
- socklen_t errlen = sizeof(err);
-
- memset(&saddr, 0, sizeof(saddr));
- pcap_strlcpy(saddr.sa_data, device, sizeof(saddr.sa_data));
- if (bind(fd, &saddr, sizeof(saddr)) == -1) {
- pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
- errno, "bind");
- return -1;
- }
-
- /* Any pending errors, e.g., network is down? */
-
- if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
- pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
- errno, "getsockopt (SO_ERROR)");
- return -1;
+ if (buf[r - 1] == '\n')
+ r--;
+ buf[r] = '\0';
+
+ for (i = 0; i < sizeof(dsa_protos) / sizeof(dsa_protos[0]); i++) {
+ if (strlen(dsa_protos[i].name) == (size_t)r &&
+ strcmp(buf, dsa_protos[i].name) == 0) {
+ handle->linktype = dsa_protos[i].linktype;
+ switch (dsa_protos[i].linktype) {
+ case DLT_EN10MB:
+ return 0;
+ default:
+ return 1;
+ }
+ }
}
- if (err > 0) {
- pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
- err, "bind");
- return -1;
- }
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "unsupported DSA tag: %s", buf);
- return 0;
+ return PCAP_ERROR;
}
-
-/* ===== System calls available on all supported kernels ============== */
-
/*
* Query the kernel for the MTU of the given interface.
*/
@@ -7169,9 +5092,8 @@ iface_get_arptype(int fd, const char *device, char *ebuf)
return ifr.ifr_hwaddr.sa_family;
}
-#ifdef SO_ATTACH_FILTER
static int
-fix_program(pcap_t *handle, struct sock_fprog *fcode, int is_mmapped)
+fix_program(pcap_t *handle, struct sock_fprog *fcode)
{
struct pcap_linux *handlep = handle->priv;
size_t prog_size;
@@ -7203,39 +5125,6 @@ fix_program(pcap_t *handle, struct sock_fprog *fcode, int is_mmapped)
*/
switch (BPF_CLASS(p->code)) {
- case BPF_RET:
- /*
- * It's a return instruction; are we capturing
- * in memory-mapped mode?
- */
- if (!is_mmapped) {
- /*
- * No; is the snapshot length a constant,
- * rather than the contents of the
- * accumulator?
- */
- if (BPF_MODE(p->code) == BPF_K) {
- /*
- * Yes - if the value to be returned,
- * i.e. the snapshot length, is
- * anything other than 0, make it
- * MAXIMUM_SNAPLEN, so that the packet
- * is truncated by "recvfrom()",
- * not by the filter.
- *
- * XXX - there's nothing we can
- * easily do if it's getting the
- * value from the accumulator; we'd
- * have to insert code to force
- * non-zero values to be
- * MAXIMUM_SNAPLEN.
- */
- if (p->k != 0)
- p->k = MAXIMUM_SNAPLEN;
- }
- }
- break;
-
case BPF_LD:
case BPF_LDX:
/*
@@ -7301,6 +5190,12 @@ fix_offset(pcap_t *handle, struct bpf_insn *p)
* special magic kernel offset for that field.
*/
p->k = SKF_AD_OFF + SKF_AD_PROTOCOL;
+ } else if (p->k == 4) {
+ /*
+ * It's the ifindex field; map it to the
+ * special magic kernel offset for that field.
+ */
+ p->k = SKF_AD_OFF + SKF_AD_IFINDEX;
} else if (p->k == 10) {
/*
* It's the packet type field; map it to the
@@ -7503,7 +5398,6 @@ reset_kernel_filter(pcap_t *handle)
return -1;
return 0;
}
-#endif
int
pcap_set_protocol_linux(pcap_t *p, int protocol)
@@ -7520,15 +5414,9 @@ pcap_set_protocol_linux(pcap_t *p, int protocol)
const char *
pcap_lib_version(void)
{
-#ifdef HAVE_PACKET_RING
- #if defined(HAVE_TPACKET3)
+#if defined(HAVE_TPACKET3)
return (PCAP_VERSION_STRING " (with TPACKET_V3)");
- #elif defined(HAVE_TPACKET2)
- return (PCAP_VERSION_STRING " (with TPACKET_V2)");
- #else
- return (PCAP_VERSION_STRING " (with TPACKET_V1)");
- #endif
#else
- return (PCAP_VERSION_STRING " (without TPACKET)");
+ return (PCAP_VERSION_STRING " (with TPACKET_V2)");
#endif
}
diff --git a/pcap-netfilter-linux.c b/pcap-netfilter-linux.c
index 91bad371..17f528fc 100644
--- a/pcap-netfilter-linux.c
+++ b/pcap-netfilter-linux.c
@@ -56,13 +56,13 @@
#include <linux/netfilter/nfnetlink_log.h>
#include <linux/netfilter/nfnetlink_queue.h>
-/* NOTE: if your program drops privilages after pcap_activate() it WON'T work with nfqueue.
+/* NOTE: if your program drops privileges after pcap_activate() it WON'T work with nfqueue.
* It took me quite some time to debug ;/
*
- * Sending any data to nfnetlink socket requires CAP_NET_ADMIN privilages,
+ * Sending any data to nfnetlink socket requires CAP_NET_ADMIN privileges,
* and in nfqueue we need to send verdict reply after recving packet.
*
- * In tcpdump you can disable dropping privilages with -Z root
+ * In tcpdump you can disable dropping privileges with -Z root
*/
#include "pcap-netfilter-linux.h"
@@ -91,7 +91,7 @@ netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_c
struct pcap_netfilter *handlep = handle->priv;
register u_char *bp, *ep;
int count = 0;
- int len;
+ ssize_t len;
/*
* Has "pcap_breakloop()" been called?
@@ -152,14 +152,25 @@ netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_c
*/
if (handle->break_loop) {
handle->bp = bp;
- handle->cc = ep - bp;
+ handle->cc = (int)(ep - bp);
if (count == 0) {
handle->break_loop = 0;
return PCAP_ERROR_BREAK;
} else
return count;
}
- if (ep - bp < NLMSG_SPACE(0)) {
+ /*
+ * NLMSG_SPACE(0) might be signed or might be unsigned,
+ * depending on whether the kernel defines NLMSG_ALIGNTO
+ * as 4, which older kernels do, or as 4U, which newer
+ * kernels do.
+ *
+ * ep - bp is of type ptrdiff_t, which is signed.
+ *
+ * To squelch warnings, we cast both to size_t, which
+ * is unsigned; ep >= bp, so the cast is safe.
+ */
+ if ((size_t)(ep - bp) < (size_t)NLMSG_SPACE(0)) {
/*
* There's less than one netlink message left
* in the buffer. Give up.
@@ -168,7 +179,7 @@ netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_c
}
if (nlh->nlmsg_len < sizeof(struct nlmsghdr) || (u_int)len < nlh->nlmsg_len) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Message truncated: (got: %d) (nlmsg_len: %u)", len, nlh->nlmsg_len);
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Message truncated: (got: %zd) (nlmsg_len: %u)", len, nlh->nlmsg_len);
return -1;
}
@@ -190,7 +201,7 @@ netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_c
const struct nfattr *payload_attr = NULL;
if (nlh->nlmsg_len < HDR_LENGTH) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Malformed message: (nlmsg_len: %u)", nlh->nlmsg_len);
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Malformed message: (nlmsg_len: %u)", nlh->nlmsg_len);
return -1;
}
@@ -240,7 +251,7 @@ netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_c
gettimeofday(&pkth.ts, NULL);
if (handle->fcode.bf_insns == NULL ||
- bpf_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen))
+ pcap_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen))
{
handlep->packets_read++;
callback(user, &pkth, payload);
@@ -262,14 +273,21 @@ netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_c
* If the message length would run past the end of the
* buffer, truncate it to the remaining space in the
* buffer.
+ *
+ * To squelch warnings, we cast ep - bp to uint32_t, which
+ * is unsigned and is the type of msg_len; ep >= bp, and
+ * len should fit in 32 bits (either it's set from an int
+ * or it's set from a recv() call with a buffer size that's
+ * an int, and we're assuming either ILP32 or LP64), so
+ * the cast is safe.
*/
- if (msg_len > ep - bp)
- msg_len = ep - bp;
+ if (msg_len > (uint32_t)(ep - bp))
+ msg_len = (uint32_t)(ep - bp);
bp += msg_len;
if (count >= max_packets && !PACKET_COUNT_IS_UNLIMITED(max_packets)) {
handle->bp = bp;
- handle->cc = ep - bp;
+ handle->cc = (int)(ep - bp);
if (handle->cc < 0)
handle->cc = 0;
return count;
@@ -299,9 +317,9 @@ netfilter_stats_linux(pcap_t *handle, struct pcap_stat *stats)
}
static int
-netfilter_inject_linux(pcap_t *handle, const void *buf _U_, size_t size _U_)
+netfilter_inject_linux(pcap_t *handle, const void *buf _U_, int size _U_)
{
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Packet injection is not supported on netfilter devices");
return (-1);
}
@@ -363,7 +381,11 @@ netfilter_send_config_msg(const pcap_t *handle, uint16_t msg_type, int ack, u_in
/* ignore interrupt system call error */
do {
- len = recvfrom(handle->fd, buf, sizeof(buf), 0, (struct sockaddr *) &snl, &addrlen);
+ /*
+ * The buffer is not so big that its size won't
+ * fit into an int.
+ */
+ len = (int)recvfrom(handle->fd, buf, sizeof(buf), 0, (struct sockaddr *) &snl, &addrlen);
} while ((len == -1) && (errno == EINTR));
if (len <= 0)
@@ -510,7 +532,7 @@ netfilter_activate(pcap_t* handle)
char *end_dev;
if (group_count == 32) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Maximum 32 netfilter groups! dev: %s",
handle->opt.device);
return PCAP_ERROR;
@@ -519,7 +541,7 @@ netfilter_activate(pcap_t* handle)
group_id = strtol(dev, &end_dev, 0);
if (end_dev != dev) {
if (group_id < 0 || group_id > 65535) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Netfilter group range from 0 to 65535 (got %ld)",
group_id);
return PCAP_ERROR;
@@ -535,7 +557,7 @@ netfilter_activate(pcap_t* handle)
}
if (type == OTHER || *dev) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Can't get netfilter group(s) index from %s",
handle->opt.device);
return PCAP_ERROR;
@@ -616,7 +638,7 @@ netfilter_activate(pcap_t* handle)
if (nflog_send_config_cmd(handle, groups[i], NFULNL_CFG_CMD_BIND, AF_UNSPEC) < 0) {
pcap_fmt_errmsg_for_errno(handle->errbuf,
PCAP_ERRBUF_SIZE, errno,
- "Can't listen on group group index");
+ "Can't listen on group index");
goto close_fail;
}
@@ -646,7 +668,7 @@ netfilter_activate(pcap_t* handle)
if (nfqueue_send_config_cmd(handle, groups[i], NFQNL_CFG_CMD_BIND, AF_UNSPEC) < 0) {
pcap_fmt_errmsg_for_errno(handle->errbuf,
PCAP_ERRBUF_SIZE, errno,
- "Can't listen on group group index");
+ "Can't listen on group index");
goto close_fail;
}
@@ -721,7 +743,7 @@ netfilter_create(const char *device, char *ebuf, int *is_ours)
/* OK, it's probably ours. */
*is_ours = 1;
- p = pcap_create_common(ebuf, sizeof (struct pcap_netfilter));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_netfilter);
if (p == NULL)
return (NULL);
diff --git a/pcap-netmap.c b/pcap-netmap.c
index b2301a7f..27d36e5b 100644
--- a/pcap-netmap.c
+++ b/pcap-netmap.c
@@ -29,7 +29,6 @@
#endif
#include <poll.h>
-#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
@@ -82,7 +81,7 @@ pcap_netmap_filter(u_char *arg, struct pcap_pkthdr *h, const u_char *buf)
const struct bpf_insn *pc = p->fcode.bf_insns;
++pn->rx_pkts;
- if (pc == NULL || bpf_filter(pc, buf, h->len, h->caplen))
+ if (pc == NULL || pcap_filter(pc, buf, h->len, h->caplen))
pn->cb(pn->cb_arg, h, buf);
}
@@ -117,7 +116,7 @@ pcap_netmap_dispatch(pcap_t *p, int cnt, pcap_handler cb, u_char *user)
/* XXX need to check the NIOCTXSYNC/poll */
static int
-pcap_netmap_inject(pcap_t *p, const void *buf, size_t size)
+pcap_netmap_inject(pcap_t *p, const void *buf, int size)
{
struct pcap_netmap *pn = p->priv;
struct nm_desc *d = pn->d;
@@ -287,7 +286,7 @@ pcap_netmap_create(const char *device, char *ebuf, int *is_ours)
*is_ours = (!strncmp(device, "netmap:", 7) || !strncmp(device, "vale", 4));
if (! *is_ours)
return NULL;
- p = pcap_create_common(ebuf, sizeof (struct pcap_netmap));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_netmap);
if (p == NULL)
return (NULL);
p->activate_op = pcap_netmap_activate;
diff --git a/pcap-new.c b/pcap-new.c
index e61cf6ab..7c006595 100644
--- a/pcap-new.c
+++ b/pcap-new.c
@@ -88,7 +88,7 @@ int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t
if (strlen(source) > PCAP_BUF_SIZE)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
return -1;
}
@@ -119,7 +119,7 @@ int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t
if (*alldevs == NULL)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"No interfaces found! Make sure libpcap/Npcap is properly installed"
" on the local machine.");
return -1;
@@ -209,7 +209,7 @@ int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t
}
/* Save the path for future reference */
- pcap_snprintf(path, sizeof(path), "%s", name);
+ snprintf(path, sizeof(path), "%s", name);
pathlen = strlen(path);
#ifdef _WIN32
@@ -224,7 +224,7 @@ int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t
if (filehandle == INVALID_HANDLE_VALUE)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
return -1;
}
@@ -237,7 +237,7 @@ int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t
if (filedata == NULL)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
return -1;
}
#endif
@@ -249,11 +249,11 @@ int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t
/* Skip the file if the pathname won't fit in the buffer */
if (pathlen + strlen(filedata.cFileName) >= sizeof(filename))
continue;
- pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName);
+ snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName);
#else
if (pathlen + strlen(filedata->d_name) >= sizeof(filename))
continue;
- pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata->d_name);
+ snprintf(filename, sizeof(filename), "%s%s", path, filedata->d_name);
#endif
fp = pcap_open_offline(filename, errbuf);
@@ -370,7 +370,7 @@ pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout,
if (strlen(source) > PCAP_BUF_SIZE)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
return NULL;
}
@@ -445,15 +445,15 @@ pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout,
fail:
if (status == PCAP_ERROR)
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
name, fp->errbuf);
else if (status == PCAP_ERROR_NO_SUCH_DEVICE ||
status == PCAP_ERROR_PERM_DENIED ||
status == PCAP_ERROR_PROMISC_PERM_DENIED)
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)",
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)",
name, pcap_statustostr(status), fp->errbuf);
else
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
name, pcap_statustostr(status));
pcap_close(fp);
return NULL;
diff --git a/pcap-nit.c b/pcap-nit.c
index 6a1a77c2..cfd95191 100644
--- a/pcap-nit.c
+++ b/pcap-nit.c
@@ -43,7 +43,6 @@
#include <netinet/tcp.h>
#include <netinet/tcpip.h>
-#include <ctype.h>
#include <errno.h>
#include <stdio.h>
@@ -168,7 +167,7 @@ pcap_read_nit(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
continue;
default:
- pcap_snprintf(p->errbuf, sizeof(p->errbuf),
+ snprintf(p->errbuf, sizeof(p->errbuf),
"bad nit state %d", nh->nh_state);
return (-1);
}
@@ -179,7 +178,7 @@ pcap_read_nit(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
caplen = nh->nh_wirelen;
if (caplen > p->snapshot)
caplen = p->snapshot;
- if (bpf_filter(p->fcode.bf_insns, cp, nh->nh_wirelen, caplen)) {
+ if (pcap_filter(p->fcode.bf_insns, cp, nh->nh_wirelen, caplen)) {
struct pcap_pkthdr h;
h.ts = nh->nh_timestamp;
h.len = nh->nh_wirelen;
@@ -197,7 +196,7 @@ pcap_read_nit(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
}
static int
-pcap_inject_nit(pcap_t *p, const void *buf, size_t size)
+pcap_inject_nit(pcap_t *p, const void *buf, int size)
{
struct sockaddr sa;
int ret;
@@ -371,7 +370,7 @@ pcap_create_interface(const char *device _U_, char *ebuf)
{
pcap_t *p;
- p = pcap_create_common(ebuf, sizeof (struct pcap_nit));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_nit);
if (p == NULL)
return (NULL);
diff --git a/pcap-npf.c b/pcap-npf.c
index da4641f3..f12c7018 100644
--- a/pcap-npf.c
+++ b/pcap-npf.c
@@ -41,6 +41,17 @@
#include <pcap-int.h>
#include <pcap/dlt.h>
+/*
+ * XXX - Packet32.h defines bpf_program, so we can't include
+ * <pcap/bpf.h>, which also defines it; that's why we define
+ * PCAP_DONT_INCLUDE_PCAP_BPF_H,
+ *
+ * However, no header in the WinPcap or Npcap SDKs defines the
+ * macros for BPF code, so we have to define them ourselves.
+ */
+#define BPF_RET 0x06
+#define BPF_K 0x00
+
/* Old-school MinGW have these headers in a different place.
*/
#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
@@ -55,6 +66,10 @@
#include <dagapi.h>
#endif /* HAVE_DAG_API */
+#include "diag-control.h"
+
+#include "pcap-airpcap.h"
+
static int pcap_setfilter_npf(pcap_t *, struct bpf_program *);
static int pcap_setfilter_win32_dag(pcap_t *, struct bpf_program *);
static int pcap_getnonblock_npf(pcap_t *);
@@ -155,7 +170,7 @@ oid_get_request(ADAPTER *adapter, bpf_u_int32 oid, void *data, size_t *lenp,
*/
oid_data_arg = malloc(sizeof (PACKET_OID_DATA) + *lenp);
if (oid_data_arg == NULL) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Couldn't allocate argument buffer for PacketRequest");
return (PCAP_ERROR);
}
@@ -240,13 +255,13 @@ pcap_stats_npf(pcap_t *p, struct pcap_stat *ps)
* have an API that returns data in a form like the Options section of a
* pcapng Interface Statistics Block:
*
- * http://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://raw.githubusercontent.com/pcapng/pcapng/master/draft-tuexen-opsawg-pcapng.xml&modeAsFormat=html/ascii&type=ascii#rfc.section.4.6
+ * https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://raw.githubusercontent.com/pcapng/pcapng/master/draft-tuexen-opsawg-pcapng.xml&modeAsFormat=html/ascii&type=ascii#rfc.section.4.6
*
* which would let us add new statistics straightforwardly and indicate which
* statistics we are and are *not* providing, rather than having to provide
* possibly-bogus values for statistics we can't provide.
*/
-struct pcap_stat *
+static struct pcap_stat *
pcap_stats_ex_npf(pcap_t *p, int *pcap_stat_size)
{
struct pcap_win *pw = p->priv;
@@ -269,7 +284,12 @@ pcap_stats_ex_npf(pcap_t *p, int *pcap_stat_size)
p->stat.ps_recv = bstats.bs_recv;
p->stat.ps_drop = bstats.bs_drop;
p->stat.ps_ifdrop = bstats.ps_ifdrop;
-#ifdef ENABLE_REMOTE
+ /*
+ * Just in case this is ever compiled for a target other than
+ * Windows, which is somewhere between extremely unlikely and
+ * impossible.
+ */
+#ifdef _WIN32
p->stat.ps_capt = bstats.bs_capt;
#endif
return (&p->stat);
@@ -283,7 +303,7 @@ pcap_setbuff_npf(pcap_t *p, int dim)
if(PacketSetBuff(pw->adapter,dim)==FALSE)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer");
return (-1);
}
return (0);
@@ -297,7 +317,7 @@ pcap_setmode_npf(pcap_t *p, int mode)
if(PacketSetMode(pw->adapter,mode)==FALSE)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: working mode not recognized");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: working mode not recognized");
return (-1);
}
@@ -312,7 +332,7 @@ pcap_setmintocopy_npf(pcap_t *p, int size)
if(PacketSetMinToCopy(pw->adapter, size)==FALSE)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: unable to set the requested mintocopy size");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: unable to set the requested mintocopy size");
return (-1);
}
return (0);
@@ -350,7 +370,7 @@ pcap_oid_set_request_npf(pcap_t *p, bpf_u_int32 oid, const void *data,
*/
oid_data_arg = malloc(sizeof (PACKET_OID_DATA) + *lenp);
if (oid_data_arg == NULL) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Couldn't allocate argument buffer for PacketRequest");
return (PCAP_ERROR);
}
@@ -383,12 +403,6 @@ pcap_sendqueue_transmit_npf(pcap_t *p, pcap_send_queue *queue, int sync)
struct pcap_win *pw = p->priv;
u_int res;
- if (pw->adapter==NULL) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "Cannot transmit a queue to an offline capture or to a TurboCap port");
- return (0);
- }
-
res = PacketSendPackets(pw->adapter,
queue->buffer,
queue->len,
@@ -396,7 +410,7 @@ pcap_sendqueue_transmit_npf(pcap_t *p, pcap_send_queue *queue, int sync)
if(res != queue->len){
pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
- GetLastError(), "Error opening adapter");
+ GetLastError(), "Error queueing packets");
}
return (res);
@@ -409,7 +423,7 @@ pcap_setuserbuffer_npf(pcap_t *p, int size)
if (size<=0) {
/* Bogus parameter */
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Error: invalid size %d",size);
return (-1);
}
@@ -418,7 +432,7 @@ pcap_setuserbuffer_npf(pcap_t *p, int size)
new_buff=(unsigned char*)malloc(sizeof(char)*size);
if (!new_buff) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Error: not enough memory");
return (-1);
}
@@ -440,7 +454,7 @@ pcap_live_dump_npf(pcap_t *p, char *filename, int maxsize, int maxpacks)
/* Set the packet driver in dump mode */
res = PacketSetMode(pw->adapter, PACKET_MODE_DUMP);
if(res == FALSE){
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Error setting dump mode");
return (-1);
}
@@ -448,7 +462,7 @@ pcap_live_dump_npf(pcap_t *p, char *filename, int maxsize, int maxpacks)
/* Set the name of the dump file */
res = PacketSetDumpName(pw->adapter, filename, (int)strlen(filename));
if(res == FALSE){
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Error setting kernel dump file name");
return (-1);
}
@@ -456,8 +470,8 @@ pcap_live_dump_npf(pcap_t *p, char *filename, int maxsize, int maxpacks)
/* Set the limits of the dump file */
res = PacketSetDumpLimits(pw->adapter, maxsize, maxpacks);
if(res == FALSE) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "Error setting dump limit");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Error setting dump limit");
return (-1);
}
@@ -472,30 +486,34 @@ pcap_live_dump_ended_npf(pcap_t *p, int sync)
return (PacketIsDumpEnded(pw->adapter, (BOOLEAN)sync));
}
+#ifdef HAVE_AIRPCAP_API
static PAirpcapHandle
pcap_get_airpcap_handle_npf(pcap_t *p)
{
-#ifdef HAVE_AIRPCAP_API
struct pcap_win *pw = p->priv;
return (PacketGetAirPcapHandle(pw->adapter));
-#else
+}
+#else /* HAVE_AIRPCAP_API */
+static PAirpcapHandle
+pcap_get_airpcap_handle_npf(pcap_t *p _U_)
+{
return (NULL);
-#endif /* HAVE_AIRPCAP_API */
}
+#endif /* HAVE_AIRPCAP_API */
static int
pcap_read_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
{
PACKET Packet;
int cc;
- int n = 0;
+ int n;
register u_char *bp, *ep;
u_char *datap;
struct pcap_win *pw = p->priv;
cc = p->cc;
- if (p->cc == 0) {
+ if (cc == 0) {
/*
* Has "pcap_breakloop()" been called?
*/
@@ -544,7 +562,7 @@ pcap_read_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
* documented as having error returns
* other than PCAP_ERROR or PCAP_ERROR_BREAK.
*/
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The interface disappeared");
} else {
pcap_fmt_errmsg_for_win32_err(p->errbuf,
@@ -565,9 +583,10 @@ pcap_read_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
* Loop through each packet.
*/
#define bhp ((struct bpf_hdr *)bp)
+ n = 0;
ep = bp + cc;
for (;;) {
- register int caplen, hdrlen;
+ register u_int caplen, hdrlen;
/*
* Has "pcap_breakloop()" been called?
@@ -601,13 +620,13 @@ pcap_read_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
* in kernel, no need to do it now - we already know
* the packet passed the filter.
*
- * XXX - bpf_filter() should always return TRUE if
+ * XXX - pcap_filter() should always return TRUE if
* handed a null pointer for the program, but it might
* just try to "run" the filter, so we check here.
*/
if (pw->filtering_in_kernel ||
p->fcode.bf_insns == NULL ||
- bpf_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) {
+ pcap_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) {
#ifdef ENABLE_REMOTE
switch (p->rmt_samp.method) {
@@ -706,7 +725,7 @@ pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
*/
PacketInitPacket(&Packet, (BYTE *)p->buffer, p->bufsize);
if (!PacketReceivePacket(pw->adapter, &Packet, TRUE)) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed");
return (-1);
}
@@ -814,7 +833,7 @@ pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
/* No underlaying filtering system. We need to filter on our own */
if (p->fcode.bf_insns)
{
- if (bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen) == 0)
+ if (pcap_filter(p->fcode.bf_insns, dp, packet_len, caplen) == 0)
{
/* Move to next packet */
header = (dag_record_t*)((char*)header + erf_record_len);
@@ -848,14 +867,14 @@ pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
/* Send a packet to the network */
static int
-pcap_inject_npf(pcap_t *p, const void *buf, size_t size)
+pcap_inject_npf(pcap_t *p, const void *buf, int size)
{
struct pcap_win *pw = p->priv;
PACKET pkt;
PacketInitPacket(&pkt, (PVOID)buf, size);
if(PacketSendPacket(pw->adapter,&pkt,TRUE) == FALSE) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: PacketSendPacket failed");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: PacketSendPacket failed");
return (-1);
}
@@ -864,7 +883,7 @@ pcap_inject_npf(pcap_t *p, const void *buf, size_t size)
* "pcap_inject()" is expected to return the number of bytes
* sent.
*/
- return ((int)size);
+ return (size);
}
static void
@@ -883,6 +902,16 @@ pcap_cleanup_npf(pcap_t *p)
pcap_cleanup_live_common(p);
}
+static void
+pcap_breakloop_npf(pcap_t *p)
+{
+ pcap_breakloop_common(p);
+ struct pcap_win *pw = p->priv;
+
+ /* XXX - what if this fails? */
+ SetEvent(PacketGetReadEvent(pw->adapter));
+}
+
static int
pcap_activate_npf(pcap_t *p)
{
@@ -890,6 +919,8 @@ pcap_activate_npf(pcap_t *p)
NetType type;
int res;
int status = 0;
+ struct bpf_insn total_insn;
+ struct bpf_program total_prog;
if (p->opt.rfmon) {
/*
@@ -921,7 +952,7 @@ pcap_activate_npf(pcap_t *p)
}
}
- /* Init WinSock */
+ /* Init Winsock if it hasn't already been initialized */
pcap_wsockinit();
pw->adapter = PacketOpenAdapter(p->opt.device);
@@ -933,12 +964,22 @@ pcap_activate_npf(pcap_t *p)
/*
* What error did we get when trying to open the adapter?
*/
- if (errcode == ERROR_BAD_UNIT) {
+ switch (errcode) {
+
+ case ERROR_BAD_UNIT:
/*
* There's no such device.
*/
return (PCAP_ERROR_NO_SUCH_DEVICE);
- } else {
+
+ case ERROR_ACCESS_DENIED:
+ /*
+ * There is, but we don't have permission to
+ * use it.
+ */
+ return (PCAP_ERROR_PERM_DENIED);
+
+ default:
/*
* Unknown - report details.
*/
@@ -1034,11 +1075,9 @@ pcap_activate_npf(pcap_t *p)
p->linktype = DLT_PPI;
break;
-#ifdef NdisMediumWirelessWan
case NdisMediumWirelessWan:
p->linktype = DLT_RAW;
break;
-#endif
default:
/*
@@ -1053,13 +1092,72 @@ pcap_activate_npf(pcap_t *p)
* some programs will report the warning.
*/
p->linktype = DLT_EN10MB;
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Unknown NdisMedium value %d, defaulting to DLT_EN10MB",
type.LinkType);
status = PCAP_WARNING;
break;
}
+#ifdef HAVE_PACKET_GET_TIMESTAMP_MODES
+ /*
+ * Set the timestamp type.
+ * (Yes, we require PacketGetTimestampModes(), not just
+ * PacketSetTimestampMode(). If we have the former, we
+ * have the latter, unless somebody's using a version
+ * of Npcap that they've hacked to provide the former
+ * but not the latter; if they've done that, either
+ * they're confused or they're trolling us.)
+ */
+ switch (p->opt.tstamp_type) {
+
+ case PCAP_TSTAMP_HOST_HIPREC_UNSYNCED:
+ /*
+ * Better than low-res, but *not* synchronized with
+ * the OS clock.
+ */
+ if (!PacketSetTimestampMode(pw->adapter, TIMESTAMPMODE_SINGLE_SYNCHRONIZATION))
+ {
+ pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
+ GetLastError(), "Cannot set the time stamp mode to TIMESTAMPMODE_SINGLE_SYNCHRONIZATION");
+ goto bad;
+ }
+ break;
+
+ case PCAP_TSTAMP_HOST_LOWPREC:
+ /*
+ * Low-res, but synchronized with the OS clock.
+ */
+ if (!PacketSetTimestampMode(pw->adapter, TIMESTAMPMODE_QUERYSYSTEMTIME))
+ {
+ pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
+ GetLastError(), "Cannot set the time stamp mode to TIMESTAMPMODE_QUERYSYSTEMTIME");
+ goto bad;
+ }
+ break;
+
+ case PCAP_TSTAMP_HOST_HIPREC:
+ /*
+ * High-res, and synchronized with the OS clock.
+ */
+ if (!PacketSetTimestampMode(pw->adapter, TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE))
+ {
+ pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
+ GetLastError(), "Cannot set the time stamp mode to TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE");
+ goto bad;
+ }
+ break;
+
+ case PCAP_TSTAMP_HOST:
+ /*
+ * XXX - do whatever the default is, for now.
+ * Set to the highest resolution that's synchronized
+ * with the system clock?
+ */
+ break;
+ }
+#endif /* HAVE_PACKET_GET_TIMESTAMP_MODES */
+
/*
* Turn a negative snapshot value (invalid), a snapshot value of
* 0 (unspecified), or a value bigger than the normal maximum
@@ -1077,7 +1175,9 @@ pcap_activate_npf(pcap_t *p)
if (PacketSetHwFilter(pw->adapter,NDIS_PACKET_TYPE_PROMISCUOUS) == FALSE)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to promiscuous mode");
+ pcap_fmt_errmsg_for_win32_err(p->errbuf,
+ PCAP_ERRBUF_SIZE, GetLastError(),
+ "failed to set hardware filter to promiscuous mode");
goto bad;
}
}
@@ -1095,7 +1195,9 @@ pcap_activate_npf(pcap_t *p)
NDIS_PACKET_TYPE_BROADCAST |
NDIS_PACKET_TYPE_MULTICAST) == FALSE)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to non-promiscuous mode");
+ pcap_fmt_errmsg_for_win32_err(p->errbuf,
+ PCAP_ERRBUF_SIZE, GetLastError(),
+ "failed to set hardware filter to non-promiscuous mode");
goto bad;
}
}
@@ -1112,12 +1214,12 @@ pcap_activate_npf(pcap_t *p)
* If the buffer size wasn't explicitly set, default to
* WIN32_DEFAULT_KERNEL_BUFFER_SIZE.
*/
- if (p->opt.buffer_size == 0)
- p->opt.buffer_size = WIN32_DEFAULT_KERNEL_BUFFER_SIZE;
+ if (p->opt.buffer_size == 0)
+ p->opt.buffer_size = WIN32_DEFAULT_KERNEL_BUFFER_SIZE;
if(PacketSetBuff(pw->adapter,p->opt.buffer_size)==FALSE)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer");
goto bad;
}
@@ -1166,7 +1268,7 @@ pcap_activate_npf(pcap_t *p)
int postype = 0;
char keyname[512];
- pcap_snprintf(keyname, sizeof(keyname), "%s\\CardParams\\%s",
+ snprintf(keyname, sizeof(keyname), "%s\\CardParams\\%s",
"SYSTEM\\CurrentControlSet\\Services\\DAG",
strstr(_strlwr(p->opt.device), "dag"));
do
@@ -1205,6 +1307,29 @@ pcap_activate_npf(pcap_t *p)
#endif /* HAVE_DAG_API */
}
+ /*
+ * If there's no filter program installed, there's
+ * no indication to the kernel of what the snapshot
+ * length should be, so no snapshotting is done.
+ *
+ * Therefore, when we open the device, we install
+ * an "accept everything" filter with the specified
+ * snapshot length.
+ */
+ total_insn.code = (u_short)(BPF_RET | BPF_K);
+ total_insn.jt = 0;
+ total_insn.jf = 0;
+ total_insn.k = p->snapshot;
+
+ total_prog.bf_len = 1;
+ total_prog.bf_insns = &total_insn;
+ if (!PacketSetBpf(pw->adapter, &total_prog)) {
+ pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
+ GetLastError(), "PacketSetBpf");
+ status = PCAP_ERROR;
+ goto bad;
+ }
+
PacketSetReadTimeout(pw->adapter, p->opt.timeout);
/* disable loopback capture if requested */
@@ -1212,7 +1337,7 @@ pcap_activate_npf(pcap_t *p)
{
if (!PacketSetLoopbackBehavior(pw->adapter, NPF_DISABLE_LOOPBACK))
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Unable to disable the capture of loopback packets.");
goto bad;
}
@@ -1241,6 +1366,7 @@ pcap_activate_npf(pcap_t *p)
p->getnonblock_op = pcap_getnonblock_npf;
p->setnonblock_op = pcap_setnonblock_npf;
p->stats_op = pcap_stats_npf;
+ p->breakloop_op = pcap_breakloop_npf;
p->stats_ex_op = pcap_stats_ex_npf;
p->setbuff_op = pcap_setbuff_npf;
p->setmode_op = pcap_setmode_npf;
@@ -1287,13 +1413,177 @@ pcap_t *
pcap_create_interface(const char *device _U_, char *ebuf)
{
pcap_t *p;
+#ifdef HAVE_PACKET_GET_TIMESTAMP_MODES
+ char *device_copy;
+ ADAPTER *adapter;
+ ULONG num_ts_modes;
+ BOOL ret;
+ DWORD error;
+ ULONG *modes;
+#endif
- p = pcap_create_common(ebuf, sizeof(struct pcap_win));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_win);
if (p == NULL)
return (NULL);
p->activate_op = pcap_activate_npf;
p->can_set_rfmon_op = pcap_can_set_rfmon_npf;
+
+#ifdef HAVE_PACKET_GET_TIMESTAMP_MODES
+ /*
+ * First, find out how many time stamp modes we have.
+ * To do that, we have to open the adapter.
+ *
+ * XXX - PacketOpenAdapter() takes a non-const pointer
+ * as an argument, so we make a copy of the argument and
+ * pass that to it.
+ */
+ device_copy = strdup(device);
+ adapter = PacketOpenAdapter(device_copy);
+ free(device_copy);
+ if (adapter != NULL)
+ {
+ /*
+ * Get the total number of time stamp modes.
+ *
+ * The buffer for PacketGetTimestampModes() is
+ * a sequence of 1 or more ULONGs. What's
+ * passed to PacketGetTimestampModes() should have
+ * the total number of ULONGs in the first ULONG;
+ * what's returned *from* PacketGetTimestampModes()
+ * has the total number of time stamp modes in
+ * the first ULONG.
+ *
+ * Yes, that means if there are N time stamp
+ * modes, the first ULONG should be set to N+1
+ * on input, and will be set to N on output.
+ *
+ * We first make a call to PacketGetTimestampModes()
+ * with a pointer to a single ULONG set to 1; the
+ * call should fail with ERROR_MORE_DATA (unless
+ * there are *no* modes, but that should never
+ * happen), and that ULONG should be set to the
+ * number of modes.
+ */
+ num_ts_modes = 1;
+ ret = PacketGetTimestampModes(adapter, &num_ts_modes);
+ if (!ret) {
+ /*
+ * OK, it failed. Did it fail with
+ * ERROR_MORE_DATA?
+ */
+ error = GetLastError();
+ if (error != ERROR_MORE_DATA) {
+ /*
+ * No, some other error. Fail.
+ */
+ pcap_fmt_errmsg_for_win32_err(ebuf,
+ PCAP_ERRBUF_SIZE, GetLastError(),
+ "Error calling PacketGetTimestampModes");
+ pcap_close(p);
+ return (NULL);
+ }
+
+ /*
+ * Yes, so we now know how many types to fetch.
+ *
+ * The buffer needs to have one ULONG for the
+ * count and num_ts_modes ULONGs for the
+ * num_ts_modes time stamp types.
+ */
+ modes = (ULONG *)malloc((1 + num_ts_modes) * sizeof(ULONG));
+ if (modes == NULL) {
+ /* Out of memory. */
+ /* XXX SET ebuf */
+ pcap_close(p);
+ return (NULL);
+ }
+ modes[0] = 1 + num_ts_modes;
+ if (!PacketGetTimestampModes(adapter, modes)) {
+ pcap_fmt_errmsg_for_win32_err(ebuf,
+ PCAP_ERRBUF_SIZE, GetLastError(),
+ "Error calling PacketGetTimestampModes");
+ free(modes);
+ pcap_close(p);
+ return (NULL);
+ }
+ if (modes[0] != num_ts_modes) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "First PacketGetTimestampModes() call gives %lu modes, second call gives %u modes",
+ num_ts_modes, modes[0]);
+ free(modes);
+ pcap_close(p);
+ return (NULL);
+ }
+ if (num_ts_modes != 0) {
+ u_int num_ts_types;
+
+ /*
+ * Allocate a buffer big enough for
+ * PCAP_TSTAMP_HOST (default) plus
+ * the explicitly specified modes.
+ */
+ p->tstamp_type_list = malloc((1 + modes[0]) * sizeof(u_int));
+ if (p->tstamp_type_list == NULL) {
+ /* XXX SET ebuf */
+ free(modes);
+ pcap_close(p);
+ return (NULL);
+ }
+ num_ts_types = 0;
+ p->tstamp_type_list[num_ts_types] =
+ PCAP_TSTAMP_HOST;
+ num_ts_types++;
+ for (ULONG i = 0; i < modes[0]; i++) {
+ switch (modes[i + 1]) {
+
+ case TIMESTAMPMODE_SINGLE_SYNCHRONIZATION:
+ /*
+ * Better than low-res,
+ * but *not* synchronized
+ * with the OS clock.
+ */
+ p->tstamp_type_list[num_ts_types] =
+ PCAP_TSTAMP_HOST_HIPREC_UNSYNCED;
+ num_ts_types++;
+ break;
+
+ case TIMESTAMPMODE_QUERYSYSTEMTIME:
+ /*
+ * Low-res, but synchronized
+ * with the OS clock.
+ */
+ p->tstamp_type_list[num_ts_types] =
+ PCAP_TSTAMP_HOST_LOWPREC;
+ num_ts_types++;
+ break;
+
+ case TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE:
+ /*
+ * High-res, and synchronized
+ * with the OS clock.
+ */
+ p->tstamp_type_list[num_ts_types] =
+ PCAP_TSTAMP_HOST_HIPREC;
+ num_ts_types++;
+ break;
+
+ default:
+ /*
+ * Unknown, so we can't
+ * report it.
+ */
+ break;
+ }
+ }
+ p->tstamp_type_count = num_ts_types;
+ free(modes);
+ }
+ }
+ PacketCloseAdapter(adapter);
+ }
+#endif /* HAVE_PACKET_GET_TIMESTAMP_MODES */
+
return (p);
}
@@ -1356,7 +1646,7 @@ pcap_setfilter_npf(pcap_t *p, struct bpf_program *fp)
}
/*
- * We filter at user level, since the kernel driver does't process the packets
+ * We filter at user level, since the kernel driver doesn't process the packets
*/
static int
pcap_setfilter_win32_dag(pcap_t *p, struct bpf_program *fp) {
@@ -1596,6 +1886,12 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
* running.
*/
break;
+
+ default:
+ /*
+ * Unknown.
+ */
+ break;
}
} else {
/*
@@ -1632,7 +1928,13 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
if (status == 0) {
/*
* We got the physical medium.
+ *
+ * XXX - we might want to check for NdisPhysicalMediumWiMax
+ * and NdisPhysicalMediumNative802_15_4 being
+ * part of the enum, and check for those in the "wireless"
+ * case.
*/
+DIAG_OFF_ENUM_SWITCH
switch (phys_medium) {
case NdisPhysicalMediumWirelessLan:
@@ -1649,10 +1951,11 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
default:
/*
- * Not wireless.
+ * Not wireless or unknown
*/
break;
}
+DIAG_ON_ENUM_SWITCH
}
#endif
@@ -1683,6 +1986,13 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
*/
*flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED;
break;
+
+ case MediaConnectStateUnknown:
+ default:
+ /*
+ * It's unknown whether it's connected or not.
+ */
+ break;
}
}
#else
@@ -1765,7 +2075,7 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
AdaptersName = (char*) malloc(NameLength);
if (AdaptersName == NULL)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot allocate enough memory to list the adapters.");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot allocate enough memory to list the adapters.");
return (-1);
}
@@ -1806,6 +2116,20 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
name = &AdaptersName[0];
while (*name != '\0') {
bpf_u_int32 flags = 0;
+
+#ifdef HAVE_AIRPCAP_API
+ /*
+ * Is this an AirPcap device?
+ * If so, ignore it; it'll get added later, by the
+ * AirPcap code.
+ */
+ if (device_is_airpcap(name, errbuf) == 1) {
+ name += strlen(name) + 1;
+ desc += strlen(desc) + 1;
+ continue;
+ }
+#endif
+
#ifdef HAVE_PACKET_IS_LOOPBACK_ADAPTER
/*
* Is this a loopback interface?
@@ -1861,10 +2185,26 @@ pcap_lookupdev(char *errbuf)
DWORD dwVersion;
DWORD dwWindowsMajorVersion;
-#pragma warning (push)
-#pragma warning (disable: 4996) /* disable MSVC's GetVersion() deprecated warning here */
+ /*
+ * We disable this in "new API" mode, because 1) in WinPcap/Npcap,
+ * it may return UTF-16 strings, for backwards-compatibility
+ * reasons, and we're also disabling the hack to make that work,
+ * for not-going-past-the-end-of-a-string reasons, and 2) we
+ * want its behavior to be consistent.
+ *
+ * In addition, it's not thread-safe, so we've marked it as
+ * deprecated.
+ */
+ if (pcap_new_api) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "pcap_lookupdev() is deprecated and is not supported in programs calling pcap_init()");
+ return (NULL);
+ }
+
+/* disable MSVC's GetVersion() deprecated warning here */
+DIAG_OFF_DEPRECATION
dwVersion = GetVersion(); /* get the OS version */
-#pragma warning (pop)
+DIAG_ON_DEPRECATION
dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) {
@@ -1895,7 +2235,7 @@ pcap_lookupdev(char *errbuf)
if(TAdaptersName == NULL)
{
- (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure");
+ (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure");
return NULL;
}
@@ -2056,7 +2396,7 @@ pcap_lib_version(void)
/*
* Generate the version string.
*/
- char *packet_version_string = PacketGetVersion();
+ const char *packet_version_string = PacketGetVersion();
if (strcmp(WINPCAP_VER_STRING, packet_version_string) == 0) {
/*
diff --git a/pcap-pf.c b/pcap-pf.c
index fde97bac..4563a225 100644
--- a/pcap-pf.c
+++ b/pcap-pf.c
@@ -48,7 +48,6 @@ struct rtentry;
#include <netinet/tcp.h>
#include <netinet/tcpip.h>
-#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
@@ -104,9 +103,7 @@ pcap_read_pf(pcap_t *pc, int cnt, pcap_handler callback, u_char *user)
register u_char *p, *bp;
register int cc, n, buflen, inc;
register struct enstamp *sp;
-#ifdef LBL_ALIGN
struct enstamp stamp;
-#endif
register u_int pad;
again:
@@ -160,19 +157,17 @@ pcap_read_pf(pcap_t *pc, int cnt, pcap_handler callback, u_char *user)
}
}
if (cc < sizeof(*sp)) {
- pcap_snprintf(pc->errbuf, sizeof(pc->errbuf),
+ snprintf(pc->errbuf, sizeof(pc->errbuf),
"pf short read (%d)", cc);
return (-1);
}
-#ifdef LBL_ALIGN
if ((long)bp & 3) {
sp = &stamp;
memcpy((char *)sp, (char *)bp, sizeof(*sp));
} else
-#endif
sp = (struct enstamp *)bp;
if (sp->ens_stamplen != sizeof(*sp)) {
- pcap_snprintf(pc->errbuf, sizeof(pc->errbuf),
+ snprintf(pc->errbuf, sizeof(pc->errbuf),
"pf short stamplen (%d)",
sp->ens_stamplen);
return (-1);
@@ -205,7 +200,7 @@ pcap_read_pf(pcap_t *pc, int cnt, pcap_handler callback, u_char *user)
* skipping that padding.
*/
if (pf->filtering_in_kernel ||
- bpf_filter(pc->fcode.bf_insns, p, sp->ens_count, buflen)) {
+ pcap_filter(pc->fcode.bf_insns, p, sp->ens_count, buflen)) {
struct pcap_pkthdr h;
pf->TotAccepted++;
h.ts = sp->ens_tstamp;
@@ -226,7 +221,7 @@ pcap_read_pf(pcap_t *pc, int cnt, pcap_handler callback, u_char *user)
}
static int
-pcap_inject_pf(pcap_t *p, const void *buf, size_t size)
+pcap_inject_pf(pcap_t *p, const void *buf, int size)
{
int ret;
@@ -261,7 +256,7 @@ pcap_stats_pf(pcap_t *p, struct pcap_stat *ps)
* full.
*
* "ps_ifdrop" counts packets dropped by the network
- * inteface (regardless of whether they would have passed
+ * interface (regardless of whether they would have passed
* the input filter, of course).
*
* If packet filtering is not being done in the kernel:
@@ -273,7 +268,7 @@ pcap_stats_pf(pcap_t *p, struct pcap_stat *ps)
* the userland filter.
*
* "ps_ifdrop" counts packets dropped by the network
- * inteface (regardless of whether they would have passed
+ * interface (regardless of whether they would have passed
* the input filter, of course).
*
* These statistics don't include packets not yet read from
@@ -331,7 +326,7 @@ pcap_activate_pf(pcap_t *p)
p->fd = pfopen(p->opt.device, O_RDONLY);
if (p->fd < 0) {
if (errno == EACCES) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"pf open: %s: Permission denied\n"
"your system may not be properly configured; see the packetfilter(4) man page",
p->opt.device);
@@ -464,7 +459,7 @@ pcap_activate_pf(pcap_t *p)
* framing", there's not much we can do, as that
* doesn't specify a particular type of header.
*/
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"unknown data-link type %u", devparams.end_dev_type);
err = PCAP_ERROR;
goto bad;
@@ -540,7 +535,7 @@ pcap_create_interface(const char *device _U_, char *ebuf)
{
pcap_t *p;
- p = pcap_create_common(ebuf, sizeof (struct pcap_pf));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_pf);
if (p == NULL)
return (NULL);
diff --git a/pcap-rdmasniff.c b/pcap-rdmasniff.c
index c50fe3fd..224821de 100644
--- a/pcap-rdmasniff.c
+++ b/pcap-rdmasniff.c
@@ -57,7 +57,7 @@ struct pcap_rdmasniff {
struct ibv_flow * flow;
struct ibv_mr * mr;
u_char * oneshot_buffer;
- unsigned port_num;
+ unsigned long port_num;
int cq_event;
u_int packets_recv;
};
@@ -156,7 +156,7 @@ rdmasniff_read(pcap_t *handle, int max_packets, pcap_handler callback, u_char *u
pktd = (u_char *) handle->buffer + wc.wr_id * RDMASNIFF_RECEIVE_SIZE;
if (handle->fcode.bf_insns == NULL ||
- bpf_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) {
+ pcap_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) {
callback(user, &pkth, pktd);
++priv->packets_recv;
++count;
@@ -197,21 +197,21 @@ rdmasniff_activate(pcap_t *handle)
priv->context = ibv_open_device(priv->rdma_device);
if (!priv->context) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Failed to open device %s", handle->opt.device);
goto error;
}
priv->pd = ibv_alloc_pd(priv->context);
if (!priv->pd) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Failed to alloc PD for device %s", handle->opt.device);
goto error;
}
priv->channel = ibv_create_comp_channel(priv->context);
if (!priv->channel) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Failed to create comp channel for device %s", handle->opt.device);
goto error;
}
@@ -219,7 +219,7 @@ rdmasniff_activate(pcap_t *handle)
priv->cq = ibv_create_cq(priv->context, RDMASNIFF_NUM_RECEIVES,
NULL, priv->channel, 0);
if (!priv->cq) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Failed to create CQ for device %s", handle->opt.device);
goto error;
}
@@ -233,7 +233,7 @@ rdmasniff_activate(pcap_t *handle)
qp_init_attr.qp_type = IBV_QPT_RAW_PACKET;
priv->qp = ibv_create_qp(priv->pd, &qp_init_attr);
if (!priv->qp) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Failed to create QP for device %s", handle->opt.device);
goto error;
}
@@ -242,7 +242,7 @@ rdmasniff_activate(pcap_t *handle)
qp_attr.qp_state = IBV_QPS_INIT;
qp_attr.port_num = priv->port_num;
if (ibv_modify_qp(priv->qp, &qp_attr, IBV_QP_STATE | IBV_QP_PORT)) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Failed to modify QP to INIT for device %s", handle->opt.device);
goto error;
}
@@ -250,7 +250,7 @@ rdmasniff_activate(pcap_t *handle)
memset(&qp_attr, 0, sizeof qp_attr);
qp_attr.qp_state = IBV_QPS_RTR;
if (ibv_modify_qp(priv->qp, &qp_attr, IBV_QP_STATE)) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Failed to modify QP to RTR for device %s", handle->opt.device);
goto error;
}
@@ -261,7 +261,7 @@ rdmasniff_activate(pcap_t *handle)
flow_attr.port = priv->port_num;
priv->flow = ibv_create_flow(priv->qp, &flow_attr);
if (!priv->flow) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Failed to create flow for device %s", handle->opt.device);
goto error;
}
@@ -269,21 +269,21 @@ rdmasniff_activate(pcap_t *handle)
handle->bufsize = RDMASNIFF_NUM_RECEIVES * RDMASNIFF_RECEIVE_SIZE;
handle->buffer = malloc(handle->bufsize);
if (!handle->buffer) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Failed to allocate receive buffer for device %s", handle->opt.device);
goto error;
}
priv->oneshot_buffer = malloc(RDMASNIFF_RECEIVE_SIZE);
if (!priv->oneshot_buffer) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Failed to allocate oneshot buffer for device %s", handle->opt.device);
goto error;
}
priv->mr = ibv_reg_mr(priv->pd, handle->buffer, handle->bufsize, IBV_ACCESS_LOCAL_WRITE);
if (!priv->mr) {
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Failed to register MR for device %s", handle->opt.device);
goto error;
}
@@ -361,14 +361,18 @@ rdmasniff_create(const char *device, char *ebuf, int *is_ours)
int numdev;
size_t namelen;
const char *port;
- unsigned port_num;
+ unsigned long port_num;
int i;
pcap_t *p = NULL;
*is_ours = 0;
dev_list = ibv_get_device_list(&numdev);
- if (!dev_list || !numdev) {
+ if (!dev_list) {
+ return NULL;
+ }
+ if (!numdev) {
+ ibv_free_device_list(dev_list);
return NULL;
}
@@ -391,7 +395,7 @@ rdmasniff_create(const char *device, char *ebuf, int *is_ours)
!strncmp(device, dev_list[i]->name, namelen)) {
*is_ours = 1;
- p = pcap_create_common(ebuf, sizeof (struct pcap_rdmasniff));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_rdmasniff);
if (p) {
p->activate_op = rdmasniff_activate;
priv = p->priv;
@@ -415,7 +419,7 @@ rdmasniff_findalldevs(pcap_if_list_t *devlistp, char *err_str)
int ret = 0;
dev_list = ibv_get_device_list(&numdev);
- if (!dev_list || !numdev) {
+ if (!dev_list) {
return 0;
}
@@ -426,11 +430,10 @@ rdmasniff_findalldevs(pcap_if_list_t *devlistp, char *err_str)
*/
if (!add_dev(devlistp, dev_list[i]->name, 0, "RDMA sniffer", err_str)) {
ret = -1;
- goto out;
+ break;
}
}
-out:
ibv_free_device_list(dev_list);
return ret;
}
diff --git a/pcap-rpcap.c b/pcap-rpcap.c
index 705f06f2..a2612e99 100644
--- a/pcap-rpcap.c
+++ b/pcap-rpcap.c
@@ -46,6 +46,14 @@
#include "rpcap-protocol.h"
#include "pcap-rpcap.h"
+#ifdef _WIN32
+#include "charconv.h" /* for utf_8_to_acp_truncated() */
+#endif
+
+#ifdef HAVE_OPENSSL
+#include "sslutils.h"
+#endif
+
/*
* This file contains the pcap module for capturing from a remote machine's
* interfaces using the RPCAP protocol.
@@ -83,6 +91,7 @@ struct activehosts
{
struct sockaddr_storage host;
SOCKET sockctrl;
+ SSL *ssl;
uint8 protocol_version;
struct activehosts *next;
};
@@ -97,6 +106,7 @@ static struct activehosts *activeHosts;
* pcap_remoteact_cleanup() for more details.
*/
static SOCKET sockmain;
+static SSL *ssl_main;
/*
* Private data for capturing remotely using the rpcap protocol.
@@ -111,11 +121,13 @@ struct pcap_rpcap {
SOCKET rmt_sockctrl; /* socket ID of the socket used for the control connection */
SOCKET rmt_sockdata; /* socket ID of the socket used for the data connection */
+ SSL *ctrl_ssl, *data_ssl; /* optional transport of rmt_sockctrl and rmt_sockdata via TLS */
int rmt_flags; /* we have to save flags, since they are passed by the pcap_open_live(), but they are used by the pcap_startcapture() */
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 */
unsigned int TotNetDrops; /* keeps the number of packets that have been dropped by the network */
@@ -155,14 +167,14 @@ static void pcap_save_current_filter_rpcap(pcap_t *fp, const char *filter);
static int pcap_setfilter_rpcap(pcap_t *fp, struct bpf_program *prog);
static int pcap_setsampling_remote(pcap_t *fp);
static int pcap_startcapture_remote(pcap_t *fp);
-static int rpcap_recv_msg_header(SOCKET sock, struct rpcap_header *header, char *errbuf);
-static int rpcap_check_msg_ver(SOCKET sock, uint8 expected_ver, struct rpcap_header *header, char *errbuf);
-static int rpcap_check_msg_type(SOCKET sock, uint8 request_type, struct rpcap_header *header, uint16 *errcode, char *errbuf);
-static int rpcap_process_msg_header(SOCKET sock, uint8 ver, uint8 request_type, struct rpcap_header *header, char *errbuf);
-static int rpcap_recv(SOCKET sock, void *buffer, size_t toread, uint32 *plen, char *errbuf);
-static void rpcap_msg_err(SOCKET sockctrl, uint32 plen, char *remote_errbuf);
-static int rpcap_discard(SOCKET sock, uint32 len, char *errbuf);
-static int rpcap_read_packet_msg(SOCKET sock, pcap_t *p, size_t size);
+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_read_packet_msg(struct pcap_rpcap const *, pcap_t *p, size_t size);
/****************************************************
* *
@@ -375,7 +387,7 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
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;
- int retval; /* generic return value */
+ int retval = 0; /* generic return value */
int msglen;
/* Structures needed for the select() call */
@@ -387,29 +399,42 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
* 'timeout', in pcap_t, is in milliseconds; we have to convert it into sec and microsec
*/
tv.tv_sec = p->opt.timeout / 1000;
- tv.tv_usec = (p->opt.timeout - tv.tv_sec * 1000) * 1000;
+ tv.tv_usec = (suseconds_t)((p->opt.timeout - tv.tv_sec * 1000) * 1000);
- /* Watch out sockdata to see if it has input */
- FD_ZERO(&rfds);
+#ifdef HAVE_OPENSSL
+ /* Check if we still have bytes available in the last decoded TLS record.
+ * If that's the case, we know SSL_read will not block. */
+ retval = pr->data_ssl && SSL_pending(pr->data_ssl) > 0;
+#endif
+ if (! retval)
+ {
+ /* Watch out sockdata to see if it has input */
+ FD_ZERO(&rfds);
- /*
- * 'fp->rmt_sockdata' has always to be set before calling the select(),
- * since it is cleared by the select()
- */
- FD_SET(pr->rmt_sockdata, &rfds);
+ /*
+ * 'fp->rmt_sockdata' has always to be set before calling the select(),
+ * since it is cleared by the select()
+ */
+ FD_SET(pr->rmt_sockdata, &rfds);
- retval = select((int) pr->rmt_sockdata + 1, &rfds, NULL, NULL, &tv);
- if (retval == -1)
- {
-#ifndef _WIN32
- if (errno == EINTR)
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ retval = 1;
+#else
+ retval = select((int) pr->rmt_sockdata + 1, &rfds, NULL, NULL, &tv);
+#endif
+
+ if (retval == -1)
{
- /* Interrupted. */
- return 0;
- }
+#ifndef _WIN32
+ if (errno == EINTR)
+ {
+ /* Interrupted. */
+ return 0;
+ }
#endif
- sock_geterror("select()", p->errbuf, PCAP_ERRBUF_SIZE);
- return -1;
+ sock_geterror("select()", p->errbuf, PCAP_ERRBUF_SIZE);
+ return -1;
+ }
}
/* There is no data waiting, so return '0' */
@@ -427,7 +452,7 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
if (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP)
{
/* Read the entire message from the network */
- msglen = sock_recv_dgram(pr->rmt_sockdata, p->buffer,
+ msglen = sock_recv_dgram(pr->rmt_sockdata, pr->data_ssl, p->buffer,
p->bufsize, p->errbuf, PCAP_ERRBUF_SIZE);
if (msglen == -1)
{
@@ -444,7 +469,7 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
/*
* Message is shorter than an rpcap header.
*/
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"UDP packet message is shorter than an rpcap header");
return -1;
}
@@ -455,7 +480,7 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
* Message is shorter than the header claims it
* is.
*/
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"UDP packet message is shorter than its rpcap header claims");
return -1;
}
@@ -471,8 +496,7 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
* The size we should get is the size of the
* packet header.
*/
- status = rpcap_read_packet_msg(pr->rmt_sockdata, p,
- sizeof(struct rpcap_header));
+ status = rpcap_read_packet_msg(pr, p, sizeof(struct rpcap_header));
if (status == -1)
{
/* Network error. */
@@ -500,12 +524,11 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
* subtracting in order to avoid an
* overflow.)
*/
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Server sent us a message larger than the largest expected packet message");
return -1;
}
- status = rpcap_read_packet_msg(pr->rmt_sockdata, p,
- sizeof(struct rpcap_header) + plen);
+ status = rpcap_read_packet_msg(pr, p, sizeof(struct rpcap_header) + plen);
if (status == -1)
{
/* Network error. */
@@ -534,7 +557,7 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
/*
* Did the server specify the version we negotiated?
*/
- if (rpcap_check_msg_ver(pr->rmt_sockdata, pr->protocol_version,
+ if (rpcap_check_msg_ver(pr->rmt_sockdata, pr->data_ssl, pr->protocol_version,
header, p->errbuf) == -1)
{
return 0; /* Return 'no packets received' */
@@ -550,7 +573,7 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
if (ntohl(net_pkt_header->caplen) > plen)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Packet's captured data goes past the end of the received packet message.");
return -1;
}
@@ -678,7 +701,9 @@ static int pcap_read_rpcap(pcap_t *p, int cnt, pcap_handler callback, u_char *us
}
/*
- * This function sends a CLOSE command to the capture server.
+ * This function sends a CLOSE command to the capture server if we're in
+ * passive mode and an ENDCAP command to the capture server if we're in
+ * active mode.
*
* It is called when the user calls pcap_close(). It sends a command
* to our peer that says 'ok, let's stop capturing'.
@@ -714,7 +739,7 @@ static void pcap_cleanup_rpcap(pcap_t *fp)
* we're closing this pcap_t, and have no place to report
* the error. No reply is sent to this message.
*/
- (void)sock_send(pr->rmt_sockctrl, (char *)&header,
+ (void)sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&header,
sizeof(struct rpcap_header), NULL, 0);
}
else
@@ -727,7 +752,7 @@ static void pcap_cleanup_rpcap(pcap_t *fp)
* as we're closing this pcap_t, and have no place to
* report the error.
*/
- if (sock_send(pr->rmt_sockctrl, (char *)&header,
+ if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&header,
sizeof(struct rpcap_header), NULL, 0) == 0)
{
/*
@@ -735,11 +760,11 @@ static void pcap_cleanup_rpcap(pcap_t *fp)
* as we're closing this pcap_t, and have no
* place to report the error.
*/
- if (rpcap_process_msg_header(pr->rmt_sockctrl,
+ if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl,
pr->protocol_version, RPCAP_MSG_ENDCAP_REQ,
&header, NULL) == 0)
{
- (void)rpcap_discard(pr->rmt_sockctrl,
+ (void)rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl,
header.plen, NULL);
}
}
@@ -747,14 +772,35 @@ static void pcap_cleanup_rpcap(pcap_t *fp)
if (pr->rmt_sockdata)
{
+#ifdef HAVE_OPENSSL
+ if (pr->data_ssl)
+ {
+ // Finish using the SSL handle for the data socket.
+ // This must be done *before* the socket is closed.
+ ssl_finish(pr->data_ssl);
+ pr->data_ssl = NULL;
+ }
+#endif
sock_close(pr->rmt_sockdata, NULL, 0);
pr->rmt_sockdata = 0;
}
if ((!active) && (pr->rmt_sockctrl))
+ {
+#ifdef HAVE_OPENSSL
+ if (pr->ctrl_ssl)
+ {
+ // Finish using the SSL handle for the control socket.
+ // This must be done *before* the socket is closed.
+ ssl_finish(pr->ctrl_ssl);
+ pr->ctrl_ssl = NULL;
+ }
+#endif
sock_close(pr->rmt_sockctrl, NULL, 0);
+ }
pr->rmt_sockctrl = 0;
+ pr->ctrl_ssl = NULL;
if (pr->currentfilter)
{
@@ -848,7 +894,7 @@ static struct pcap_stat *rpcap_stats_rpcap(pcap_t *p, struct pcap_stat *ps, int
if (mode != PCAP_STATS_STANDARD)
#endif
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Invalid stats mode %d", mode);
return NULL;
}
@@ -879,19 +925,19 @@ static struct pcap_stat *rpcap_stats_rpcap(pcap_t *p, struct pcap_stat *ps, int
RPCAP_MSG_STATS_REQ, 0, 0);
/* Send the PCAP_STATS command */
- if (sock_send(pr->rmt_sockctrl, (char *)&header,
+ if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&header,
sizeof(struct rpcap_header), p->errbuf, PCAP_ERRBUF_SIZE) < 0)
return NULL; /* Unrecoverable network error */
/* Receive and process the reply message header. */
- if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->protocol_version,
+ if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl, pr->protocol_version,
RPCAP_MSG_STATS_REQ, &header, p->errbuf) == -1)
return NULL; /* Error */
plen = header.plen;
/* Read the reply body */
- if (rpcap_recv(pr->rmt_sockctrl, (char *)&netstats,
+ if (rpcap_recv(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&netstats,
sizeof(struct rpcap_stats), &plen, p->errbuf) == -1)
goto error;
@@ -908,7 +954,7 @@ static struct pcap_stat *rpcap_stats_rpcap(pcap_t *p, struct pcap_stat *ps, int
#endif /* _WIN32 */
/* Discard the rest of the message. */
- if (rpcap_discard(pr->rmt_sockctrl, plen, p->errbuf) == -1)
+ if (rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, plen, p->errbuf) == -1)
goto error_nodiscard;
return ps;
@@ -919,7 +965,7 @@ error:
* We already reported an error; if this gets an error, just
* drive on.
*/
- (void)rpcap_discard(pr->rmt_sockctrl, plen, NULL);
+ (void)rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, plen, NULL);
error_nodiscard:
return NULL;
@@ -960,7 +1006,7 @@ rpcap_remoteact_getsock(const char *host, int *error, char *errbuf)
retval = getaddrinfo(host, "0", &hints, &addrinfo);
if (retval != 0)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "getaddrinfo() %s",
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "getaddrinfo() %s",
gai_strerror(retval));
*error = 1;
return NULL;
@@ -1039,6 +1085,10 @@ static int pcap_startcapture_remote(pcap_t *fp)
int sockbufsize = 0;
uint32 server_sockbufsize;
+ // Take the opportunity to clear pr->data_ssl before any goto error,
+ // as it seems pr->priv is not zeroed after its malloced.
+ pr->data_ssl = NULL;
+
/*
* Let's check if sampling has been required.
* If so, let's set it first
@@ -1178,18 +1228,18 @@ static int pcap_startcapture_remote(pcap_t *fp)
if (pcap_pack_bpffilter(fp, &sendbuf[sendbufidx], &sendbufidx, &fp->fcode))
goto error_nodiscard;
- if (sock_send(pr->rmt_sockctrl, sendbuf, sendbufidx, fp->errbuf,
+ if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, sendbuf, sendbufidx, fp->errbuf,
PCAP_ERRBUF_SIZE) < 0)
goto error_nodiscard;
/* Receive and process the reply message header. */
- if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->protocol_version,
+ if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl, pr->protocol_version,
RPCAP_MSG_STARTCAP_REQ, &header, fp->errbuf) == -1)
goto error_nodiscard;
plen = header.plen;
- if (rpcap_recv(pr->rmt_sockctrl, (char *)&startcapreply,
+ if (rpcap_recv(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&startcapreply,
sizeof(struct rpcap_startcapreply), &plen, fp->errbuf) == -1)
goto error;
@@ -1211,7 +1261,7 @@ static int pcap_startcapture_remote(pcap_t *fp)
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = ai_family; /* Use the same address family of the control socket */
hints.ai_socktype = (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) ? SOCK_DGRAM : SOCK_STREAM;
- pcap_snprintf(portdata, PCAP_BUF_SIZE, "%d", ntohs(startcapreply.portdata));
+ snprintf(portdata, PCAP_BUF_SIZE, "%d", ntohs(startcapreply.portdata));
/* Let's the server pick up a free network port for us */
if (sock_initaddress(host, portdata, &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1)
@@ -1248,6 +1298,14 @@ static int pcap_startcapture_remote(pcap_t *fp)
/* Let's save the socket of the data connection */
pr->rmt_sockdata = sockdata;
+#ifdef HAVE_OPENSSL
+ if (pr->uses_ssl)
+ {
+ pr->data_ssl = ssl_promotion(0, sockdata, fp->errbuf, PCAP_ERRBUF_SIZE);
+ if (! pr->data_ssl) goto error;
+ }
+#endif
+
/*
* Set the size of the socket buffer for the data socket.
* It has the same size as the local capture buffer used
@@ -1335,7 +1393,7 @@ static int pcap_startcapture_remote(pcap_t *fp)
fp->cc = 0;
/* Discard the rest of the message. */
- if (rpcap_discard(pr->rmt_sockctrl, plen, fp->errbuf) == -1)
+ if (rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, plen, fp->errbuf) == -1)
goto error_nodiscard;
/*
@@ -1375,14 +1433,36 @@ error:
* We already reported an error; if this gets an error, just
* drive on.
*/
- (void)rpcap_discard(pr->rmt_sockctrl, plen, NULL);
+ (void)rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, plen, NULL);
error_nodiscard:
- if ((sockdata) && (sockdata != -1)) /* we can be here because sockdata said 'error' */
+#ifdef HAVE_OPENSSL
+ if (pr->data_ssl)
+ {
+ // Finish using the SSL handle for the data socket.
+ // This must be done *before* the socket is closed.
+ ssl_finish(pr->data_ssl);
+ pr->data_ssl = NULL;
+ }
+#endif
+
+ /* we can be here because sockdata said 'error' */
+ if ((sockdata != 0) && (sockdata != INVALID_SOCKET))
sock_close(sockdata, NULL, 0);
if (!active)
+ {
+#ifdef HAVE_OPENSSL
+ if (pr->ctrl_ssl)
+ {
+ // Finish using the SSL handle for the control socket.
+ // This must be done *before* the socket is closed.
+ ssl_finish(pr->ctrl_ssl);
+ pr->ctrl_ssl = NULL;
+ }
+#endif
sock_close(pr->rmt_sockctrl, NULL, 0);
+ }
if (addrinfo != NULL)
freeaddrinfo(addrinfo);
@@ -1408,7 +1488,7 @@ error_nodiscard:
* This function can be called in two cases:
* - pcap_startcapture_remote() is called (we have to send the filter
* along with the 'start capture' command)
- * - we want to udpate the filter during a capture (i.e. pcap_setfilter()
+ * - we want to update the filter during a capture (i.e. pcap_setfilter()
* after the capture has been started)
*
* This function serializes the filter into the sending buffer ('sendbuf',
@@ -1515,19 +1595,19 @@ static int pcap_updatefilter_remote(pcap_t *fp, struct bpf_program *prog)
if (pcap_pack_bpffilter(fp, &sendbuf[sendbufidx], &sendbufidx, prog))
return -1;
- if (sock_send(pr->rmt_sockctrl, sendbuf, sendbufidx, fp->errbuf,
+ if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, sendbuf, sendbufidx, fp->errbuf,
PCAP_ERRBUF_SIZE) < 0)
return -1;
/* Receive and process the reply message header. */
- if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->protocol_version,
+ if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl, pr->protocol_version,
RPCAP_MSG_UPDATEFILTER_REQ, &header, fp->errbuf) == -1)
return -1;
/*
* It shouldn't have any contents; discard it if it does.
*/
- if (rpcap_discard(pr->rmt_sockctrl, header.plen, fp->errbuf) == -1)
+ if (rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, header.plen, fp->errbuf) == -1)
return -1;
return 0;
@@ -1672,7 +1752,7 @@ static int pcap_createfilter_norpcappkt(pcap_t *fp, struct bpf_program *prog)
mydataport) == -1)
{
/* Failed. */
- pcap_snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
"Can't allocate memory for new filter");
return -1;
}
@@ -1689,7 +1769,7 @@ static int pcap_createfilter_norpcappkt(pcap_t *fp, struct bpf_program *prog)
myaddress, peeraddress, mydataport) == -1)
{
/* Failed. */
- pcap_snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
"Can't allocate memory for new filter");
return -1;
}
@@ -1745,12 +1825,12 @@ static int pcap_setsampling_remote(pcap_t *fp)
* that do fit into the message.
*/
if (fp->rmt_samp.method < 0 || fp->rmt_samp.method > 255) {
- pcap_snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
"Invalid sampling method %d", fp->rmt_samp.method);
return -1;
}
if (fp->rmt_samp.value < 0 || fp->rmt_samp.value > 65535) {
- pcap_snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
"Invalid sampling value %d", fp->rmt_samp.value);
return -1;
}
@@ -1775,19 +1855,19 @@ static int pcap_setsampling_remote(pcap_t *fp)
sampling_pars->method = (uint8)fp->rmt_samp.method;
sampling_pars->value = (uint16)htonl(fp->rmt_samp.value);
- if (sock_send(pr->rmt_sockctrl, sendbuf, sendbufidx, fp->errbuf,
+ if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, sendbuf, sendbufidx, fp->errbuf,
PCAP_ERRBUF_SIZE) < 0)
return -1;
/* Receive and process the reply message header. */
- if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->protocol_version,
+ if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl, pr->protocol_version,
RPCAP_MSG_SETSAMPLING_REQ, &header, fp->errbuf) == -1)
return -1;
/*
* It shouldn't have any contents; discard it if it does.
*/
- if (rpcap_discard(pr->rmt_sockctrl, header.plen, fp->errbuf) == -1)
+ if (rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, header.plen, fp->errbuf) == -1)
return -1;
return 0;
@@ -1831,7 +1911,7 @@ 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, uint8 *ver, struct pcap_rmtauth *auth, char *errbuf)
+static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8 *ver, struct pcap_rmtauth *auth, char *errbuf)
{
char sendbuf[RPCAP_NETBUF_SIZE]; /* temporary buffer in which data that has to be sent is buffered */
int sendbufidx = 0; /* index which keeps the number of bytes currently buffered */
@@ -1859,7 +1939,7 @@ static int rpcap_doauth(SOCKET sockctrl, uint8 *ver, struct pcap_rmtauth *auth,
str_length = strlen(auth->username);
if (str_length > 65535)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "User name is too long (> 65535 bytes)");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "User name is too long (> 65535 bytes)");
return -1;
}
length += (uint16)str_length;
@@ -1869,7 +1949,7 @@ static int rpcap_doauth(SOCKET sockctrl, uint8 *ver, struct pcap_rmtauth *auth,
str_length = strlen(auth->password);
if (str_length > 65535)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Password is too long (> 65535 bytes)");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Password is too long (> 65535 bytes)");
return -1;
}
length += (uint16)str_length;
@@ -1877,7 +1957,7 @@ static int rpcap_doauth(SOCKET sockctrl, uint8 *ver, struct pcap_rmtauth *auth,
break;
default:
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication type not recognized.");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication type not recognized.");
return -1;
}
@@ -1930,12 +2010,12 @@ static int rpcap_doauth(SOCKET sockctrl, uint8 *ver, struct pcap_rmtauth *auth,
rpauth->slen2 = htons(rpauth->slen2);
}
- if (sock_send(sockctrl, sendbuf, sendbufidx, errbuf,
+ if (sock_send(sockctrl, ssl, sendbuf, sendbufidx, errbuf,
PCAP_ERRBUF_SIZE) < 0)
return -1;
/* Receive and process the reply message header */
- if (rpcap_process_msg_header(sockctrl, 0, RPCAP_MSG_AUTH_REQ,
+ if (rpcap_process_msg_header(sockctrl, ssl, 0, RPCAP_MSG_AUTH_REQ,
&header, errbuf) == -1)
return -1;
@@ -1951,20 +2031,20 @@ static int rpcap_doauth(SOCKET sockctrl, uint8 *ver, struct pcap_rmtauth *auth,
if (plen < sizeof(struct rpcap_authreply))
{
/* No - discard it and fail. */
- (void)rpcap_discard(sockctrl, plen, NULL);
+ (void)rpcap_discard(sockctrl, ssl, plen, NULL);
return -1;
}
/* Read the reply body */
- if (rpcap_recv(sockctrl, (char *)&authreply,
+ if (rpcap_recv(sockctrl, ssl, (char *)&authreply,
sizeof(struct rpcap_authreply), &plen, errbuf) == -1)
{
- (void)rpcap_discard(sockctrl, plen, NULL);
+ (void)rpcap_discard(sockctrl, ssl, plen, NULL);
return -1;
}
/* Discard the rest of the message, if there is any. */
- if (rpcap_discard(sockctrl, plen, errbuf) == -1)
+ if (rpcap_discard(sockctrl, ssl, plen, errbuf) == -1)
return -1;
/*
@@ -1976,7 +2056,7 @@ static int rpcap_doauth(SOCKET sockctrl, uint8 *ver, struct pcap_rmtauth *auth,
/*
* Bogus - give up on this server.
*/
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"The server's minimum supported protocol version is greater than its maximum supported protocol version");
return -1;
}
@@ -2025,7 +2105,7 @@ novers:
/*
* There is no version we both support; that is a fatal error.
*/
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"The server doesn't support any protocol version that we support");
return -1;
}
@@ -2034,7 +2114,7 @@ novers:
static int
pcap_getnonblock_rpcap(pcap_t *p)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Non-blocking mode isn't supported for capturing remotely with rpcap");
return (-1);
}
@@ -2042,15 +2122,16 @@ pcap_getnonblock_rpcap(pcap_t *p)
static int
pcap_setnonblock_rpcap(pcap_t *p, int nonblock _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Non-blocking mode isn't supported for capturing remotely with rpcap");
return (-1);
}
static int
rpcap_setup_session(const char *source, struct pcap_rmtauth *auth,
- int *activep, SOCKET *sockctrlp, uint8 *protocol_versionp,
- char *host, char *port, char *iface, char *errbuf)
+ int *activep, SOCKET *sockctrlp, uint8 *uses_sslp, SSL **sslp,
+ int rmt_flags, uint8 *protocol_versionp, char *host, char *port,
+ char *iface, char *errbuf)
{
int type;
struct activehosts *activeconn; /* active connection, if there is one */
@@ -2061,7 +2142,8 @@ rpcap_setup_session(const char *source, struct pcap_rmtauth *auth,
* You must have a valid source string even if we're in active mode,
* because otherwise the call to the following function will fail.
*/
- if (pcap_parsesrcstr(source, &type, host, port, iface, errbuf) == -1)
+ if (pcap_parsesrcstr_ex(source, &type, host, port, iface, uses_sslp,
+ errbuf) == -1)
return -1;
/*
@@ -2069,13 +2151,25 @@ rpcap_setup_session(const char *source, struct pcap_rmtauth *auth,
*/
if (type != PCAP_SRC_IFREMOTE)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Non-remote interface passed to remote capture routine");
return -1;
}
+ /*
+ * We don't yet support DTLS, so if the user asks for a TLS
+ * connection and asks for data packets to be sent over UDP,
+ * we have to give up.
+ */
+ if (*uses_sslp && (rmt_flags & PCAP_OPENFLAG_DATATX_UDP))
+ {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "TLS not supported with UDP forward of remote packets");
+ return -1;
+ }
+
/* Warning: this call can be the first one called by the user. */
- /* For this reason, we have to initialize the WinSock support. */
+ /* For this reason, we have to initialize the Winsock support. */
if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
return -1;
@@ -2085,6 +2179,7 @@ rpcap_setup_session(const char *source, struct pcap_rmtauth *auth,
{
*activep = 1;
*sockctrlp = activeconn->sockctrl;
+ *sslp = activeconn->ssl;
*protocol_versionp = activeconn->protocol_version;
}
else
@@ -2134,9 +2229,36 @@ rpcap_setup_session(const char *source, struct pcap_rmtauth *auth,
freeaddrinfo(addrinfo);
addrinfo = NULL;
- if (rpcap_doauth(*sockctrlp, protocol_versionp, auth,
+ if (*uses_sslp)
+ {
+#ifdef HAVE_OPENSSL
+ *sslp = ssl_promotion(0, *sockctrlp, errbuf,
+ PCAP_ERRBUF_SIZE);
+ if (!*sslp)
+ {
+ sock_close(*sockctrlp, NULL, 0);
+ return -1;
+ }
+#else
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "No TLS support");
+ sock_close(*sockctrlp, NULL, 0);
+ return -1;
+#endif
+ }
+
+ if (rpcap_doauth(*sockctrlp, *sslp, protocol_versionp, auth,
errbuf) == -1)
{
+#ifdef HAVE_OPENSSL
+ if (*sslp)
+ {
+ // Finish using the SSL handle for the socket.
+ // This must be done *before* the socket is
+ // closed.
+ ssl_finish(*sslp);
+ }
+#endif
sock_close(*sockctrlp, NULL, 0);
return -1;
}
@@ -2190,6 +2312,7 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim
struct pcap_rpcap *pr; /* structure used when doing a remote live capture */
char host[PCAP_BUF_SIZE], ctrlport[PCAP_BUF_SIZE], iface[PCAP_BUF_SIZE];
SOCKET sockctrl;
+ SSL *ssl = NULL;
uint8 protocol_version; /* negotiated protocol version */
int active;
uint32 plen;
@@ -2200,7 +2323,7 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim
struct rpcap_header header; /* header of the RPCAP packet */
struct rpcap_openreply openreply; /* open reply message */
- fp = pcap_create_common(errbuf, sizeof (struct pcap_rpcap));
+ fp = PCAP_CREATE_COMMON(errbuf, struct pcap_rpcap);
if (fp == NULL)
{
return NULL;
@@ -2236,13 +2359,17 @@ 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,
- &protocol_version, host, ctrlport, iface, errbuf) == -1)
+ &pr->uses_ssl, &ssl, flags, &protocol_version, host, ctrlport,
+ iface, errbuf) == -1)
{
/* Session setup failed. */
pcap_close(fp);
return NULL;
}
+ /* All good so far, save the ssl handler */
+ ssl_main = ssl;
+
/*
* Now it's time to start playing with the RPCAP protocol
* RPCAP open command: create the request message
@@ -2258,29 +2385,29 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim
RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE))
goto error_nodiscard;
- if (sock_send(sockctrl, sendbuf, sendbufidx, errbuf,
+ if (sock_send(sockctrl, ssl, sendbuf, sendbufidx, errbuf,
PCAP_ERRBUF_SIZE) < 0)
goto error_nodiscard;
/* Receive and process the reply message header. */
- if (rpcap_process_msg_header(sockctrl, protocol_version,
+ if (rpcap_process_msg_header(sockctrl, ssl, protocol_version,
RPCAP_MSG_OPEN_REQ, &header, errbuf) == -1)
goto error_nodiscard;
plen = header.plen;
/* Read the reply body */
- if (rpcap_recv(sockctrl, (char *)&openreply,
+ if (rpcap_recv(sockctrl, ssl, (char *)&openreply,
sizeof(struct rpcap_openreply), &plen, errbuf) == -1)
goto error;
/* Discard the rest of the message, if there is any. */
- if (rpcap_discard(sockctrl, plen, errbuf) == -1)
+ if (rpcap_discard(sockctrl, ssl, plen, errbuf) == -1)
goto error_nodiscard;
/* Set proper fields into the pcap_t struct */
fp->linktype = ntohl(openreply.linktype);
- fp->tzoff = ntohl(openreply.tzoff);
pr->rmt_sockctrl = sockctrl;
+ pr->ctrl_ssl = ssl;
pr->protocol_version = protocol_version;
pr->rmt_clientside = 1;
@@ -2312,11 +2439,21 @@ error:
* We already reported an error; if this gets an error, just
* drive on.
*/
- (void)rpcap_discard(sockctrl, plen, NULL);
+ (void)rpcap_discard(sockctrl, pr->ctrl_ssl, plen, NULL);
error_nodiscard:
if (!active)
+ {
+#ifdef HAVE_OPENSSL
+ if (ssl)
+ {
+ // Finish using the SSL handle for the socket.
+ // This must be done *before* the socket is closed.
+ ssl_finish(ssl);
+ }
+#endif
sock_close(sockctrl, NULL, 0);
+ }
pcap_close(fp);
return NULL;
@@ -2344,11 +2481,13 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
{
uint8 protocol_version; /* protocol version */
SOCKET sockctrl; /* socket descriptor of the control connection */
+ SSL *ssl = NULL; /* optional SSL handler for sockctrl */
uint32 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;
char host[PCAP_BUF_SIZE], port[PCAP_BUF_SIZE];
char tmpstring[PCAP_BUF_SIZE + 1]; /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */
pcap_if_t *lastdev; /* Last device in the pcap_if_t list */
@@ -2361,8 +2500,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,
- &protocol_version, host, port, NULL, errbuf) == -1)
+ if (rpcap_setup_session(source, auth, &active, &sockctrl, &uses_ssl,
+ &ssl, 0, &protocol_version, host, port, NULL, errbuf) == -1)
{
/* Session setup failed. */
return -1;
@@ -2372,12 +2511,12 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
rpcap_createhdr(&header, protocol_version, RPCAP_MSG_FINDALLIF_REQ,
0, 0);
- if (sock_send(sockctrl, (char *)&header, sizeof(struct rpcap_header),
+ if (sock_send(sockctrl, ssl, (char *)&header, sizeof(struct rpcap_header),
errbuf, PCAP_ERRBUF_SIZE) < 0)
goto error_nodiscard;
/* Receive and process the reply message header. */
- if (rpcap_process_msg_header(sockctrl, protocol_version,
+ if (rpcap_process_msg_header(sockctrl, ssl, protocol_version,
RPCAP_MSG_FINDALLIF_REQ, &header, errbuf) == -1)
goto error_nodiscard;
@@ -2396,7 +2535,7 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
tmpstring2[PCAP_BUF_SIZE] = 0;
/* receive the findalldevs structure from remote host */
- if (rpcap_recv(sockctrl, (char *)&findalldevs_if,
+ if (rpcap_recv(sockctrl, ssl, (char *)&findalldevs_if,
sizeof(struct rpcap_findalldevs_if), &plen, errbuf) == -1)
goto error;
@@ -2440,20 +2579,20 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
if (findalldevs_if.namelen >= sizeof(tmpstring))
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface name too long");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface name too long");
goto error;
}
/* Retrieve adapter name */
- if (rpcap_recv(sockctrl, tmpstring,
+ if (rpcap_recv(sockctrl, ssl, tmpstring,
findalldevs_if.namelen, &plen, errbuf) == -1)
goto error;
tmpstring[findalldevs_if.namelen] = 0;
/* Create the new device identifier */
- if (pcap_createsrcstr(tmpstring2, PCAP_SRC_IFREMOTE,
- host, port, tmpstring, errbuf) == -1)
+ if (pcap_createsrcstr_ex(tmpstring2, PCAP_SRC_IFREMOTE,
+ host, port, tmpstring, uses_ssl, errbuf) == -1)
goto error;
dev->name = strdup(tmpstring2);
@@ -2469,12 +2608,12 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
{
if (findalldevs_if.desclen >= sizeof(tmpstring))
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface description too long");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface description too long");
goto error;
}
/* Retrieve adapter description */
- if (rpcap_recv(sockctrl, tmpstring,
+ if (rpcap_recv(sockctrl, ssl, tmpstring,
findalldevs_if.desclen, &plen, errbuf) == -1)
goto error;
@@ -2499,7 +2638,7 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
struct rpcap_findalldevs_ifaddr ifaddr;
/* Retrieve the interface addresses */
- if (rpcap_recv(sockctrl, (char *)&ifaddr,
+ if (rpcap_recv(sockctrl, ssl, (char *)&ifaddr,
sizeof(struct rpcap_findalldevs_ifaddr),
&plen, errbuf) == -1)
goto error;
@@ -2573,13 +2712,21 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
}
/* Discard the rest of the message. */
- if (rpcap_discard(sockctrl, plen, errbuf) == 1)
+ if (rpcap_discard(sockctrl, ssl, plen, errbuf) == 1)
goto error_nodiscard;
/* Control connection has to be closed only in case the remote machine is in passive mode */
if (!active)
{
/* DO not send RPCAP_CLOSE, since we did not open a pcap_t; no need to free resources */
+#ifdef HAVE_OPENSSL
+ if (ssl)
+ {
+ // Finish using the SSL handle for the socket.
+ // This must be done *before* the socket is closed.
+ ssl_finish(ssl);
+ }
+#endif
if (sock_close(sockctrl, errbuf, PCAP_ERRBUF_SIZE))
return -1;
}
@@ -2603,12 +2750,22 @@ error:
*
* Checks if all the data has been read; if not, discard the data in excess
*/
- (void) rpcap_discard(sockctrl, plen, NULL);
+ (void) rpcap_discard(sockctrl, ssl, plen, NULL);
error_nodiscard:
/* Control connection has to be closed only in case the remote machine is in passive mode */
if (!active)
+ {
+#ifdef HAVE_OPENSSL
+ if (ssl)
+ {
+ // Finish using the SSL handle for the socket.
+ // This must be done *before* the socket is closed.
+ ssl_finish(ssl);
+ }
+#endif
sock_close(sockctrl, NULL, 0);
+ }
/* To avoid inconsistencies in the number of sock_init() */
sock_cleanup();
@@ -2626,7 +2783,7 @@ error_nodiscard:
* to implement; we provide some APIs for it that work only with rpcap.
*/
-SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf)
+SOCKET pcap_remoteact_accept_ex(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, int uses_ssl, char *errbuf)
{
/* socket-related variables */
struct addrinfo hints; /* temporary struct to keep settings needed to open the new socket */
@@ -2634,6 +2791,7 @@ SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *
struct sockaddr_storage from; /* generic sockaddr_storage variable */
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 */
struct activehosts *temp, *prev; /* temp var needed to scan he host list chain */
@@ -2647,7 +2805,7 @@ SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *
hints.ai_socktype = SOCK_STREAM;
/* Warning: this call can be the first one called by the user. */
- /* For this reason, we have to initialize the WinSock support. */
+ /* For this reason, we have to initialize the Winsock support. */
if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
return (SOCKET)-1;
@@ -2691,11 +2849,36 @@ SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *
return (SOCKET)-2;
}
+ /* Promote to SSL early before any error message may be sent */
+ if (uses_ssl)
+ {
+#ifdef HAVE_OPENSSL
+ ssl = ssl_promotion(0, sockctrl, errbuf, PCAP_ERRBUF_SIZE);
+ if (! ssl)
+ {
+ sock_close(sockctrl, NULL, 0);
+ return (SOCKET)-1;
+ }
+#else
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "No TLS support");
+ sock_close(sockctrl, NULL, 0);
+ return (SOCKET)-1;
+#endif
+ }
+
/* 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);
- rpcap_senderror(sockctrl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+ rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+#ifdef HAVE_OPENSSL
+ if (ssl)
+ {
+ // Finish using the SSL handle for the socket.
+ // This must be done *before* the socket is closed.
+ ssl_finish(ssl);
+ }
+#endif
sock_close(sockctrl, NULL, 0);
return (SOCKET)-1;
}
@@ -2703,7 +2886,15 @@ SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *
/* checks if the connecting host is among the ones allowed */
if (sock_check_hostlist((char *)hostlist, RPCAP_HOSTLIST_SEP, &from, errbuf, PCAP_ERRBUF_SIZE) < 0)
{
- rpcap_senderror(sockctrl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+ rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+#ifdef HAVE_OPENSSL
+ if (ssl)
+ {
+ // Finish using the SSL handle for the socket.
+ // This must be done *before* the socket is closed.
+ ssl_finish(ssl);
+ }
+#endif
sock_close(sockctrl, NULL, 0);
return (SOCKET)-1;
}
@@ -2711,10 +2902,18 @@ SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *
/*
* Send authentication to the remote machine.
*/
- if (rpcap_doauth(sockctrl, &protocol_version, auth, errbuf) == -1)
+ if (rpcap_doauth(sockctrl, ssl, &protocol_version, auth, errbuf) == -1)
{
/* Unrecoverable error. */
- rpcap_senderror(sockctrl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+ rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+#ifdef HAVE_OPENSSL
+ if (ssl)
+ {
+ // Finish using the SSL handle for the socket.
+ // This must be done *before* the socket is closed.
+ ssl_finish(ssl);
+ }
+#endif
sock_close(sockctrl, NULL, 0);
return (SOCKET)-3;
}
@@ -2751,19 +2950,33 @@ SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *
{
pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
errno, "malloc() failed");
- rpcap_senderror(sockctrl, protocol_version, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+ rpcap_senderror(sockctrl, ssl, protocol_version, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+#ifdef HAVE_OPENSSL
+ if (ssl)
+ {
+ // Finish using the SSL handle for the socket.
+ // This must be done *before* the socket is closed.
+ ssl_finish(ssl);
+ }
+#endif
sock_close(sockctrl, NULL, 0);
return (SOCKET)-1;
}
memcpy(&temp->host, &from, fromlen);
temp->sockctrl = sockctrl;
+ temp->ssl = ssl;
temp->protocol_version = protocol_version;
temp->next = NULL;
return sockctrl;
}
+SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf)
+{
+ return pcap_remoteact_accept_ex(address, port, hostlist, connectinghost, auth, 0, errbuf);
+}
+
int pcap_remoteact_close(const char *host, char *errbuf)
{
struct activehosts *temp, *prev; /* temp var needed to scan the host list chain */
@@ -2782,7 +2995,7 @@ int pcap_remoteact_close(const char *host, char *errbuf)
retval = getaddrinfo(host, "0", &hints, &addrinfo);
if (retval != 0)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "getaddrinfo() %s", gai_strerror(retval));
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "getaddrinfo() %s", gai_strerror(retval));
return -1;
}
@@ -2804,7 +3017,7 @@ int pcap_remoteact_close(const char *host, char *errbuf)
* Don't check for errors, since we're
* just cleaning up.
*/
- if (sock_send(temp->sockctrl,
+ if (sock_send(temp->sockctrl, temp->ssl,
(char *)&header,
sizeof(struct rpcap_header), errbuf,
PCAP_ERRBUF_SIZE) < 0)
@@ -2813,12 +3026,32 @@ int pcap_remoteact_close(const char *host, char *errbuf)
* Let that error be the one we
* report.
*/
+#ifdef HAVE_OPENSSL
+ if (temp->ssl)
+ {
+ // Finish using the SSL handle
+ // for the socket.
+ // This must be done *before*
+ // the socket is closed.
+ ssl_finish(temp->ssl);
+ }
+#endif
(void)sock_close(temp->sockctrl, NULL,
0);
status = -1;
}
else
{
+#ifdef HAVE_OPENSSL
+ if (temp->ssl)
+ {
+ // Finish using the SSL handle
+ // for the socket.
+ // This must be done *before*
+ // the socket is closed.
+ ssl_finish(temp->ssl);
+ }
+#endif
if (sock_close(temp->sockctrl, errbuf,
PCAP_ERRBUF_SIZE) == -1)
status = -1;
@@ -2855,12 +3088,22 @@ int pcap_remoteact_close(const char *host, char *errbuf)
/* To avoid inconsistencies in the number of sock_init() */
sock_cleanup();
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The host you want to close the active connection is not known");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "The host you want to close the active connection is not known");
return -1;
}
void pcap_remoteact_cleanup(void)
{
+# ifdef HAVE_OPENSSL
+ if (ssl_main)
+ {
+ // Finish using the SSL handle for the main active socket.
+ // This must be done *before* the socket is closed.
+ ssl_finish(ssl_main);
+ ssl_main = NULL;
+ }
+# endif
+
/* Very dirty, but it works */
if (sockmain)
{
@@ -2869,7 +3112,6 @@ void pcap_remoteact_cleanup(void)
/* To avoid inconsistencies in the number of sock_init() */
sock_cleanup();
}
-
}
int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf)
@@ -2901,7 +3143,7 @@ int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf)
if ((size < 0) || (len >= (size_t)size))
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The string you provided is not able to keep "
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "The string you provided is not able to keep "
"the hostnames for all the active connections");
return -1;
}
@@ -2919,11 +3161,11 @@ int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf)
/*
* Receive the header of a message.
*/
-static int rpcap_recv_msg_header(SOCKET sock, struct rpcap_header *header, char *errbuf)
+static int rpcap_recv_msg_header(SOCKET sock, SSL *ssl, struct rpcap_header *header, char *errbuf)
{
int nrecv;
- nrecv = sock_recv(sock, (char *) header, sizeof(struct rpcap_header),
+ nrecv = sock_recv(sock, ssl, (char *) header, sizeof(struct rpcap_header),
SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
PCAP_ERRBUF_SIZE);
if (nrecv == -1)
@@ -2939,7 +3181,7 @@ static int rpcap_recv_msg_header(SOCKET sock, struct rpcap_header *header, char
* Make sure the protocol version of a received message is what we were
* expecting.
*/
-static int rpcap_check_msg_ver(SOCKET sock, uint8 expected_ver, struct rpcap_header *header, char *errbuf)
+static int rpcap_check_msg_ver(SOCKET sock, SSL *ssl, uint8 expected_ver, struct rpcap_header *header, char *errbuf)
{
/*
* Did the server specify the version we negotiated?
@@ -2949,7 +3191,7 @@ static int rpcap_check_msg_ver(SOCKET sock, uint8 expected_ver, struct rpcap_hea
/*
* Discard the rest of the message.
*/
- if (rpcap_discard(sock, header->plen, errbuf) == -1)
+ if (rpcap_discard(sock, ssl, header->plen, errbuf) == -1)
return -1;
/*
@@ -2957,7 +3199,7 @@ static int rpcap_check_msg_ver(SOCKET sock, uint8 expected_ver, struct rpcap_hea
*/
if (errbuf != NULL)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Server sent us a message with version %u when we were expecting %u",
header->ver, expected_ver);
}
@@ -2970,7 +3212,7 @@ static int rpcap_check_msg_ver(SOCKET sock, uint8 expected_ver, struct rpcap_hea
* 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, uint8 request_type, struct rpcap_header *header, uint16 *errcode, char *errbuf)
+static int rpcap_check_msg_type(SOCKET sock, SSL *ssl, uint8 request_type, struct rpcap_header *header, uint16 *errcode, char *errbuf)
{
const char *request_type_string;
const char *msg_type_string;
@@ -2985,7 +3227,7 @@ static int rpcap_check_msg_type(SOCKET sock, uint8 request_type, struct rpcap_he
* Hand that error back to our caller.
*/
*errcode = ntohs(header->value);
- rpcap_msg_err(sock, header->plen, errbuf);
+ rpcap_msg_err(sock, ssl, header->plen, errbuf);
return -1;
}
@@ -3004,7 +3246,7 @@ static int rpcap_check_msg_type(SOCKET sock, uint8 request_type, struct rpcap_he
/*
* Discard the rest of the message.
*/
- if (rpcap_discard(sock, header->plen, errbuf) == -1)
+ if (rpcap_discard(sock, ssl, header->plen, errbuf) == -1)
return -1;
/*
@@ -3017,17 +3259,17 @@ static int rpcap_check_msg_type(SOCKET sock, uint8 request_type, struct rpcap_he
if (request_type_string == NULL)
{
/* This should not happen. */
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"rpcap_check_msg_type called for request message with type %u",
request_type);
return -1;
}
if (msg_type_string != NULL)
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"%s message received in response to a %s message",
msg_type_string, request_type_string);
else
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Message of unknown type %u message received in response to a %s request",
header->type, request_type_string);
}
@@ -3040,11 +3282,11 @@ static int rpcap_check_msg_type(SOCKET sock, uint8 request_type, struct rpcap_he
/*
* Receive and process the header of a message.
*/
-static int rpcap_process_msg_header(SOCKET sock, uint8 expected_ver, uint8 request_type, struct rpcap_header *header, char *errbuf)
+static int rpcap_process_msg_header(SOCKET sock, SSL *ssl, uint8 expected_ver, uint8 request_type, struct rpcap_header *header, char *errbuf)
{
uint16 errcode;
- if (rpcap_recv_msg_header(sock, header, errbuf) == -1)
+ if (rpcap_recv_msg_header(sock, ssl, header, errbuf) == -1)
{
/* Network error. */
return -1;
@@ -3053,13 +3295,13 @@ static int rpcap_process_msg_header(SOCKET sock, uint8 expected_ver, uint8 reque
/*
* Did the server specify the version we negotiated?
*/
- if (rpcap_check_msg_ver(sock, expected_ver, header, errbuf) == -1)
+ if (rpcap_check_msg_ver(sock, ssl, expected_ver, header, errbuf) == -1)
return -1;
/*
* Check the message type.
*/
- return rpcap_check_msg_type(sock, request_type, header,
+ return rpcap_check_msg_type(sock, ssl, request_type, header,
&errcode, errbuf);
}
@@ -3072,17 +3314,17 @@ static int rpcap_process_msg_header(SOCKET sock, uint8 expected_ver, uint8 reque
* Returns 0 on success, logs a message and returns -1 on a network
* error.
*/
-static int rpcap_recv(SOCKET sock, void *buffer, size_t toread, uint32 *plen, char *errbuf)
+static int rpcap_recv(SOCKET sock, SSL *ssl, void *buffer, size_t toread, uint32 *plen, char *errbuf)
{
int nread;
if (toread > *plen)
{
/* The server sent us a bad message */
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Message payload is too short");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Message payload is too short");
return -1;
}
- nread = sock_recv(sock, buffer, toread,
+ nread = sock_recv(sock, ssl, buffer, toread,
SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE);
if (nread == -1)
{
@@ -3095,7 +3337,7 @@ static int rpcap_recv(SOCKET sock, void *buffer, size_t toread, uint32 *plen, ch
/*
* This handles the RPCAP_MSG_ERROR message.
*/
-static void rpcap_msg_err(SOCKET sockctrl, uint32 plen, char *remote_errbuf)
+static void rpcap_msg_err(SOCKET sockctrl, SSL *ssl, uint32 plen, char *remote_errbuf)
{
char errbuf[PCAP_ERRBUF_SIZE];
@@ -3105,12 +3347,12 @@ static void rpcap_msg_err(SOCKET sockctrl, uint32 plen, char *remote_errbuf)
* Message is too long; just read as much of it as we
* can into the buffer provided, and discard the rest.
*/
- if (sock_recv(sockctrl, remote_errbuf, PCAP_ERRBUF_SIZE - 1,
+ if (sock_recv(sockctrl, ssl, remote_errbuf, PCAP_ERRBUF_SIZE - 1,
SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
PCAP_ERRBUF_SIZE) == -1)
{
// Network error.
- pcap_snprintf(remote_errbuf, PCAP_ERRBUF_SIZE, "Read of error message from client failed: %s", errbuf);
+ snprintf(remote_errbuf, PCAP_ERRBUF_SIZE, "Read of error message from client failed: %s", errbuf);
return;
}
@@ -3119,10 +3361,19 @@ static void rpcap_msg_err(SOCKET sockctrl, uint32 plen, char *remote_errbuf)
*/
remote_errbuf[PCAP_ERRBUF_SIZE - 1] = '\0';
+#ifdef _WIN32
+ /*
+ * If we're not in UTF-8 mode, convert it to the local
+ * code page.
+ */
+ if (!pcap_utf_8_mode)
+ utf_8_to_acp_truncated(remote_errbuf);
+#endif
+
/*
* Throw away the rest.
*/
- (void)rpcap_discard(sockctrl, plen - (PCAP_ERRBUF_SIZE - 1), remote_errbuf);
+ (void)rpcap_discard(sockctrl, ssl, plen - (PCAP_ERRBUF_SIZE - 1), remote_errbuf);
}
else if (plen == 0)
{
@@ -3131,12 +3382,12 @@ static void rpcap_msg_err(SOCKET sockctrl, uint32 plen, char *remote_errbuf)
}
else
{
- if (sock_recv(sockctrl, remote_errbuf, plen,
+ if (sock_recv(sockctrl, ssl, remote_errbuf, plen,
SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
PCAP_ERRBUF_SIZE) == -1)
{
// Network error.
- pcap_snprintf(remote_errbuf, PCAP_ERRBUF_SIZE, "Read of error message from client failed: %s", errbuf);
+ snprintf(remote_errbuf, PCAP_ERRBUF_SIZE, "Read of error message from client failed: %s", errbuf);
return;
}
@@ -3153,11 +3404,11 @@ static void rpcap_msg_err(SOCKET sockctrl, uint32 plen, char *remote_errbuf)
* Returns 0 on success, logs a message and returns -1 on a network
* error.
*/
-static int rpcap_discard(SOCKET sock, uint32 len, char *errbuf)
+static int rpcap_discard(SOCKET sock, SSL *ssl, uint32 len, char *errbuf)
{
if (len != 0)
{
- if (sock_discard(sock, len, errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_discard(sock, ssl, len, errbuf, PCAP_ERRBUF_SIZE) == -1)
{
// Network error.
return -1;
@@ -3170,7 +3421,7 @@ static int rpcap_discard(SOCKET sock, uint32 len, char *errbuf)
* Read bytes into the pcap_t's buffer until we have the specified
* number of bytes read or we get an error or interrupt indication.
*/
-static int rpcap_read_packet_msg(SOCKET sock, pcap_t *p, size_t size)
+static int rpcap_read_packet_msg(struct pcap_rpcap const *rp, pcap_t *p, size_t size)
{
u_char *bp;
int cc;
@@ -3189,9 +3440,10 @@ static int rpcap_read_packet_msg(SOCKET sock, pcap_t *p, size_t size)
* We haven't read all of the packet header yet.
* Read what remains, which could be all of it.
*/
- bytes_read = sock_recv(sock, bp, size - cc,
+ bytes_read = sock_recv(rp->rmt_sockdata, rp->data_ssl, bp, size - cc,
SOCK_RECEIVEALL_NO|SOCK_EOF_IS_ERROR, p->errbuf,
PCAP_ERRBUF_SIZE);
+
if (bytes_read == -1)
{
/*
@@ -3220,7 +3472,7 @@ static int rpcap_read_packet_msg(SOCKET sock, pcap_t *p, size_t size)
* Update the read pointer and byte count, and
* return an error indication.
*/
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The server terminated the connection.");
return -1;
}
diff --git a/pcap-savefile.manfile.in b/pcap-savefile.manfile.in
index 748d7afc..a7ae9afb 100644
--- a/pcap-savefile.manfile.in
+++ b/pcap-savefile.manfile.in
@@ -17,7 +17,7 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP-SAVEFILE @MAN_FILE_FORMATS@ "8 March 2015"
+.TH PCAP-SAVEFILE @MAN_FILE_FORMATS@ "24 April 2020"
.SH NAME
pcap-savefile \- libpcap savefile format
.SH DESCRIPTION
@@ -51,6 +51,8 @@ Link-layer header type
.TE
.RE
.PP
+The per-file header length is 24 octets.
+.PP
All fields in the per-file header are in the byte order of the host
writing the file. Normally, the first field in the per-file header is a
4-byte magic number, with the value 0xa1b2c3d4. The magic number, when
@@ -117,6 +119,8 @@ Un-truncated length of the packet data
.TE
.RE
.PP
+The per-packet header length is 16 octets.
+.PP
All fields in the per-packet header are in the byte order of the host
writing the file. The per-packet header begins with a time stamp giving
the approximate time the packet was captured; the time stamp consists of
@@ -130,4 +134,4 @@ the packet not been truncated by the snapshot length. The two lengths
will be equal if the number of bytes of packet data are less than or
equal to the snapshot length.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap-septel.c b/pcap-septel.c
index 24cb47bb..e917edd7 100644
--- a/pcap-septel.c
+++ b/pcap-septel.c
@@ -17,7 +17,6 @@
#include "pcap-int.h"
-#include <ctype.h>
#include <netinet/in.h>
#include <sys/mman.h>
#include <sys/socket.h>
@@ -32,7 +31,6 @@
#include "pcap-septel.h"
-static int septel_setfilter(pcap_t *p, struct bpf_program *fp);
static int septel_stats(pcap_t *p, struct pcap_stat *ps);
static int septel_getnonblock(pcap_t *p);
static int septel_setnonblock(pcap_t *p, int nonblock);
@@ -47,7 +45,7 @@ struct pcap_septel {
/*
* Read at most max_packets from the capture queue and call the callback
* for each of them. Returns the number of packets handled, -1 if an
- * error occured, or -2 if we were told to break out of the loop.
+ * error occurred, or -2 if we were told to break out of the loop.
*/
static int septel_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) {
@@ -126,7 +124,7 @@ loop:
caplen = packet_len;
}
/* Run the packet filter if there is one. */
- if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) {
+ if ((p->fcode.bf_insns == NULL) || pcap_filter(p->fcode.bf_insns, dp, packet_len, caplen)) {
/* get a time stamp , consisting of :
@@ -171,7 +169,7 @@ loop:
static int
-septel_inject(pcap_t *handle, const void *buf _U_, size_t size _U_)
+septel_inject(pcap_t *handle, const void *buf _U_, int size _U_)
{
pcap_strlcpy(handle->errbuf, "Sending packets isn't supported on Septel cards",
PCAP_ERRBUF_SIZE);
@@ -209,7 +207,7 @@ static pcap_t *septel_activate(pcap_t* handle) {
handle->read_op = septel_read;
handle->inject_op = septel_inject;
- handle->setfilter_op = septel_setfilter;
+ handle->setfilter_op = install_bpf_program;
handle->set_datalink_op = NULL; /* can't change data link type */
handle->getnonblock_op = septel_getnonblock;
handle->setnonblock_op = septel_setnonblock;
@@ -235,7 +233,7 @@ pcap_t *septel_create(const char *device, char *ebuf, int *is_ours) {
/* OK, it's probably ours. */
*is_ours = 1;
- p = pcap_create_common(ebuf, sizeof (struct pcap_septel));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_septel);
if (p == NULL)
return NULL;
@@ -276,28 +274,6 @@ septel_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
/*
- * Installs the given bpf filter program in the given pcap structure. There is
- * no attempt to store the filter in kernel memory as that is not supported
- * with Septel cards.
- */
-static int septel_setfilter(pcap_t *p, struct bpf_program *fp) {
- if (!p)
- return -1;
- if (!fp) {
- strncpy(p->errbuf, "setfilter: No filter specified",
- sizeof(p->errbuf));
- return -1;
- }
-
- /* Make our private copy of the filter */
-
- if (install_bpf_program(p, fp) < 0)
- return -1;
-
- return (0);
-}
-
-/*
* We don't support non-blocking mode. I'm not sure what we'd
* do to support it and, given that we don't support select()/
* poll()/epoll_wait()/kevent() etc., it probably doesn't
@@ -338,7 +314,7 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
pcap_t *
pcap_create_interface(const char *device, char *errbuf)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"This version of libpcap only supports Septel cards");
return (NULL);
}
diff --git a/pcap-sita.c b/pcap-sita.c
index b9dda9c5..c53f3235 100644
--- a/pcap-sita.c
+++ b/pcap-sita.c
@@ -72,6 +72,14 @@ typedef struct unit {
int len; /* the current size of the inbound message */
} unit_t;
+/*
+ * Private data.
+ * Currently contains nothing.
+ */
+struct pcap_sita {
+ int dummy;
+};
+
static unit_t units[MAX_CHASSIS+1][MAX_GEOSLOT+1]; /* we use indexes of 1 through 8, but we reserve/waste index 0 */
static fd_set readfds; /* a place to store the file descriptors for the connections to the IOPs */
static int max_fs;
@@ -266,7 +274,7 @@ int acn_parse_hosts_file(char *errbuf) { /* returns: -1 = error, 0 = OK */
empty_unit_table();
if ((fp = fopen("/etc/hosts", "r")) == NULL) { /* try to open the hosts file and if it fails */
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot open '/etc/hosts' for reading."); /* return the nohostsfile error response */
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot open '/etc/hosts' for reading."); /* return the nohostsfile error response */
return -1;
}
while (fgets(buf, MAX_LINE_SIZE-1, fp)) { /* while looping over the file */
@@ -289,15 +297,15 @@ int acn_parse_hosts_file(char *errbuf) { /* returns: -1 = error, 0 = OK */
geoslot = *(ptr2 + 5) - '0'; /* and geo-slot number */
if (chassis < 1 || chassis > MAX_CHASSIS ||
geoslot < 1 || geoslot > MAX_GEOSLOT) { /* if the chassis and/or slot numbers appear to be bad... */
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Invalid ACN name in '/etc/hosts'."); /* warn the user */
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Invalid ACN name in '/etc/hosts'."); /* warn the user */
continue; /* and ignore the entry */
}
- if ((ptr2 = (char *)malloc(strlen(ptr) + 1)) == NULL) {
+ ptr2 = strdup(ptr); /* copy the IP address into our malloc'ed memory */
+ if (ptr2 == NULL) {
pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
errno, "malloc");
continue;
}
- strcpy(ptr2, ptr); /* copy the IP address into our malloc'ed memory */
u = &units[chassis][geoslot];
u->ip = ptr2; /* and remember the whole shebang */
u->chassis = chassis;
@@ -407,19 +415,18 @@ static void acn_freealldevs(void) {
static void nonUnified_IOP_port_name(char *buf, size_t bufsize, const char *proto, unit_t *u) {
- pcap_snprintf(buf, bufsize, "%s_%d_%d", proto, u->chassis, u->geoslot);
+ snprintf(buf, bufsize, "%s_%d_%d", proto, u->chassis, u->geoslot);
}
static void unified_IOP_port_name(char *buf, size_t bufsize, const char *proto, unit_t *u, int IOPportnum) {
int portnum;
portnum = ((u->chassis - 1) * 64) + ((u->geoslot - 1) * 8) + IOPportnum + 1;
- pcap_snprintf(buf, bufsize, "%s_%d", proto, portnum);
+ snprintf(buf, bufsize, "%s_%d", proto, portnum);
}
static char *translate_IOP_to_pcap_name(unit_t *u, char *IOPname, bpf_u_int32 iftype) {
iface_t *iface_ptr, *iface;
- char *name;
char buf[32];
char *proto;
char *port;
@@ -434,15 +441,12 @@ static char *translate_IOP_to_pcap_name(unit_t *u, char *IOPname, bpf_u_int32 if
iface->iftype = iftype; /* remember the interface type of this interface */
- name = malloc(strlen(IOPname) + 1); /* get memory for the IOP's name */
- if (name == NULL) { /* oops, we didn't get the memory requested */
+ iface->IOPname = strdup(IOPnam); /* copy it and stick it into the structure */
+ if (iface->IOPname == NULL) { /* oops, we didn't get the memory requested */
fprintf(stderr, "Error...couldn't allocate memory for IOPname...value of errno is: %d\n", errno);
return NULL;
}
- strcpy(name, IOPname); /* and copy it in */
- iface->IOPname = name; /* and stick it into the structure */
-
if (strncmp(IOPname, "lo", 2) == 0) {
IOPportnum = atoi(&IOPname[2]);
switch (iftype) {
@@ -478,15 +482,12 @@ static char *translate_IOP_to_pcap_name(unit_t *u, char *IOPname, bpf_u_int32 if
return NULL;
}
- name = malloc(strlen(buf) + 1); /* get memory for that name */
- if (name == NULL) { /* oops, we didn't get the memory requested */
+ iface->name = strdup(buf); /* make a copy and stick it into the structure */
+ if (iface->name == NULL) { /* oops, we didn't get the memory requested */
fprintf(stderr, "Error...couldn't allocate memory for IOP port name...value of errno is: %d\n", errno);
return NULL;
}
- strcpy(name, buf); /* and copy it in */
- iface->name = name; /* and stick it into the structure */
-
if (u->iface == 0) { /* if this is the first name */
u->iface = iface; /* stick this entry at the head of the list */
} else {
@@ -703,7 +704,7 @@ static int process_client_data (char *errbuf) { /* returns: -1 = error, 0
prev_iff = iff;
newname = translate_IOP_to_pcap_name(u, iff->name, interfaceType); /* add a translation entry and get a point to the mangled name */
- bigger_buffer = realloc(iff->name, strlen(newname) + 1));
+ bigger_buffer = realloc(iff->name, strlen(newname) + 1);
if (bigger_buffer == NULL) { /* we now re-write the name stored in the interface list */
pcap_fmt_errmsg_for_errno(errbuf,
PCAP_ERRBUF_SIZE, errno, "realloc");
@@ -754,9 +755,9 @@ static void wait_for_all_answers(void) {
memcpy(&working_set, &readfds, sizeof(readfds)); /* otherwise, we still have to listen for more stuff, till we timeout */
retval = select(max_fs + 1, &working_set, NULL, NULL, &tv);
- if (retval == -1) { /* an error occured !!!!! */
+ if (retval == -1) { /* an error occurred !!!!! */
return;
- } else if (retval == 0) { /* timeout occured, so process what we've got sofar and return */
+ } else if (retval == 0) { /* timeout occurred, so process what we've got sofar and return */
printf("timeout\n");
return;
} else {
@@ -883,7 +884,7 @@ static void acn_start_monitor(int fd, int snaplen, int timeout, int promiscuous,
//printf("acn_start_monitor() complete\n"); // fulko
}
-static int pcap_inject_acn(pcap_t *p, const void *buf _U_, size_t size _U_) {
+static int pcap_inject_acn(pcap_t *p, const void *buf _U_, int size _U_) {
pcap_strlcpy(p->errbuf, "Sending packets isn't supported on ACN adapters",
PCAP_ERRBUF_SIZE);
return (-1);
@@ -915,12 +916,6 @@ static int pcap_setfilter_acn(pcap_t *handle, struct bpf_program *bpf) {
return 0;
}
-static int pcap_setdirection_acn(pcap_t *handle, pcap_direction_t d) {
- pcap_snprintf(handle->errbuf, sizeof(handle->errbuf),
- "Setting direction is not supported on ACN adapters");
- return -1;
-}
-
static int acn_read_n_bytes_with_timeout(pcap_t *handle, int count) {
struct timeval tv;
int retval, fd;
@@ -940,10 +935,10 @@ static int acn_read_n_bytes_with_timeout(pcap_t *handle, int count) {
bp = handle->bp;
while (count) {
retval = select(fd + 1, &w_fds, NULL, NULL, &tv);
- if (retval == -1) { /* an error occured !!!!! */
+ if (retval == -1) { /* an error occurred !!!!! */
// fprintf(stderr, "error during packet data read\n");
- return -1; /* but we need to return a good indication to prevent unneccessary popups */
- } else if (retval == 0) { /* timeout occured, so process what we've got sofar and return */
+ return -1; /* but we need to return a good indication to prevent unnecessary popups */
+ } else if (retval == 0) { /* timeout occurred, so process what we've got sofar and return */
// fprintf(stderr, "timeout during packet data read\n");
return -1;
} else {
@@ -997,7 +992,7 @@ static int pcap_activate_sita(pcap_t *handle) {
handle->inject_op = pcap_inject_acn;
handle->setfilter_op = pcap_setfilter_acn;
- handle->setdirection_op = pcap_setdirection_acn;
+ handle->setdirection_op = NULL; /* Not implemented */
handle->set_datalink_op = NULL; /* can't change data link type */
handle->getnonblock_op = pcap_getnonblock_fd;
handle->setnonblock_op = pcap_setnonblock_fd;
@@ -1046,7 +1041,7 @@ static int pcap_activate_sita(pcap_t *handle) {
pcap_t *pcap_create_interface(const char *device _U_, char *ebuf) {
pcap_t *p;
- p = pcap_create_common(ebuf, 0);
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_sita);
if (p == NULL)
return (NULL);
diff --git a/pcap-sita.html b/pcap-sita.html
index 4a8fe1a2..33f1e10f 100644
--- a/pcap-sita.html
+++ b/pcap-sita.html
@@ -22,7 +22,7 @@ A { text-decoration:none }
<UL>
<STRONG>Note:</STRONG> This document is part of the libpcap Git and was derived from 'pcap.3' (circa Aug/07).
<P>
- The ACN provides a customized/distributed version of this library that alows SMPs to
+ The ACN provides a customized/distributed version of this library that allows SMPs to
interact with the various IOPs within the site providing a standard mechanism
to capture LAN and WAN message traffic.
<P>
@@ -31,7 +31,7 @@ A { text-decoration:none }
<TR>
<TH VALIGN=TOP>SMP</TH>
<TD VALIGN=TOP>The Supervisory Management Processor where Wireshark (or equivalent)
- runs in conjuction with a libpcap front-end.</TD>
+ runs in conjunction with a libpcap front-end.</TD>
</TR>
<TR>
<TH VALIGN=TOP>IOP</TH>
@@ -43,7 +43,7 @@ A { text-decoration:none }
<P>
Each IOP will be capable of supporting multiple connections from an SMP
enabling monitoring of more than one interface at a time, each through
- its own seperate connection. The IOP is responsible to ensure and report
+ its own separate connection. The IOP is responsible to ensure and report
an error if any attempt is made to monitor the same interface more than once.
<P>
There are three applications that will be supported by the ACN version of libpcap.
@@ -121,8 +121,8 @@ A { text-decoration:none }
<TR><TH VALIGN=TOP NOWRAP>IOP -> SMP</TH>
<TD>
After any required processing is complete, the IOP will return a
- null terminated string containing an error message if one occured.
- If no error occured, a empty string is still returned.
+ null terminated string containing an error message if one occurred.
+ If no error occurred, a empty string is still returned.
Errors are:
<UL>
<LI>"Interface (xxx) does not exist."
@@ -298,7 +298,7 @@ A { text-decoration:none }
<TD>
The SMP reads only the next packet from the reverse channel of the connection
between the SMP and the IOP that provides the captured data (via calling pcap_dispatch()
- with a count of 1) and returns seperate pointers to both the
+ with a count of 1) and returns separate pointers to both the
packet header and packet data by invoking an internal callback.
</TD>
</TR>
@@ -322,7 +322,7 @@ A { text-decoration:none }
<TR><TH VALIGN=TOP NOWRAP>IOP -> SMP</TH>
<TD>
The IOP returns a null terminated error string if it failed to accept the filter.
- If no error occured, then a NULL terminated empty string is returned instead.
+ If no error occurred, then a NULL terminated empty string is returned instead.
Errors are:
<UL>
<LI>"Invalid BPF."
@@ -362,7 +362,7 @@ A { text-decoration:none }
<TR><TH VALIGN=TOP NOWRAP>SMP -> IOP</TH>
<TD>
The SMP closes the file descriptor, and if the descriptor is that of
- the comminucation session with an IOP, it too is terminated.
+ the communication session with an IOP, it too is terminated.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>IOP</TH>
@@ -370,7 +370,7 @@ A { text-decoration:none }
If the IOP detects that its communication session with an SMP
has closed, it will terminate any monitoring in progress,
release any resources and close its end of the session.
- It will not maintain persistance of any information or prior mode of operation.
+ It will not maintain persistence of any information or prior mode of operation.
</TD>
</TR>
</TABLE></TD></TR>
@@ -442,7 +442,7 @@ A { text-decoration:none }
<TD VALIGN=TOP ALIGN=CENTER NOWRAP>IOP -> SMP</TD>
<TD VALIGN=TOP>The IOP returns a list of sequences of information as
defined by the return parameter of this function call (as shown in the following table).
- Elements are specified by providing an unsigned byte preceeding the actual data that contains length information.
+ Elements are specified by providing an unsigned byte preceding the actual data that contains length information.
<P>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
<TR>
@@ -635,7 +635,7 @@ A { text-decoration:none }
<TD VALIGN=TOP>BPF program</TD>
<TD VALIGN=TOP ALIGN=CENTER>'n'</TD>
<TD VALIGN=TOP>8 bytes of each command (repeated 'n' times).<BR>
- Each command consists of that C-style structure which contains:
+ Each command consists of that C-style structure which contains:
<P>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
<TR>
@@ -719,7 +719,7 @@ A { text-decoration:none }
<TR>
<TD VALIGN=TOP>ps_ifdrop</TD>
<TD VALIGN=TOP ALIGN=CENTER>4</TD>
- <TD VALIGN=TOP>The number of packets dropped by the network inteface
+ <TD VALIGN=TOP>The number of packets dropped by the network interface
(regardless of whether they would have passed the input filter).</TD>
</TR>
</TABLE>
@@ -839,7 +839,7 @@ A { text-decoration:none }
<UL>
PCAP, Wireshark and Tcpdump enhancements have been added to the ACN to support
monitoring of its ports, however each of these facilities were focused on capturing
- and displaying traffic from LAN interfaces. The SITA extentions to these facilities
+ and displaying traffic from LAN interfaces. The SITA extensions to these facilities
are used to also provide the ability to capture, filter, and display information from
an ACN's WAN ports.
<P>
@@ -849,7 +849,7 @@ A { text-decoration:none }
<P>
<UL TYPE=DISC>
<LI>For Ethernet (like) devices, the packet format is unchanged from the standard Pcap format.
- <LI>For WAN devices, the packet contains a 5 byte header that preceeds the actual captured data
+ <LI>For WAN devices, the packet contains a 5 byte header that precedes the actual captured data
described by the following table:
</UL>
<P>
diff --git a/pcap-snf.c b/pcap-snf.c
index 50d92cd9..a9162eba 100644
--- a/pcap-snf.c
+++ b/pcap-snf.c
@@ -10,7 +10,6 @@
#include <string.h>
#include <errno.h>
-#include <ctype.h>
#ifndef _WIN32
#include <netinet/in.h>
#include <sys/mman.h>
@@ -177,7 +176,7 @@ snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
caplen = p->snapshot;
if ((p->fcode.bf_insns == NULL) ||
- bpf_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) {
+ pcap_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) {
hdr.ts = snf_timestamp_to_timeval(req.timestamp, p->opt.tstamp_precision);
hdr.caplen = caplen;
hdr.len = req.length;
@@ -194,26 +193,7 @@ snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
}
static int
-snf_setfilter(pcap_t *p, struct bpf_program *fp)
-{
- if (!p)
- return -1;
- if (!fp) {
- strncpy(p->errbuf, "setfilter: No filter specified",
- sizeof(p->errbuf));
- return -1;
- }
-
- /* Make our private copy of the filter */
-
- if (install_bpf_program(p, fp) < 0)
- return -1;
-
- return (0);
-}
-
-static int
-snf_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
+snf_inject(pcap_t *p, const void *buf _U_, int size _U_)
{
#ifdef SNF_HAVE_INJECT_API
struct pcap_snf *ps = p->priv;
@@ -253,7 +233,7 @@ snf_activate(pcap_t* p)
int flags = -1, ring_id = -1;
if (device == NULL) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL");
return -1;
}
@@ -327,7 +307,7 @@ snf_activate(pcap_t* p)
p->linktype = DLT_EN10MB;
p->read_op = snf_read;
p->inject_op = snf_inject;
- p->setfilter_op = snf_setfilter;
+ p->setfilter_op = install_bpf_program;
p->setdirection_op = NULL; /* Not implemented.*/
p->set_datalink_op = snf_set_datalink;
p->getnonblock_op = snf_getnonblock;
@@ -355,7 +335,7 @@ snf_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
const char *nr = NULL;
if (snf_init(SNF_VERSION_API)) {
- (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"snf_getifaddrs: snf_init failed");
return (-1);
}
@@ -370,7 +350,7 @@ snf_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
errno = 0;
merge = strtol(nr, NULL, 0);
if (errno) {
- (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"snf_getifaddrs: SNF_FLAGS is not a valid number");
return (-1);
}
@@ -408,7 +388,7 @@ snf_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
* entry for the device, if they're not already in the
* list of IP addresses for the device?
*/
- (void)pcap_snprintf(desc,MAX_DESC_LENGTH,"Myricom %ssnf%d",
+ (void)snprintf(desc,MAX_DESC_LENGTH,"Myricom %ssnf%d",
merge ? "Merge Bitmask Port " : "",
merge ? 1 << ifa->snf_ifa_portnum : ifa->snf_ifa_portnum);
/*
@@ -484,8 +464,8 @@ snf_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
/*
* Add a new entry with all ports bitmask
*/
- (void)pcap_snprintf(name,MAX_DESC_LENGTH,"snf%d",allports);
- (void)pcap_snprintf(desc,MAX_DESC_LENGTH,"Myricom Merge Bitmask All Ports snf%d",
+ (void)snprintf(name,MAX_DESC_LENGTH,"snf%d",allports);
+ (void)snprintf(desc,MAX_DESC_LENGTH,"Myricom Merge Bitmask All Ports snf%d",
allports);
/*
* XXX - is there any notion of "up" and "running" that
@@ -560,7 +540,7 @@ snf_create(const char *device, char *ebuf, int *is_ours)
/* OK, it's probably ours. */
*is_ours = 1;
- p = pcap_create_common(ebuf, sizeof (struct pcap_snf));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_snf);
if (p == NULL)
return NULL;
ps = p->priv;
@@ -568,7 +548,6 @@ snf_create(const char *device, char *ebuf, int *is_ours)
/*
* We support microsecond and nanosecond time stamps.
*/
- p->tstamp_precision_count = 2;
p->tstamp_precision_list = malloc(2 * sizeof(u_int));
if (p->tstamp_precision_list == NULL) {
pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno,
@@ -578,6 +557,7 @@ snf_create(const char *device, char *ebuf, int *is_ours)
}
p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO;
p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO;
+ p->tstamp_precision_count = 2;
p->activate_op = snf_activate;
ps->snf_boardnum = boardnum;
@@ -605,7 +585,7 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
pcap_t *
pcap_create_interface(const char *device, char *errbuf)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"This version of libpcap only supports SNF cards");
return NULL;
}
diff --git a/pcap-snit.c b/pcap-snit.c
index 9c6fbd48..ca6222cf 100644
--- a/pcap-snit.c
+++ b/pcap-snit.c
@@ -53,7 +53,6 @@
#include <netinet/tcp.h>
#include <netinet/tcpip.h>
-#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
@@ -190,7 +189,7 @@ pcap_read_snit(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
if (caplen > p->snapshot)
caplen = p->snapshot;
- if (bpf_filter(p->fcode.bf_insns, cp, nlp->nh_pktlen, caplen)) {
+ if (pcap_filter(p->fcode.bf_insns, cp, nlp->nh_pktlen, caplen)) {
struct pcap_pkthdr h;
h.ts = ntp->nh_timestamp;
h.len = nlp->nh_pktlen;
@@ -208,7 +207,7 @@ pcap_read_snit(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
}
static int
-pcap_inject_snit(pcap_t *p, const void *buf, size_t size)
+pcap_inject_snit(pcap_t *p, const void *buf, int size)
{
struct strbuf ctl, data;
@@ -460,7 +459,7 @@ pcap_create_interface(const char *device _U_, char *ebuf)
{
pcap_t *p;
- p = pcap_create_common(ebuf, sizeof (struct pcap_snit));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_snit);
if (p == NULL)
return (NULL);
diff --git a/pcap-snoop.c b/pcap-snoop.c
index a598bae5..2f44b1dd 100644
--- a/pcap-snoop.c
+++ b/pcap-snoop.c
@@ -126,7 +126,7 @@ again:
}
if (p->fcode.bf_insns == NULL ||
- bpf_filter(p->fcode.bf_insns, cp, datalen, caplen)) {
+ pcap_filter(p->fcode.bf_insns, cp, datalen, caplen)) {
struct pcap_pkthdr h;
++psn->stat.ps_recv;
h.ts.tv_sec = sh->snoop_timestamp.tv_sec;
@@ -140,7 +140,7 @@ again:
}
static int
-pcap_inject_snoop(pcap_t *p, const void *buf, size_t size)
+pcap_inject_snoop(pcap_t *p, const void *buf, int size)
{
int ret;
@@ -310,7 +310,7 @@ pcap_activate_snoop(pcap_t *p)
p->linktype = DLT_NULL;
ll_hdrlen = 4;
} else {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"snoop: unknown physical layer type");
goto bad;
}
@@ -421,7 +421,7 @@ pcap_create_interface(const char *device _U_, char *ebuf)
{
pcap_t *p;
- p = pcap_create_common(ebuf, sizeof (struct pcap_snoop));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_snoop);
if (p == NULL)
return (NULL);
diff --git a/pcap-tc.c b/pcap-tc.c
index 65fb0e2b..9902633a 100644
--- a/pcap-tc.c
+++ b/pcap-tc.c
@@ -126,7 +126,6 @@ static void TcCleanup(pcap_t *p);
static int TcInject(pcap_t *p, const void *buf, int size);
static int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user);
static int TcStats(pcap_t *p, struct pcap_stat *ps);
-static int TcSetFilter(pcap_t *p, struct bpf_program *fp);
#ifdef _WIN32
static struct pcap_stat *TcStatsEx(pcap_t *p, int *pcap_stat_size);
static int TcSetBuff(pcap_t *p, int dim);
@@ -253,58 +252,6 @@ typedef struct _PPI_HEADER
#pragma pack(pop)
#ifdef _WIN32
-//
-// This wrapper around loadlibrary appends the system folder (usually c:\windows\system32)
-// to the relative path of the DLL, so that the DLL is always loaded from an absolute path
-// (It's no longer possible to load airpcap.dll from the application folder).
-// This solves the DLL Hijacking issue discovered in August 2010
-// http://blog.metasploit.com/2010/08/exploiting-dll-hijacking-flaws.html
-//
-HMODULE LoadLibrarySafe(LPCTSTR lpFileName)
-{
- TCHAR path[MAX_PATH];
- TCHAR fullFileName[MAX_PATH];
- UINT res;
- HMODULE hModule = NULL;
- do
- {
- res = GetSystemDirectory(path, MAX_PATH);
-
- if (res == 0)
- {
- //
- // some bad failure occurred;
- //
- break;
- }
-
- if (res > MAX_PATH)
- {
- //
- // the buffer was not big enough
- //
- SetLastError(ERROR_INSUFFICIENT_BUFFER);
- break;
- }
-
- if (res + 1 + _tcslen(lpFileName) + 1 < MAX_PATH)
- {
- memcpy(fullFileName, path, res * sizeof(TCHAR));
- fullFileName[res] = _T('\\');
- memcpy(&fullFileName[res + 1], lpFileName, (_tcslen(lpFileName) + 1) * sizeof(TCHAR));
-
- hModule = LoadLibrary(fullFileName);
- }
- else
- {
- SetLastError(ERROR_INSUFFICIENT_BUFFER);
- }
-
- }while(FALSE);
-
- return hModule;
-}
-
/*
* NOTE: this function should be called by the pcap functions that can theoretically
* deal with the Tc library for the first time, namely listing the adapters and
@@ -341,34 +288,34 @@ TC_API_LOAD_STATUS LoadTcFunctions(void)
currentStatus = TC_API_CANNOT_LOAD;
- g_TcFunctions.hTcApiDllHandle = LoadLibrarySafe("TcApi.dll");
+ g_TcFunctions.hTcApiDllHandle = pcap_load_code("TcApi.dll");
if (g_TcFunctions.hTcApiDllHandle == NULL) break;
- g_TcFunctions.QueryPortList = (TcFcnQueryPortList) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcQueryPortList");
- g_TcFunctions.FreePortList = (TcFcnFreePortList) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcFreePortList");
+ g_TcFunctions.QueryPortList = (TcFcnQueryPortList) pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcQueryPortList");
+ g_TcFunctions.FreePortList = (TcFcnFreePortList) pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcFreePortList");
- g_TcFunctions.StatusGetString = (TcFcnStatusGetString) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatusGetString");
+ g_TcFunctions.StatusGetString = (TcFcnStatusGetString) pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatusGetString");
- g_TcFunctions.PortGetName = (TcFcnPortGetName) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPortGetName");
- g_TcFunctions.PortGetDescription = (TcFcnPortGetDescription) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPortGetDescription");
+ g_TcFunctions.PortGetName = (TcFcnPortGetName) pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPortGetName");
+ g_TcFunctions.PortGetDescription = (TcFcnPortGetDescription) pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPortGetDescription");
- g_TcFunctions.InstanceOpenByName = (TcFcnInstanceOpenByName) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceOpenByName");
- g_TcFunctions.InstanceClose = (TcFcnInstanceClose) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceClose");
- g_TcFunctions.InstanceSetFeature = (TcFcnInstanceSetFeature) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceSetFeature");
- g_TcFunctions.InstanceQueryFeature = (TcFcnInstanceQueryFeature) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryFeature");
- g_TcFunctions.InstanceReceivePackets = (TcFcnInstanceReceivePackets) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceReceivePackets");
- g_TcFunctions.InstanceGetReceiveWaitHandle = (TcFcnInstanceGetReceiveWaitHandle)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceGetReceiveWaitHandle");
- g_TcFunctions.InstanceTransmitPackets = (TcFcnInstanceTransmitPackets)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceTransmitPackets");
- g_TcFunctions.InstanceQueryStatistics = (TcFcnInstanceQueryStatistics)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryStatistics");
+ g_TcFunctions.InstanceOpenByName = (TcFcnInstanceOpenByName) pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceOpenByName");
+ g_TcFunctions.InstanceClose = (TcFcnInstanceClose) pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceClose");
+ g_TcFunctions.InstanceSetFeature = (TcFcnInstanceSetFeature) pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceSetFeature");
+ g_TcFunctions.InstanceQueryFeature = (TcFcnInstanceQueryFeature) pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryFeature");
+ g_TcFunctions.InstanceReceivePackets = (TcFcnInstanceReceivePackets) pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceReceivePackets");
+ g_TcFunctions.InstanceGetReceiveWaitHandle = (TcFcnInstanceGetReceiveWaitHandle)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceGetReceiveWaitHandle");
+ g_TcFunctions.InstanceTransmitPackets = (TcFcnInstanceTransmitPackets)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceTransmitPackets");
+ g_TcFunctions.InstanceQueryStatistics = (TcFcnInstanceQueryStatistics)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryStatistics");
- g_TcFunctions.PacketsBufferCreate = (TcFcnPacketsBufferCreate) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCreate");
- g_TcFunctions.PacketsBufferDestroy = (TcFcnPacketsBufferDestroy) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferDestroy");
- g_TcFunctions.PacketsBufferQueryNextPacket = (TcFcnPacketsBufferQueryNextPacket)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferQueryNextPacket");
- g_TcFunctions.PacketsBufferCommitNextPacket = (TcFcnPacketsBufferCommitNextPacket)GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCommitNextPacket");
+ g_TcFunctions.PacketsBufferCreate = (TcFcnPacketsBufferCreate) pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCreate");
+ g_TcFunctions.PacketsBufferDestroy = (TcFcnPacketsBufferDestroy) pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferDestroy");
+ g_TcFunctions.PacketsBufferQueryNextPacket = (TcFcnPacketsBufferQueryNextPacket)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferQueryNextPacket");
+ g_TcFunctions.PacketsBufferCommitNextPacket = (TcFcnPacketsBufferCommitNextPacket)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCommitNextPacket");
- g_TcFunctions.StatisticsDestroy = (TcFcnStatisticsDestroy) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatisticsDestroy");
- g_TcFunctions.StatisticsUpdate = (TcFcnStatisticsUpdate) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatisticsUpdate");
- g_TcFunctions.StatisticsQueryValue = (TcFcnStatisticsQueryValue) GetProcAddress(g_TcFunctions.hTcApiDllHandle, "TcStatisticsQueryValue");
+ g_TcFunctions.StatisticsDestroy = (TcFcnStatisticsDestroy) pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatisticsDestroy");
+ g_TcFunctions.StatisticsUpdate = (TcFcnStatisticsUpdate) pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatisticsUpdate");
+ g_TcFunctions.StatisticsQueryValue = (TcFcnStatisticsQueryValue) pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatisticsQueryValue");
if ( g_TcFunctions.QueryPortList == NULL
|| g_TcFunctions.FreePortList == NULL
@@ -552,7 +499,7 @@ TcActivate(pcap_t *p)
if (pt->PpiPacket == NULL)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error allocating memory");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error allocating memory");
return PCAP_ERROR;
}
@@ -587,7 +534,7 @@ TcActivate(pcap_t *p)
if (status != TC_SUCCESS)
{
/* Adapter detected but we are not able to open it. Return failure. */
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error opening TurboCap adapter: %s", g_TcFunctions.StatusGetString(status));
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error opening TurboCap adapter: %s", g_TcFunctions.StatusGetString(status));
return PCAP_ERROR;
}
@@ -619,7 +566,7 @@ TcActivate(pcap_t *p)
if (status != TC_SUCCESS)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error enabling reception on a TurboCap instance: %s", g_TcFunctions.StatusGetString(status));
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error enabling reception on a TurboCap instance: %s", g_TcFunctions.StatusGetString(status));
goto bad;
}
@@ -658,12 +605,12 @@ TcActivate(pcap_t *p)
if (status != TC_SUCCESS)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error setting the read timeout a TurboCap instance: %s", g_TcFunctions.StatusGetString(status));
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error setting the read timeout a TurboCap instance: %s", g_TcFunctions.StatusGetString(status));
goto bad;
}
p->read_op = TcRead;
- p->setfilter_op = TcSetFilter;
+ p->setfilter_op = install_bpf_program;
p->setdirection_op = NULL; /* Not implemented. */
p->set_datalink_op = TcSetDatalink;
p->getnonblock_op = TcGetNonBlock;
@@ -756,7 +703,7 @@ TcCreate(const char *device, char *ebuf, int *is_ours)
/* OK, it's probably ours. */
*is_ours = 1;
- p = pcap_create_common(ebuf, sizeof (struct pcap_tc));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_tc);
if (p == NULL)
return NULL;
@@ -791,14 +738,14 @@ static int TcSetDatalink(pcap_t *p, int dlt)
static int TcGetNonBlock(pcap_t *p)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Non-blocking mode isn't supported for TurboCap ports");
return -1;
}
static int TcSetNonBlock(pcap_t *p, int nonblock)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Non-blocking mode isn't supported for TurboCap ports");
return -1;
}
@@ -840,7 +787,7 @@ static int TcInject(pcap_t *p, const void *buf, int size)
if (size >= 0xFFFF)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: the TurboCap API does not support packets larger than 64k");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: the TurboCap API does not support packets larger than 64k");
return -1;
}
@@ -848,7 +795,7 @@ static int TcInject(pcap_t *p, const void *buf, int size)
if (status != TC_SUCCESS)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCreate failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCreate failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
return -1;
}
@@ -868,12 +815,12 @@ static int TcInject(pcap_t *p, const void *buf, int size)
if (status != TC_SUCCESS)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcInstanceTransmitPackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcInstanceTransmitPackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
}
}
else
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCommitNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCommitNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
}
g_TcFunctions.PacketsBufferDestroy(buffer);
@@ -913,7 +860,7 @@ static int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
status = g_TcFunctions.InstanceReceivePackets(pt->TcInstance, &pt->TcPacketsBuffer);
if (status != TC_SUCCESS)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcInstanceReceivePackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcInstanceReceivePackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
return -1;
}
}
@@ -963,14 +910,14 @@ static int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
if (status != TC_SUCCESS)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcPacketsBufferQueryNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcPacketsBufferQueryNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
return -1;
}
/* No underlaying filtering system. We need to filter on our own */
if (p->fcode.bf_insns)
{
- filterResult = bpf_filter(p->fcode.bf_insns, data, tcHeader.Length, tcHeader.CapturedLength);
+ filterResult = pcap_filter(p->fcode.bf_insns, data, tcHeader.Length, tcHeader.CapturedLength);
if (filterResult == 0)
{
@@ -1053,7 +1000,7 @@ TcStats(pcap_t *p, struct pcap_stat *ps)
if (status != TC_SUCCESS)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
return -1;
}
@@ -1062,7 +1009,7 @@ TcStats(pcap_t *p, struct pcap_stat *ps)
status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter);
if (status != TC_SUCCESS)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
return -1;
}
if (counter <= (ULONGLONG)0xFFFFFFFF)
@@ -1077,7 +1024,7 @@ TcStats(pcap_t *p, struct pcap_stat *ps)
status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS, &counter);
if (status != TC_SUCCESS)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
return -1;
}
if (counter <= (ULONGLONG)0xFFFFFFFF)
@@ -1100,27 +1047,6 @@ TcStats(pcap_t *p, struct pcap_stat *ps)
}
-/*
- * We filter at user level, since the kernel driver does't process the packets
- */
-static int
-TcSetFilter(pcap_t *p, struct bpf_program *fp)
-{
- if(!fp)
- {
- strncpy(p->errbuf, "setfilter: No filter specified", sizeof(p->errbuf));
- return -1;
- }
-
- /* Install a user level filter */
- if (install_bpf_program(p, fp) < 0)
- {
- return -1;
- }
-
- return 0;
-}
-
#ifdef _WIN32
static struct pcap_stat *
TcStatsEx(pcap_t *p, int *pcap_stat_size)
@@ -1136,7 +1062,7 @@ TcStatsEx(pcap_t *p, int *pcap_stat_size)
if (status != TC_SUCCESS)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
return NULL;
}
@@ -1145,7 +1071,7 @@ TcStatsEx(pcap_t *p, int *pcap_stat_size)
status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter);
if (status != TC_SUCCESS)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
return NULL;
}
if (counter <= (ULONGLONG)0xFFFFFFFF)
@@ -1160,7 +1086,7 @@ TcStatsEx(pcap_t *p, int *pcap_stat_size)
status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS, &counter);
if (status != TC_SUCCESS)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
return NULL;
}
if (counter <= (ULONGLONG)0xFFFFFFFF)
@@ -1198,7 +1124,7 @@ TcSetMode(pcap_t *p, int mode)
{
if (mode != MODE_CAPT)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mode %u not supported by TurboCap devices. TurboCap only supports capture.", mode);
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mode %u not supported by TurboCap devices. TurboCap only supports capture.", mode);
return -1;
}
@@ -1213,7 +1139,7 @@ TcSetMinToCopy(pcap_t *p, int size)
if (size < 0)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mintocopy cannot be less than 0.");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mintocopy cannot be less than 0.");
return -1;
}
@@ -1221,7 +1147,7 @@ TcSetMinToCopy(pcap_t *p, int size)
if (status != TC_SUCCESS)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error setting the mintocopy: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error setting the mintocopy: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
}
return 0;
@@ -1238,7 +1164,7 @@ TcGetReceiveWaitHandle(pcap_t *p)
static int
TcOidGetRequest(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_, size_t *lenp _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"An OID get request cannot be performed on a TurboCap device");
return PCAP_ERROR;
}
@@ -1247,7 +1173,7 @@ static int
TcOidSetRequest(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
size_t *lenp _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"An OID set request cannot be performed on a TurboCap device");
return PCAP_ERROR;
}
@@ -1255,7 +1181,7 @@ TcOidSetRequest(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
static u_int
TcSendqueueTransmit(pcap_t *p, pcap_send_queue *queue _U_, int sync _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Packets cannot be bulk transmitted on a TurboCap device");
return 0;
}
@@ -1263,7 +1189,7 @@ TcSendqueueTransmit(pcap_t *p, pcap_send_queue *queue _U_, int sync _U_)
static int
TcSetUserBuffer(pcap_t *p, int size _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The user buffer cannot be set on a TurboCap device");
return -1;
}
@@ -1271,7 +1197,7 @@ TcSetUserBuffer(pcap_t *p, int size _U_)
static int
TcLiveDump(pcap_t *p, char *filename _U_, int maxsize _U_, int maxpacks _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Live packet dumping cannot be performed on a TurboCap device");
return -1;
}
@@ -1279,7 +1205,7 @@ TcLiveDump(pcap_t *p, char *filename _U_, int maxsize _U_, int maxpacks _U_)
static int
TcLiveDumpEnded(pcap_t *p, int sync _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Live packet dumping cannot be performed on a TurboCap device");
return -1;
}
diff --git a/pcap-tstamp.manmisc.in b/pcap-tstamp.manmisc.in
index 6437e80e..eea8c1d2 100644
--- a/pcap-tstamp.manmisc.in
+++ b/pcap-tstamp.manmisc.in
@@ -19,7 +19,7 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP-TSTAMP @MAN_MISC_INFO@ "8 March 2015"
+.TH PCAP-TSTAMP @MAN_MISC_INFO@ "14 July 2020"
.SH NAME
pcap-tstamp \- packet time stamps in libpcap
.SH DESCRIPTION
@@ -58,7 +58,20 @@ single adjustment;
different CPU cores on a multi-core or multi-processor system might be
running at different speeds, or might not have time counters all
synchronized, so packets time-stamped by different cores might not have
-consistent time stamps.
+consistent time stamps;
+.IP
+some time sources, such as those that supply POSIX "seconds since the
+Epoch" time, do not count leap seconds, meaning that the seconds
+portion
+.RB ( tv_sec )
+of the time stamp might not be incremented for a leap second, so that
+the fraction-of-a-second part of the time stamp might roll over past
+zero but the second part would not change, or the clock might run
+slightly more slowly for a period before the leap second.
+.LP
+For these reasons, time differences between packet time stamps will not
+necessarily accurately reflect the time differences between the receipt
+or transmission times of the packets.
.LP
In addition, packets time-stamped by different cores might be
time-stamped in one order and added to the queue of packets for libpcap
@@ -73,6 +86,9 @@ the host operating system. Those time stamps might not, however, be
synchronized with the host operating system's clock, so that, for
example, the time stamp of a packet might not correspond to the time
stamp of an event on the host triggered by the arrival of that packet.
+If they are synchronized with the host operating system's clock, some of
+the issues listed above with time stamps supplied by the host operating
+system may also apply to time stamps supplied by the capture device.
.LP
Depending on the capture device and the software on the host, libpcap
might allow different types of time stamp to be used. The
@@ -87,15 +103,15 @@ The list might be empty, in which case no choice of time stamp type is
offered for that capture device. If the list is not empty, the
.BR pcap_set_tstamp_type (3PCAP)
routine can be used after a
-.B pcap_create()
+.BR pcap_create ()
call and before a
-.B pcap_activate()
+.BR pcap_activate ()
call to specify the type of time stamp to be used on the device.
The time stamp types are listed here; the first value is the #define to
use in code, the second value is the value returned by
-.B pcap_tstamp_type_val_to_name(3PCAP)
+.BR pcap_tstamp_type_val_to_name (3PCAP)
and accepted by
-.BR pcap_tstamp_type_name_to_val(3PCAP) .
+.BR pcap_tstamp_type_name_to_val (3PCAP) .
.RS 5
.TP 5
.BR PCAP_TSTAMP_HOST " - " host
@@ -110,9 +126,14 @@ system's clock.
.TP 5
.BR PCAP_TSTAMP_HOST_HIPREC " - " host_hiprec
Time stamp provided by the host on which the capture is being done.
-This is a high-precision time stamp; it might or might not be
-synchronized with the host operating system's clock. It might be more
-expensive to fetch than
+This is a high-precision time stamp, synchronized with the host
+operating system's clock. It might be more expensive to fetch than
+.BR PCAP_TSTAMP_HOST_LOWPREC .
+.TP 5
+.BR PCAP_TSTAMP_HOST_HIPREC_UNSYNCED " - " host_hiprec_unsynced
+Time stamp provided by the host on which the capture is being done.
+This is a high-precision time stamp, not synchronized with the host
+operating system's clock. It might be more expensive to fetch than
.BR PCAP_TSTAMP_HOST_LOWPREC .
.TP 5
.BR PCAP_TSTAMP_ADAPTER " - " adapter
@@ -126,6 +147,18 @@ done. This is a high-precision time stamp; it is not synchronized with
the host operating system's clock.
.RE
.LP
+Time stamps synchronized with the system clock can go backwards, as the
+system clock can go backwards. If a clock is not in sync with the
+system clock, that could be because the system clock isn't keeping
+accurate time, because the other clock isn't keeping accurate time, or
+both.
+.LP
+Host-provided time stamps generally correspond to the time when the
+time-stamping code sees the packet; this could be some unknown amount of
+time after the first or last bit of the packet is received by the
+network adapter, due to batching of interrupts for packet arrival,
+queueing delays, etc..
+.LP
By default, when performing a live capture or reading from a savefile,
time stamps are supplied as seconds since January 1, 1970, 00:00:00 UTC,
and microseconds since that seconds value, even if higher-resolution
@@ -137,15 +170,15 @@ discarded.
The
.BR pcap_set_tstamp_precision (3PCAP)
routine can be used after a
-.B pcap_create()
+.BR pcap_create ()
call and after a
-.B pcap_activate()
+.BR pcap_activate ()
call to specify the resolution of the time stamps to get for the device.
If the hardware or software cannot supply a higher-resolution time
stamp, the
-.B pcap_set_tstamp_precision()
+.BR pcap_set_tstamp_precision ()
call will fail, and the time stamps supplied after the
-.B pcap_activate()
+.BR pcap_activate ()
call will have microsecond resolution.
.LP
When opening a savefile, the
@@ -165,4 +198,4 @@ the time stamp supplied by the hardware or operating system and, when
reading a savefile, this does not indicate the actual precision of time
stamps in the file.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap-types.h b/pcap-types.h
index 9614f9f1..7d0fe81f 100644
--- a/pcap-types.h
+++ b/pcap-types.h
@@ -35,7 +35,6 @@
* Get u_int defined, by hook or by crook.
*/
#ifdef _WIN32
-
/*
* This defines u_int.
*/
diff --git a/pcap-usb-linux.c b/pcap-usb-linux.c
index b306dca9..3596428e 100644
--- a/pcap-usb-linux.c
+++ b/pcap-usb-linux.c
@@ -41,11 +41,12 @@
#include "pcap-usb-linux.h"
#include "pcap/usb.h"
+#include "extract.h"
+
#ifdef NEED_STRERROR_H
#include "strerror.h"
#endif
-#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
@@ -136,7 +137,7 @@ static int usb_stats_linux_bin(pcap_t *, struct pcap_stat *);
static int usb_read_linux(pcap_t *, int , pcap_handler , u_char *);
static int usb_read_linux_bin(pcap_t *, int , pcap_handler , u_char *);
static int usb_read_linux_mmap(pcap_t *, int , pcap_handler , u_char *);
-static int usb_inject_linux(pcap_t *, const void *, size_t);
+static int usb_inject_linux(pcap_t *, const void *, int);
static int usb_setdirection_linux(pcap_t *, pcap_direction_t);
static void usb_cleanup_linux_mmap(pcap_t *);
@@ -145,7 +146,7 @@ have_binary_usbmon(void)
{
struct utsname utsname;
char *version_component, *endp;
- int major, minor, subminor;
+ long major, minor, subminor;
if (uname(&utsname) == 0) {
/*
@@ -230,7 +231,7 @@ usb_dev_add(pcap_if_list_t *devlistp, int n, char *err_str)
{
char dev_name[10];
char dev_descr[30];
- pcap_snprintf(dev_name, 10, USB_IFACE"%d", n);
+ snprintf(dev_name, 10, USB_IFACE"%d", n);
/*
* XXX - is there any notion of "up" and "running"?
*/
@@ -251,7 +252,7 @@ usb_dev_add(pcap_if_list_t *devlistp, int n, char *err_str)
* PCAP_IF_CONNECTION_STATUS_CONNECTED or
* PCAP_IF_CONNECTION_STATUS_DISCONNECTED?
*/
- pcap_snprintf(dev_descr, 30, "Raw USB traffic, bus number %d", n);
+ snprintf(dev_descr, 30, "Raw USB traffic, bus number %d", n);
if (add_dev(devlistp, dev_name, 0, dev_descr, err_str) == NULL)
return -1;
}
@@ -363,9 +364,9 @@ usb_findalldevs(pcap_if_list_t *devlistp, char *err_str)
len = strlen(name);
/* if this file name does not end with a number it's not of our interest */
- if ((len < 1) || !isdigit(name[--len]))
+ if ((len < 1) || !PCAP_ISDIGIT(name[--len]))
continue;
- while (isdigit(name[--len]));
+ while (PCAP_ISDIGIT(name[--len]));
if (sscanf(&name[len+1], "%d", &n) != 1)
continue;
@@ -490,6 +491,10 @@ int usb_mmap(pcap_t* handle)
#define USB_REQ_GET_DESCRIPTOR 6
#define USB_DT_DEVICE 1
+#define USB_DT_CONFIG 2
+
+#define USB_DEVICE_DESCRIPTOR_SIZE 18
+#define USB_CONFIG_DESCRIPTOR_SIZE 9
/* probe the descriptors of the devices attached to the bus */
/* the descriptors will end up in the captured packet stream */
@@ -501,12 +506,14 @@ probe_devices(int bus)
struct usbdevfs_ctrltransfer ctrl;
struct dirent* data;
int ret = 0;
- char buf[sizeof("/dev/bus/usb/000/") + NAME_MAX];
+ char busdevpath[sizeof("/dev/bus/usb/000/") + NAME_MAX];
DIR* dir;
+ uint8_t descriptor[USB_DEVICE_DESCRIPTOR_SIZE];
+ uint8_t configdesc[USB_CONFIG_DESCRIPTOR_SIZE];
/* scan usb bus directories for device nodes */
- pcap_snprintf(buf, sizeof(buf), "/dev/bus/usb/%03d", bus);
- dir = opendir(buf);
+ snprintf(busdevpath, sizeof(busdevpath), "/dev/bus/usb/%03d", bus);
+ dir = opendir(busdevpath);
if (!dir)
return;
@@ -517,9 +524,9 @@ probe_devices(int bus)
if (name[0] == '.')
continue;
- pcap_snprintf(buf, sizeof(buf), "/dev/bus/usb/%03d/%s", bus, data->d_name);
+ snprintf(busdevpath, sizeof(busdevpath), "/dev/bus/usb/%03d/%s", bus, data->d_name);
- fd = open(buf, O_RDWR);
+ fd = open(busdevpath, O_RDWR);
if (fd == -1)
continue;
@@ -532,19 +539,43 @@ probe_devices(int bus)
ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
ctrl.wValue = USB_DT_DEVICE << 8;
ctrl.wIndex = 0;
- ctrl.wLength = sizeof(buf);
+ ctrl.wLength = sizeof(descriptor);
#else
ctrl.requesttype = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
ctrl.request = USB_REQ_GET_DESCRIPTOR;
ctrl.value = USB_DT_DEVICE << 8;
ctrl.index = 0;
- ctrl.length = sizeof(buf);
+ ctrl.length = sizeof(descriptor);
#endif
- ctrl.data = buf;
+ ctrl.data = descriptor;
ctrl.timeout = CTRL_TIMEOUT;
ret = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
+ /* Request CONFIGURATION descriptor alone to know wTotalLength */
+#ifdef HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE
+ ctrl.wValue = USB_DT_CONFIG << 8;
+ ctrl.wLength = sizeof(configdesc);
+#else
+ ctrl.value = USB_DT_CONFIG << 8;
+ ctrl.length = sizeof(configdesc);
+#endif
+ ctrl.data = configdesc;
+ ret = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
+ if (ret >= 0) {
+ uint16_t wtotallength;
+ wtotallength = EXTRACT_LE_U_2(&configdesc[2]);
+#ifdef HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE
+ ctrl.wLength = wtotallength;
+#else
+ ctrl.length = wtotallength;
+#endif
+ ctrl.data = malloc(wtotallength);
+ if (ctrl.data) {
+ ret = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
+ free(ctrl.data);
+ }
+ }
close(fd);
}
closedir(dir);
@@ -586,7 +617,7 @@ usb_create(const char *device, char *ebuf, int *is_ours)
/* OK, it's probably ours. */
*is_ours = 1;
- p = pcap_create_common(ebuf, sizeof (struct pcap_usb_linux));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_usb_linux);
if (p == NULL)
return (NULL);
@@ -627,7 +658,7 @@ usb_activate(pcap_t* handle)
/*get usb bus index from device name */
if (sscanf(handle->opt.device, USB_IFACE"%d", &handlep->bus_index) != 1)
{
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Can't get USB bus index from %s", handle->opt.device);
return PCAP_ERROR;
}
@@ -638,7 +669,7 @@ usb_activate(pcap_t* handle)
* We have binary-mode support.
* Try to open the binary interface.
*/
- pcap_snprintf(full_path, USB_LINE_LEN, LINUX_USB_MON_DEV"%d", handlep->bus_index);
+ snprintf(full_path, USB_LINE_LEN, LINUX_USB_MON_DEV"%d", handlep->bus_index);
handle->fd = open(full_path, O_RDONLY, 0);
if (handle->fd < 0)
{
@@ -731,7 +762,7 @@ usb_activate(pcap_t* handle)
* We don't have binary mode support.
* Try opening the text-mode device.
*/
- pcap_snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR"/%dt", handlep->bus_index);
+ snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR"/%dt", handlep->bus_index);
handle->fd = open(full_path, O_RDONLY, 0);
if (handle->fd < 0)
{
@@ -741,7 +772,7 @@ usb_activate(pcap_t* handle)
* Not found at the new location; try
* the old location.
*/
- pcap_snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR_OLD"/%dt", handlep->bus_index);
+ snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR_OLD"/%dt", handlep->bus_index);
handle->fd = open(full_path, O_RDONLY, 0);
}
if (handle->fd < 0) {
@@ -832,6 +863,7 @@ usb_read_linux(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_cha
struct pcap_usb_linux *handlep = handle->priv;
unsigned timestamp;
int tag, cnt, ep_num, dev_addr, dummy, ret, urb_len, data_len;
+ ssize_t read_ret;
char etype, pipeid1, pipeid2, status[16], urb_tag, line[USB_LINE_LEN];
char *string = line;
u_char * rawdata = handle->buffer;
@@ -842,14 +874,14 @@ usb_read_linux(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_cha
/* ignore interrupt system call errors */
do {
- ret = read(handle->fd, line, USB_LINE_LEN - 1);
+ read_ret = read(handle->fd, line, USB_LINE_LEN - 1);
if (handle->break_loop)
{
handle->break_loop = 0;
return -2;
}
- } while ((ret == -1) && (errno == EINTR));
- if (ret < 0)
+ } while ((read_ret == -1) && (errno == EINTR));
+ if (read_ret < 0)
{
if (errno == EAGAIN)
return 0; /* no data there */
@@ -861,15 +893,19 @@ usb_read_linux(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_cha
/* read urb header; %n argument may increment return value, but it's
* not mandatory, so does not count on it*/
- string[ret] = 0;
+ string[read_ret] = 0;
ret = sscanf(string, "%x %d %c %c%c:%d:%d %s%n", &tag, &timestamp, &etype,
&pipeid1, &pipeid2, &dev_addr, &ep_num, status,
&cnt);
if (ret < 8)
{
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
- "Can't parse USB bus message '%s', too few tokens (expected 8 got %d)",
- string, ret);
+ char string_truncated[181];
+
+ strncpy(string_truncated, string, sizeof(string_truncated));
+ string_truncated[sizeof(string_truncated) - 1] = 0;
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "Can't parse USB bus message '%s', too few tokens (expected 8 got %d)",
+ string_truncated, ret);
return -1;
}
uhdr->id = tag;
@@ -886,7 +922,7 @@ usb_read_linux(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_cha
return -1;
}
uhdr->ts_sec = pkth.ts.tv_sec;
- uhdr->ts_usec = pkth.ts.tv_usec;
+ uhdr->ts_usec = (int32_t)pkth.ts.tv_usec;
/* parse endpoint information */
if (pipeid1 == 'C')
@@ -932,7 +968,7 @@ usb_read_linux(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_cha
str5, &cnt);
if (ret < 5)
{
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Can't parse USB bus message '%s', too few tokens (expected 5 got %d)",
string, ret);
return -1;
@@ -956,7 +992,7 @@ usb_read_linux(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_cha
ret = sscanf(string, " %d%n", &urb_len, &cnt);
if (ret < 1)
{
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Can't parse urb length from '%s'", string);
return -1;
}
@@ -974,7 +1010,7 @@ usb_read_linux(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_cha
/* check for data presence; data is present if and only if urb tag is '=' */
if (sscanf(string, " %c", &urb_tag) != 1)
{
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Can't parse urb tag from '%s'", string);
return -1;
}
@@ -1010,7 +1046,7 @@ got:
pkth.caplen = (bpf_u_int32)handle->snapshot;
if (handle->fcode.bf_insns == NULL ||
- bpf_filter(handle->fcode.bf_insns, handle->buffer,
+ pcap_filter(handle->fcode.bf_insns, handle->buffer,
pkth.len, pkth.caplen)) {
handlep->packets_read++;
callback(user, &pkth, handle->buffer);
@@ -1020,9 +1056,9 @@ got:
}
static int
-usb_inject_linux(pcap_t *handle, const void *buf _U_, size_t size _U_)
+usb_inject_linux(pcap_t *handle, const void *buf _U_, int size _U_)
{
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Packet injection is not supported on USB devices");
return (-1);
}
@@ -1031,13 +1067,14 @@ static int
usb_stats_linux(pcap_t *handle, struct pcap_stat *stats)
{
struct pcap_usb_linux *handlep = handle->priv;
- int dummy, ret, consumed, cnt;
+ int dummy, cnt;
+ ssize_t ret, consumed;
char string[USB_LINE_LEN];
char token[USB_LINE_LEN];
char * ptr = string;
int fd;
- pcap_snprintf(string, USB_LINE_LEN, USB_TEXT_DIR"/%ds", handlep->bus_index);
+ snprintf(string, USB_LINE_LEN, USB_TEXT_DIR"/%ds", handlep->bus_index);
fd = open(string, O_RDONLY, 0);
if (fd < 0)
{
@@ -1047,7 +1084,7 @@ usb_stats_linux(pcap_t *handle, struct pcap_stat *stats)
* Not found at the new location; try the old
* location.
*/
- pcap_snprintf(string, USB_LINE_LEN, USB_TEXT_DIR_OLD"/%ds", handlep->bus_index);
+ snprintf(string, USB_LINE_LEN, USB_TEXT_DIR_OLD"/%ds", handlep->bus_index);
fd = open(string, O_RDONLY, 0);
}
if (fd < 0) {
@@ -1066,7 +1103,7 @@ usb_stats_linux(pcap_t *handle, struct pcap_stat *stats)
if (ret < 0)
{
- pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Can't read stats from fd %d ", fd);
return -1;
}
@@ -1108,6 +1145,10 @@ usb_stats_linux(pcap_t *handle, struct pcap_stat *stats)
static int
usb_setdirection_linux(pcap_t *p, pcap_direction_t d)
{
+ /*
+ * It's guaranteed, at this point, that d is a valid
+ * direction value.
+ */
p->direction = d;
return 0;
}
@@ -1208,11 +1249,11 @@ usb_read_linux_bin(pcap_t *handle, int max_packets _U_, pcap_handler callback, u
*/
pkth.len = sizeof(pcap_usb_header) + info.hdr->urb_len;
}
- pkth.ts.tv_sec = info.hdr->ts_sec;
+ pkth.ts.tv_sec = (time_t)info.hdr->ts_sec;
pkth.ts.tv_usec = info.hdr->ts_usec;
if (handle->fcode.bf_insns == NULL ||
- bpf_filter(handle->fcode.bf_insns, handle->buffer,
+ pcap_filter(handle->fcode.bf_insns, handle->buffer,
pkth.len, pkth.caplen)) {
handlep->packets_read++;
callback(user, &pkth, handle->buffer);
@@ -1323,11 +1364,11 @@ 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;
}
- pkth.ts.tv_sec = hdr->ts_sec;
+ pkth.ts.tv_sec = (time_t)hdr->ts_sec;
pkth.ts.tv_usec = hdr->ts_usec;
if (handle->fcode.bf_insns == NULL ||
- bpf_filter(handle->fcode.bf_insns, (u_char*) hdr,
+ pcap_filter(handle->fcode.bf_insns, (u_char*) hdr,
pkth.len, pkth.caplen)) {
handlep->packets_read++;
callback(user, &pkth, (u_char*) hdr);
@@ -1335,7 +1376,7 @@ usb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_ch
}
}
- /* with max_packets specifying "unlimited" we stop afer the first chunk*/
+ /* with max_packets specifying "unlimited" we stop after the first chunk*/
if (PACKET_COUNT_IS_UNLIMITED(max_packets) || (packets == max_packets))
break;
}
diff --git a/pcap.3pcap.in b/pcap.3pcap.in
index 80101403..492c227e 100644
--- a/pcap.3pcap.in
+++ b/pcap.3pcap.in
@@ -17,7 +17,7 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP 3PCAP "25 July 2018"
+.TH PCAP 3PCAP "9 September 2020"
.SH NAME
pcap \- Packet Capture library
.SH SYNOPSIS
@@ -35,12 +35,69 @@ on the network, even those destined for other hosts, are accessible
through this mechanism.
It also supports saving captured packets to a ``savefile'', and reading
packets from a ``savefile''.
+.SS Initializing
+.BR pcap_init ()
+initializes the library. It takes an argument giving options;
+currently, the options are:
+.TP
+.B PCAP_CHAR_ENC_LOCAL
+Treat all strings supplied as arguments, and return all strings to the
+caller, as being in the local character encoding.
+.TP
+.B PCAP_CHAR_ENC_UTF_8
+Treat all strings supplied as arguments, and return all strings to the
+caller, as being in UTF-8.
+.PP
+On UNIX-like systems, the local character encoding is assumed to be
+UTF-8, so no character encoding transformations are done.
+.PP
+On Windows, the local character encoding is the local ANSI code page.
+.PP
+If
+.BR pcap_init ()
+is called, the deprecated
+.BR pcap_lookupdev ()
+routine always fails, so it should not be used, and, on Windows,
+.BR pcap_create ()
+does not attempt to handle UTF-16LE strings.
+.PP
+If
+.BR pcap_init ()
+is not called, strings are treated as being in the local ANSI code page
+on Windows,
+.BR pcap_lookupdev ()
+will succeed if there is a device on which to capture, and
+.BR pcap_create ()
+makes an attempt to check whether the string passed as an argument is a
+UTF-16LE string - note that this attempt is unsafe, as it may run past
+the end of the string - to handle
+.BR pcap_lookupdev ()
+returning a UTF-16LE string. Programs that don't call
+.BR pcap_init ()
+should, on Windows, call
+.BR pcap_wsockinit ()
+to initialize Winsock; this is not necessary if
+.BR pcap_init ()
+is called, as
+.BR pcap_init ()
+will initialize Winsock itself on Windows.
+.TP
+.B Routines
+.RS
+.TP
+.BR pcap_init (3PCAP)
+initialize the library
+.RE
.SS Opening a capture handle for reading
To open a handle for a live capture, given the name of the network or
other interface on which the capture should be done, call
.BR pcap_create (),
set the appropriate options on the handle, and then activate it with
.BR pcap_activate ().
+If
+.BR pcap_activate ()
+fails, the handle should be closed with
+.BR pcap_close ().
.PP
To obtain a list of devices that can be opened for a live capture, call
.BR pcap_findalldevs ();
@@ -121,7 +178,9 @@ Note that even if an application does not set promiscuous mode, the
adapter could well be in promiscuous mode for some other reason.
.IP
For now, this doesn't work on the "any" device; if an argument of "any"
-or NULL is supplied, the setting of promiscuous mode is ignored.
+or
+.B NULL
+is supplied, the setting of promiscuous mode is ignored.
.IP
Promiscuous mode is set with
.BR pcap_set_promisc ().
@@ -249,7 +308,7 @@ that device. A user can be given that privilege by, for example, adding
that privilege to the user's
.B defaultpriv
key with the
-.B usermod (@MAN_ADMIN_COMMANDS@)
+.BR usermod (@MAN_ADMIN_COMMANDS@)
command.
.TP
.B Under HP-UX with DLPI:
@@ -262,14 +321,11 @@ setuid to root.
.TP
.B Under Linux:
You must be root or the application capturing packets must be installed
-setuid to root (unless your distribution has a kernel
+setuid to root, unless your distribution has a kernel
that supports capability bits such as CAP_NET_RAW and code to allow
those capability bits to be given to particular accounts and to cause
those bits to be set on a user's initial processes when they log in, in
-which case you must have CAP_NET_RAW in order to capture and
-CAP_NET_ADMIN to enumerate network devices with, for example, the
-.B \-D
-flag).
+which case you must have CAP_NET_RAW in order to capture.
.TP
.B Under ULTRIX and Digital UNIX/Tru64 UNIX:
Any user may capture network traffic.
@@ -320,6 +376,8 @@ any given link-layer header type, such as
for Ethernet. For example, the "any" device on Linux will have a
link-layer header type of
.B DLT_LINUX_SLL
+or
+.B DLT_LINUX_SLL2
even if all devices on the system at the time the "any" device is opened
have some other data link type, such as
.B DLT_EN10MB
@@ -515,7 +573,11 @@ set link-layer header type for a device
get name for a link-layer header type
.TP
.BR pcap_datalink_val_to_description (3PCAP)
+.PD 0
+.TP
+.BR pcap_datalink_val_to_description_or_dlt (3PCAP)
get description for a link-layer header type
+.PD
.TP
.BR pcap_datalink_name_to_val (3PCAP)
get link-layer header type corresponding to a name
@@ -585,7 +647,9 @@ packet. It returns a
.I const u_char
to the first
.B caplen
-bytes of the packet on success, and NULL on error.
+bytes of the packet on success, and
+.B NULL
+on error.
.PP
.BR pcap_next_ex ()
is passed two pointer arguments, one of which points to a
@@ -648,7 +712,7 @@ from the device.
Not all handles have such a descriptor available;
.BR pcap_get_selectable_fd ()
will return
-.B PCAP_ERROR
+.B \-1
if no such descriptor is available. If no such
descriptor is available, this may be because the device must be polled
periodically for packets; in that case,
@@ -659,7 +723,9 @@ whose value can be used as a timeout in those routines. When the
routine returns, an attmept should be made to read packets from the
device. If
.BR pcap_get_required_select_timeout ()
-returns NULL, no such timeout is available, and those routines cannot be
+returns
+.BR NULL ,
+no such timeout is available, and those routines cannot be
used with the device.
.PP
In addition, for various
@@ -723,13 +789,12 @@ and
.BR poll (2)
.TP
.BR pcap_get_required_select_timeout (3PCAP)
-if no descriptor usable with
+attempt to get a timeout required for using a
+.B pcap_t
+in calls such as
.BR select (2)
and
.BR poll (2)
-is available for the
-.BR pcap_t ,
-attempt to get a timeout usable with those routines
.RE
.SS Filters
In order to cause only certain packets to be returned when reading
@@ -893,8 +958,9 @@ for a live capture, using
.BR pcap_inject ()
or
.BR pcap_sendpacket ().
-(The two routines exist for compatibility with both OpenBSD and WinPcap;
-they perform the same function, but have different return values.)
+(The two routines exist for compatibility with both OpenBSD and
+WinPcap/Npcap; they perform the same function, but have different return
+values.)
.TP
.B Routines
.RS
@@ -958,8 +1024,12 @@ use an
script or some other configuration script to check whether the libpcap
1.0 APIs are available and use them only if they are.
.SH SEE ALSO
-autoconf(1), tcpdump(1), tcpslice(1), pcap-filter(@MAN_MISC_INFO@), pfconfig(8),
-usermod(@MAN_ADMIN_COMMANDS@)
+.BR autoconf (1),
+.BR tcpdump (1),
+.BR tcpslice (1),
+.BR pcap-filter (@MAN_MISC_INFO@),
+.BR pfconfig (8),
+.BR usermod (@MAN_ADMIN_COMMANDS@)
.SH AUTHORS
The original authors of libpcap are:
.LP
@@ -978,5 +1048,5 @@ To report a security issue please send an e-mail to security@tcpdump.org.
.LP
To report bugs and other problems, contribute patches, request a
feature, provide generic feedback etc please see the file
-.I CONTRIBUTING
+.I CONTRIBUTING.md
in the libpcap source tree root.
diff --git a/pcap.c b/pcap.c
index 5c8b51a2..ed8570aa 100644
--- a/pcap.c
+++ b/pcap.c
@@ -53,7 +53,6 @@ struct rtentry; /* declarations in <net/if.h> */
#include <netinet/in.h>
#endif /* _WIN32 */
-#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -62,11 +61,9 @@ struct rtentry; /* declarations in <net/if.h> */
#endif
#include <fcntl.h>
#include <errno.h>
-#ifdef HAVE_LIMITS_H
#include <limits.h>
-#else
-#define INT_MAX 2147483647
-#endif
+
+#include "diag-control.h"
#ifdef HAVE_OS_PROTO_H
#include "os-proto.h"
@@ -96,7 +93,7 @@ struct rtentry; /* declarations in <net/if.h> */
#include "pcap-tc.h"
#endif /* HAVE_TC_API */
-#ifdef PCAP_SUPPORT_USB
+#ifdef PCAP_SUPPORT_LINUX_USBMON
#include "pcap-usb-linux.h"
#endif
@@ -124,56 +121,201 @@ struct rtentry; /* declarations in <net/if.h> */
#include "pcap-rdmasniff.h"
#endif
+#ifdef PCAP_SUPPORT_DPDK
+#include "pcap-dpdk.h"
+#endif
+
+#ifdef HAVE_AIRPCAP_API
+#include "pcap-airpcap.h"
+#endif
+
#ifdef _WIN32
/*
* DllMain(), required when built as a Windows DLL.
+ *
+ * To quote the WSAStartup() documentation:
+ *
+ * The WSAStartup function typically leads to protocol-specific helper
+ * DLLs being loaded. As a result, the WSAStartup function should not
+ * be called from the DllMain function in a application DLL. This can
+ * potentially cause deadlocks.
+ *
+ * and the WSACleanup() documentation:
+ *
+ * The WSACleanup function typically leads to protocol-specific helper
+ * DLLs being unloaded. As a result, the WSACleanup function should not
+ * be called from the DllMain function in a application DLL. This can
+ * potentially cause deadlocks.
+ *
+ * So we don't initialize Winsock here. pcap_init() should be called
+ * to initialize pcap on both UN*X and Windows; it will initialize
+ * Winsock on Windows. (It will also be initialized as needed if
+ * pcap_init() hasn't been called.)
*/
BOOL WINAPI DllMain(
- HANDLE hinstDLL,
- DWORD dwReason,
- LPVOID lpvReserved
+ HANDLE hinstDLL _U_,
+ DWORD dwReason _U_,
+ LPVOID lpvReserved _U_
)
{
return (TRUE);
}
/*
- * Start WinSock.
- * Exported in case some applications using WinPcap/Npcap called it,
- * even though it wasn't exported.
+ * Start Winsock.
+ * Internal routine.
*/
-int
-wsockinit(void)
+static int
+internal_wsockinit(char *errbuf)
{
WORD wVersionRequested;
WSADATA wsaData;
static int err = -1;
static int done = 0;
+ int status;
if (done)
return (err);
- wVersionRequested = MAKEWORD( 1, 1);
- err = WSAStartup( wVersionRequested, &wsaData );
- atexit ((void(*)(void))WSACleanup);
+ /*
+ * Versions of Windows that don't support Winsock 2.2 are
+ * too old for us.
+ */
+ wVersionRequested = MAKEWORD(2, 2);
+ status = WSAStartup(wVersionRequested, &wsaData);
done = 1;
-
- if ( err != 0 )
- err = -1;
+ if (status != 0) {
+ if (errbuf != NULL) {
+ pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE,
+ status, "WSAStartup() failed");
+ }
+ return (err);
+ }
+ atexit ((void(*)(void))WSACleanup);
+ err = 0;
return (err);
}
/*
+ * Exported in case some applications using WinPcap/Npcap called it,
+ * even though it wasn't exported.
+ */
+int
+wsockinit(void)
+{
+ return (internal_wsockinit(NULL));
+}
+
+/*
* This is the exported function; new programs should call this.
+ * *Newer* programs should call pcap_init().
*/
int
pcap_wsockinit(void)
{
- return (wsockinit());
+ return (internal_wsockinit(NULL));
}
#endif /* _WIN32 */
/*
+ * Do whatever initialization is needed for libpcap.
+ *
+ * The argument specifies whether we use the local code page or UTF-8
+ * for strings; on UN*X, we just assume UTF-8 in places where the encoding
+ * would matter, whereas, on Windows, we use the local code page for
+ * PCAP_CHAR_ENC_LOCAL and UTF-8 for PCAP_CHAR_ENC_UTF_8.
+ *
+ * On Windows, we also disable the hack in pcap_create() to deal with
+ * being handed UTF-16 strings, because if the user calls this they're
+ * explicitly declaring that they will either be passing local code
+ * page strings or UTF-8 strings, so we don't need to allow UTF-16LE
+ * strings to be passed. For good measure, on Windows *and* UN*X,
+ * we disable pcap_lookupdev(), to prevent anybody from even
+ * *trying* to pass the result of pcap_lookupdev() - which might be
+ * UTF-16LE on Windows, for ugly compatibility reasons - to pcap_create()
+ * or pcap_open_live() or pcap_open().
+ *
+ * Returns 0 on success, -1 on error.
+ */
+int pcap_new_api; /* pcap_lookupdev() always fails */
+int pcap_utf_8_mode; /* Strings should be in UTF-8. */
+
+int
+pcap_init(unsigned int opts, char *errbuf)
+{
+ static int initialized;
+
+ /*
+ * Don't allow multiple calls that set different modes; that
+ * may mean a library is initializing pcap in one mode and
+ * a program using that library, or another library used by
+ * that program, is initializing it in another mode.
+ */
+ switch (opts) {
+
+ case PCAP_CHAR_ENC_LOCAL:
+ /* Leave "UTF-8 mode" off. */
+ if (initialized) {
+ if (pcap_utf_8_mode) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Multiple pcap_init calls with different character encodings");
+ return (-1);
+ }
+ }
+ break;
+
+ case PCAP_CHAR_ENC_UTF_8:
+ /* Turn on "UTF-8 mode". */
+ if (initialized) {
+ if (!pcap_utf_8_mode) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Multiple pcap_init calls with different character encodings");
+ return (-1);
+ }
+ }
+ pcap_utf_8_mode = 1;
+ break;
+
+ default:
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Unknown options specified");
+ return (-1);
+ }
+
+ /*
+ * Turn the appropriate mode on for error messages; those routines
+ * are also used in rpcapd, which has no access to pcap's internal
+ * UTF-8 mode flag, so we have to call a routine to set its
+ * UTF-8 mode flag.
+ */
+ pcap_fmt_set_encoding(opts);
+
+ if (initialized) {
+ /*
+ * Nothing more to do; for example, on Windows, we've
+ * already initialized Winsock.
+ */
+ return (0);
+ }
+
+#ifdef _WIN32
+ /*
+ * Now set up Winsock.
+ */
+ if (internal_wsockinit(errbuf) == -1) {
+ /* Failed. */
+ return (-1);
+ }
+#endif
+
+ /*
+ * We're done.
+ */
+ initialized = 1;
+ pcap_new_api = 1;
+ return (0);
+}
+
+/*
* String containing the library version.
* Not explicitly exported via a header file - the right API to use
* is pcap_lib_version() - but some programs included it, so we
@@ -191,12 +333,12 @@ pcap_set_not_initialized_message(pcap_t *pcap)
{
if (pcap->activated) {
/* A module probably forgot to set the function pointer */
- (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+ (void)snprintf(pcap->errbuf, sizeof(pcap->errbuf),
"This operation isn't properly handled by that device");
return;
}
/* in case the caller doesn't check for PCAP_ERROR_NOT_ACTIVATED */
- (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+ (void)snprintf(pcap->errbuf, sizeof(pcap->errbuf),
"This handle hasn't been activated yet");
}
@@ -210,7 +352,7 @@ pcap_read_not_initialized(pcap_t *pcap, int cnt _U_, pcap_handler callback _U_,
}
static int
-pcap_inject_not_initialized(pcap_t *pcap, const void * buf _U_, size_t size _U_)
+pcap_inject_not_initialized(pcap_t *pcap, const void * buf _U_, int size _U_)
{
pcap_set_not_initialized_message(pcap);
/* this means 'not initialized' */
@@ -258,7 +400,7 @@ pcap_stats_not_initialized(pcap_t *pcap, struct pcap_stat *ps _U_)
}
#ifdef _WIN32
-struct pcap_stat *
+static struct pcap_stat *
pcap_stats_ex_not_initialized(pcap_t *pcap, int *pcap_stat_size _U_)
{
pcap_set_not_initialized_message(pcap);
@@ -313,7 +455,8 @@ pcap_oid_set_request_not_initialized(pcap_t *pcap, bpf_u_int32 oid _U_,
}
static u_int
-pcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue, int sync)
+pcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue _U_,
+ int sync _U_)
{
pcap_set_not_initialized_message(pcap);
return (0);
@@ -534,7 +677,7 @@ static struct capture_source_type {
#ifdef PCAP_SUPPORT_BT_MONITOR
{ bt_monitor_findalldevs, bt_monitor_create },
#endif
-#ifdef PCAP_SUPPORT_USB
+#ifdef PCAP_SUPPORT_LINUX_USBMON
{ usb_findalldevs, usb_create },
#endif
#ifdef PCAP_SUPPORT_NETFILTER
@@ -549,6 +692,12 @@ static struct capture_source_type {
#ifdef PCAP_SUPPORT_RDMASNIFF
{ rdmasniff_findalldevs, rdmasniff_create },
#endif
+#ifdef PCAP_SUPPORT_DPDK
+ { pcap_dpdk_findalldevs, pcap_dpdk_create },
+#endif
+#ifdef HAVE_AIRPCAP_API
+ { airpcap_findalldevs, airpcap_create },
+#endif
{ NULL, NULL }
};
@@ -628,39 +777,26 @@ dup_sockaddr(struct sockaddr *sa, size_t sa_length)
*
* The figure of merit, which is lower the "better" the interface is,
* has the uppermost bit set if the interface isn't running, the bit
- * below that set if the interface isn't up, the bit below that set
- * if the interface is a loopback interface, and the interface index
- * in the 29 bits below that. (Yes, we assume u_int is 32 bits.)
+ * below that set if the interface isn't up, the bit below that
+ * set if the interface is a loopback interface, and the bit below
+ * that set if it's the "any" interface.
+ *
+ * Note: we don't sort by unit number because 1) not all interfaces have
+ * a unit number (systemd, for example, might assign interface names
+ * based on the interface's MAC address or on the physical location of
+ * the adapter's connector), and 2) if the name does end with a simple
+ * unit number, it's not a global property of the interface, it's only
+ * useful as a sort key for device names with the same prefix, so xyz0
+ * shouldn't necessarily sort before abc2. This means that interfaces
+ * with the same figure of merit will be sorted by the order in which
+ * the mechanism from which we're getting the interfaces supplies them.
*/
static u_int
get_figure_of_merit(pcap_if_t *dev)
{
- const char *cp;
u_int n;
- if (strcmp(dev->name, "any") == 0) {
- /*
- * Give the "any" device an artificially high instance
- * number, so it shows up after all other non-loopback
- * interfaces.
- */
- n = 0x1FFFFFFF; /* 29 all-1 bits */
- } else {
- /*
- * A number at the end of the device name string is
- * assumed to be an instance number. Add 1 to the
- * instance number, and use 0 for "no instance
- * number", so we don't put "no instance number"
- * devices and "instance 0" devices together.
- */
- cp = dev->name + strlen(dev->name) - 1;
- while (cp-1 >= dev->name && *(cp-1) >= '0' && *(cp-1) <= '9')
- cp--;
- if (*cp >= '0' && *cp <= '9')
- n = atoi(cp) + 1;
- else
- n = 0;
- }
+ n = 0;
if (!(dev->flags & PCAP_IF_RUNNING))
n |= 0x80000000;
if (!(dev->flags & PCAP_IF_UP))
@@ -687,6 +823,13 @@ get_figure_of_merit(pcap_if_t *dev)
if (dev->flags & PCAP_IF_LOOPBACK)
n |= 0x10000000;
+ /*
+ * Sort the "any" device before loopback and disconnected devices,
+ * but after all other devices.
+ */
+ if (strcmp(dev->name, "any") == 0)
+ n |= 0x08000000;
+
return (n);
}
@@ -887,7 +1030,7 @@ find_or_add_if(pcap_if_list_t *devlistp, const char *name,
* see if it looks like a loopback device.
*/
if (name[0] == 'l' && name[1] == 'o' &&
- (isdigit((unsigned char)(name[2])) || name[2] == '\0')
+ (PCAP_ISDIGIT(name[2]) || name[2] == '\0'))
pcap_flags |= PCAP_IF_LOOPBACK;
#endif
#ifdef IFF_UP
@@ -1368,6 +1511,22 @@ pcap_lookupdev(char *errbuf)
static char device[IF_NAMESIZE + 1];
char *ret;
+ /*
+ * We disable this in "new API" mode, because 1) in WinPcap/Npcap,
+ * it may return UTF-16 strings, for backwards-compatibility
+ * reasons, and we're also disabling the hack to make that work,
+ * for not-going-past-the-end-of-a-string reasons, and 2) we
+ * want its behavior to be consistent.
+ *
+ * In addition, it's not thread-safe, so we've marked it as
+ * deprecated.
+ */
+ if (pcap_new_api) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "pcap_lookupdev() is deprecated and is not supported in programs calling pcap_init()");
+ return (NULL);
+ }
+
if (pcap_findalldevs(&alldevs, errbuf) == -1)
return (NULL);
@@ -1431,7 +1590,7 @@ pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp,
#ifdef PCAP_SUPPORT_BT
|| strstr(device, "bluetooth") != NULL
#endif
-#ifdef PCAP_SUPPORT_USB
+#ifdef PCAP_SUPPORT_LINUX_USBMON
|| strstr(device, "usbmon") != NULL
#endif
#ifdef HAVE_SNF_API
@@ -1441,6 +1600,9 @@ pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp,
|| strncmp(device, "netmap:", 7) == 0
|| strncmp(device, "vale", 4) == 0
#endif
+#ifdef PCAP_SUPPORT_DPDK
+ || strncmp(device, "dpdk:", 5) == 0
+#endif
) {
*netp = *maskp = 0;
return 0;
@@ -1460,7 +1622,7 @@ pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp,
(void)pcap_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
if (errno == EADDRNOTAVAIL) {
- (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"%s: no IPv4 address assigned", device);
} else {
pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
@@ -1493,7 +1655,7 @@ pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp,
else if (IN_CLASSC(*netp))
*maskp = IN_CLASSC_NET;
else {
- (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"inet class for 0x%x unknown", *netp);
return (-1);
}
@@ -1685,7 +1847,8 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop,
*
* XXX - %-escaping?
*/
- if (pcap_strcasecmp(scheme, "rpcap") == 0 &&
+ if ((pcap_strcasecmp(scheme, "rpcap") == 0 ||
+ pcap_strcasecmp(scheme, "rpcaps") == 0) &&
strchr(colonp + 3, '/') == NULL) {
/*
* Local device.
@@ -1788,7 +1951,7 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop,
/*
* There's no closing square bracket.
*/
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
"IP-literal in URL doesn't end with ]");
free(userinfo);
free(authority);
@@ -1801,7 +1964,7 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop,
* There's extra crud after the
* closing square bracketn.
*/
- pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
"Extra text after IP-literal in URL");
free(userinfo);
free(authority);
@@ -1896,8 +2059,8 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop,
}
int
-pcap_createsrcstr(char *source, int type, const char *host, const char *port,
- const char *name, char *errbuf)
+pcap_createsrcstr_ex(char *source, int type, const char *host, const char *port,
+ const char *name, unsigned char uses_ssl, char *errbuf)
{
switch (type) {
@@ -1907,13 +2070,15 @@ pcap_createsrcstr(char *source, int type, const char *host, const char *port,
pcap_strlcat(source, name, PCAP_BUF_SIZE);
return (0);
} else {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"The file name cannot be NULL.");
return (-1);
}
case PCAP_SRC_IFREMOTE:
- pcap_strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE);
+ pcap_strlcpy(source,
+ (uses_ssl ? "rpcaps://" : PCAP_SRC_IF_STRING),
+ PCAP_BUF_SIZE);
if (host != NULL && *host != '\0') {
if (strchr(host, ':') != NULL) {
/*
@@ -1934,7 +2099,7 @@ pcap_createsrcstr(char *source, int type, const char *host, const char *port,
pcap_strlcat(source, "/", PCAP_BUF_SIZE);
} else {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"The host name cannot be NULL.");
return (-1);
}
@@ -1953,15 +2118,23 @@ pcap_createsrcstr(char *source, int type, const char *host, const char *port,
return (0);
default:
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"The interface type is not valid.");
return (-1);
}
}
+
int
-pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
- char *name, char *errbuf)
+pcap_createsrcstr(char *source, int type, const char *host, const char *port,
+ const char *name, char *errbuf)
+{
+ return (pcap_createsrcstr_ex(source, type, host, port, name, 0, errbuf));
+}
+
+int
+pcap_parsesrcstr_ex(const char *source, int *type, char *host, char *port,
+ char *name, unsigned char *uses_ssl, char *errbuf)
{
char *scheme, *tmpuserinfo, *tmphost, *tmpport, *tmppath;
@@ -1972,6 +2145,8 @@ pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
*port = '\0';
if (name)
*name = '\0';
+ if (uses_ssl)
+ *uses_ssl = 0;
/* Parse the source string */
if (pcap_parse_source(source, &scheme, &tmpuserinfo, &tmphost,
@@ -1997,16 +2172,24 @@ pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
return (0);
}
- if (strcmp(scheme, "rpcap") == 0) {
+ int is_rpcap = 0;
+ if (strcmp(scheme, "rpcaps") == 0) {
+ is_rpcap = 1;
+ if (uses_ssl) *uses_ssl = 1;
+ } else if (strcmp(scheme, "rpcap") == 0) {
+ is_rpcap = 1;
+ }
+
+ if (is_rpcap) {
/*
- * rpcap://
+ * rpcap[s]://
*
* pcap_parse_source() has already handled the case of
- * rpcap://device
+ * rpcap[s]://device
*/
if (host && tmphost) {
if (tmpuserinfo)
- pcap_snprintf(host, PCAP_BUF_SIZE, "%s@%s",
+ snprintf(host, PCAP_BUF_SIZE, "%s@%s",
tmpuserinfo, tmphost);
else
pcap_strlcpy(host, tmphost, PCAP_BUF_SIZE);
@@ -2056,6 +2239,13 @@ pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
free(scheme);
return (0);
}
+
+int
+pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
+ char *name, char *errbuf)
+{
+ return (pcap_parsesrcstr_ex(source, type, host, port, name, NULL, errbuf));
+}
#endif
pcap_t *
@@ -2089,19 +2279,31 @@ pcap_create(const char *device, char *errbuf)
* string, not a string in the local code page.
*
* To work around that, we check whether the string
- * looks as if it might be a UTF-16LE strinh and, if
+ * looks as if it might be a UTF-16LE string and, if
* so, convert it back to the local code page's
* extended ASCII.
*
- * XXX - you *cannot* reliably detect whether a
- * string is UTF-16LE or not; "a" could either
- * be a one-character ASCII string or the first
- * character of a UTF-16LE string. This particular
- * version of this heuristic dates back to WinPcap
- * 4.1.1; PacketOpenAdapter() does uses the same
- * heuristic, with the exact same vulnerability.
+ * We disable that check in "new API" mode, because:
+ *
+ * 1) You *cannot* reliably detect whether a
+ * string is UTF-16LE or not; "a" could either
+ * be a one-character ASCII string or the first
+ * character of a UTF-16LE string.
+ *
+ * 2) Doing that test can run past the end of
+ * the string, if it's a 1-character ASCII
+ * string
+ *
+ * This particular version of this heuristic dates
+ * back to WinPcap 4.1.1; PacketOpenAdapter() does
+ * uses the same heuristic, with the exact same
+ * vulnerability.
+ *
+ * That's why we disable this in "new API" mode.
+ * We keep it around in legacy mode for backwards
+ * compatibility.
*/
- if (device[0] != '\0' && device[1] == '\0') {
+ if (!pcap_new_api && device[0] != '\0' && device[1] == '\0') {
size_t length;
length = wcslen((wchar_t *)device);
@@ -2113,7 +2315,7 @@ pcap_create(const char *device, char *errbuf)
return (NULL);
}
- pcap_snprintf(device_str, length + 1, "%ws",
+ snprintf(device_str, length + 1, "%ws",
(const wchar_t *)device);
} else
#endif
@@ -2225,36 +2427,31 @@ initialize_ops(pcap_t *p)
* be used for pcap_next()/pcap_next_ex().
*/
p->oneshot_callback = pcap_oneshot;
+
+ /*
+ * Default breakloop operation - implementations can override
+ * this, but should call pcap_breakloop_common() before doing
+ * their own logic.
+ */
+ p->breakloop_op = pcap_breakloop_common;
}
static pcap_t *
-pcap_alloc_pcap_t(char *ebuf, size_t size)
+pcap_alloc_pcap_t(char *ebuf, size_t total_size, size_t private_offset)
{
char *chunk;
pcap_t *p;
/*
- * Allocate a chunk of memory big enough for a pcap_t
- * plus a structure following it of size "size". The
- * structure following it is a private data structure
- * for the routines that handle this pcap_t.
- *
- * The structure following it must be aligned on
- * the appropriate alignment boundary for this platform.
- * We align on an 8-byte boundary as that's probably what
- * at least some platforms do, even with 32-bit integers,
- * and because we can't be sure that some values won't
- * require 8-byte alignment even on platforms with 32-bit
- * integers.
- */
-#define PCAP_T_ALIGNED_SIZE ((sizeof(pcap_t) + 7U) & ~0x7U)
- chunk = malloc(PCAP_T_ALIGNED_SIZE + size);
+ * total_size is the size of a structure containing a pcap_t
+ * followed by a private structure.
+ */
+ chunk = calloc(total_size, 1);
if (chunk == NULL) {
pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
errno, "malloc");
return (NULL);
}
- memset(chunk, 0, PCAP_T_ALIGNED_SIZE + size);
/*
* Get a pointer to the pcap_t at the beginning.
@@ -2271,26 +2468,24 @@ pcap_alloc_pcap_t(char *ebuf, size_t size)
#endif /* MSDOS */
#endif /* _WIN32 */
- if (size == 0) {
- /* No private data was requested. */
- p->priv = NULL;
- } else {
- /*
- * Set the pointer to the private data; that's the structure
- * of size "size" following the pcap_t.
- */
- p->priv = (void *)(chunk + PCAP_T_ALIGNED_SIZE);
- }
+ /*
+ * private_offset is the offset, in bytes, of the private
+ * data from the beginning of the structure.
+ *
+ * Set the pointer to the private data; that's private_offset
+ * bytes past the pcap_t.
+ */
+ p->priv = (void *)(chunk + private_offset);
return (p);
}
pcap_t *
-pcap_create_common(char *ebuf, size_t size)
+pcap_create_common(char *ebuf, size_t total_size, size_t private_offset)
{
pcap_t *p;
- p = pcap_alloc_pcap_t(ebuf, size);
+ p = pcap_alloc_pcap_t(ebuf, total_size, private_offset);
if (p == NULL)
return (NULL);
@@ -2342,7 +2537,7 @@ int
pcap_check_activated(pcap_t *p)
{
if (p->activated) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't perform "
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't perform "
" operation on activated capture");
return (-1);
}
@@ -2550,7 +2745,7 @@ pcap_activate(pcap_t *p)
* handle errors other than PCAP_ERROR, return the
* error message corresponding to the status.
*/
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s",
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s",
pcap_statustostr(status));
}
@@ -2608,7 +2803,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *er
NULL, errbuf));
}
if (srctype == PCAP_SRC_FILE) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown URL scheme \"file\"");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown URL scheme \"file\"");
return (NULL);
}
if (srctype == PCAP_SRC_IFLOCAL) {
@@ -2655,26 +2850,26 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *er
return (p);
fail:
if (status == PCAP_ERROR)
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %.*s", device,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %.*s", device,
PCAP_ERRBUF_SIZE - 3, p->errbuf);
else if (status == PCAP_ERROR_NO_SUCH_DEVICE ||
status == PCAP_ERROR_PERM_DENIED ||
status == PCAP_ERROR_PROMISC_PERM_DENIED)
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%.*s)", device,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%.*s)", device,
pcap_statustostr(status), PCAP_ERRBUF_SIZE - 6, p->errbuf);
else
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device,
pcap_statustostr(status));
pcap_close(p);
return (NULL);
}
pcap_t *
-pcap_open_offline_common(char *ebuf, size_t size)
+pcap_open_offline_common(char *ebuf, size_t total_size, size_t private_offset)
{
pcap_t *p;
- p = pcap_alloc_pcap_t(ebuf, size);
+ p = pcap_alloc_pcap_t(ebuf, total_size, private_offset);
if (p == NULL)
return (NULL);
@@ -2725,7 +2920,7 @@ pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
void
pcap_breakloop(pcap_t *p)
{
- p->break_loop = 1;
+ p->breakloop_op(p);
}
int
@@ -2848,11 +3043,11 @@ pcap_set_datalink(pcap_t *p, int dlt)
unsupported:
dlt_name = pcap_datalink_val_to_name(dlt);
if (dlt_name != NULL) {
- (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf),
+ (void) snprintf(p->errbuf, sizeof(p->errbuf),
"%s is not one of the DLTs supported by this device",
dlt_name);
} else {
- (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf),
+ (void) snprintf(p->errbuf, sizeof(p->errbuf),
"DLT %d is not one of the DLTs supported by this device",
dlt);
}
@@ -2965,7 +3160,7 @@ static struct dlt_choice dlt_choices[] = {
DLT_CHOICE(RAW, "Raw IP"),
DLT_CHOICE(SLIP_BSDOS, "BSD/OS SLIP"),
DLT_CHOICE(PPP_BSDOS, "BSD/OS PPP"),
- DLT_CHOICE(ATM_CLIP, "Linux Classical IP-over-ATM"),
+ DLT_CHOICE(ATM_CLIP, "Linux Classical IP over ATM"),
DLT_CHOICE(PPP_SERIAL, "PPP over serial"),
DLT_CHOICE(PPP_ETHER, "PPPoE"),
DLT_CHOICE(SYMANTEC_FIREWALL, "Symantec Firewall"),
@@ -3094,6 +3289,18 @@ static struct dlt_choice dlt_choices[] = {
DLT_CHOICE(ETHERNET_MPACKET, "802.3br mPackets"),
DLT_CHOICE(DISPLAYPORT_AUX, "DisplayPort AUX channel monitoring data"),
DLT_CHOICE(LINUX_SLL2, "Linux cooked v2"),
+ DLT_CHOICE(OPENVIZSLA, "OpenVizsla USB"),
+ DLT_CHOICE(EBHSCR, "Elektrobit High Speed Capture and Replay (EBHSCR)"),
+ DLT_CHOICE(VPP_DISPATCH, "VPP graph dispatch tracer"),
+ DLT_CHOICE(DSA_TAG_BRCM, "Broadcom tag"),
+ DLT_CHOICE(DSA_TAG_BRCM_PREPEND, "Broadcom tag (prepended)"),
+ DLT_CHOICE(IEEE802_15_4_TAP, "IEEE 802.15.4 with pseudo-header"),
+ DLT_CHOICE(DSA_TAG_DSA, "Marvell DSA"),
+ DLT_CHOICE(DSA_TAG_EDSA, "Marvell EDSA"),
+ DLT_CHOICE(ELEE, "ELEE lawful intercept packets"),
+ DLT_CHOICE(Z_WAVE_SERIAL, "Z-Wave serial frames between host and chip"),
+ DLT_CHOICE(USB_2_0, "USB 2.0/1.1/1.0 as transmitted over the cable"),
+ DLT_CHOICE(ATSC_ALP, "ATSC Link-Layer Protocol packets"),
DLT_CHOICE_SENTINEL
};
@@ -3143,7 +3350,7 @@ pcap_datalink_val_to_description_or_dlt(int dlt)
if (description != NULL) {
return description;
} else {
- (void)pcap_snprintf(unkbuf, sizeof(unkbuf), "DLT %u", dlt);
+ (void)snprintf(unkbuf, sizeof(unkbuf), "DLT %u", dlt);
return unkbuf;
}
}
@@ -3160,6 +3367,7 @@ static struct tstamp_type_choice tstamp_type_choices[] = {
{ "host_hiprec", "Host, high precision", PCAP_TSTAMP_HOST_HIPREC },
{ "adapter", "Adapter", PCAP_TSTAMP_ADAPTER },
{ "adapter_unsynced", "Adapter, not synced with system time", PCAP_TSTAMP_ADAPTER_UNSYNCED },
+ { "host_hiprec_unsynced", "Host, high precision, not synced with system time", PCAP_TSTAMP_HOST_HIPREC_UNSYNCED },
{ NULL, NULL, 0 }
};
@@ -3245,18 +3453,33 @@ pcap_file(pcap_t *p)
return (p->rfile);
}
+#ifdef _WIN32
int
pcap_fileno(pcap_t *p)
{
-#ifndef _WIN32
- return (p->fd);
-#else
- if (p->handle != INVALID_HANDLE_VALUE)
+ if (p->handle != INVALID_HANDLE_VALUE) {
+ /*
+ * This is a bogus and now-deprecated API; we
+ * squelch the narrowing warning for the cast
+ * from HANDLE to DWORD. If Windows programmmers
+ * need to get at the HANDLE for a pcap_t, *if*
+ * there is one, they should request such a
+ * routine (and be prepared for it to return
+ * INVALID_HANDLE_VALUE).
+ */
+DIAG_OFF_NARROWING
return ((int)(DWORD)p->handle);
- else
+DIAG_ON_NARROWING
+ } else
return (PCAP_ERROR);
-#endif
}
+#else /* _WIN32 */
+int
+pcap_fileno(pcap_t *p)
+{
+ return (p->fd);
+}
+#endif /* _WIN32 */
#if !defined(_WIN32) && !defined(MSDOS)
int
@@ -3265,7 +3488,7 @@ pcap_get_selectable_fd(pcap_t *p)
return (p->selectable_fd);
}
-struct timeval *
+const struct timeval *
pcap_get_required_select_timeout(pcap_t *p)
{
return (p->required_select_timeout);
@@ -3435,7 +3658,7 @@ pcap_statustostr(int errnum)
case PCAP_ERROR_TSTAMP_PRECISION_NOTSUP:
return ("That device doesn't support that time stamp precision");
}
- (void)pcap_snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum);
+ (void)snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum);
return(ebuf);
}
@@ -3463,7 +3686,7 @@ pcap_strerror(int errnum)
if ((unsigned int)errnum < sys_nerr)
return ((char *)sys_errlist[errnum]);
- (void)pcap_snprintf(errbuf, sizeof errbuf, "Unknown error: %d", errnum);
+ (void)snprintf(errbuf, sizeof errbuf, "Unknown error: %d", errnum);
return (errbuf);
#endif
}
@@ -3484,11 +3707,29 @@ int
pcap_setdirection(pcap_t *p, pcap_direction_t d)
{
if (p->setdirection_op == NULL) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "Setting direction is not implemented on this platform");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Setting direction is not supported on this device");
return (-1);
- } else
- return (p->setdirection_op(p, d));
+ } else {
+ switch (d) {
+
+ case PCAP_D_IN:
+ case PCAP_D_OUT:
+ case PCAP_D_INOUT:
+ /*
+ * Valid direction.
+ */
+ return (p->setdirection_op(p, d));
+
+ default:
+ /*
+ * Invalid direction.
+ */
+ snprintf(p->errbuf, sizeof(p->errbuf),
+ "Invalid direction");
+ return (-1);
+ }
+ }
}
int
@@ -3620,7 +3861,7 @@ pcap_get_airpcap_handle(pcap_t *p)
handle = p->get_airpcap_handle_op(p);
if (handle == NULL) {
- (void)pcap_snprintf(p->errbuf, sizeof(p->errbuf),
+ (void)snprintf(p->errbuf, sizeof(p->errbuf),
"This isn't an AirPcap device");
}
return (handle);
@@ -3657,8 +3898,28 @@ pcap_close_all(void)
{
struct pcap *handle;
- while ((handle = pcaps_to_close) != NULL)
+ while ((handle = pcaps_to_close) != NULL) {
pcap_close(handle);
+
+ /*
+ * If a pcap module adds a pcap_t to the "close all"
+ * list by calling pcap_add_to_pcaps_to_close(), it
+ * must have a cleanup routine that removes it from the
+ * list, by calling pcap_remove_from_pcaps_to_close(),
+ * and must make that cleanup routine the cleanup_op
+ * for the pcap_t.
+ *
+ * That means that, after pcap_close() - which calls
+ * the cleanup_op for the pcap_t - the pcap_t must
+ * have been removed from the list, so pcaps_to_close
+ * must not be equal to handle.
+ *
+ * We check for that, and abort if handle is still
+ * at the head of the list, to prevent infinite loops.
+ */
+ if (pcaps_to_close == handle)
+ abort();
+ }
}
int
@@ -3716,6 +3977,13 @@ pcap_remove_from_pcaps_to_close(pcap_t *p)
}
void
+pcap_breakloop_common(pcap_t *p)
+{
+ p->break_loop = 1;
+}
+
+
+void
pcap_cleanup_live_common(pcap_t *p)
{
if (p->buffer != NULL) {
@@ -3756,6 +4024,12 @@ pcap_cleanup_live_common(pcap_t *p)
int
pcap_sendpacket(pcap_t *p, const u_char *buf, int size)
{
+ if (size <= 0) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "The number of bytes to be sent must be positive");
+ return (PCAP_ERROR);
+ }
+
if (p->inject_op(p, buf, size) == -1)
return (-1);
return (0);
@@ -3768,7 +4042,23 @@ pcap_sendpacket(pcap_t *p, const u_char *buf, int size)
int
pcap_inject(pcap_t *p, const void *buf, size_t size)
{
- return (p->inject_op(p, buf, size));
+ /*
+ * We return the number of bytes written, so the number of
+ * bytes to write must fit in an int.
+ */
+ if (size > INT_MAX) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "More than %d bytes cannot be injected", INT_MAX);
+ return (PCAP_ERROR);
+ }
+
+ if (size == 0) {
+ pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
+ errno, "The number of bytes to be injected must not be zero");
+ return (PCAP_ERROR);
+ }
+
+ return (p->inject_op(p, buf, (int)size));
}
void
@@ -3781,6 +4071,81 @@ pcap_close(pcap_t *p)
}
/*
+ * Helpers for safely loding code at run time.
+ * Currently Windows-only.
+ */
+#ifdef _WIN32
+//
+// This wrapper around loadlibrary appends the system folder (usually
+// C:\Windows\System32) to the relative path of the DLL, so that the DLL
+// is always loaded from an absolute path (it's no longer possible to
+// load modules from the application folder).
+// This solves the DLL Hijacking issue discovered in August 2010:
+//
+// https://blog.rapid7.com/2010/08/23/exploiting-dll-hijacking-flaws/
+// https://blog.rapid7.com/2010/08/23/application-dll-load-hijacking/
+// (the purported Rapid7 blog post link in the first of those two links
+// is broken; the second of those links works.)
+//
+// If any links there are broken from all the content shuffling Rapid&
+// did, see archived versions of the posts at their original homes, at
+//
+// https://web.archive.org/web/20110122175058/http://blog.metasploit.com/2010/08/exploiting-dll-hijacking-flaws.html
+// https://web.archive.org/web/20100828112111/http://blog.rapid7.com/?p=5325
+//
+pcap_code_handle_t
+pcap_load_code(const char *name)
+{
+ /*
+ * XXX - should this work in UTF-16LE rather than in the local
+ * ANSI code page?
+ */
+ CHAR path[MAX_PATH];
+ CHAR fullFileName[MAX_PATH];
+ UINT res;
+ HMODULE hModule = NULL;
+
+ do
+ {
+ res = GetSystemDirectoryA(path, MAX_PATH);
+
+ if (res == 0) {
+ //
+ // some bad failure occurred;
+ //
+ break;
+ }
+
+ if (res > MAX_PATH) {
+ //
+ // the buffer was not big enough
+ //
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ break;
+ }
+
+ if (res + 1 + strlen(name) + 1 < MAX_PATH) {
+ memcpy(fullFileName, path, res * sizeof(TCHAR));
+ fullFileName[res] = '\\';
+ memcpy(&fullFileName[res + 1], name, (strlen(name) + 1) * sizeof(TCHAR));
+
+ hModule = LoadLibraryA(fullFileName);
+ } else
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+
+ } while(FALSE);
+
+ return hModule;
+}
+
+pcap_funcptr_t
+pcap_find_function(pcap_code_handle_t code, const char *func)
+{
+ return (GetProcAddress(code, func));
+}
+#endif
+
+/*
* Given a BPF program, a pcap_pkthdr structure for a packet, and the raw
* data for the packet, check whether the packet passes the filter.
* Returns the return value of the filter program, which will be zero if
@@ -3793,7 +4158,7 @@ pcap_offline_filter(const struct bpf_program *fp, const struct pcap_pkthdr *h,
const struct bpf_insn *fcode = fp->bf_insns;
if (fcode != NULL)
- return (bpf_filter(fcode, pkt, h->len, h->caplen));
+ return (pcap_filter(fcode, pkt, h->len, h->caplen));
else
return (0);
}
@@ -3801,7 +4166,7 @@ pcap_offline_filter(const struct bpf_program *fp, const struct pcap_pkthdr *h,
static int
pcap_can_set_rfmon_dead(pcap_t *p)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Rfmon mode doesn't apply on a pcap_open_dead pcap_t");
return (PCAP_ERROR);
}
@@ -3810,15 +4175,15 @@ static int
pcap_read_dead(pcap_t *p, int cnt _U_, pcap_handler callback _U_,
u_char *user _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Packets aren't available from a pcap_open_dead pcap_t");
return (-1);
}
static int
-pcap_inject_dead(pcap_t *p, const void *buf _U_, size_t size _U_)
+pcap_inject_dead(pcap_t *p, const void *buf _U_, int size _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Packets can't be sent on a pcap_open_dead pcap_t");
return (-1);
}
@@ -3826,7 +4191,7 @@ pcap_inject_dead(pcap_t *p, const void *buf _U_, size_t size _U_)
static int
pcap_setfilter_dead(pcap_t *p, struct bpf_program *fp _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"A filter cannot be set on a pcap_open_dead pcap_t");
return (-1);
}
@@ -3834,7 +4199,7 @@ pcap_setfilter_dead(pcap_t *p, struct bpf_program *fp _U_)
static int
pcap_setdirection_dead(pcap_t *p, pcap_direction_t d _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The packet direction cannot be set on a pcap_open_dead pcap_t");
return (-1);
}
@@ -3842,7 +4207,7 @@ pcap_setdirection_dead(pcap_t *p, pcap_direction_t d _U_)
static int
pcap_set_datalink_dead(pcap_t *p, int dlt _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The link-layer header type cannot be set on a pcap_open_dead pcap_t");
return (-1);
}
@@ -3850,7 +4215,7 @@ pcap_set_datalink_dead(pcap_t *p, int dlt _U_)
static int
pcap_getnonblock_dead(pcap_t *p)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"A pcap_open_dead pcap_t does not have a non-blocking mode setting");
return (-1);
}
@@ -3858,7 +4223,7 @@ pcap_getnonblock_dead(pcap_t *p)
static int
pcap_setnonblock_dead(pcap_t *p, int nonblock _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"A pcap_open_dead pcap_t does not have a non-blocking mode setting");
return (-1);
}
@@ -3866,40 +4231,40 @@ pcap_setnonblock_dead(pcap_t *p, int nonblock _U_)
static int
pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Statistics aren't available from a pcap_open_dead pcap_t");
return (-1);
}
#ifdef _WIN32
-struct pcap_stat *
+static struct pcap_stat *
pcap_stats_ex_dead(pcap_t *p, int *pcap_stat_size _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Statistics aren't available from a pcap_open_dead pcap_t");
return (NULL);
}
static int
-pcap_setbuff_dead(pcap_t *p, int dim)
+pcap_setbuff_dead(pcap_t *p, int dim _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The kernel buffer size cannot be set on a pcap_open_dead pcap_t");
return (-1);
}
static int
-pcap_setmode_dead(pcap_t *p, int mode)
+pcap_setmode_dead(pcap_t *p, int mode _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"impossible to set mode on a pcap_open_dead pcap_t");
return (-1);
}
static int
-pcap_setmintocopy_dead(pcap_t *p, int size)
+pcap_setmintocopy_dead(pcap_t *p, int size _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The mintocopy parameter cannot be set on a pcap_open_dead pcap_t");
return (-1);
}
@@ -3907,7 +4272,7 @@ pcap_setmintocopy_dead(pcap_t *p, int size)
static HANDLE
pcap_getevent_dead(pcap_t *p)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"A pcap_open_dead pcap_t has no event handle");
return (INVALID_HANDLE_VALUE);
}
@@ -3916,7 +4281,7 @@ static int
pcap_oid_get_request_dead(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_,
size_t *lenp _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"An OID get request cannot be performed on a pcap_open_dead pcap_t");
return (PCAP_ERROR);
}
@@ -3925,45 +4290,47 @@ static int
pcap_oid_set_request_dead(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
size_t *lenp _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"An OID set request cannot be performed on a pcap_open_dead pcap_t");
return (PCAP_ERROR);
}
static u_int
-pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue, int sync)
+pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue _U_,
+ int sync _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Packets cannot be transmitted on a pcap_open_dead pcap_t");
return (0);
}
static int
-pcap_setuserbuffer_dead(pcap_t *p, int size)
+pcap_setuserbuffer_dead(pcap_t *p, int size _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The user buffer cannot be set on a pcap_open_dead pcap_t");
return (-1);
}
static int
-pcap_live_dump_dead(pcap_t *p, char *filename, int maxsize, int maxpacks)
+pcap_live_dump_dead(pcap_t *p, char *filename _U_, int maxsize _U_,
+ int maxpacks _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
return (-1);
}
static int
-pcap_live_dump_ended_dead(pcap_t *p, int sync)
+pcap_live_dump_ended_dead(pcap_t *p, int sync _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
return (-1);
}
static PAirpcapHandle
-pcap_get_airpcap_handle_dead(pcap_t *p)
+pcap_get_airpcap_handle_dead(pcap_t *p _U_)
{
return (NULL);
}
diff --git a/pcap/bpf.h b/pcap/bpf.h
index 9d748952..ccb93cc7 100644
--- a/pcap/bpf.h
+++ b/pcap/bpf.h
@@ -58,10 +58,21 @@
* I don't have earlier versions available to check), or QNX-style
* multiple-include protection (as per GitHub pull request #394).
*
+ * We trust that they will define structures and macros and types in
+ * a fashion that's source-compatible and binary-compatible with our
+ * definitions.
+ *
* We do not check for BPF_MAJOR_VERSION, as that's defined by
* <linux/filter.h>, which is directly or indirectly included in some
* programs that also include pcap.h, and <linux/filter.h> doesn't
- * define stuff we need.
+ * define stuff we need. We *do* protect against <linux/filter.h>
+ * defining various macros for BPF code itself; <linux/filter.h> says
+ *
+ * Try and keep these values and structures similar to BSD, especially
+ * the BPF code definitions which need to match so you can share filters
+ *
+ * so we trust that it will define them in a fashion that's source-compatible
+ * and binary-compatible with our definitions.
*
* This also provides our own multiple-include protection.
*/
@@ -108,6 +119,8 @@ struct bpf_program {
#include <pcap/dlt.h>
+#ifndef __LINUX_FILTER_H__
+
/*
* The instruction encodings.
*
@@ -228,6 +241,8 @@ struct bpf_program {
/* 0xf0 reserved */
/* 0xf8 reserved */
+#endif /* __LINUX_FILTER_H__ */
+
/*
* The instruction data structure.
*/
@@ -238,14 +253,27 @@ struct bpf_insn {
bpf_u_int32 k;
};
+#ifndef __LINUX_FILTER_H__
+
/*
* Macros for insn array initializers.
*/
#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }
-PCAP_API int bpf_validate(const struct bpf_insn *, int);
-PCAP_API u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int);
+#endif /* __LINUX_FILTER_H__ */
+
+PCAP_AVAILABLE_0_4
+PCAP_API u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int);
+
+PCAP_AVAILABLE_0_6
+PCAP_API int bpf_validate(const struct bpf_insn *f, int len);
+
+PCAP_AVAILABLE_0_4
+PCAP_API char *bpf_image(const struct bpf_insn *, int);
+
+PCAP_AVAILABLE_0_6
+PCAP_API void bpf_dump(const struct bpf_program *, int);
/*
* Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST).
diff --git a/pcap/compiler-tests.h b/pcap/compiler-tests.h
index ea5962c7..a69c2b09 100644
--- a/pcap/compiler-tests.h
+++ b/pcap/compiler-tests.h
@@ -38,7 +38,7 @@
/*
* This was introduced by Clang:
*
- * http://clang.llvm.org/docs/LanguageExtensions.html#has-attribute
+ * https://clang.llvm.org/docs/LanguageExtensions.html#has-attribute
*
* in some version (which version?); it has been picked up by GCC 5.0.
*/
diff --git a/pcap/dlt.h b/pcap/dlt.h
index 8dacf024..eaba34f3 100644
--- a/pcap/dlt.h
+++ b/pcap/dlt.h
@@ -136,7 +136,7 @@
#define DLT_PFSYNC 18
#endif
-#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */
+#define DLT_ATM_CLIP 19 /* Linux Classical IP over ATM */
/*
* Apparently Redback uses this for its SmartEdge 400/800. I hope
@@ -465,7 +465,7 @@
#define DLT_DOCSIS 143
/*
- * Linux-IrDA packets. Protocol defined at http://www.irda.org.
+ * Linux-IrDA packets. Protocol defined at https://www.irda.org.
* Those packets include IrLAP headers and above (IrLMP...), but
* don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy
* framing can be handled by the hardware and depend on the bitrate.
@@ -473,7 +473,7 @@
* interface (irdaX), but not on a raw serial port.
* Note the capture is done in "Linux-cooked" mode, so each packet include
* a fake packet header (struct sll_header). This is because IrDA packet
- * decoding is dependant on the direction of the packet (incomming or
+ * decoding is dependent on the direction of the packet (incoming or
* outgoing).
* When/if other platform implement IrDA capture, we may revisit the
* issue and define a real DLT_IRDA...
@@ -565,7 +565,7 @@
* input packets such as port scans, packets from old lost connections,
* etc. to force the connection to stay up).
*
- * The first byte of the PPP header (0xff03) is modified to accomodate
+ * The first byte of the PPP header (0xff03) is modified to accommodate
* the direction - 0x00 = IN, 0x01 = OUT.
*/
#define DLT_PPP_PPPD 166
@@ -607,7 +607,7 @@
/*
* Link types requested by Gregor Maier <gregor@endace.com> of Endace
* Measurement Systems. They add an ERF header (see
- * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of
+ * https://www.endace.com/support/EndaceRecordFormat.pdf) in front of
* the link-layer header.
*/
#define DLT_ERF_ETH 175 /* Ethernet */
@@ -750,7 +750,7 @@
/*
* Various link-layer types, with a pseudo-header, for SITA
- * (http://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com).
+ * (https://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com).
*/
#define DLT_SITA 196
@@ -817,8 +817,11 @@
* PPP, with a one-byte direction pseudo-header prepended - zero means
* "received by this host", non-zero (any non-zero value) means "sent by
* this host" - as per Will Barker <w.barker@zen.co.uk>.
+ *
+ * Don't confuse this with DLT_PPP_WITH_DIRECTION, which is an old
+ * name for what is now called DLT_PPP_PPPD.
*/
-#define DLT_PPP_WITH_DIR 204 /* Don't confuse with DLT_PPP_WITH_DIRECTION */
+#define DLT_PPP_WITH_DIR 204
/*
* Cisco HDLC, with a one-byte direction pseudo-header prepended - zero
@@ -862,7 +865,7 @@
/*
* Media Oriented Systems Transport (MOST) bus for multimedia
- * transport - http://www.mostcooperation.com/ - as requested
+ * transport - https://www.mostcooperation.com/ - as requested
* by Hannes Kaelber <hannes.kaelber@x2e.de>.
*/
#define DLT_MOST 211
@@ -1048,16 +1051,16 @@
/*
* Raw D-Bus:
*
- * http://www.freedesktop.org/wiki/Software/dbus
+ * https://www.freedesktop.org/wiki/Software/dbus
*
* messages:
*
- * http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages
+ * https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages
*
* starting with the endianness flag, followed by the message type, etc.,
* but without the authentication handshake before the message sequence:
*
- * http://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol
+ * https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol
*
* Requested by Martin Vidner <martin@vidner.net>.
*/
@@ -1075,7 +1078,7 @@
* DVB-CI (DVB Common Interface for communication between a PC Card
* module and a DVB receiver). See
*
- * http://www.kaiser.cx/pcap-dvbci.html
+ * https://www.kaiser.cx/pcap-dvbci.html
*
* for the specification.
*
@@ -1364,9 +1367,9 @@
/*
* per: Stefanha at gmail.com for
- * http://lists.sandelman.ca/pipermail/tcpdump-workers/2017-May/000772.html
+ * https://lists.sandelman.ca/pipermail/tcpdump-workers/2017-May/000772.html
* and: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/vsockmon.h
- * for: http://qemu-project.org/Features/VirtioVsock
+ * for: https://qemu-project.org/Features/VirtioVsock
*/
#define DLT_VSOCK 271
@@ -1378,7 +1381,7 @@
/*
* Excentis DOCSIS 3.1 RF sniffer (XRA-31)
* per: bruno.verstuyft at excentis.com
- * http://www.xra31.com/xra-header
+ * https://www.xra31.com/xra-header
*/
#define DLT_DOCSIS31_XRA31 273
@@ -1390,7 +1393,7 @@
/*
* DisplayPort AUX channel monitoring data as specified by VESA
- * DisplayPort(DP) Standard preceeded by a pseudo-header.
+ * DisplayPort(DP) Standard preceded by a pseudo-header.
* per dirk.eibach at gdsys.cc
*/
#define DLT_DISPLAYPORT_AUX 275
@@ -1401,6 +1404,83 @@
#define DLT_LINUX_SLL2 276
/*
+ * Sercos Monitor, per Manuel Jacob <manuel.jacob at steinbeis-stg.de>
+ */
+#define DLT_SERCOS_MONITOR 277
+
+/*
+ * OpenVizsla http://openvizsla.org is open source USB analyzer hardware.
+ * It consists of FPGA with attached USB phy and FTDI chip for streaming
+ * the data to the host PC.
+ *
+ * Current OpenVizsla data encapsulation format is described here:
+ * https://github.com/matwey/libopenvizsla/wiki/OpenVizsla-protocol-description
+ *
+ */
+#define DLT_OPENVIZSLA 278
+
+/*
+ * The Elektrobit High Speed Capture and Replay (EBHSCR) protocol is produced
+ * by a PCIe Card for interfacing high speed automotive interfaces.
+ *
+ * The specification for this frame format can be found at:
+ * https://www.elektrobit.com/ebhscr
+ *
+ * for Guenter.Ebermann at elektrobit.com
+ *
+ */
+#define DLT_EBHSCR 279
+
+/*
+ * The https://fd.io vpp graph dispatch tracer produces pcap trace files
+ * in the format documented here:
+ * https://fdio-vpp.readthedocs.io/en/latest/gettingstarted/developers/vnet.html#graph-dispatcher-pcap-tracing
+ */
+#define DLT_VPP_DISPATCH 280
+
+/*
+ * Broadcom Ethernet switches (ROBO switch) 4 bytes proprietary tagging format.
+ */
+#define DLT_DSA_TAG_BRCM 281
+#define DLT_DSA_TAG_BRCM_PREPEND 282
+
+/*
+ * IEEE 802.15.4 with pseudo-header and optional meta-data TLVs, PHY payload
+ * exactly as it appears in the spec (no padding, no nothing), and FCS if
+ * specified by FCS Type TLV; requested by James Ko <jck@exegin.com>.
+ * Specification at https://github.com/jkcko/ieee802.15.4-tap
+ */
+#define DLT_IEEE802_15_4_TAP 283
+
+/*
+ * Marvell (Ethertype) Distributed Switch Architecture proprietary tagging format.
+ */
+#define DLT_DSA_TAG_DSA 284
+#define DLT_DSA_TAG_EDSA 285
+
+/*
+ * Payload of lawful intercept packets using the ELEE protocol;
+ * https://socket.hr/draft-dfranusic-opsawg-elee-00.xml
+ * https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://socket.hr/draft-dfranusic-opsawg-elee-00.xml&modeAsFormat=html/ascii
+ */
+#define DLT_ELEE 286
+
+/*
+ * Serial frames transmitted between a host and a Z-Wave chip.
+ */
+#define DLT_Z_WAVE_SERIAL 287
+
+/*
+ * USB 2.0, 1.1, and 1.0 packets as transmitted over the cable.
+ */
+#define DLT_USB_2_0 288
+
+/*
+ * ATSC Link-Layer Protocol (A/330) packets.
+ */
+#define DLT_ATSC_ALP 289
+
+/*
* 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
@@ -1410,7 +1490,7 @@
#ifdef DLT_MATCHING_MAX
#undef DLT_MATCHING_MAX
#endif
-#define DLT_MATCHING_MAX 276 /* highest value in the "matching" range */
+#define DLT_MATCHING_MAX 289 /* highest value in the "matching" range */
/*
* DLT and savefile link type values are split into a class and
diff --git a/pcap/funcattrs.h b/pcap/funcattrs.h
index e64da93a..cdc083d8 100644
--- a/pcap/funcattrs.h
+++ b/pcap/funcattrs.h
@@ -147,6 +147,70 @@
#define PCAP_API PCAP_API_DEF extern
/*
+ * Definitions to 1) indicate what version of libpcap first had a given
+ * API and 2) allow upstream providers whose build environments allow
+ * APIs to be designated as "first available in this release" to do so
+ * by appropriately defining them.
+ *
+ * Yes, that's you, Apple. :-) Please define PCAP_AVAILABLE_MACOS()
+ * as necessary to make various APIs "weak exports" to make it easier
+ * for software that's distributed in binary form and that uses libpcap
+ * to run on multiple macOS versions and use new APIs when available.
+ * (Yes, such third-party software exists - Wireshark provides binary
+ * packages for macOS, for example. tcpdump doesn't count, as that's
+ * provided by Apple, so each release can come with a version compiled
+ * to use the APIs present in that release.)
+ *
+ * We don't define it ourselves because, if you're building and
+ * installing libpcap on macOS yourself, the APIs will be available
+ * no matter what OS version you're installing it on.
+ *
+ * For other platforms, we don't define them, leaving it up to
+ * others to do so based on their OS versions, if appropriate.
+ *
+ * We start with libpcap 0.4, as that was the last LBL release, and
+ * I've never seen earlier releases.
+ */
+#ifdef __APPLE__
+#define PCAP_AVAILABLE_MACOS(v) /* define to say "first appears in v" */
+#define PCAP_AVAILABLE_0_4 PCAP_AVAILABLE_MACOS(10.0) /* Did any version of Mac OS X ship with this? */
+#define PCAP_AVAILABLE_0_5 PCAP_AVAILABLE_MACOS(10.0) /* Did any version of Mac OS X ship with this? */
+#define PCAP_AVAILABLE_0_6 PCAP_AVAILABLE_MACOS(10.1)
+#define PCAP_AVAILABLE_0_7 PCAP_AVAILABLE_MACOS(10.4)
+#define PCAP_AVAILABLE_0_8 PCAP_AVAILABLE_MACOS(10.4)
+#define PCAP_AVAILABLE_0_9 PCAP_AVAILABLE_MACOS(10.5)
+#define PCAP_AVAILABLE_1_0 PCAP_AVAILABLE_MACOS(10.6)
+/* #define PCAP_AVAILABLE_1_1 no routines added to the API */
+#define PCAP_AVAILABLE_1_2 PCAP_AVAILABLE_MACOS(10.9)
+/* #define PCAP_AVAILABLE_1_3 no routines added to the API */
+/* #define PCAP_AVAILABLE_1_4 no routines added to the API */
+#define PCAP_AVAILABLE_1_5 PCAP_AVAILABLE_MACOS(10.10)
+/* #define PCAP_AVAILABLE_1_6 no routines added to the API */
+#define PCAP_AVAILABLE_1_7 PCAP_AVAILABLE_MACOS(10.12)
+#define PCAP_AVAILABLE_1_8 PCAP_AVAILABLE_MACOS(10.13) /* only Windows adds routines to the API; XXX - what version first had it? */
+#define PCAP_AVAILABLE_1_9 PCAP_AVAILABLE_MACOS(10.13)
+#define PCAP_AVAILABLE_1_10 /* not released yet, so not in macOS yet */
+#else /* __APPLE__ */
+#define PCAP_AVAILABLE_0_4
+#define PCAP_AVAILABLE_0_5
+#define PCAP_AVAILABLE_0_6
+#define PCAP_AVAILABLE_0_7
+#define PCAP_AVAILABLE_0_8
+#define PCAP_AVAILABLE_0_9
+#define PCAP_AVAILABLE_1_0
+/* #define PCAP_AVAILABLE_1_1 no routines added to the API */
+#define PCAP_AVAILABLE_1_2
+/* #define PCAP_AVAILABLE_1_3 no routines added to the API */
+/* #define PCAP_AVAILABLE_1_4 no routines added to the API */
+#define PCAP_AVAILABLE_1_5
+/* #define PCAP_AVAILABLE_1_6 no routines added to the API */
+#define PCAP_AVAILABLE_1_7
+#define PCAP_AVAILABLE_1_8
+#define PCAP_AVAILABLE_1_9
+#define PCAP_AVAILABLE_1_10
+#endif /* __APPLE__ */
+
+/*
* PCAP_NORETURN, before a function declaration, means "this function
* never returns". (It must go before the function declaration, e.g.
* "extern PCAP_NORETURN func(...)" rather than after the function
@@ -233,10 +297,10 @@
* __attribute__((deprecated(msg))).
*/
#define PCAP_DEPRECATED(func, msg) __attribute__((deprecated))
-#elif (defined(_MSC_VER) && (_MSC_VER >= 1500)) && !defined(BUILDING_PCAP)
+#elif defined(_MSC_VER) && !defined(BUILDING_PCAP)
/*
- * MSVC from Visual Studio 2008 or later, and we're not building
- * libpcap itself.
+ * MSVC, and we're not building libpcap itself; it's VS 2015
+ * or later, so we have the deprecated pragma.
*
* If we *are* building libpcap, we don't want this, as it'll warn
* us even if we *define* the function.
@@ -251,11 +315,7 @@
*/
#ifdef _MSC_VER
#include <sal.h>
- #if _MSC_VER > 1400
- #define PCAP_FORMAT_STRING(p) _Printf_format_string_ p
- #else
- #define PCAP_FORMAT_STRING(p) __format_string p
- #endif
+ #define PCAP_FORMAT_STRING(p) _Printf_format_string_ p
#else
#define PCAP_FORMAT_STRING(p) p
#endif
diff --git a/pcap/namedb.h b/pcap/namedb.h
index c66846d3..34a0ae7e 100644
--- a/pcap/namedb.h
+++ b/pcap/namedb.h
@@ -59,7 +59,8 @@ 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_API bpf_u_int32 **pcap_nametoaddr(const char *)
+PCAP_DEPRECATED(pcap_nametoaddr, "this is not reentrant; use 'pcap_nametoaddrinfo' instead");
PCAP_API struct addrinfo *pcap_nametoaddrinfo(const char *);
PCAP_API bpf_u_int32 pcap_nametonetaddr(const char *);
diff --git a/pcap/pcap-inttypes.h b/pcap/pcap-inttypes.h
index 8b1eb8b9..1cfa0bfc 100644
--- a/pcap/pcap-inttypes.h
+++ b/pcap/pcap-inttypes.h
@@ -32,97 +32,49 @@
#define pcap_pcap_inttypes_h
/*
- * Get the integer types and PRi[doux]64 values from C99 <inttypes.h>
- * defined, by hook or by crook.
+ * If we're compiling with Visual Studio, make sure we have at least
+ * VS 2015 or later, so we have sufficient C99 support.
+ *
+ * XXX - verify that we have at least C99 support on UN*Xes?
+ *
+ * What about MinGW or various DOS toolchains? We're currently assuming
+ * sufficient C99 support there.
*/
#if defined(_MSC_VER)
/*
- * Compiler is MSVC.
+ * Compiler is MSVC. Make sure we have VS 2015 or later.
*/
- #if _MSC_VER >= 1800
- /*
- * VS 2013 or newer; we have <inttypes.h>.
- */
- #include <inttypes.h>
- #else
- /*
- * Earlier VS; we have to define this stuff ourselves.
- */
- typedef unsigned char uint8_t;
- typedef signed char int8_t;
- typedef unsigned short uint16_t;
- typedef signed short int16_t;
- typedef unsigned int uint32_t;
- typedef signed int int32_t;
- #ifdef _MSC_EXTENSIONS
- typedef unsigned _int64 uint64_t;
- typedef _int64 int64_t;
- #else /* _MSC_EXTENSIONS */
- typedef unsigned long long uint64_t;
- typedef long long int64_t;
- #endif
- #endif
-
- /*
- * These may be defined by <inttypes.h>.
- *
- * XXX - for MSVC, we always want the _MSC_EXTENSIONS versions.
- * What about other compilers? If, as the MinGW Web site says MinGW
- * does, the other compilers just use Microsoft's run-time library,
- * then they should probably use the _MSC_EXTENSIONS even if the
- * compiler doesn't define _MSC_EXTENSIONS.
- *
- * XXX - we currently aren't using any of these, but this allows
- * their use in the future.
- */
- #ifndef PRId64
- #ifdef _MSC_EXTENSIONS
- #define PRId64 "I64d"
- #else
- #define PRId64 "lld"
- #endif
- #endif /* PRId64 */
-
- #ifndef PRIo64
- #ifdef _MSC_EXTENSIONS
- #define PRIo64 "I64o"
- #else
- #define PRIo64 "llo"
- #endif
- #endif /* PRIo64 */
-
- #ifndef PRIx64
- #ifdef _MSC_EXTENSIONS
- #define PRIx64 "I64x"
- #else
- #define PRIx64 "llx"
- #endif
+ #if _MSC_VER < 1900
+ #error "Building libpcap requires VS 2015 or later"
#endif
+#endif
- #ifndef PRIu64
- #ifdef _MSC_EXTENSIONS
- #define PRIu64 "I64u"
- #else
- #define PRIu64 "llu"
- #endif
- #endif
+/*
+ * Include <inttypes.h> to get the integer types and PRi[doux]64 values
+ * defined.
+ *
+ * If the compiler is MSVC, we require VS 2015 or newer, so we
+ * have <inttypes.h> - and support for %zu in the formatted
+ * printing functions.
+ *
+ * If the compiler is MinGW, we assume we have <inttypes.h> - and
+ * support for %zu in the formatted printing functions.
+ *
+ * If the target is UN*X, we assume we have a C99-or-later development
+ * environment, and thus have <inttypes.h> - and support for %zu in
+ * the formatted printing functions.
+ *
+ * If the target is MS-DOS, we assume we have <inttypes.h> - and support
+ * for %zu in the formatted printing functions.
+ *
+ * I.e., assume we have <inttypes.h> and that it suffices.
+ */
- /*
- * MSVC's support library doesn't support %zu to print a size_t until
- * Visual Studio 2017, but supports %Iu earlier, so use that.
- */
- #define PRIsize "Iu"
-#elif defined(__MINGW32__) || !defined(_WIN32)
- /*
- * Compiler is MinGW or target is UN*X or MS-DOS. Just use
- * <inttypes.h>.
- */
- #include <inttypes.h>
+/*
+ * XXX - somehow make sure we have enough C99 support with other
+ * compilers and support libraries?
+ */
- /*
- * Assume the support library supports %zu; it's required by C99.
- */
- #define PRIsize "zu"
-#endif
+#include <inttypes.h>
#endif /* pcap/pcap-inttypes.h */
diff --git a/pcap/pcap.h b/pcap/pcap.h
index 90614dd0..8182bef4 100644
--- a/pcap/pcap.h
+++ b/pcap/pcap.h
@@ -69,6 +69,49 @@
#ifndef lib_pcap_pcap_h
#define lib_pcap_pcap_h
+/*
+ * 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.
+ * (I'm looking at *you*, lwIP!)
+ *
+ * Attempt to detect this, and undefine _MSC_VER so that we can *reliably*
+ * use it to know what compiler is being used and, if it's Visual Studio,
+ * what version is being used.
+ */
+#if defined(_MSC_VER)
+ /*
+ * We assume here that software such as that doesn't define _MSC_FULL_VER
+ * as well and that it defines _MSC_VER with a value > 1200.
+ *
+ * DO NOT BREAK THESE ASSUMPTIONS. IF YOU FEEL YOU MUST DEFINE _MSC_VER
+ * WITH A COMPILER THAT'S NOT MICROSOFT'S C COMPILER, PLEASE CONTACT
+ * US SO THAT WE CAN MAKE IT SO THAT YOU DON'T HAVE TO DO THAT. THANK
+ * YOU.
+ *
+ * OK, is _MSC_FULL_VER defined?
+ */
+ #if !defined(_MSC_FULL_VER)
+ /*
+ * According to
+ *
+ * https://sourceforge.net/p/predef/wiki/Compilers/
+ *
+ * with "Visual C++ 6.0 Processor Pack"/Visual C++ 6.0 SP6 and
+ * later, _MSC_FULL_VER is defined, so either this is an older
+ * version of Visual C++ or it's not Visual C++ at all.
+ *
+ * For Visual C++ 6.0, _MSC_VER is defined as 1200.
+ */
+ #if _MSC_VER > 1200
+ /*
+ * If this is Visual C++, _MSC_FULL_VER should be defined, so we
+ * assume this isn't Visual C++, and undo the lie that it is.
+ */
+ #undef _MSC_VER
+ #endif
+ #endif
+#endif
+
#include <pcap/funcattrs.h>
#include <pcap/pcap-inttypes.h>
@@ -127,6 +170,7 @@ typedef struct pcap_addr pcap_addr_t;
* of the flags used in the printout phases of tcpdump.
* Many fields here are 32 bit ints so compilers won't insert unwanted
* padding; these files need to be interchangeable across architectures.
+ * Documentation: https://www.tcpdump.org/manpages/pcap-savefile.5.txt.
*
* Do not change the layout of this structure, in any way (this includes
* changes that only affect the length of fields in this structure).
@@ -154,7 +198,7 @@ typedef struct pcap_addr pcap_addr_t;
*
* Then supply the changes by forking the branch at
*
- * https://github.com/the-tcpdump-group/libpcap/issues
+ * https://github.com/the-tcpdump-group/libpcap/tree/master
*
* and issuing a pull request, so that future versions of libpcap and
* programs that use it (such as tcpdump) will be able to read your new
@@ -164,8 +208,8 @@ struct pcap_file_header {
bpf_u_int32 magic;
u_short version_major;
u_short version_minor;
- bpf_int32 thiszone; /* gmt to local correction */
- bpf_u_int32 sigfigs; /* accuracy of timestamps */
+ bpf_int32 thiszone; /* gmt to local correction; this is always 0 */
+ bpf_u_int32 sigfigs; /* accuracy of timestamps; this is always 0 */
bpf_u_int32 snaplen; /* max length saved portion of each pkt */
bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */
};
@@ -201,7 +245,7 @@ typedef enum {
struct pcap_pkthdr {
struct timeval ts; /* time stamp */
bpf_u_int32 caplen; /* length of portion present */
- bpf_u_int32 len; /* length this packet (off wire) */
+ bpf_u_int32 len; /* length of this packet (off wire) */
};
/*
@@ -321,35 +365,91 @@ typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *,
#define PCAP_NETMASK_UNKNOWN 0xffffffff
/*
+ * Initialize pcap. If this isn't called, pcap is initialized to
+ * a mode source-compatible and binary-compatible with older versions
+ * that lack this routine.
+ */
+
+/*
+ * Initialization options.
+ * All bits not listed here are reserved for expansion.
+ *
+ * On UNIX-like systems, the local character encoding is assumed to be
+ * UTF-8, so no character encoding transformations are done.
+ *
+ * On Windows, the local character encoding is the local ANSI code page.
+ */
+#define PCAP_CHAR_ENC_LOCAL 0x00000000U /* strings are in the local character encoding */
+#define PCAP_CHAR_ENC_UTF_8 0x00000001U /* strings are in UTF-8 */
+
+PCAP_AVAILABLE_1_10
+PCAP_API int pcap_init(unsigned int, char *);
+
+/*
* We're deprecating pcap_lookupdev() for various reasons (not
* thread-safe, can behave weirdly with WinPcap). Callers
* 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_AVAILABLE_0_4
PCAP_API int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *);
+PCAP_AVAILABLE_1_0
PCAP_API pcap_t *pcap_create(const char *, char *);
+
+PCAP_AVAILABLE_1_0
PCAP_API int pcap_set_snaplen(pcap_t *, int);
+
+PCAP_AVAILABLE_1_0
PCAP_API int pcap_set_promisc(pcap_t *, int);
+
+PCAP_AVAILABLE_1_0
PCAP_API int pcap_can_set_rfmon(pcap_t *);
+
+PCAP_AVAILABLE_1_0
PCAP_API int pcap_set_rfmon(pcap_t *, int);
+
+PCAP_AVAILABLE_1_0
PCAP_API int pcap_set_timeout(pcap_t *, int);
+
+PCAP_AVAILABLE_1_2
PCAP_API int pcap_set_tstamp_type(pcap_t *, int);
+
+PCAP_AVAILABLE_1_5
PCAP_API int pcap_set_immediate_mode(pcap_t *, int);
+
+PCAP_AVAILABLE_1_0
PCAP_API int pcap_set_buffer_size(pcap_t *, int);
+
+PCAP_AVAILABLE_1_5
PCAP_API int pcap_set_tstamp_precision(pcap_t *, int);
+
+PCAP_AVAILABLE_1_5
PCAP_API int pcap_get_tstamp_precision(pcap_t *);
+
+PCAP_AVAILABLE_1_0
PCAP_API int pcap_activate(pcap_t *);
+PCAP_AVAILABLE_1_2
PCAP_API int pcap_list_tstamp_types(pcap_t *, int **);
+
+PCAP_AVAILABLE_1_2
PCAP_API void pcap_free_tstamp_types(int *);
+
+PCAP_AVAILABLE_1_2
PCAP_API int pcap_tstamp_type_name_to_val(const char *);
+
+PCAP_AVAILABLE_1_2
PCAP_API const char *pcap_tstamp_type_val_to_name(int);
+
+PCAP_AVAILABLE_1_2
PCAP_API const char *pcap_tstamp_type_val_to_description(int);
#ifdef __linux__
+PCAP_AVAILABLE_1_9
PCAP_API int pcap_set_protocol_linux(pcap_t *, int);
#endif
@@ -359,8 +459,7 @@ PCAP_API int pcap_set_protocol_linux(pcap_t *, int);
*
* A system that supports PCAP_TSTAMP_HOST is offering time stamps
* provided by the host machine, rather than by the capture device,
- * but not committing to any characteristics of the time stamp;
- * it will not offer any of the PCAP_TSTAMP_HOST_ subtypes.
+ * but not committing to any characteristics of the time stamp.
*
* PCAP_TSTAMP_HOST_LOWPREC is a time stamp, provided by the host machine,
* that's low-precision but relatively cheap to fetch; it's normally done
@@ -368,10 +467,15 @@ PCAP_API int pcap_set_protocol_linux(pcap_t *, int);
* fetch from system calls.
*
* PCAP_TSTAMP_HOST_HIPREC is a time stamp, provided by the host machine,
- * that's high-precision; it might be more expensive to fetch. It might
- * or might not be synchronized with the system clock, and might have
+ * that's high-precision; it might be more expensive to fetch. It is
+ * synchronized with the system clock.
+ *
+ * PCAP_TSTAMP_HOST_HIPREC_UNSYNCED is a time stamp, provided by the host
+ * machine, that's high-precision; it might be more expensive to fetch.
+ * It is not synchronized with the system clock, and might have
* problems with time stamps for packets received on different CPUs,
- * depending on the platform.
+ * depending on the platform. It might be more likely to be strictly
+ * monotonic than PCAP_TSTAMP_HOST_HIPREC.
*
* PCAP_TSTAMP_ADAPTER is a high-precision time stamp supplied by the
* capture device; it's synchronized with the system clock.
@@ -391,11 +495,12 @@ PCAP_API int pcap_set_protocol_linux(pcap_t *, int);
* the packet is received by the network adapter, due to batching
* of interrupts for packet arrival, queueing delays, etc..
*/
-#define PCAP_TSTAMP_HOST 0 /* host-provided, unknown characteristics */
-#define PCAP_TSTAMP_HOST_LOWPREC 1 /* host-provided, low precision */
-#define PCAP_TSTAMP_HOST_HIPREC 2 /* host-provided, high precision */
-#define PCAP_TSTAMP_ADAPTER 3 /* device-provided, synced with the system clock */
-#define PCAP_TSTAMP_ADAPTER_UNSYNCED 4 /* device-provided, not synced with the system clock */
+#define PCAP_TSTAMP_HOST 0 /* host-provided, unknown characteristics */
+#define PCAP_TSTAMP_HOST_LOWPREC 1 /* host-provided, low precision, synced with the system clock */
+#define PCAP_TSTAMP_HOST_HIPREC 2 /* host-provided, high precision, synced with the system clock */
+#define PCAP_TSTAMP_ADAPTER 3 /* device-provided, synced with the system clock */
+#define PCAP_TSTAMP_ADAPTER_UNSYNCED 4 /* device-provided, not synced with the system clock */
+#define PCAP_TSTAMP_HOST_HIPREC_UNSYNCED 5 /* host-provided, high precision, not synced with the system clock */
/*
* Time stamp resolution types.
@@ -406,13 +511,25 @@ PCAP_API int pcap_set_protocol_linux(pcap_t *, int);
#define PCAP_TSTAMP_PRECISION_MICRO 0 /* use timestamps with microsecond precision, default */
#define PCAP_TSTAMP_PRECISION_NANO 1 /* use timestamps with nanosecond precision */
+PCAP_AVAILABLE_0_4
PCAP_API pcap_t *pcap_open_live(const char *, int, int, int, char *);
+
+PCAP_AVAILABLE_0_6
PCAP_API pcap_t *pcap_open_dead(int, int);
+
+PCAP_AVAILABLE_1_5
PCAP_API pcap_t *pcap_open_dead_with_tstamp_precision(int, int, u_int);
+
+PCAP_AVAILABLE_1_5
PCAP_API pcap_t *pcap_open_offline_with_tstamp_precision(const char *, u_int, char *);
+
+PCAP_AVAILABLE_0_4
PCAP_API pcap_t *pcap_open_offline(const char *, char *);
+
#ifdef _WIN32
+ PCAP_AVAILABLE_1_5
PCAP_API pcap_t *pcap_hopen_offline_with_tstamp_precision(intptr_t, u_int, char *);
+
PCAP_API pcap_t *pcap_hopen_offline(intptr_t, char *);
/*
* If we're building libpcap, these are internal routines in savefile.c,
@@ -434,60 +551,153 @@ PCAP_API pcap_t *pcap_open_offline(const char *, char *);
pcap_hopen_offline(_get_osfhandle(_fileno(f)), b)
#endif
#else /*_WIN32*/
+ PCAP_AVAILABLE_1_5
PCAP_API pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *, u_int, char *);
+
+ PCAP_AVAILABLE_0_9
PCAP_API pcap_t *pcap_fopen_offline(FILE *, char *);
#endif /*_WIN32*/
+PCAP_AVAILABLE_0_4
PCAP_API void pcap_close(pcap_t *);
+
+PCAP_AVAILABLE_0_4
PCAP_API int pcap_loop(pcap_t *, int, pcap_handler, u_char *);
+
+PCAP_AVAILABLE_0_4
PCAP_API int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *);
+
+PCAP_AVAILABLE_0_4
PCAP_API const u_char *pcap_next(pcap_t *, struct pcap_pkthdr *);
+
+PCAP_AVAILABLE_0_8
PCAP_API int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **);
+
+PCAP_AVAILABLE_0_8
PCAP_API void pcap_breakloop(pcap_t *);
+
+PCAP_AVAILABLE_0_4
PCAP_API int pcap_stats(pcap_t *, struct pcap_stat *);
+
+PCAP_AVAILABLE_0_4
PCAP_API int pcap_setfilter(pcap_t *, struct bpf_program *);
+
+PCAP_AVAILABLE_0_9
PCAP_API int pcap_setdirection(pcap_t *, pcap_direction_t);
+
+PCAP_AVAILABLE_0_7
PCAP_API int pcap_getnonblock(pcap_t *, char *);
+
+PCAP_AVAILABLE_0_7
PCAP_API int pcap_setnonblock(pcap_t *, int, char *);
+
+PCAP_AVAILABLE_0_9
PCAP_API int pcap_inject(pcap_t *, const void *, size_t);
+
+PCAP_AVAILABLE_0_8
PCAP_API int pcap_sendpacket(pcap_t *, const u_char *, int);
+
+PCAP_AVAILABLE_1_0
PCAP_API const char *pcap_statustostr(int);
+
+PCAP_AVAILABLE_0_4
PCAP_API const char *pcap_strerror(int);
+
+PCAP_AVAILABLE_0_4
PCAP_API char *pcap_geterr(pcap_t *);
+
+PCAP_AVAILABLE_0_4
PCAP_API void pcap_perror(pcap_t *, const char *);
+
+PCAP_AVAILABLE_0_4
PCAP_API int pcap_compile(pcap_t *, struct bpf_program *, const char *, int,
bpf_u_int32);
+
+PCAP_AVAILABLE_0_5
PCAP_API int pcap_compile_nopcap(int, int, struct bpf_program *,
const char *, int, bpf_u_int32);
+
+/* XXX - this took two arguments in 0.4 and 0.5 */
+PCAP_AVAILABLE_0_6
PCAP_API void pcap_freecode(struct bpf_program *);
+
+PCAP_AVAILABLE_1_0
PCAP_API int pcap_offline_filter(const struct bpf_program *,
const struct pcap_pkthdr *, const u_char *);
+
+PCAP_AVAILABLE_0_4
PCAP_API int pcap_datalink(pcap_t *);
+
+PCAP_AVAILABLE_1_0
PCAP_API int pcap_datalink_ext(pcap_t *);
+
+PCAP_AVAILABLE_0_8
PCAP_API int pcap_list_datalinks(pcap_t *, int **);
+
+PCAP_AVAILABLE_0_8
PCAP_API int pcap_set_datalink(pcap_t *, int);
+
+PCAP_AVAILABLE_0_8
PCAP_API void pcap_free_datalinks(int *);
+
+PCAP_AVAILABLE_0_8
PCAP_API int pcap_datalink_name_to_val(const char *);
+
+PCAP_AVAILABLE_0_8
PCAP_API const char *pcap_datalink_val_to_name(int);
+
+PCAP_AVAILABLE_0_8
PCAP_API const char *pcap_datalink_val_to_description(int);
+
+PCAP_AVAILABLE_1_10
PCAP_API const char *pcap_datalink_val_to_description_or_dlt(int);
+
+PCAP_AVAILABLE_0_4
PCAP_API int pcap_snapshot(pcap_t *);
+
+PCAP_AVAILABLE_0_4
PCAP_API int pcap_is_swapped(pcap_t *);
+
+PCAP_AVAILABLE_0_4
PCAP_API int pcap_major_version(pcap_t *);
+
+PCAP_AVAILABLE_0_4
PCAP_API int pcap_minor_version(pcap_t *);
+
+PCAP_AVAILABLE_1_9
PCAP_API int pcap_bufsize(pcap_t *);
/* XXX */
+PCAP_AVAILABLE_0_4
PCAP_API FILE *pcap_file(pcap_t *);
+
+#ifdef _WIN32
+/*
+ * This probably shouldn't have been kept in WinPcap; most if not all
+ * UN*X code that used it won't work on Windows. We deprecate it; if
+ * anybody really needs access to whatever HANDLE may be associated
+ * with a pcap_t (there's no guarantee that there is one), we can add
+ * 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, "use 'pcap_handle'");
+#else /* _WIN32 */
+PCAP_AVAILABLE_0_4
PCAP_API int pcap_fileno(pcap_t *);
+#endif /* _WIN32 */
#ifdef _WIN32
PCAP_API int pcap_wsockinit(void);
#endif
+PCAP_AVAILABLE_0_4
PCAP_API pcap_dumper_t *pcap_dump_open(pcap_t *, const char *);
+
#ifdef _WIN32
+ PCAP_AVAILABLE_0_9
PCAP_API pcap_dumper_t *pcap_dump_hopen(pcap_t *, intptr_t);
+
/*
* If we're building libpcap, this is an internal routine in sf-pcap.c, so
* we must not define it as a macro.
@@ -506,17 +716,35 @@ PCAP_API pcap_dumper_t *pcap_dump_open(pcap_t *, const char *);
pcap_dump_hopen(p, _get_osfhandle(_fileno(f)))
#endif
#else /*_WIN32*/
+ PCAP_AVAILABLE_0_9
PCAP_API pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp);
#endif /*_WIN32*/
+
+PCAP_AVAILABLE_1_7
PCAP_API pcap_dumper_t *pcap_dump_open_append(pcap_t *, const char *);
+
+PCAP_AVAILABLE_0_8
PCAP_API FILE *pcap_dump_file(pcap_dumper_t *);
+
+PCAP_AVAILABLE_0_9
PCAP_API long pcap_dump_ftell(pcap_dumper_t *);
+
+PCAP_AVAILABLE_1_9
PCAP_API int64_t pcap_dump_ftell64(pcap_dumper_t *);
+
+PCAP_AVAILABLE_0_8
PCAP_API int pcap_dump_flush(pcap_dumper_t *);
+
+PCAP_AVAILABLE_0_4
PCAP_API void pcap_dump_close(pcap_dumper_t *);
+
+PCAP_AVAILABLE_0_4
PCAP_API void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *);
+PCAP_AVAILABLE_0_7
PCAP_API int pcap_findalldevs(pcap_if_t **, char *);
+
+PCAP_AVAILABLE_0_7
PCAP_API void pcap_freealldevs(pcap_if_t *);
/*
@@ -524,7 +752,7 @@ PCAP_API void pcap_freealldevs(pcap_if_t *);
* version string directly.
*
* On at least some UNIXes, if you import data from a shared library into
- * an program, the data is bound into the program binary, so if the string
+ * a program, the data is bound into the program binary, so if the string
* in the version of the library with which the program was linked isn't
* the same as the string in the version of the library with which the
* program is being run, various undesirable things may happen (warnings,
@@ -534,22 +762,9 @@ PCAP_API void pcap_freealldevs(pcap_if_t *);
*
* On Windows, the string is constructed at run time.
*/
+PCAP_AVAILABLE_0_8
PCAP_API const char *pcap_lib_version(void);
-/*
- * On at least some versions of NetBSD and QNX, we don't want to declare
- * bpf_filter() here, as it's also be declared in <net/bpf.h>, with a
- * different signature, but, on other BSD-flavored UN*Xes, it's not
- * declared in <net/bpf.h>, so we *do* want to declare it here, so it's
- * declared when we build pcap-bpf.c.
- */
-#if !defined(__NetBSD__) && !defined(__QNX__)
- PCAP_API u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int);
-#endif
-PCAP_API int bpf_validate(const struct bpf_insn *f, int len);
-PCAP_API char *bpf_image(const struct bpf_insn *, int);
-PCAP_API void bpf_dump(const struct bpf_program *, int);
-
#if defined(_WIN32)
/*
@@ -583,7 +798,10 @@ PCAP_API void bpf_dump(const struct bpf_program *, int);
PCAP_API HANDLE pcap_getevent(pcap_t *p);
+ PCAP_AVAILABLE_1_8
PCAP_API int pcap_oid_get_request(pcap_t *, bpf_u_int32, void *, size_t *);
+
+ PCAP_AVAILABLE_1_8
PCAP_API int pcap_oid_set_request(pcap_t *, bpf_u_int32, const void *, size_t *);
PCAP_API pcap_send_queue* pcap_sendqueue_alloc(u_int memsize);
@@ -626,8 +844,11 @@ PCAP_API void bpf_dump(const struct bpf_program *, int);
* UN*X definitions
*/
+ PCAP_AVAILABLE_0_8
PCAP_API int pcap_get_selectable_fd(pcap_t *);
- PCAP_API struct timeval *pcap_get_required_select_timeout(pcap_t *);
+
+ PCAP_AVAILABLE_1_9
+ PCAP_API const struct timeval *pcap_get_required_select_timeout(pcap_t *);
#endif /* _WIN32/MSDOS/UN*X */
@@ -660,14 +881,17 @@ PCAP_API void bpf_dump(const struct bpf_program *, int);
* - rpcap://devicename [opens the selected device devices available on the local host, without using the RPCAP protocol]
* - rpcap://host/devicename [opens the selected device available on a remote host]
* - rpcap://host:port/devicename [opens the selected device available on a remote host, using a non-standard port for RPCAP]
- * - adaptername [to open a local adapter; kept for compability, but it is strongly discouraged]
- * - (NULL) [to open the first local adapter; kept for compability, but it is strongly discouraged]
+ * - adaptername [to open a local adapter; kept for compatibility, but it is strongly discouraged]
+ * - (NULL) [to open the first local adapter; kept for compatibility, but it is strongly discouraged]
*
* The formats allowed by the pcap_findalldevs_ex() are the following:
* - file://folder/ [lists all the files in the given folder]
* - rpcap:// [lists all local adapters]
* - rpcap://host:port/ [lists the devices available on a remote host]
*
+ * In all the above, "rpcaps://" can be substituted for "rpcap://" to enable
+ * SSL (if it has been compiled in).
+ *
* Referring to the 'host' and 'port' parameters, they can be either numeric or literal. Since
* IPv6 is fully supported, these are the allowed formats:
*
@@ -728,7 +952,7 @@ PCAP_API void bpf_dump(const struct bpf_program *, int);
#define PCAP_OPENFLAG_DATATX_UDP 0x00000002
/*
- * Specifies wheether the remote probe will capture its own generated
+ * Specifies whether the remote probe will capture its own generated
* traffic.
*
* In case the remote probe uses the same interface to capture traffic
@@ -797,7 +1021,7 @@ PCAP_API void bpf_dump(const struct bpf_program *, int);
#define RPCAP_RMTAUTH_PWD 1
/*
- * This structure keeps the information needed to autheticate the user
+ * This structure keeps the information needed to authenticate the user
* on a remote machine.
*
* The remote machine can either grant or refuse the access according
@@ -856,10 +1080,15 @@ struct pcap_rmtauth
* For opening a remote capture, pcap_open() is currently the only
* API available.
*/
+PCAP_AVAILABLE_1_9
PCAP_API pcap_t *pcap_open(const char *source, int snaplen, int flags,
int read_timeout, struct pcap_rmtauth *auth, char *errbuf);
+
+PCAP_AVAILABLE_1_9
PCAP_API int pcap_createsrcstr(char *source, int type, const char *host,
const char *port, const char *name, char *errbuf);
+
+PCAP_AVAILABLE_1_9
PCAP_API int pcap_parsesrcstr(const char *source, int *type, char *host,
char *port, char *name, char *errbuf);
@@ -882,6 +1111,7 @@ PCAP_API int pcap_parsesrcstr(const char *source, int *type, char *host,
* For listing remote capture devices, pcap_findalldevs_ex() is currently
* the only API available.
*/
+PCAP_AVAILABLE_1_9
PCAP_API int pcap_findalldevs_ex(const char *source,
struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf);
@@ -952,6 +1182,7 @@ struct pcap_samp
/*
* New functions.
*/
+PCAP_AVAILABLE_1_9
PCAP_API struct pcap_samp *pcap_setsampling(pcap_t *p);
/*
@@ -961,12 +1192,24 @@ PCAP_API struct pcap_samp *pcap_setsampling(pcap_t *p);
/* Maximum length of an host name (needed for the RPCAP active mode) */
#define RPCAP_HOSTLIST_SIZE 1024
+PCAP_AVAILABLE_1_9
PCAP_API SOCKET pcap_remoteact_accept(const char *address, const char *port,
const char *hostlist, char *connectinghost,
struct pcap_rmtauth *auth, char *errbuf);
+
+PCAP_AVAILABLE_1_10
+PCAP_API SOCKET pcap_remoteact_accept_ex(const char *address, const char *port,
+ const char *hostlist, char *connectinghost,
+ struct pcap_rmtauth *auth, int uses_ssl, char *errbuf);
+
+PCAP_AVAILABLE_1_9
PCAP_API int pcap_remoteact_list(char *hostlist, char sep, int size,
char *errbuf);
+
+PCAP_AVAILABLE_1_9
PCAP_API int pcap_remoteact_close(const char *host, char *errbuf);
+
+PCAP_AVAILABLE_1_9
PCAP_API void pcap_remoteact_cleanup(void);
#ifdef __cplusplus
diff --git a/pcap/socket.h b/pcap/socket.h
index 6f27cba1..ee2e393e 100644
--- a/pcap/socket.h
+++ b/pcap/socket.h
@@ -49,15 +49,6 @@
#include <ws2tcpip.h>
/*
- * Winsock doesn't have this UN*X type; it's used in the UN*X
- * sockets API.
- *
- * XXX - do we need to worry about UN*Xes so old that *they*
- * don't have it, either?
- */
- typedef int socklen_t;
-
- /*
* Winsock doesn't have this POSIX type; it's used for the
* tv_usec value of struct timeval.
*/
diff --git a/pcap_activate.3pcap b/pcap_activate.3pcap
index 162a9293..169a7565 100644
--- a/pcap_activate.3pcap
+++ b/pcap_activate.3pcap
@@ -17,7 +17,7 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP_ACTIVATE 3PCAP "31 July 2016"
+.TH PCAP_ACTIVATE 3PCAP "24 November 2019"
.SH NAME
pcap_activate \- activate a capture handle
.SH SYNOPSIS
@@ -31,13 +31,15 @@ int pcap_activate(pcap_t *p);
.ft
.fi
.SH DESCRIPTION
-.B pcap_activate()
+.BR pcap_activate ()
is used to activate a packet capture handle to look
at packets on the network, with the options that were set on the handle
being in effect.
.SH RETURN VALUE
-.B pcap_activate()
-returns 0 on success without warnings, a non-zero positive value on
+.BR pcap_activate ()
+returns
+.B 0
+on success without warnings, a non-zero positive value on
success with warnings, and a negative value on error.
A non-zero return value indicates what warning or error condition
occurred.
@@ -50,15 +52,15 @@ promiscuous mode.
.TP
.B PCAP_WARNING_TSTAMP_TYPE_NOTSUP
The time stamp type specified in a previous
-.B pcap_set_tstamp_type(3PCAP)
+.BR pcap_set_tstamp_type (3PCAP)
call isn't supported by the capture source (the time stamp type is
left as the default),
.TP
.B PCAP_WARNING
Another warning condition occurred;
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
may be called with
.I p
as an argument to fetch or display a message describing the warning
@@ -89,9 +91,9 @@ The capture source device is not up.
.TP
.B PCAP_ERROR
Another error occurred.
-.B pcap_geterr()
+.BR pcap_geterr ()
or
-.B pcap_perror()
+.BR pcap_perror ()
may be called with
.I p
as an argument to fetch or display a message describing the error.
@@ -102,9 +104,9 @@ If
or
.B PCAP_ERROR_PERM_DENIED
is returned,
-.B pcap_geterr()
+.BR pcap_geterr ()
or
-.B pcap_perror()
+.BR pcap_perror ()
may be called with
.I p
as an argument to fetch or display an message giving additional details
@@ -115,8 +117,15 @@ Additional warning and error codes may be added in the future; a program
should check for positive, negative, and zero return codes, and treat
all positive return codes as warnings and all negative return
codes as errors.
-.B pcap_statustostr(3PCAP)
+.BR pcap_statustostr (3PCAP)
can be called, with a warning or error code as an argument, to fetch a
message describing the warning or error code.
+.LP
+If
+.BR pcap_activate ()
+fails, the
+.I pcap_t *
+is not closed and freed; it should be closed using
+.BR pcap_close ().
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_breakloop.3pcap b/pcap_breakloop.3pcap
index cc000d2e..996290f9 100644
--- a/pcap_breakloop.3pcap
+++ b/pcap_breakloop.3pcap
@@ -31,11 +31,11 @@ void pcap_breakloop(pcap_t *);
.ft
.fi
.SH DESCRIPTION
-.B pcap_breakloop()
+.BR pcap_breakloop ()
sets a flag that will force
-.B pcap_dispatch(3PCAP)
+.BR pcap_dispatch (3PCAP)
or
-.B pcap_loop(3PCAP)
+.BR pcap_loop (3PCAP)
to return rather than looping; they will return the number of packets
that have been processed so far, or
.B PCAP_ERROR_BREAK
@@ -69,9 +69,9 @@ You will need to use whatever mechanism the OS provides for
breaking a thread out of blocking calls in order to unblock the thread,
such as thread cancellation or thread signalling in systems that support
POSIX threads, or
-.B SetEvent()
+.BR SetEvent ()
on the result of
-.B pcap_getevent()
+.BR pcap_getevent ()
on a
.B pcap_t
on which the thread is blocked on Windows. Asynchronous procedure calls
@@ -81,35 +81,35 @@ will not be in an alertable state.
.ft R
.PP
Note that
-.B pcap_next()
+.BR pcap_next ()
and
-.B pcap_next_ex()
+.BR pcap_next_ex ()
will, on some platforms, loop reading packets from the OS; that loop
will not necessarily be terminated by a signal, so
-.B pcap_breakloop()
+.BR pcap_breakloop ()
should be used to terminate packet processing even if
-.B pcap_next()
+.BR pcap_next ()
or
-.B pcap_next_ex()
+.BR pcap_next_ex ()
is being used.
.PP
-.B pcap_breakloop()
+.BR pcap_breakloop ()
does not guarantee that no further packets will be processed by
-.B pcap_dispatch()
+.BR pcap_dispatch ()
or
-.B pcap_loop()
+.BR pcap_loop ()
after it is called; at most one more packet might be processed.
.PP
If
.B PCAP_ERROR_BREAK
is returned from
-.B pcap_dispatch()
+.BR pcap_dispatch ()
or
-.BR pcap_loop() ,
+.BR pcap_loop (),
the flag is cleared, so a subsequent call will resume reading packets.
If a positive number is returned, the flag is not cleared, so a
subsequent call will return
.B PCAP_ERROR_BREAK
and clear the flag.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_can_set_rfmon.3pcap b/pcap_can_set_rfmon.3pcap
index 0baac7a6..be03956b 100644
--- a/pcap_can_set_rfmon.3pcap
+++ b/pcap_can_set_rfmon.3pcap
@@ -31,13 +31,16 @@ int pcap_can_set_rfmon(pcap_t *p);
.ft
.fi
.SH DESCRIPTION
-.B pcap_can_set_rfmon()
+.BR pcap_can_set_rfmon ()
checks whether monitor mode could be set on a capture handle when
the handle is activated.
.SH RETURN VALUE
-.B pcap_can_set_rfmon()
-returns 0 if monitor mode could not be set,
-1 if monitor mode could be set, and a negative value on error.
+.BR pcap_can_set_rfmon ()
+returns
+.B 0
+if monitor mode could not be set,
+.B 1
+if monitor mode could be set, and a negative value on error.
A negative return value indicates what error condition occurred.
The possible error values are:
.TP
@@ -54,19 +57,24 @@ The capture handle has already been activated.
.TP
.B PCAP_ERROR
Another error occurred.
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
or
-.B \%pcap_perror(3PCAP)
+.BR \%pcap_perror (3PCAP)
may be called with
.I p
as an argument to fetch or display a message describing the error.
.LP
Additional error codes may be added in the future; a program should
-check for 0, 1, and negative, return codes, and treat all negative
+check for
+.BR 0 ,
+.BR 1 ,
+and negative, return codes, and treat all negative
return codes as errors.
-.B pcap_statustostr(3PCAP)
+.BR pcap_statustostr (3PCAP)
can be called, with a warning or error code as an argument, to fetch a
message describing the warning or error code.
.SH SEE ALSO
-pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP),
-pcap_set_rfmon(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_create (3PCAP),
+.BR pcap_activate (3PCAP),
+.BR pcap_set_rfmon (3PCAP)
diff --git a/pcap_close.3pcap b/pcap_close.3pcap
index e2316a41..c4ac3fad 100644
--- a/pcap_close.3pcap
+++ b/pcap_close.3pcap
@@ -31,9 +31,9 @@ void pcap_close(pcap_t *p);
.ft
.fi
.SH DESCRIPTION
-.B pcap_close()
+.BR pcap_close ()
closes the files associated with
.I p
and deallocates resources.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_compile.3pcap.in b/pcap_compile.3pcap.in
index 824f52b3..8238e54f 100644
--- a/pcap_compile.3pcap.in
+++ b/pcap_compile.3pcap.in
@@ -33,7 +33,7 @@ const char *str, int optimize, bpf_u_int32 netmask);
.ft
.fi
.SH DESCRIPTION
-.B pcap_compile()
+.BR pcap_compile ()
is used to compile the string
.I str
into a filter program. See
@@ -43,7 +43,7 @@ for the syntax of that string.
is a pointer to a
.I bpf_program
struct and is filled in by
-.BR pcap_compile() .
+.BR pcap_compile ().
.I optimize
controls whether optimization on the resulting code is performed.
.I netmask
@@ -59,24 +59,26 @@ for IPv4 broadcast addresses will fail to compile, but all other tests in
the filter program will be OK.
.LP
NOTE: in libpcap 1.8.0 and later,
-.B pcap_compile()
+.BR pcap_compile ()
can be used in multiple threads within a single process. However, in
earlier versions of libpcap, it is
.I not
safe to use
-.B pcap_compile()
+.BR pcap_compile ()
in multiple threads in a single process without some form of mutual
exclusion allowing only one thread to call it at any given time.
.SH RETURN VALUE
-.B pcap_compile()
-returns 0 on success and
+.BR pcap_compile ()
+returns
+.B 0
+on success and
.B PCAP_ERROR
on failure. If
.B PCAP_ERROR
is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
may be called with
.I p
as an argument to fetch or display the error text.
@@ -86,4 +88,6 @@ The
.B PCAP_NETMASK_UNKNOWN
constant became available in libpcap release 1.1.0.
.SH SEE ALSO
-pcap(3PCAP), pcap_setfilter(3PCAP), pcap_freecode(3PCAP),
+.BR pcap (3PCAP),
+.BR pcap_setfilter (3PCAP),
+.BR pcap_freecode (3PCAP)
diff --git a/pcap_create.3pcap b/pcap_create.3pcap
index 5a15007b..bd42d733 100644
--- a/pcap_create.3pcap
+++ b/pcap_create.3pcap
@@ -36,7 +36,7 @@ pcap_t *pcap_create(const char *source, char *errbuf);
.ft
.fi
.SH DESCRIPTION
-.B pcap_create()
+.BR pcap_create ()
is used to create a packet capture handle to look
at packets on the network.
.I source
@@ -48,12 +48,12 @@ argument of "any" or
can be used to capture packets from all interfaces.
.PP
The returned handle must be activated with
-.B pcap_activate(3PCAP)
+.BR pcap_activate (3PCAP)
before packets can be captured
with it; options for the capture, such as promiscuous mode, can be set
on the handle before activating it.
.SH RETURN VALUE
-.B pcap_create()
+.BR pcap_create ()
returns a
.I pcap_t *
on success and
@@ -69,4 +69,4 @@ is assumed to be able to hold at least
.B PCAP_ERRBUF_SIZE
chars.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_datalink.3pcap.in b/pcap_datalink.3pcap.in
index 26203683..abb73750 100644
--- a/pcap_datalink.3pcap.in
+++ b/pcap_datalink.3pcap.in
@@ -31,19 +31,19 @@ int pcap_datalink(pcap_t *p);
.ft
.fi
.SH DESCRIPTION
-.B pcap_datalink()
+.BR pcap_datalink ()
returns the link-layer header type for the live capture or ``savefile''
specified by
.IR p .
.PP
It must not be called on a pcap descriptor created by
-.B \%pcap_create(3PCAP)
+.BR \%pcap_create (3PCAP)
that has not yet been activated by
-.BR \%pcap_activate(3PCAP) .
+.BR \%pcap_activate (3PCAP).
.PP
.I https://www.tcpdump.org/linktypes.html
lists the values
-.B pcap_datalink()
+.BR pcap_datalink ()
can return and describes the packet formats that
correspond to those values.
.PP
@@ -55,14 +55,17 @@ any given link-layer header type, such as
for Ethernet. For example, the "any" device on Linux will have a
link-layer header type of
.B DLT_LINUX_SLL
+or
+.B DLT_LINUX_SLL2
even if all devices on the system at the time the "any" device is opened
have some other data link type, such as
.B DLT_EN10MB
for Ethernet.
.SH RETURN VALUE
-.B pcap_datalink()
+.BR pcap_datalink ()
returns the link-layer header type on success and
.B PCAP_ERROR_NOT_ACTIVATED
if called on a capture handle that has been created but not activated.
.SH SEE ALSO
-pcap(3PCAP), pcap-linktype(@MAN_MISC_INFO@)
+.BR pcap (3PCAP),
+.BR pcap-linktype (@MAN_MISC_INFO@)
diff --git a/pcap_datalink_name_to_val.3pcap b/pcap_datalink_name_to_val.3pcap
index dd4688f0..d2cb1031 100644
--- a/pcap_datalink_name_to_val.3pcap
+++ b/pcap_datalink_name_to_val.3pcap
@@ -32,7 +32,7 @@ int pcap_datalink_name_to_val(const char *name);
.ft
.fi
.SH DESCRIPTION
-.B pcap_datalink_name_to_val()
+.BR pcap_datalink_name_to_val ()
translates a link-layer header type name, which is a
.B DLT_
name with the
@@ -40,10 +40,10 @@ name with the
removed, to the corresponding link-layer header type value. The
translation is case-insensitive.
.SH RETURN VALUE
-.B pcap_datalink_name_to_val()
+.BR pcap_datalink_name_to_val ()
returns the type value on success and
.B PCAP_ERROR
if the name is not a known
-type name..
+type name.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_datalink_val_to_name.3pcap b/pcap_datalink_val_to_name.3pcap
index f42165fb..bbfa3f80 100644
--- a/pcap_datalink_val_to_name.3pcap
+++ b/pcap_datalink_val_to_name.3pcap
@@ -17,7 +17,7 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP_DATALINK_VAL_TO_NAME 3PCAP "12 October 2016"
+.TH PCAP_DATALINK_VAL_TO_NAME 3PCAP "15 April 2019"
.SH NAME
pcap_datalink_val_to_name, pcap_datalink_val_to_description,
pcap_datalink_val_to_description_or_dlt \- get a
@@ -35,7 +35,7 @@ const char *pcap_datalink_val_to_description_or_dlt(int dlt);
.ft
.fi
.SH DESCRIPTION
-.B pcap_datalink_val_to_name()
+.BR pcap_datalink_val_to_name ()
translates a link-layer header type value to the corresponding
link-layer header type name, which is the
.B DLT_
@@ -47,7 +47,7 @@ is returned if the type value does not correspond to a known
.B DLT_
value.
.PP
-.B pcap_datalink_val_to_description()
+.BR pcap_datalink_val_to_description ()
translates a link-layer header type value to a short description of that
link-layer header type.
.B NULL
@@ -55,12 +55,22 @@ is returned if the type value does not correspond to a known
.B DLT_
value.
.PP
-.B pcap_datalink_val_to_description_or_dlt()
+.BR pcap_datalink_val_to_description_or_dlt ()
translates a link-layer header type value to a short description of that
-link-layer header type just like pcap_datalink_val_to_description.
+link-layer header type just like
+.BR pcap_datalink_val_to_description ().
If the type value does not correspond to a known
.B DLT_
value, the string "DLT n" is returned, where n is the value of
the dlt argument.
+.SH BACKWARD COMPATIBILITY
+The
+.BR pcap_datalink_val_to_description_or_dlt ()
+function first became available in libpcap release 1.10.0. In previous
+releases,
+.BR pcap_datalink_val_to_description ()
+would have to be called and, if it returned
+.BR NULL ,
+a default string would have to be constructed.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_dump.3pcap b/pcap_dump.3pcap
index 7f201b7c..ba7f75ad 100644
--- a/pcap_dump.3pcap
+++ b/pcap_dump.3pcap
@@ -33,18 +33,18 @@ u_char *sp);
.ft
.fi
.SH DESCRIPTION
-.B pcap_dump()
+.BR pcap_dump ()
outputs a packet to the ``savefile'' opened with
-.BR pcap_dump_open(3PCAP) .
+.BR pcap_dump_open (3PCAP).
Note that its calling arguments are suitable for use with
-.B pcap_dispatch(3PCAP)
+.BR pcap_dispatch (3PCAP)
or
-.BR pcap_loop(3PCAP) .
+.BR pcap_loop (3PCAP).
If called directly, the
.I user
parameter is of type
.B pcap_dumper_t
as returned by
-.BR pcap_dump_open() .
+.BR pcap_dump_open ().
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_dump_close.3pcap b/pcap_dump_close.3pcap
index bd95a52b..a62eb34d 100644
--- a/pcap_dump_close.3pcap
+++ b/pcap_dump_close.3pcap
@@ -31,7 +31,9 @@ void pcap_dump_close(pcap_dumper_t *p);
.ft
.fi
.SH DESCRIPTION
-.B pcap_dump_close()
+.BR pcap_dump_close ()
closes the ``savefile.''
.SH SEE ALSO
-pcap(3PCAP), pcap_dump_open(3PCAP), pcap_dump(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_dump_open (3PCAP),
+.BR pcap_dump (3PCAP)
diff --git a/pcap_dump_file.3pcap b/pcap_dump_file.3pcap
index d2074312..9fd6c7ec 100644
--- a/pcap_dump_file.3pcap
+++ b/pcap_dump_file.3pcap
@@ -31,8 +31,8 @@ FILE *pcap_dump_file(pcap_dumper_t *p);
.ft
.fi
.SH DESCRIPTION
-.B pcap_dump_file()
+.BR pcap_dump_file ()
returns the standard I/O stream of the ``savefile'' opened by
-.BR pcap_dump_open(3PCAP) .
+.BR pcap_dump_open (3PCAP).
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_dump_flush.3pcap b/pcap_dump_flush.3pcap
index 5d174745..c6e0f86e 100644
--- a/pcap_dump_flush.3pcap
+++ b/pcap_dump_flush.3pcap
@@ -31,15 +31,18 @@ int pcap_dump_flush(pcap_dumper_t *p);
.ft
.fi
.SH DESCRIPTION
-.B pcap_dump_flush()
+.BR pcap_dump_flush ()
flushes the output buffer to the ``savefile,'' so that any packets
written with
-.B pcap_dump(3PCAP)
+.BR pcap_dump (3PCAP)
but not yet written to the ``savefile'' will be written.
.SH RETURN VALUE
-.B pcap_dump_flush()
-returns 0 on success and
+.BR pcap_dump_flush ()
+returns
+.B 0
+on success and
.B PCAP_ERROR
on failure.
.SH SEE ALSO
-pcap(3PCAP), pcap_dump_open(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_dump_open (3PCAP)
diff --git a/pcap_dump_ftell.3pcap b/pcap_dump_ftell.3pcap
index 20cb995e..062d6095 100644
--- a/pcap_dump_ftell.3pcap
+++ b/pcap_dump_ftell.3pcap
@@ -33,18 +33,18 @@ int64_t pcap_dump_ftell64(pcap_dumper_t *p);
.ft
.fi
.SH DESCRIPTION
-.B pcap_dump_ftell()
+.BR pcap_dump_ftell ()
returns the current file position for the ``savefile'', representing the
number of bytes written by
-.B pcap_dump_open(3PCAP)
+.BR pcap_dump_open (3PCAP)
and
-.BR pcap_dump(3PCAP) .
+.BR pcap_dump (3PCAP).
.B PCAP_ERROR
is returned on error. If the current file position does not fit in a
.BR long ,
it will be truncated; this can happen on 32-bit UNIX-like systems with
large file support and on Windows.
-.B pcap_dump_ftell64()
+.BR pcap_dump_ftell64 ()
returns the current file position in a
.BR int64_t ,
so if file offsets that don't fit in a
@@ -54,5 +54,11 @@ but that fit in a
are supported, this will return the file offset without truncation.
.B PCAP_ERROR
is returned on error.
+.SH BACKWARD COMPATIBILITY
+The function
+.BR pcap_dump_ftell64 ()
+became available in libpcap release 1.9.0. In previous releases, there
+was no mechanism to obtain a file offset that is too large to fit in a
+.BR long .
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_dump_open.3pcap.in b/pcap_dump_open.3pcap.in
index b86696f0..fddecb8d 100644
--- a/pcap_dump_open.3pcap.in
+++ b/pcap_dump_open.3pcap.in
@@ -17,9 +17,10 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP_DUMP_OPEN 3PCAP "22 August 2018"
+.TH PCAP_DUMP_OPEN 3PCAP "3 July 2020"
.SH NAME
-pcap_dump_open, pcap_dump_fopen \- open a file to which to write packets
+pcap_dump_open, pcap_dump_open_append, pcap_dump_fopen \- open a file to
+which to write packets
.SH SYNOPSIS
.nf
.ft B
@@ -34,7 +35,7 @@ pcap_dumper_t *pcap_dump_fopen(pcap_t *p, FILE *fp);
.ft
.fi
.SH DESCRIPTION
-.B pcap_dump_open()
+.BR pcap_dump_open ()
is called to open a ``savefile'' for writing.
.I fname
specifies the name of the file to open. The file will have
@@ -42,62 +43,66 @@ the same format as those used by
.BR tcpdump (1)
and
.BR tcpslice (1).
+If the file does not exist, it will be created; if the file exists, it
+will be truncated and overwritten.
The name "-" is a synonym
for
.BR stdout .
.PP
-.B pcap_dump_fopen()
+.BR pcap_dump_fopen ()
is called to write data to an existing open stream
.IR fp ;
this stream will be closed by a subsequent call to
-.BR pcap_dump_close(3PCAP) .
+.BR pcap_dump_close (3PCAP).
+The stream is assumed to be at the beginning of a file that has been
+newly created or truncated, so that writes will start at the beginning
+of the file.
Note that on Windows, that stream should be opened in binary mode.
.PP
.I p
is a capture or ``savefile'' handle returned by an earlier call to
-.B pcap_create(3PCAP)
+.BR pcap_create (3PCAP)
and activated by an earlier call to
-.BR \%pcap_activate(3PCAP) ,
+.BR \%pcap_activate (3PCAP),
or returned by an earlier call to
-.BR \%pcap_open_offline(3PCAP) ,
-.BR pcap_open_live(3PCAP) ,
+.BR \%pcap_open_offline (3PCAP),
+.BR pcap_open_live (3PCAP),
or
-.BR pcap_open_dead(3PCAP) .
+.BR pcap_open_dead (3PCAP).
The time stamp precision, link-layer type, and snapshot length from
.I p
are used as the link-layer type and snapshot length of the output file.
.PP
-.B pcap_dump_open_append()
+.BR pcap_dump_open_append ()
is like
-.B pcap_dump_open()
-but does not create the file if it does not exist and, if it does
-already exist, and is a pcap file with the same byte order as the host
-opening the file, and has the same time stamp precision, link-layer
-header type, and snapshot length as
+.BR pcap_dump_open ()
+but, if the file already exists, and is a pcap file with the same byte
+order as the host opening the file, and has the same time stamp
+precision, link-layer header type, and snapshot length as
.IR p ,
it will write new packets at the end of the file.
.SH RETURN VALUES
A pointer to a
.B pcap_dumper_t
structure to use in subsequent
-.B pcap_dump(3PCAP)
+.BR pcap_dump (3PCAP)
and
-.B pcap_dump_close(3PCAP)
+.BR pcap_dump_close (3PCAP)
calls is returned on success.
.B NULL
is returned on failure.
If
.B NULL
is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
can be used to get the error text.
.SH BACKWARD COMPATIBILITY
.PP
The
-.B pcap_dump_open_append()
+.BR pcap_dump_open_append ()
function became available in libpcap release 1.7.2. In previous
releases, there is no support for appending packets to an existing
savefile.
.SH SEE ALSO
-pcap(3PCAP),
-\%pcap-savefile(@MAN_FILE_FORMATS@)
+.BR pcap (3PCAP),
+.BR \%pcap-savefile (@MAN_FILE_FORMATS@)
diff --git a/pcap_file.3pcap b/pcap_file.3pcap
index 981451ba..74029732 100644
--- a/pcap_file.3pcap
+++ b/pcap_file.3pcap
@@ -31,29 +31,29 @@ FILE *pcap_file(pcap_t *p);
.ft
.fi
.SH DESCRIPTION
-.B pcap_file()
+.BR pcap_file ()
returns the standard I/O stream of the ``savefile,'' if a ``savefile''
was opened with
-.BR pcap_open_offline(3PCAP) ,
+.BR pcap_open_offline (3PCAP),
or
.BR NULL ,
if a network device was opened with
-.B pcap_create(3PCAP)
+.BR pcap_create (3PCAP)
and
-.BR \%pcap_activate(3PCAP) ,
+.BR \%pcap_activate (3PCAP),
or with
-.BR pcap_open_live(3PCAP) .
+.BR pcap_open_live (3PCAP).
.PP
Note that the Packet Capture library is usually built with large file
support, so the standard I/O stream of the ``savefile'' might refer to
a file larger than 2 gigabytes; applications that use
-.B pcap_file()
+.BR pcap_file ()
should, if possible, use calls that support large files on the return
value of
-.B pcap_file()
+.BR pcap_file ()
or the value returned by
-.B fileno(3)
+.BR fileno (3)
when passed the return value of
-.BR pcap_file() .
+.BR pcap_file ().
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_fileno.3pcap b/pcap_fileno.3pcap
index 60ac1294..6d0edf88 100644
--- a/pcap_fileno.3pcap
+++ b/pcap_fileno.3pcap
@@ -35,31 +35,31 @@ If
.I p
refers to a network device that was opened for a live capture using
a combination of
-.B pcap_create(3PCAP)
+.BR pcap_create (3PCAP)
and
-.BR pcap_activate(3PCAP) ,
+.BR pcap_activate (3PCAP),
or using
-.BR pcap_open_live(3PCAP) ,
-.B pcap_fileno()
+.BR pcap_open_live (3PCAP),
+.BR pcap_fileno ()
returns the file descriptor from which captured packets are read.
.LP
If
.I p
refers to a ``savefile'' that was opened using functions such as
-.BR pcap_open_offline(3PCAP)
+.BR pcap_open_offline (3PCAP)
or
-.BR pcap_fopen_offline(3PCAP) ,
+.BR pcap_fopen_offline (3PCAP),
a ``dead''
.B pcap_t
opened using
-.BR pcap_open_dead(3PCAP) ,
+.BR pcap_open_dead (3PCAP),
or a
.B pcap_t
that was created with
-.B pcap_create()
+.BR pcap_create ()
but that has not yet been activated with
-.BR pcap_activate() ,
+.BR pcap_activate (),
it returns
.BR PCAP_ERROR .
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_findalldevs.3pcap b/pcap_findalldevs.3pcap
index 712e255a..41c98fe1 100644
--- a/pcap_findalldevs.3pcap
+++ b/pcap_findalldevs.3pcap
@@ -17,7 +17,7 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP_FINDALLDEVS 3PCAP "22 August 2018"
+.TH PCAP_FINDALLDEVS 3PCAP "23 August 2018"
.SH NAME
pcap_findalldevs, pcap_freealldevs \- get a list of capture devices, and
free that list
@@ -38,21 +38,21 @@ void pcap_freealldevs(pcap_if_t *alldevs);
.ft
.fi
.SH DESCRIPTION
-.B pcap_findalldevs()
+.BR pcap_findalldevs ()
constructs a list of network devices that can be opened with
-.B pcap_create(3PCAP)
+.BR pcap_create (3PCAP)
and
-.B pcap_activate(3PCAP)
+.BR pcap_activate (3PCAP)
or with
-.BR pcap_open_live(3PCAP) .
+.BR pcap_open_live (3PCAP).
(Note that there may be network devices that cannot be opened by the
process calling
-.BR pcap_findalldevs() ,
+.BR pcap_findalldevs (),
because, for example, that process does not have sufficient privileges
to open them for capturing; if so, those devices will not appear on the
list.)
If
-.B pcap_findalldevs()
+.BR pcap_findalldevs ()
succeeds, the pointer pointed to by
.I alldevsp
is set to point to the first element of the list, or to
@@ -72,7 +72,7 @@ for the last element of the list
.TP
.B name
a pointer to a string giving a name for the device to pass to
-.B pcap_open_live()
+.BR pcap_open_live ()
.TP
.B description
if not
@@ -194,12 +194,14 @@ for IPv6 addresses, it can be interpreted as if it pointed to a
.BR "struct sockaddr_in6".
.PP
The list of devices must be freed with
-.BR pcap_freealldevs(3PCAP) ,
+.BR pcap_freealldevs (3PCAP),
which frees the list pointed to by
.IR alldevs .
.SH RETURN VALUE
-.B pcap_findalldevs()
-returns 0 on success and
+.BR pcap_findalldevs ()
+returns
+.B 0
+on success and
.B PCAP_ERROR
on failure; as indicated, finding no
devices is considered success, rather than failure, so 0 will be
@@ -228,4 +230,4 @@ and
.B PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE
constants became available in libpcap release 1.9.0.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_freecode.3pcap b/pcap_freecode.3pcap
index 4e71efa4..65915fa1 100644
--- a/pcap_freecode.3pcap
+++ b/pcap_freecode.3pcap
@@ -31,13 +31,13 @@ void pcap_freecode(struct bpf_program *);
.ft
.fi
.SH DESCRIPTION
-.B pcap_freecode()
+.BR pcap_freecode ()
is used to free up allocated memory pointed to by a
.I bpf_program
struct generated by
-.B pcap_compile(3PCAP)
+.BR pcap_compile (3PCAP)
when that BPF program is no longer needed, for example after it
has been made the filter program for a pcap structure by a call to
-.BR pcap_setfilter(3PCAP) .
+.BR pcap_setfilter (3PCAP).
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_get_required_select_timeout.3pcap b/pcap_get_required_select_timeout.3pcap
index e58cb4e7..0256a6a5 100644
--- a/pcap_get_required_select_timeout.3pcap
+++ b/pcap_get_required_select_timeout.3pcap
@@ -17,10 +17,10 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP_GET_REQUIRED_SELECT_TIMEOUT 3PCAP "25 July 2018"
+.TH PCAP_GET_REQUIRED_SELECT_TIMEOUT 3PCAP "29 January 2020"
.SH NAME
-pcap_get_required_select_timeout \- get a file descriptor on which a
-select() can be done for a live capture
+pcap_get_required_select_timeout \- get a timeout to be used when doing
+select() for a live capture
.SH SYNOPSIS
.nf
.ft B
@@ -28,53 +28,98 @@ select() can be done for a live capture
.ft
.LP
.ft B
-struct timeval *pcap_get_required_select_timeout(pcap_t *p);
+const struct timeval *pcap_get_required_select_timeout(pcap_t *p);
.ft
.fi
.SH DESCRIPTION
-.B pcap_get_required_select_timeout()
+.BR pcap_get_required_select_timeout ()
returns, on UNIX, a pointer to a
.B struct timeval
containing a value that must be used as the minimum timeout in
-.BR select(2) ,
-.BR poll(2) ,
-.BR epoll_wait(2) ,
+.BR select (2),
+.BR poll (2),
+.BR epoll_wait (2),
and
-.B kevent()
-calls if
-.B pcap_get_selectable_fd(3PCAP)
+.BR kevent (2)
+calls, or
+.B NULL
+if there is no such timeout.
+If a
+.RB non- NULL
+value is returned, it must be used regardless of whether
+.BR pcap_get_selectable_fd (3PCAP)
returns
-.BR PCAP_ERROR .
+.B \-1
+for any descriptor on which those calls are being done.
+.BR pcap_get_required_select_timeout ()
+should be called for all
+.BR pcap_t s
+before a call to
+.BR select (),
+.BR poll (),
+.BR epoll_wait (),
+or
+.BR kevent (),
+and any timeouts used for those calls should be updated as appropriate
+given the new value of the timeout.
+.PP
+For
+.BR kevent (),
+one
+.B EVFILT_TIMER
+filter per selectable descriptor can be used, rather than using the
+timeout argument to
+.BR kevent ();
+if the
+.B EVFILT_TIMER
+event for a particular selectable descriptor signals an event,
+.BR pcap_dispatch (3PCAP)
+should be called for the corresponding
+.BR pcap_t .
+.PP
+On Linux systems with
+.BR timerfd_create (2),
+one timer object created by
+.BR timerfd_create ()
+per selectable descriptor can be used, rather than using the timeout
+argument to
+.BR epoll_wait ();
+if the
+timer object for a particular selectable descriptor signals an event,
+.BR pcap_dispatch (3PCAP)
+should be called for the corresponding
+.BR pcap_t .
.PP
-The timeout that should be used in those calls must be no larger than
+Otherwise, a timeout value no larger than
the smallest of all timeouts returned by
-.B \%pcap_get_required_select_timeout()
-for devices from which packets will be captured.
+.BR \%pcap_get_required_select_timeout ()
+for devices from which packets will be captured and any other timeouts
+to be used in the call should be used as the timeout for the call, and,
+when the call returns,
+.BR pcap_dispatch (3PCAP)
+should be called for all
+.BR pcap_t s
+for which a
+.RB non- NULL
+timeout was returned, regardless of whether it's indicated as having
+anything to read from it or not.
.PP
-The device for which
-.B pcap_get_selectable_fd()
-returned
-.B PCAP_ERROR
-must be put in non-blocking mode with
-.BR pcap_setnonblock(3PCAP) ,
-and an attempt must always be made to read packets from the device
-when the
-.BR select() ,
-.BR poll() ,
-.BR epoll_wait() ,
-or
-.B kevent()
-call returns.
+All devices with a
+.RB non- NULL
+timeout must be put in non-blocking mode with
+.BR pcap_setnonblock (3PCAP).
.PP
Note that a device on which a read can be done without blocking may,
on some platforms, not have any packets to read if the packet buffer
timeout has expired. A call to
-.B pcap_dispatch(3PCAP)
+.BR pcap_dispatch ()
or
-.B pcap_next_ex(3PCAP)
-will return 0 in this case, but will not block.
+.BR pcap_next_ex (3PCAP)
+will return
+.B 0
+in this case, but will not block.
.PP
-.B pcap_get_required_select_timeout()
+.BR pcap_get_required_select_timeout ()
is not available on Windows.
.SH RETURN VALUE
A pointer to a
@@ -85,14 +130,50 @@ is returned.
.SH BACKWARD COMPATIBILITY
This function became available in libpcap release 1.9.0. In previous
releases,
-.BR select() ,
-.BR poll() ,
-.BR epoll_wait() ,
+.BR select (),
+.BR poll (),
+.BR epoll_wait (),
and
-.B kevent()
+.BR kevent ()
cannot be used on any capture source for which
-.B pcap_get_selectable_fd
-returns \-1.
+.BR pcap_get_selectable_fd ()
+returns
+.BR \-1 .
+.PP
+In libpcap release 1.10.0 and later, the timeout value can change from
+call to call, so
+.BR pcap_get_required_select_timeout ()
+must be called before each call to
+.BR select (),
+.BR poll (),
+.BR epoll_wait (),
+or
+.BR kevent (),
+and the new value must be used to calculate timeouts for the call. Code
+that does that will also work with libpcap 1.9.x releases, so code
+using
+.BR pcap_get_required_select_timeout ()
+should be changed to call it for each call to
+.BR select (),
+.BR poll (),
+.BR epoll_wait (),
+or
+.BR kevent ()
+even if the code must also work with libpcap 1.9.x.
+.SH BACKWARD COMPATIBILITY
+This function became available in libpcap release 1.9.0. In previous
+releases,
+.BR select (),
+.BR poll (),
+.BR epoll_wait (),
+and
+.BR kevent ()
+could not be used for devices that don't provide a selectable file
+descriptor.
.SH SEE ALSO
-pcap(3PCAP), pcap_get_selectable_fd(3PCAP), select(2), poll(2),
-epoll_wait(2), kqueue(2)
+.BR pcap (3PCAP),
+.BR pcap_get_selectable_fd (3PCAP),
+.BR select (2),
+.BR poll (2),
+.BR epoll_wait (2),
+.BR kqueue (2)
diff --git a/pcap_get_selectable_fd.3pcap b/pcap_get_selectable_fd.3pcap
index 7f43db39..ed333038 100644
--- a/pcap_get_selectable_fd.3pcap
+++ b/pcap_get_selectable_fd.3pcap
@@ -17,7 +17,7 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP_GET_SELECTABLE_FD 3PCAP "25 July 2018"
+.TH PCAP_GET_SELECTABLE_FD 3PCAP "29 January 2020"
.SH NAME
pcap_get_selectable_fd \- get a file descriptor on which a select() can
be done for a live capture
@@ -32,42 +32,42 @@ int pcap_get_selectable_fd(pcap_t *p);
.ft
.fi
.SH DESCRIPTION
-.B pcap_get_selectable_fd()
+.BR pcap_get_selectable_fd ()
returns, on UNIX, a file descriptor number for a file descriptor on
which one can
do a
-.BR select(2) ,
-.BR poll(2) ,
-.BR epoll_wait(2) ,
-.BR kevent() ,
+.BR select (2),
+.BR poll (2),
+.BR epoll_wait (2),
+.BR kevent (2),
or other such call
to wait for it to be possible to read packets without blocking, if such
a descriptor exists, or
-.BR PCAP_ERROR ,
+.BR \-1 ,
if no such descriptor exists.
.PP
Some network devices opened with
-.B pcap_create(3PCAP)
+.BR pcap_create (3PCAP)
and
-.BR pcap_activate(3PCAP) ,
+.BR pcap_activate (3PCAP),
or with
-.BR pcap_open_live(3PCAP) ,
+.BR pcap_open_live (3PCAP),
do not support those calls (for example, regular network devices on
FreeBSD 4.3 and 4.4, and Endace DAG devices), so
-.B PCAP_ERROR
+.B \-1
is returned for
those devices. In that case, those calls must be given a timeout less
than or equal to the timeout returned by
-.B pcap_get_required_select_timeout(3PCAP)
+.BR pcap_get_required_select_timeout (3PCAP)
for the device for which
-.B pcap_get_selectable_fd()
+.BR pcap_get_selectable_fd ()
returned
-.BR PCAP_ERROR ,
+.BR \-1 ,
the device must be put in non-blocking mode with a call to
-.BR \%pcap_setnonblock(3PCAP) ,
+.BR \%pcap_setnonblock (3PCAP),
and an attempt must always be made to read packets from the device
when the call returns. If
-.B \%pcap_get_required_select_timeout()
+.BR \%pcap_get_required_select_timeout ()
returns
.BR NULL ,
it is not possible to wait for packets to arrive on the device in an
@@ -76,9 +76,9 @@ event loop.
Note that a device on which a read can be done without blocking may,
on some platforms, not have any packets to read if the packet buffer
timeout has expired. A call to
-.B pcap_dispatch(3PCAP)
+.BR pcap_dispatch (3PCAP)
or
-.B pcap_next_ex(3PCAP)
+.BR pcap_next_ex (3PCAP)
will return 0 in this case, but will not block.
.PP
Note that in:
@@ -91,18 +91,18 @@ OpenBSD prior to OpenBSD 2.4;
.IP
Mac OS X prior to Mac OS X 10.7;
.PP
-.BR select() ,
-.BR poll() ,
+.BR select (),
+.BR poll (),
and
-.B kevent()
+.BR kevent ()
do not work correctly on BPF devices;
-.B pcap_get_selectable_fd()
+.BR pcap_get_selectable_fd ()
will return a file descriptor on most of those versions (the exceptions
being FreeBSD 4.3 and 4.4), but a simple
-.BR select() ,
-.BR poll() ,
+.BR select (),
+.BR poll (),
or
-.B kevent()
+.BR kevent ()
call will not indicate that the descriptor is readable until a full
buffer's worth of packets is received, even if the packet timeout
expires before then. To work around this, code that uses
@@ -119,33 +119,34 @@ work correctly on BPF devices, so the workaround isn't necessary,
although it does no harm.)
.PP
Note also that
-.B poll()
+.BR poll ()
and
-.B kevent()
+.BR kevent ()
doesn't work on character special files, including BPF devices, in Mac
OS X 10.4 and 10.5, so, while
-.B select()
+.BR select ()
can be used on the descriptor returned by
-.BR pcap_get_selectable_fd() ,
-.B poll()
+.BR pcap_get_selectable_fd (),
+.BR poll ()
and
-.B kevent()
+.BR kevent ()
cannot be used on it those versions of Mac OS X.
-.BR poll() ,
+.BR poll (),
but not
-.BR kevent() ,
+.BR kevent (),
works on that descriptor in Mac OS X releases prior to
10.4;
-.B poll()
+.BR poll ()
and
-.B kevent()
+.BR kevent ()
work on that descriptor in Mac OS X 10.6 and later.
.PP
-.B pcap_get_selectable_fd()
+.BR pcap_get_selectable_fd ()
is not available on Windows.
.SH RETURN VALUE
A selectable file descriptor is returned if one exists; otherwise,
-.B PCAP_ERROR
+.B \-1
is returned.
.SH SEE ALSO
-pcap(3PCAP), kqueue(2)
+.BR pcap (3PCAP),
+.BR kqueue (2)
diff --git a/pcap_get_tstamp_precision.3pcap.in b/pcap_get_tstamp_precision.3pcap.in
index 2e72e0ba..7dbb5690 100644
--- a/pcap_get_tstamp_precision.3pcap.in
+++ b/pcap_get_tstamp_precision.3pcap.in
@@ -19,7 +19,7 @@
.\"IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
.\"WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-.TH PCAP_GET_TSTAMP_PRECISION 3PCAP "18 December 2013"
+.TH PCAP_GET_TSTAMP_PRECISION 3PCAP "23 August 2018"
.SH NAME
pcap_get_tstamp_precision \- get the time stamp precision returned in
captures
@@ -34,11 +34,11 @@ int pcap_get_tstamp_precision(pcap_t *p);
.ft
.fi
.SH DESCRIPTION
-.B pcap_get_tstamp_precision()
+.BR pcap_get_tstamp_precision ()
returns the precision of the time stamp returned in packet captures on the pcap
descriptor.
.SH RETURN VALUE
-.B pcap_get_tstamp_precision()
+.BR pcap_get_tstamp_precision ()
returns
.B PCAP_TSTAMP_PRECISION_MICRO
or
@@ -51,6 +51,6 @@ This function became available in libpcap release 1.5.1. In previous
releases, time stamps from a capture device or savefile are always given
in seconds and microseconds.
.SH SEE ALSO
-pcap(3PCAP),
-pcap_set_tstamp_precision(3PCAP),
-pcap-tstamp(@MAN_MISC_INFO@)
+.BR pcap (3PCAP),
+.BR pcap_set_tstamp_precision (3PCAP),
+.BR pcap-tstamp (@MAN_MISC_INFO@)
diff --git a/pcap_geterr.3pcap b/pcap_geterr.3pcap
index ee681c8c..72e23e38 100644
--- a/pcap_geterr.3pcap
+++ b/pcap_geterr.3pcap
@@ -32,7 +32,7 @@ void pcap_perror(pcap_t *p, const char *prefix);
.ft
.fi
.SH DESCRIPTION
-.B pcap_geterr()
+.BR pcap_geterr ()
returns the error text pertaining to the last pcap library error.
.BR NOTE :
the pointer it returns will no longer point to a valid error message
@@ -42,10 +42,10 @@ passed to it is closed; you must use or copy the string before closing
the
.BR pcap_t .
.PP
-.B pcap_perror()
+.BR pcap_perror ()
prints the text of the last pcap library error on
.BR stderr ,
prefixed by
.IR prefix .
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_init.3pcap b/pcap_init.3pcap
new file mode 100644
index 00000000..543f0833
--- /dev/null
+++ b/pcap_init.3pcap
@@ -0,0 +1,99 @@
+.\" Copyright (c) 1994, 1996, 1997
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that: (1) source code distributions
+.\" retain the above copyright notice and this paragraph in its entirety, (2)
+.\" distributions including binary code include the above copyright notice and
+.\" this paragraph in its entirety in the documentation or other materials
+.\" provided with the distribution, and (3) all advertising materials mentioning
+.\" features or use of this software display the following acknowledgement:
+.\" ``This product includes software developed by the University of California,
+.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+.\" the University nor the names of its contributors may be used to endorse
+.\" or promote products derived from this software without specific prior
+.\" written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.TH PCAP_INIT 3PCAP "11 April 2020"
+.SH NAME
+pcap_init \- initialize the library
+.SH SYNOPSIS
+.nf
+.ft B
+#include <pcap/pcap.h>
+.ft
+.LP
+.nf
+.ft B
+char errbuf[PCAP_ERRBUF_SIZE];
+.ft
+.LP
+.ft B
+int pcap_init(unsigned int opts, char *errbuf);
+.ft
+.fi
+.SH DESCRIPTION
+.BR pcap_init ()
+is used to initialize the Packet Capture library.
+.I opts
+specifies options for the library;
+currently, the options are:
+.TP
+.B PCAP_CHAR_ENC_LOCAL
+Treat all strings supplied as arguments, and return all strings to the
+caller, as being in the local character encoding.
+.TP
+.B PCAP_CHAR_ENC_UTF_8
+Treat all strings supplied as arguments, and return all strings to the
+caller, as being in UTF-8.
+.PP
+On UNIX-like systems, the local character encoding is assumed to be
+UTF-8, so no character encoding transformations are done.
+.PP
+On Windows, the local character encoding is the local ANSI code page.
+.PP
+If
+.BR pcap_init ()
+is not called, strings are treated as being in the local ANSI code page
+on Windows,
+.BR pcap_lookupdev (3PCAP)
+will succeed if there is a device on which to capture, and
+.BR pcap_create (3PCAP)
+makes an attempt to check whether the string passed as an argument is a
+UTF-16LE string - note that this attempt is unsafe, as it may run past
+the end of the string - to handle
+.BR pcap_lookupdev ()
+returning a UTF-16LE string. Programs that don't call
+.BR pcap_init ()
+should, on Windows, call
+.BR pcap_wsockinit ()
+to initialize Winsock; this is not necessary if
+.BR pcap_init ()
+is called, as
+.BR pcap_init ()
+will initialize Winsock itself on Windows.
+.SH RETURN VALUE
+.BR pcap_init ()
+returns
+.B 0
+on success and
+.B \-1
+on failure.
+If
+.B \-1
+is returned,
+.I errbuf
+is filled in with an appropriate error message.
+.I errbuf
+is assumed to be able to hold at least
+.B PCAP_ERRBUF_SIZE
+chars.
+.SH BACKWARD COMPATIBILITY
+This function became available in libpcap release 1.10.0. In previous
+releases, on Windows, all strings supplied as arguments, and all strings
+returned to the caller, are in the local character encoding.
+.SH SEE ALSO
+.BR pcap (3PCAP)
diff --git a/pcap_inject.3pcap b/pcap_inject.3pcap
index 92a92638..6b4554e7 100644
--- a/pcap_inject.3pcap
+++ b/pcap_inject.3pcap
@@ -32,7 +32,7 @@ int pcap_sendpacket(pcap_t *p, const u_char *buf, int size);
.ft
.fi
.SH DESCRIPTION
-.B pcap_inject()
+.BR pcap_inject ()
sends a raw packet through the network interface;
.I buf
points to the data of the packet, including the link-layer header, and
@@ -42,7 +42,7 @@ is the number of bytes in the packet.
Note that, even if you successfully open the network interface, you
might not have permission to send packets on it, or it might not support
sending packets; as
-.B pcap_open_live(3PCAP)
+.BR pcap_open_live (3PCAP)
doesn't have a flag to indicate whether to open for capturing, sending,
or capturing and sending, you cannot request an open that supports
sending and be notified at open time whether sending will be possible.
@@ -51,7 +51,7 @@ Note also that some devices might not support sending packets.
Note that, on some platforms, the link-layer header of the packet that's
sent might not be the same as the link-layer header of the packet
supplied to
-.BR pcap_inject() ,
+.BR pcap_inject (),
as the source link-layer address, if the header contains such an
address, might be changed to be the address assigned to the interface on
which the packet it sent, if the platform doesn't support sending
@@ -61,34 +61,38 @@ libpcap used when attaching to the device, even on platforms that
.I do
nominally support sending completely raw and unchanged packets.
.PP
-.B pcap_sendpacket()
+.BR pcap_sendpacket ()
is like
-.BR pcap_inject() ,
-but it returns 0 on success, rather than returning the number of bytes
+.BR pcap_inject (),
+but it returns
+.B 0
+on success, rather than returning the number of bytes
written.
-.RB ( pcap_inject()
+.RB ( pcap_inject ()
comes from OpenBSD;
-.B pcap_sendpacket()
-comes from WinPcap. Both are provided for compatibility.)
+.BR pcap_sendpacket ()
+comes from WinPcap/Npcap. Both are provided for compatibility.)
.SH RETURN VALUE
-.B pcap_inject()
+.BR pcap_inject ()
returns the number of bytes written on success and
.B PCAP_ERROR
on failure.
.PP
-.B pcap_sendpacket()
-returns 0 on success and
+.BR pcap_sendpacket ()
+returns
+.B 0
+on success and
.B PCAP_ERROR
on failure.
.PP
If
.B PCAP_ERROR
is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
may be called with
.I p
as an argument to fetch or display the error text.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_is_swapped.3pcap b/pcap_is_swapped.3pcap
index 67f762fe..260601a9 100644
--- a/pcap_is_swapped.3pcap
+++ b/pcap_is_swapped.3pcap
@@ -31,21 +31,21 @@ int pcap_is_swapped(pcap_t *p);
.ft
.fi
.SH DESCRIPTION
-.B pcap_is_swapped()
-returns true (1) if
+.BR pcap_is_swapped ()
+returns true (\fB1\fP) if
.I p
refers to a ``savefile'' that uses a different byte order
than the current system. For a live capture, it always returns false
-(0).
+(\fB0\fP).
.PP
It must not be called on a pcap descriptor created by
-.B \%pcap_create(3PCAP)
+.BR \%pcap_create (3PCAP)
that has not yet been activated by
-.BR \%pcap_activate(3PCAP) .
+.BR \%pcap_activate (3PCAP).
.SH RETURN VALUE
-.B pcap_is_swapped()
-returns true (1) or false (0) on success and
+.BR pcap_is_swapped ()
+returns true (\fB1\fP) or false (\fB0\fP) on success and
.B PCAP_ERROR_NOT_ACTIVATED
if called on a capture handle that has been created but not activated.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_lib_version.3pcap b/pcap_lib_version.3pcap
index 4b86b2d5..73ed2b88 100644
--- a/pcap_lib_version.3pcap
+++ b/pcap_lib_version.3pcap
@@ -31,9 +31,9 @@ const char *pcap_lib_version(void);
.ft
.fi
.SH DESCRIPTION
-.B pcap_lib_version()
+.BR pcap_lib_version ()
returns a pointer to a string giving information about the version of
the libpcap library being used; note that it contains more information
than just a version number.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_list_datalinks.3pcap.in b/pcap_list_datalinks.3pcap.in
index 60ba478f..d6e31499 100644
--- a/pcap_list_datalinks.3pcap.in
+++ b/pcap_list_datalinks.3pcap.in
@@ -33,25 +33,25 @@ void pcap_free_datalinks(int *dlt_list);
.ft
.fi
.SH DESCRIPTION
-.B pcap_list_datalinks()
+.BR pcap_list_datalinks ()
is used to get a list of the supported link-layer header types of the
interface associated with the pcap descriptor.
-.B pcap_list_datalinks()
+.BR pcap_list_datalinks ()
allocates an array to hold the list and sets
.IR *dlt_buf
to point to that array.
.LP
The caller is responsible for freeing the array with
-.BR pcap_free_datalinks() ,
+.BR pcap_free_datalinks (),
which frees the list of link-layer header types pointed to by
.IR dlt_list .
.LP
It must not be called on a pcap descriptor created by
-.B \%pcap_create(3PCAP)
+.BR \%pcap_create (3PCAP)
that has not yet been activated by
-.BR \%pcap_activate(3PCAP) .
+.BR \%pcap_activate (3PCAP).
.SH RETURN VALUE
-.B pcap_list_datalinks()
+.BR pcap_list_datalinks ()
returns the number of link-layer header types in the array on success,
.B PCAP_ERROR_NOT_ACTIVATED
if called on a capture handle that has been created but not activated,
@@ -61,13 +61,13 @@ on other errors.
If
.B PCAP_ERROR
is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
or
-.B \%pcap_perror(3PCAP)
+.BR \%pcap_perror (3PCAP)
may be called with
.I p
as an argument to fetch or display the error text.
.SH SEE ALSO
-pcap(3PCAP),
-pcap_datalink_val_to_name(3PCAP),
-pcap-linktype(@MAN_MISC_INFO@)
+.BR pcap (3PCAP),
+.BR pcap_datalink_val_to_name (3PCAP),
+.BR pcap-linktype (@MAN_MISC_INFO@)
diff --git a/pcap_list_tstamp_types.3pcap.in b/pcap_list_tstamp_types.3pcap.in
index e2487f70..74ef00ac 100644
--- a/pcap_list_tstamp_types.3pcap.in
+++ b/pcap_list_tstamp_types.3pcap.in
@@ -18,7 +18,7 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP_LIST_TSTAMP_TYPES 3PCAP "22 August 2018"
+.TH PCAP_LIST_TSTAMP_TYPES 3PCAP "8 September 2019"
.SH NAME
pcap_list_tstamp_types, pcap_free_tstamp_types \- get a list of time
stamp types supported by a capture device, and free that list
@@ -34,10 +34,10 @@ void pcap_free_tstamp_types(int *tstamp_types);
.ft
.fi
.SH DESCRIPTION
-.B pcap_list_tstamp_types()
+.BR pcap_list_tstamp_types ()
is used to get a list of the supported time stamp types of the interface
associated with the pcap descriptor.
-.B pcap_list_tstamp_types()
+.BR pcap_list_tstamp_types ()
allocates an array to hold the list and sets
.I *tstamp_typesp
to point to the array.
@@ -46,11 +46,11 @@ See
for a list of all the time stamp types.
.PP
The caller is responsible for freeing the array with
-.BR pcap_free_tstamp_types() ,
+.BR pcap_free_tstamp_types (),
which frees the list pointed to by
.IR tstamp_types .
.SH RETURN VALUE
-.B pcap_list_tstamp_types()
+.BR pcap_list_tstamp_types ()
returns the number of time stamp types in the array on success and
.B PCAP_ERROR
on failure.
@@ -65,9 +65,9 @@ one or more types).
If
.B PCAP_ERROR
is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
may be called with
.I p
as an argument to fetch or display the error text.
@@ -77,5 +77,6 @@ These functions became available in libpcap release 1.2.1. In previous
releases, the time stamp type cannot be set; only the default time stamp
type offered by a capture source is available.
.SH SEE ALSO
-pcap(3PCAP), pcap_tstamp_type_val_to_name(3PCAP),
-pcap-tstamp(@MAN_MISC_INFO@)
+.BR pcap (3PCAP),
+.BR pcap_tstamp_type_val_to_name (3PCAP),
+.BR pcap-tstamp (@MAN_MISC_INFO@)
diff --git a/pcap_lookupdev.3pcap b/pcap_lookupdev.3pcap
index 29f09e37..b5d548f0 100644
--- a/pcap_lookupdev.3pcap
+++ b/pcap_lookupdev.3pcap
@@ -39,22 +39,30 @@ char errbuf[PCAP_ERRBUF_SIZE];
.B This interface is obsoleted by
.BR pcap_findalldevs (3PCAP).
To find a default device on which to capture, call
-.B pcap_findalldevs()
+.BR pcap_findalldevs ()
and, if the list it returns is not empty, use the first device in the
list. (If the list is empty, there are no devices on which capture is
possible.)
.LP
-.B pcap_lookupdev()
+.B If
+.BR pcap_init (3PCAP)
+.B has been called, this interface always returns
+.BR NULL .
+.LP
+.BR pcap_lookupdev ()
returns a pointer to a string giving the name of a network device
suitable for use with
-.B pcap_create(3PCAP)
+.BR pcap_create (3PCAP)
and
-.BR \%pcap_activate(3PCAP) ,
+.BR \%pcap_activate (3PCAP),
or with
-.BR pcap_open_live(3PCAP) ,
+.BR pcap_open_live (3PCAP),
and with
-.BR pcap_lookupnet(3PCAP) .
+.BR pcap_lookupnet (3PCAP).
If there is an error,
+or if
+.BR pcap_init (3PCAP)
+has been called,
.B NULL
is returned and
.I errbuf
@@ -64,16 +72,15 @@ is assumed to be able to hold at least
.B PCAP_ERRBUF_SIZE
chars.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
.SH BUGS
The pointer returned by
-.B pcap_lookupdev()
+.BR pcap_lookupdev ()
points to a static buffer; subsequent calls to
-.B pcap_lookupdev()
+.BR pcap_lookupdev ()
in the same thread, or calls to
-.B pcap_lookupdev()
+.BR pcap_lookupdev ()
in another thread, may overwrite that buffer.
.LP
-In WinPcap, this function may return a UTF-16 string rather than an
-ASCII or UTF-8 string.
-
+In WinPcap and Npcap, this function may return a UTF-16 string rather
+than an ASCII or UTF-8 string.
diff --git a/pcap_lookupnet.3pcap b/pcap_lookupnet.3pcap
index f6094453..c12fa55e 100644
--- a/pcap_lookupnet.3pcap
+++ b/pcap_lookupnet.3pcap
@@ -38,7 +38,7 @@ bpf_u_int32 *maskp, char *errbuf);
.ft
.fi
.SH DESCRIPTION
-.B pcap_lookupnet()
+.BR pcap_lookupnet ()
is used to determine the IPv4 network number and mask
associated with the network device
.IR device .
@@ -50,8 +50,10 @@ are
.I bpf_u_int32
pointers.
.SH RETURN VALUE
-.B pcap_lookupnet()
-returns 0 on success and
+.BR pcap_lookupnet ()
+returns
+.B 0
+on success and
.B PCAP_ERROR
on failure. If
.B PCAP_ERROR
@@ -63,4 +65,4 @@ is assumed to be able to hold at least
.B PCAP_ERRBUF_SIZE
chars.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_loop.3pcap b/pcap_loop.3pcap
index 0193714b..3d741efa 100644
--- a/pcap_loop.3pcap
+++ b/pcap_loop.3pcap
@@ -17,7 +17,7 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP_LOOP 3PCAP "25 July 2018"
+.TH PCAP_LOOP 3PCAP "22 August 2020"
.SH NAME
pcap_loop, pcap_dispatch \- process packets from a live capture or savefile
.SH SYNOPSIS
@@ -42,28 +42,32 @@ pcap_handler callback, u_char *user);
.ft
.fi
.SH DESCRIPTION
-.B pcap_loop()
+.BR pcap_loop ()
processes packets from a live capture or ``savefile'' until
.I cnt
packets are processed, the end of the ``savefile'' is
reached when reading from a ``savefile'',
-.B pcap_breakloop(3PCAP)
+.BR pcap_breakloop (3PCAP)
is called, or an error occurs.
It does
.B not
return when live packet buffer timeouts occur.
-A value of \-1 or 0 for
+A value of
+.B \-1
+or
+.B 0
+for
.I cnt
is equivalent to infinity, so that packets are processed until another
ending condition occurs.
.PP
-.B pcap_dispatch()
+.BR pcap_dispatch ()
processes packets from a live capture or ``savefile'' until
.I cnt
packets are processed, the end of the current bufferful of packets is
reached when doing a live capture, the end of the ``savefile'' is
reached when reading from a ``savefile'',
-.B pcap_breakloop()
+.BR pcap_breakloop ()
is called, or an error occurs.
Thus, when doing a live capture,
.I cnt
@@ -71,7 +75,11 @@ is the maximum number of packets to process before returning, but is not
a minimum number; when reading a live capture, only one
bufferful of packets is read at a time, so fewer than
.I cnt
-packets may be processed. A value of \-1 or 0 for
+packets may be processed. A value of
+.B \-1
+or
+.B 0
+for
.I cnt
causes all the packets received in one buffer to be processed when
reading a live capture, and causes all the packets in the file to be
@@ -79,20 +87,11 @@ processed when reading a ``savefile''.
.PP
Note that, when doing a live capture on some platforms, if the read
timeout expires when there are no packets available,
-.B pcap_dispatch()
+.BR pcap_dispatch ()
will return 0, even when not in non-blocking mode, as there are no
packets to process. Applications should be prepared for this to happen,
but must not rely on it happening.
.PP
-.ft B
-(In older versions of libpcap, the behavior when
-\fIcnt\fP
-was 0 was undefined; different platforms and devices behaved
-differently, so code that must work with older versions of libpcap
-should use \-1, not 0, as the value of
-\fIcnt\fP.)
-.ft R
-.PP
.I callback
specifies a
.I pcap_handler
@@ -102,9 +101,9 @@ a
pointer which is passed in the
.I user
argument to
-.B pcap_loop()
+.BR pcap_loop ()
or
-.BR pcap_dispatch() ,
+.BR pcap_dispatch (),
a
.I const struct pcap_pkthdr
pointer pointing to the packet time stamp and lengths, and a
@@ -123,25 +122,25 @@ them.
.PP
The bytes of data from the packet begin with a link-layer header. The
format of the link-layer header is indicated by the return value of the
-.B pcap_datalink(3PCAP)
+.BR pcap_datalink (3PCAP)
routine when handed the
.B pcap_t
value also passed to
-.B pcap_loop()
+.BR pcap_loop ()
or
-.BR pcap_dispatch() .
+.BR pcap_dispatch ().
.I https://www.tcpdump.org/linktypes.html
lists the values
-.B pcap_datalink()
+.BR pcap_datalink ()
can return and describes the packet formats that
correspond to those values. The value it returns will be valid for all
packets received unless and until
-.B pcap_set_datalink(3PCAP)
+.BR pcap_set_datalink (3PCAP)
is called; after a successful call to
-.BR pcap_set_datalink() ,
+.BR pcap_set_datalink (),
all subsequent packets will have a link-layer header of the type
specified by the link-layer header type value passed to
-.BR pcap_set_datalink() .
+.BR pcap_set_datalink ().
.PP
Do
.B NOT
@@ -151,13 +150,17 @@ any given link-layer header type, such as
for Ethernet. For example, the "any" device on Linux will have a
link-layer header type of
.B DLT_LINUX_SLL
+or
+.B DLT_LINUX_SLL2
even if all devices on the system at the time the "any" device is opened
have some other data link type, such as
.B DLT_EN10MB
for Ethernet.
.SH RETURN VALUE
-.B pcap_loop()
-returns 0 if
+.BR pcap_loop ()
+returns
+.B 0
+if
.I cnt
is exhausted or if, when reading from a ``savefile'', no more packets
are available. It returns
@@ -165,14 +168,14 @@ are available. It returns
if an error occurs or
.B PCAP_ERROR_BREAK
if the loop terminated due to a call to
-.B pcap_breakloop()
+.BR pcap_breakloop ()
before any packets were processed.
It does
.B not
return when live packet buffer timeouts occur; instead, it attempts to
read more packets.
.PP
-.B pcap_dispatch()
+.BR pcap_dispatch ()
returns the number of packets processed on success; this can be 0 if no
packets were read from a live capture (if, for example, they were
discarded because they didn't pass the packet filter, or if, on
@@ -185,7 +188,7 @@ in a ``savefile.'' It returns
if an error occurs or
.B PCAP_ERROR_BREAK
if the loop terminated due to a call to
-.B pcap_breakloop()
+.BR pcap_breakloop ()
before any packets were processed.
.ft B
If your application uses pcap_breakloop(),
@@ -196,11 +199,24 @@ rather than just checking for a return value < 0.
If
.B PCAP_ERROR
is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
may be called with
.I p
as an argument to fetch or display the error text.
+.SH BACKWARD COMPATIBILITY
+.PP
+In libpcap versions before 1.5.0, the behavior when
+.I cnt
+was
+.B 0
+was undefined; different platforms and devices behaved differently,
+so code that must work with these versions of libpcap should use
+.BR \-1 ,
+not
+.BR 0 ,
+as the value of
+.IR cnt .
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_major_version.3pcap b/pcap_major_version.3pcap
index 2fedfd2d..393705b4 100644
--- a/pcap_major_version.3pcap
+++ b/pcap_major_version.3pcap
@@ -35,9 +35,9 @@ int pcap_minor_version(pcap_t *p);
If
.I p
refers to a ``savefile'',
-.B pcap_major_version()
+.BR pcap_major_version ()
returns the major number of the file format of the ``savefile'' and
-.B pcap_minor_version()
+.BR pcap_minor_version ()
returns the minor number of the file format of the ``savefile''. The
version number is stored in the ``savefile''; note that the meaning of
its values depends on the type of ``savefile'' (for example, pcap or
@@ -46,9 +46,9 @@ pcapng).
If
.I p
refers to a live capture, the values returned by
-.B pcap_major_version()
+.BR pcap_major_version ()
and
-.B pcap_minor_version()
+.BR pcap_minor_version ()
are not meaningful.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_next_ex.3pcap b/pcap_next_ex.3pcap
index f0eb82d1..2bd1a427 100644
--- a/pcap_next_ex.3pcap
+++ b/pcap_next_ex.3pcap
@@ -34,7 +34,7 @@ const u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h);
.ft
.fi
.SH DESCRIPTION
-.B pcap_next_ex()
+.BR pcap_next_ex ()
reads the next packet and returns a success/failure indication.
If the packet was read without problems, the pointer pointed to by the
.I pkt_header
@@ -47,16 +47,16 @@ argument is set to point to the data in the packet. The
.I struct pcap_pkthdr
and the packet data are not to be freed by the caller, and are not
guaranteed to be valid after the next call to
-.BR pcap_next_ex() ,
-.BR pcap_next() ,
-.BR pcap_loop(3PCAP) ,
+.BR pcap_next_ex (),
+.BR pcap_next (),
+.BR pcap_loop (3PCAP),
or
-.BR pcap_dispatch(3PCAP) ;
+.BR pcap_dispatch (3PCAP);
if the code needs them to remain valid, it must make a copy of them.
.PP
-.B pcap_next()
+.BR pcap_next ()
reads the next packet (by calling
-.B pcap_dispatch()
+.BR pcap_dispatch ()
with a
.I cnt
of 1) and returns a
@@ -64,11 +64,11 @@ of 1) and returns a
pointer to the data in that packet. The
packet data is not to be freed by the caller, and is not
guaranteed to be valid after the next call to
-.BR pcap_next_ex() ,
-.BR pcap_next() ,
-.BR pcap_loop() ,
+.BR pcap_next_ex (),
+.BR pcap_next (),
+.BR pcap_loop (),
or
-.BR pcap_dispatch() ;
+.BR pcap_dispatch ();
if the code needs it to remain valid, it must make a copy of it.
The
.I pcap_pkthdr
@@ -78,25 +78,25 @@ is filled in with the appropriate values for the packet.
.PP
The bytes of data from the packet begin with a link-layer header. The
format of the link-layer header is indicated by the return value of the
-.B pcap_datalink(PCAP)
+.BR pcap_datalink (3PCAP)
routine when handed the
.B pcap_t
value also passed to
-.B pcap_loop()
+.BR pcap_loop ()
or
-.BR pcap_dispatch() .
+.BR pcap_dispatch ().
.I https://www.tcpdump.org/linktypes.html
lists the values
-.B pcap_datalink()
+.BR pcap_datalink ()
can return and describes the packet formats that
correspond to those values. The value it returns will be valid for all
packets received unless and until
-.B pcap_set_datalink(3PCAP)
+.BR pcap_set_datalink (3PCAP)
is called; after a successful call to
-.BR pcap_set_datalink() ,
+.BR pcap_set_datalink (),
all subsequent packets will have a link-layer header of the type
specified by the link-layer header type value passed to
-.BR pcap_set_datalink() .
+.BR pcap_set_datalink ().
.PP
Do
.B NOT
@@ -106,13 +106,19 @@ any given link-layer header type, such as
for Ethernet. For example, the "any" device on Linux will have a
link-layer header type of
.B DLT_LINUX_SLL
+or
+.B DLT_LINUX_SLL2
even if all devices on the system at the time the "any" device is opened
have some other data link type, such as
.B DLT_EN10MB
for Ethernet.
.SH RETURN VALUE
-.B pcap_next_ex()
-returns 1 if the packet was read without problems, 0 if packets are
+.BR pcap_next_ex ()
+returns
+.B 1
+if the packet was read without problems,
+.B 0
+if packets are
being read from a live capture and the packet buffer timeout expired,
.B PCAP_ERROR
if an error occurred while reading the packet, and
@@ -122,14 +128,14 @@ are being read from a ``savefile'' and there are no more packets to read
from the savefile. If
.B PCAP_ERROR
is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
may be called with
.I p
as an argument to fetch or display the error text.
.PP
-.B pcap_next()
+.BR pcap_next ()
returns a pointer to the packet data on success, and returns
.B NULL
if an error occurred, or if no packets were read from a live capture
@@ -141,4 +147,4 @@ non-blocking mode and no packets were available to be read), or if no
more packets are available in a ``savefile.'' Unfortunately, there is no
way to determine whether an error occurred or not.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_offline_filter.3pcap b/pcap_offline_filter.3pcap
index 724f8366..dbb6e966 100644
--- a/pcap_offline_filter.3pcap
+++ b/pcap_offline_filter.3pcap
@@ -33,13 +33,13 @@ const struct pcap_pkthdr *h, const u_char *pkt)
.ft
.fi
.SH DESCRIPTION
-.B pcap_offline_filter()
+.BR pcap_offline_filter ()
checks whether a filter matches a packet.
.I fp
is a pointer to a
.I bpf_program
struct, usually the result of a call to
-.BR pcap_compile(3PCAP) .
+.BR pcap_compile (3PCAP).
.I h
points to the
.I pcap_pkthdr
@@ -47,9 +47,9 @@ structure for the packet, and
.I pkt
points to the data in the packet.
.SH RETURN VALUE
-.B pcap_offline_filter()
+.BR pcap_offline_filter ()
returns the return value of the filter program. This will be zero if
the packet doesn't match the filter and non-zero if the packet matches
the filter.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_open_dead.3pcap.in b/pcap_open_dead.3pcap.in
index 97a97f3a..ced7d6cf 100644
--- a/pcap_open_dead.3pcap.in
+++ b/pcap_open_dead.3pcap.in
@@ -35,18 +35,18 @@ pcap_t *pcap_open_dead_with_tstamp_precision(int linktype, int snaplen,
.fi
.SH DESCRIPTION
.PP
-.B pcap_open_dead()
+.BR pcap_open_dead ()
and
-.B pcap_open_dead_with_tstamp_precision()
+.BR pcap_open_dead_with_tstamp_precision ()
are used for creating a
.B pcap_t
structure to use when calling the other functions in libpcap. It is
typically used when just using libpcap for compiling BPF code; it can
also be used if using
-.BR pcap_dump_open(3PCAP) ,
-.BR pcap_dump(3PCAP) ,
+.BR pcap_dump_open (3PCAP),
+.BR pcap_dump (3PCAP),
and
-.B pcap_dump_close(3PCAP)
+.BR pcap_dump_close (3PCAP)
to write a savefile if there is no
.B pcap_t
that supplies the packets to be written.
@@ -60,11 +60,11 @@ specifies the snapshot length for the
.BR pcap_t .
.PP
When
-.BR pcap_open_dead_with_tstamp_precision() ,
+.BR pcap_open_dead_with_tstamp_precision (),
is used to create a
.B pcap_t
for use with
-.BR pcap_dump_open() ,
+.BR pcap_dump_open (),
.I precision
specifies the time stamp precision for packets;
.B PCAP_TSTAMP_PRECISION_MICRO
@@ -73,6 +73,13 @@ seconds and microseconds, and
.B PCAP_TSTAMP_PRECISION_NANO
should be specified if the packets to be written have time stamps in
seconds and nanoseconds. Its value does not affect
-.BR pcap_compile(3PCAP) .
+.BR pcap_compile (3PCAP).
+.SH BACKWARD COMPATIBILITY
+The
+.BR pcap_open_dead_with_tstamp_precision ()
+function became available in libpcap release 1.5.1. In previous
+releases, there was no mechanism to open a savefile for writing with
+time stamps given in seconds and nanoseconds.
.SH SEE ALSO
-pcap(3PCAP), \%pcap-linktype(@MAN_MISC_INFO@)
+.BR pcap (3PCAP),
+.BR \%pcap-linktype (@MAN_MISC_INFO@)
diff --git a/pcap_open_live.3pcap b/pcap_open_live.3pcap
index 3286e294..b8c17299 100644
--- a/pcap_open_live.3pcap
+++ b/pcap_open_live.3pcap
@@ -38,7 +38,7 @@ int promisc, int to_ms, char *errbuf);
.ft
.fi
.SH DESCRIPTION
-.B pcap_open_live()
+.BR pcap_open_live ()
is used to obtain a packet capture handle to look
at packets on the network.
.I device
@@ -53,7 +53,10 @@ can be used to capture packets from all interfaces.
specifies the snapshot length to be set on the handle.
.PP
.I promisc
-specifies if the interface is to be put into promiscuous mode.
+specifies whether the interface is to be put into promiscuous mode.
+If
+.I promisc
+is non-zero, promiscuous mode will be set, otherwise it will not be set.
.PP
.I to_ms
specifies the packet buffer timeout, as a non-negative value, in
@@ -61,7 +64,7 @@ milliseconds. (See
.BR pcap (3PCAP)
for an explanation of the packet buffer timeout.)
.SH RETURN VALUE
-.B pcap_open_live()
+.BR pcap_open_live ()
returns a
.I pcap_t *
on success and
@@ -74,11 +77,11 @@ is returned,
is filled in with an appropriate error message.
.I errbuf
may also be set to warning text when
-.B pcap_open_live()
+.BR pcap_open_live ()
succeeds; to detect this case the caller should store a zero-length string in
.I errbuf
before calling
-.B pcap_open_live()
+.BR pcap_open_live ()
and display the warning to the user if
.I errbuf
is no longer a zero-length string.
@@ -87,4 +90,5 @@ is assumed to be able to hold at least
.B PCAP_ERRBUF_SIZE
chars.
.SH SEE ALSO
-pcap_create(3PCAP), pcap_activate(3PCAP)
+.BR pcap_create (3PCAP),
+.BR pcap_activate (3PCAP)
diff --git a/pcap_open_offline.3pcap.in b/pcap_open_offline.3pcap.in
index 2bfbbace..5e878fea 100644
--- a/pcap_open_offline.3pcap.in
+++ b/pcap_open_offline.3pcap.in
@@ -17,7 +17,7 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP_OPEN_OFFLINE 3PCAP "8 January 2018 "
+.TH PCAP_OPEN_OFFLINE 3PCAP "23 August 2018"
.SH NAME
pcap_open_offline, pcap_open_offline_with_tstamp_precision,
pcap_fopen_offline, pcap_fopen_offline_with_tstamp_precision \- open a saved capture file for reading
@@ -42,9 +42,9 @@ pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *fp,
.ft
.fi
.SH DESCRIPTION
-.B pcap_open_offline()
+.BR pcap_open_offline ()
and
-.B pcap_open_offline_with_tstamp_precision()
+.BR pcap_open_offline_with_tstamp_precision ()
are called to open a ``savefile'' for reading.
.PP
.I fname
@@ -60,7 +60,7 @@ be read.
The name "-" is a synonym for
.BR stdin .
.PP
-.B pcap_open_offline_with_tstamp_precision()
+.BR pcap_open_offline_with_tstamp_precision ()
takes an additional
.I precision
argument specifying the time stamp precision desired;
@@ -76,22 +76,22 @@ precision as the requested precision, they will be scaled up or down as
necessary before being supplied.
.PP
Alternatively, you may call
-.B pcap_fopen_offline()
+.BR pcap_fopen_offline ()
or
-.B pcap_fopen_offline_with_tstamp_precision()
+.BR pcap_fopen_offline_with_tstamp_precision ()
to read dumped data from an existing open stream
.IR fp .
-.B pcap_fopen_offline_with_tstamp_precision()
+.BR pcap_fopen_offline_with_tstamp_precision ()
takes an additional
.I precision
argument as described above.
Note that on Windows, that stream should be opened in binary mode.
.SH RETURN VALUE
-.BR pcap_open_offline() ,
-.BR pcap_open_offline_with_tstamp_precision() ,
-.BR pcap_fopen_offline() ,
+.BR pcap_open_offline (),
+.BR pcap_open_offline_with_tstamp_precision (),
+.BR pcap_fopen_offline (),
and
-.B pcap_fopen_offline_with_tstamp_precision()
+.BR pcap_fopen_offline_with_tstamp_precision ()
return a
.I pcap_t *
on success and
@@ -107,10 +107,11 @@ is assumed to be able to hold at least
.B PCAP_ERRBUF_SIZE
chars.
.SH BACKWARD COMPATIBILITY
-.B pcap_open_offline_with_tstamp_precision
+.BR pcap_open_offline_with_tstamp_precision ()
and
-.B pcap_fopen_offline_with_tstamp_precision
+.BR pcap_fopen_offline_with_tstamp_precision ()
became available in libpcap release 1.5.1. In previous releases, time
stamps from a savefile are always given in seconds and microseconds.
.SH SEE ALSO
-pcap(3PCAP), pcap-savefile(@MAN_FILE_FORMATS@)
+.BR pcap (3PCAP),
+.BR pcap-savefile (@MAN_FILE_FORMATS@)
diff --git a/pcap_set_buffer_size.3pcap b/pcap_set_buffer_size.3pcap
index 684f739c..49492c06 100644
--- a/pcap_set_buffer_size.3pcap
+++ b/pcap_set_buffer_size.3pcap
@@ -31,15 +31,19 @@ int pcap_set_buffer_size(pcap_t *p, int buffer_size);
.ft
.fi
.SH DESCRIPTION
-.B pcap_set_buffer_size()
+.BR pcap_set_buffer_size ()
sets the buffer size that will be used on a capture handle when
the handle is activated to
.IR buffer_size ,
which is in units of bytes.
.SH RETURN VALUE
-.B pcap_set_buffer_size()
-returns 0 on success or
+.BR pcap_set_buffer_size ()
+returns
+.B 0
+on success or
.B PCAP_ERROR_ACTIVATED
if called on a capture handle that has been activated.
.SH SEE ALSO
-pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_create (3PCAP),
+.BR pcap_activate (3PCAP)
diff --git a/pcap_set_datalink.3pcap b/pcap_set_datalink.3pcap
index 66cfdb1e..14e9d209 100644
--- a/pcap_set_datalink.3pcap
+++ b/pcap_set_datalink.3pcap
@@ -32,22 +32,25 @@ int pcap_set_datalink(pcap_t *p, int dlt);
.ft
.fi
.SH DESCRIPTION
-.B pcap_set_datalink()
+.BR pcap_set_datalink ()
is used to set the current link-layer header type of the pcap descriptor
to the type specified by
.IR dlt .
.SH RETURN VALUE
-.B pcap_set_datalink()
-returns 0 on success and
+.BR pcap_set_datalink ()
+returns
+.B 0
+on success and
.B PCAP_ERROR
on failure. If
.B PCAP_ERROR
is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
may be called with
.I p
as an argument to fetch or display the error text.
.SH SEE ALSO
-pcap(3PCAP), pcap_datalink_name_to_val(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_datalink_name_to_val (3PCAP)
diff --git a/pcap_set_immediate_mode.3pcap.in b/pcap_set_immediate_mode.3pcap.in
index 2fe45c54..e493d55a 100644
--- a/pcap_set_immediate_mode.3pcap.in
+++ b/pcap_set_immediate_mode.3pcap.in
@@ -18,7 +18,7 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP_SET_IMMEDIATE_MODE 3PCAP "22 August 2018"
+.TH PCAP_SET_IMMEDIATE_MODE 3PCAP "23 August 2018"
.SH NAME
pcap_set_immediate_mode \- set immediate mode for a not-yet-activated capture
handle
@@ -32,7 +32,7 @@ int pcap_set_immediate_mode(pcap_t *p, int immediate_mode);
.ft
.fi
.SH DESCRIPTION
-.B pcap_set_immediate_mode()
+.BR pcap_set_immediate_mode ()
sets whether immediate mode should be set on a capture handle when
the handle is activated. In immediate mode, packets are always
delivered as soon as they arrive, with no buffering.
@@ -40,8 +40,10 @@ If
.I immediate_mode
is non-zero, immediate mode will be set, otherwise it will not be set.
.SH RETURN VALUE
-.B pcap_set_immediate_mode()
-returns 0 on success or
+.BR pcap_set_immediate_mode ()
+returns
+.B 0
+on success or
.B PCAP_ERROR_ACTIVATED
if called on a capture handle that has been activated.
.SH BACKWARD COMPATIBILITY
@@ -54,11 +56,11 @@ immediate mode must be turned on with a
.B BIOCIMMEDIATE
.BR ioctl (2),
as documented in
-.BR bpf(@MAN_DEVICES@) ,
+.BR bpf (@MAN_DEVICES@),
on the descriptor returned by
-.B pcap_fileno(3PCAP),
+.BR pcap_fileno (3PCAP),
after
-.BR pcap_activate(3PCAP)
+.BR pcap_activate (3PCAP)
is called;
.IP
on Solaris 10 and earlier versions of Solaris, immediate mode must be
@@ -70,26 +72,28 @@ on Digital UNIX/Tru64 UNIX, immediate mode must be turned on by doing a
.B BIOCMBIC
.BR ioctl ,
as documented in
-.BR packetfilter(7) ,
+.BR packetfilter (7),
to clear the
.B ENBATCH
flag on the descriptor returned by
-.B pcap_fileno(3PCAP),
+.BR pcap_fileno (3PCAP),
after
-.BR pcap_activate(3PCAP)
+.BR pcap_activate (3PCAP)
is called;
.IP
on Windows, immediate mode must be turned on by calling
-.B pcap_setmintocopy()
+.BR pcap_setmintocopy ()
with a size of 0.
.PP
On Linux, with previous releases of libpcap, capture devices are always
in immediate mode; however, in 1.5.0 and later, they are, by default,
.B not
in immediate mode, so if
-.B pcap_set_immediate_mode()
+.BR pcap_set_immediate_mode ()
is available, it should be used.
.PP
On other platforms, capture devices are always in immediate mode.
.SH SEE ALSO
-pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_create (3PCAP),
+.BR pcap_activate (3PCAP)
diff --git a/pcap_set_promisc.3pcap b/pcap_set_promisc.3pcap
index fcd797a3..cfc6cdda 100644
--- a/pcap_set_promisc.3pcap
+++ b/pcap_set_promisc.3pcap
@@ -31,16 +31,20 @@ int pcap_set_promisc(pcap_t *p, int promisc);
.ft
.fi
.SH DESCRIPTION
-.B pcap_set_promisc()
+.BR pcap_set_promisc ()
sets whether promiscuous mode should be set on a capture handle when
the handle is activated.
If
.I promisc
is non-zero, promiscuous mode will be set, otherwise it will not be set.
.SH RETURN VALUE
-.B pcap_set_promisc()
-returns 0 on success or
+.BR pcap_set_promisc ()
+returns
+.B 0
+on success or
.B PCAP_ERROR_ACTIVATED
if called on a capture handle that has been activated.
.SH SEE ALSO
-pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_create (3PCAP),
+.BR pcap_activate (3PCAP)
diff --git a/pcap_set_protocol_linux.3pcap b/pcap_set_protocol_linux.3pcap
index 873017ba..a891d749 100644
--- a/pcap_set_protocol_linux.3pcap
+++ b/pcap_set_protocol_linux.3pcap
@@ -17,7 +17,7 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP_SET_PROTOCOL_LINUX 3PCAP "24 August 2017"
+.TH PCAP_SET_PROTOCOL_LINUX 3PCAP "22 August 2018"
.SH NAME
pcap_set_protocol_linux \- set capture protocol for a not-yet-activated
capture handle
@@ -32,7 +32,7 @@ int pcap_set_protocol_linux(pcap_t *p, int protocol);
.fi
.SH DESCRIPTION
On network interface devices on Linux,
-.B pcap_set_protocol_linux()
+.BR pcap_set_protocol_linux ()
sets the protocol to be used in the
.BR socket (2)
call to create a capture socket when the handle is activated. The
@@ -48,21 +48,25 @@ other than a network interface, it will have no effect.
.LP
It should not be used in portable code; instead, a filter should be
specified with
-.BR pcap_setfilter(3PCAP) .
+.BR pcap_setfilter (3PCAP).
.LP
If a given network interface provides a standard link-layer header, with
a standard packet type, but provides some packet types with a different
socket-layer protocol type from the one in the link-layer header, that
packet type cannot be filtered with a filter specified with
-.B pcap_setfilter()
+.BR pcap_setfilter ()
but can be filtered by specifying the socket-layer protocol type using
-.BR pcap_set_protocol_linux() .
+.BR pcap_set_protocol_linux ().
.SH RETURN VALUE
-.B pcap_set_protocol_linux()
-returns 0 on success or
+.BR pcap_set_protocol_linux ()
+returns
+.B 0
+on success or
.B PCAP_ERROR_ACTIVATED
if called on a capture handle that has been activated.
.SH BACKWARD COMPATIBILITY
This function became available in libpcap release 1.9.0.
.SH SEE ALSO
-pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_create (3PCAP),
+.BR pcap_activate (3PCAP)
diff --git a/pcap_set_rfmon.3pcap b/pcap_set_rfmon.3pcap
index 691518a5..2b104c25 100644
--- a/pcap_set_rfmon.3pcap
+++ b/pcap_set_rfmon.3pcap
@@ -31,17 +31,21 @@ int pcap_set_rfmon(pcap_t *p, int rfmon);
.ft
.fi
.SH DESCRIPTION
-.B pcap_set_rfmon()
+.BR pcap_set_rfmon ()
sets whether monitor mode should be set on a capture handle when
the handle is activated.
If
.I rfmon
is non-zero, monitor mode will be set, otherwise it will not be set.
.SH RETURN VALUE
-.B pcap_set_rfmon()
-returns 0 on success or
+.BR pcap_set_rfmon ()
+returns
+.B 0
+on success or
.B PCAP_ERROR_ACTIVATED
if called on a capture handle that has been activated.
.SH SEE ALSO
-pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP),
-pcap_can_set_rfmon(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_create (3PCAP),
+.BR pcap_activate (3PCAP),
+.BR pcap_can_set_rfmon (3PCAP)
diff --git a/pcap_set_snaplen.3pcap b/pcap_set_snaplen.3pcap
index 44eb1548..e3acff15 100644
--- a/pcap_set_snaplen.3pcap
+++ b/pcap_set_snaplen.3pcap
@@ -31,14 +31,18 @@ int pcap_set_snaplen(pcap_t *p, int snaplen);
.ft
.fi
.SH DESCRIPTION
-.B pcap_set_snaplen()
+.BR pcap_set_snaplen ()
sets the snapshot length to be used on a capture handle when the handle
is activated to
.IR snaplen .
.SH RETURN VALUE
-.B pcap_set_snaplen()
-returns 0 on success or
+.BR pcap_set_snaplen ()
+returns
+.B 0
+on success or
.B PCAP_ERROR_ACTIVATED
if called on a capture handle that has been activated.
.SH SEE ALSO
-pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_create (3PCAP),
+.BR pcap_activate (3PCAP)
diff --git a/pcap_set_timeout.3pcap b/pcap_set_timeout.3pcap
index e67b8132..d909b2c4 100644
--- a/pcap_set_timeout.3pcap
+++ b/pcap_set_timeout.3pcap
@@ -31,7 +31,7 @@ int pcap_set_timeout(pcap_t *p, int to_ms);
.ft
.fi
.SH DESCRIPTION
-.B pcap_set_timeout()
+.BR pcap_set_timeout ()
sets the packet buffer timeout that will be used on a capture handle
when the handle is activated to
.IR to_ms ,
@@ -44,10 +44,13 @@ behavior if the timeout is set to zero or to a negative value. We
recommend always setting the timeout to a non-zero value unless
immediate mode is set, in which case the timeout has no effect.
.SH RETURN VALUE
-.B pcap_set_timeout()
-returns 0 on success or
+.BR pcap_set_timeout ()
+returns
+.B 0
+on success or
.B PCAP_ERROR_ACTIVATED
if called on a capture handle that has been activated.
.SH SEE ALSO
-pcap_create(3PCAP), pcap_activate(3PCAP),
-\%pcap_set_immediate_mode(3PCAP)
+.BR pcap_create (3PCAP),
+.BR pcap_activate (3PCAP),
+.BR \%pcap_set_immediate_mode (3PCAP)
diff --git a/pcap_set_tstamp_precision.3pcap.in b/pcap_set_tstamp_precision.3pcap.in
index dc2b4b3d..eb449d5d 100644
--- a/pcap_set_tstamp_precision.3pcap.in
+++ b/pcap_set_tstamp_precision.3pcap.in
@@ -19,7 +19,7 @@
.\"IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
.\"WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-.TH PCAP_SET_TSTAMP_PRECISION 3PCAP "5 February 2015"
+.TH PCAP_SET_TSTAMP_PRECISION 3PCAP "23 August 2018"
.SH NAME
pcap_set_tstamp_precision \- set the time stamp precision returned in
captures
@@ -34,22 +34,24 @@ int pcap_set_tstamp_precision(pcap_t *p, int tstamp_precision);
.ft
.fi
.SH DESCRIPTION
-.B pcap_set_tstamp_precision()
+.BR pcap_set_tstamp_precision ()
sets the precision of the time stamp desired for packets captured on the pcap
descriptor to the type specified by
.IR tstamp_precision .
It must be called on a pcap descriptor created by
-.B pcap_create(3PCAP)
+.BR pcap_create (3PCAP)
that has not yet been activated by
-.BR pcap_activate(3PCAP) .
+.BR pcap_activate (3PCAP).
Two time stamp precisions are supported, microseconds and nanoseconds. One can
use options
.B PCAP_TSTAMP_PRECISION_MICRO and
.B PCAP_TSTAMP_PRECISION_NANO
to request desired precision. By default, time stamps are in microseconds.
.SH RETURN VALUE
-.B pcap_set_tstamp_precision()
-returns 0 on success if the specified time stamp precision is expected to be
+.BR pcap_set_tstamp_precision ()
+returns
+.B 0
+on success if the specified time stamp precision is expected to be
supported by the capture device,
.B PCAP_ERROR_TSTAMP_PRECISION_NOTSUP
if the capture device does not support the requested time stamp
@@ -61,6 +63,6 @@ This function became available in libpcap release 1.5.1. In previous
releases, time stamps from a capture device or savefile are always given
in seconds and microseconds.
.SH SEE ALSO
-pcap(3PCAP),
-pcap_get_tstamp_precision(3PCAP),
-pcap-tstamp(@MAN_MISC_INFO@)
+.BR pcap (3PCAP),
+.BR pcap_get_tstamp_precision (3PCAP),
+.BR pcap-tstamp (@MAN_MISC_INFO@)
diff --git a/pcap_set_tstamp_type.3pcap.in b/pcap_set_tstamp_type.3pcap.in
index 9833f46a..e19d6e5f 100644
--- a/pcap_set_tstamp_type.3pcap.in
+++ b/pcap_set_tstamp_type.3pcap.in
@@ -18,7 +18,7 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.TH PCAP_SET_TSTAMP_TYPE 3PCAP "22 August 2018"
+.TH PCAP_SET_TSTAMP_TYPE 3PCAP "8 September 2019"
.SH NAME
pcap_set_tstamp_type \- set the time stamp type to be used by a
capture device
@@ -33,23 +33,25 @@ int pcap_set_tstamp_type(pcap_t *p, int tstamp_type);
.ft
.fi
.SH DESCRIPTION
-.B pcap_set_tstamp_type()
+.BR pcap_set_tstamp_type ()
sets the type of time stamp desired for packets captured on the pcap
descriptor to the type specified by
.IR tstamp_type .
It must be called on a pcap descriptor created by
-.B pcap_create(3PCAP)
+.BR pcap_create (3PCAP)
that has not yet been activated by
-.BR pcap_activate(3PCAP) .
-.B pcap_list_tstamp_types(3PCAP)
+.BR pcap_activate (3PCAP).
+.BR pcap_list_tstamp_types (3PCAP)
will give a list of the time stamp types supported by a given capture
device.
See
.BR pcap-tstamp (@MAN_MISC_INFO@)
for a list of all the time stamp types.
.SH RETURN VALUE
-.B pcap_set_tstamp_type()
-returns 0 on success if the specified time stamp type is expected to be
+.BR pcap_set_tstamp_type ()
+returns
+.B 0
+on success if the specified time stamp type is expected to be
supported by the capture device,
.B PCAP_WARNING_TSTAMP_TYPE_NOTSUP
if the specified time stamp type is not supported by the
@@ -66,5 +68,5 @@ This function became available in libpcap release 1.2.1. In previous
releases, the time stamp type cannot be set; only the default time stamp
type offered by a capture source is available.
.SH SEE ALSO
-pcap(3PCAP),
-pcap_tstamp_type_name_to_val(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_tstamp_type_name_to_val (3PCAP)
diff --git a/pcap_setdirection.3pcap b/pcap_setdirection.3pcap
index f174b98f..7b388450 100644
--- a/pcap_setdirection.3pcap
+++ b/pcap_setdirection.3pcap
@@ -31,7 +31,7 @@ int pcap_setdirection(pcap_t *p, pcap_direction_t d);
.ft
.fi
.SH DESCRIPTION
-.B pcap_setdirection()
+.BR pcap_setdirection ()
is used to specify a direction that packets will be captured.
.I d
is one of the constants
@@ -48,7 +48,7 @@ will capture packets received by or sent by the device.
.B PCAP_D_INOUT
is the default setting if this function is not called.
.PP
-.B pcap_setdirection()
+.BR pcap_setdirection ()
isn't necessarily fully supported on all platforms; some platforms might
return an error for all values, and some other platforms might not
support
@@ -56,17 +56,19 @@ support
.PP
This operation is not supported if a ``savefile'' is being read.
.SH RETURN VALUE
-.B pcap_setdirection()
-returns 0 on success and
+.BR pcap_setdirection ()
+returns
+.B 0
+on success and
.B PCAP_ERROR
on failure. If
.B PCAP_ERROR
is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
may be called with
.I p
as an argument to fetch or display the error text.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_setfilter.3pcap b/pcap_setfilter.3pcap
index 87296939..1e3c5a59 100644
--- a/pcap_setfilter.3pcap
+++ b/pcap_setfilter.3pcap
@@ -31,25 +31,27 @@ int pcap_setfilter(pcap_t *p, struct bpf_program *fp);
.ft
.fi
.SH DESCRIPTION
-.B pcap_setfilter()
+.BR pcap_setfilter ()
is used to specify a filter program.
.I fp
is a pointer to a
.I bpf_program
struct, usually the result of a call to
-.BR \%pcap_compile(3PCAP) .
+.BR \%pcap_compile (3PCAP).
.SH RETURN VALUE
-.B pcap_setfilter()
-returns 0 on success and
+.BR pcap_setfilter ()
+returns
+.B 0
+on success and
.B PCAP_ERROR
on failure. If
.B PCAP_ERROR
is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
may be called with
.I p
as an argument to fetch or display the error text.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_setnonblock.3pcap b/pcap_setnonblock.3pcap
index e8adebea..65cfea28 100644
--- a/pcap_setnonblock.3pcap
+++ b/pcap_setnonblock.3pcap
@@ -38,7 +38,7 @@ int pcap_getnonblock(pcap_t *p, char *errbuf);
.ft
.fi
.SH DESCRIPTION
-.B pcap_setnonblock()
+.BR pcap_setnonblock ()
puts a capture handle into ``non-blocking'' mode, or takes it out
of ``non-blocking'' mode, depending on whether the
.I nonblock
@@ -47,30 +47,46 @@ If there is an error,
.B PCAP_ERROR
is returned and
.I errbuf
-is filled in with an appropriate error message; otherwise, 0 is
-returned.
+is filled in with an appropriate error message; otherwise,
+.B 0
+is returned.
+.PP
In
``non-blocking'' mode, an attempt to read from the capture descriptor
with
-.B pcap_dispatch(3PCAP)
-will, if no packets are currently available to be read, return 0
-immediately rather than blocking waiting for packets to arrive.
-.B pcap_loop(3PCAP)
+.BR pcap_dispatch (3PCAP)
and
-.B pcap_next(3PCAP)
-will not work in ``non-blocking'' mode.
+.BR pcap_next_ex (3PCAP)
+will, if no packets are currently available to be read, return
+.B 0
+immediately rather than blocking waiting for packets to arrive.
+.PP
+.BR pcap_loop (3PCAP)
+will loop forever, consuming CPU time when no packets are currently
+available;
+.BR pacp_dispatch ()
+should be used instead.
+.BR pcap_next (3PCAP)
+will return
+.B NULL
+if there are no packets currently available to read;
+this is indistinguishable from an error, so
+.BR pcap_next_ex ()
+should be used instead.
.PP
When first activated with
-.B pcap_activate(3PCAP)
+.BR pcap_activate (3PCAP)
or opened with
-.B pcap_open_live(3PCAP) ,
+.BR pcap_open_live (3PCAP) ,
a capture handle is not in ``non-blocking mode''; a call to
-.B pcap_setnonblock()
+.BR pcap_setnonblock ()
is required in order to put it into ``non-blocking'' mode.
.SH RETURN VALUE
-.B pcap_getnonblock()
+.BR pcap_getnonblock ()
returns the current ``non-blocking'' state of the capture descriptor; it
-always returns 0 on ``savefiles''.
+always returns
+.B 0
+on ``savefiles''.
If there is an error,
.B PCAP_ERROR
is returned and
@@ -82,4 +98,6 @@ is assumed to be able to hold at least
.B PCAP_ERRBUF_SIZE
chars.
.SH SEE ALSO
-pcap(3PCAP), pcap_next_ex(3PCAP), pcap_geterr(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_next_ex (3PCAP),
+.BR pcap_geterr (3PCAP)
diff --git a/pcap_snapshot.3pcap b/pcap_snapshot.3pcap
index ee54bb08..25f6e036 100644
--- a/pcap_snapshot.3pcap
+++ b/pcap_snapshot.3pcap
@@ -31,22 +31,22 @@ int pcap_snapshot(pcap_t *p);
.ft
.fi
.SH DESCRIPTION
-.B pcap_snapshot()
+.BR pcap_snapshot ()
returns the snapshot length specified when
-.B pcap_set_snaplen(3PCAP)
+.BR pcap_set_snaplen (3PCAP)
or
-.B pcap_open_live(3PCAP)
+.BR pcap_open_live (3PCAP)
was called, for a live capture, or the snapshot length from the capture
file, for a ``savefile''.
.PP
It must not be called on a pcap descriptor created by
-.B \%pcap_create(3PCAP)
+.BR \%pcap_create (3PCAP)
that has not yet been activated by
-.BR \%pcap_activate(3PCAP) .
+.BR \%pcap_activate (3PCAP).
.SH RETURN VALUE
-.B pcap_snapshot()
+.BR pcap_snapshot ()
returns the snapshot length on success and
.B PCAP_ERROR_NOT_ACTIVATED
if called on a capture handle that has been created but not activated.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_stats.3pcap b/pcap_stats.3pcap
index 465dada4..aa03013c 100644
--- a/pcap_stats.3pcap
+++ b/pcap_stats.3pcap
@@ -31,13 +31,13 @@ int pcap_stats(pcap_t *p, struct pcap_stat *ps);
.ft
.fi
.SH DESCRIPTION
-.B pcap_stats()
+.BR pcap_stats ()
fills in the
.B struct pcap_stat
pointed to by its second argument. The values represent
packet statistics from the start of the run to the time of the call.
.PP
-.B pcap_stats()
+.BR pcap_stats ()
is supported only on live captures, not on ``savefiles''; no statistics
are stored in ``savefiles'', so no statistics are available when reading
from a ``savefile''.
@@ -82,19 +82,21 @@ no packets were dropped by the interface, or it might mean that the
statistic is unavailable, so it should not be treated as an indication
that the interface did not drop any packets.
.SH RETURN VALUE
-.B pcap_stats()
-returns 0 on success and returns
+.BR pcap_stats ()
+returns
+.B 0
+on success and returns
.B PCAP_ERROR
if there is an error or if
.I p
doesn't support packet statistics. If
.B PCAP_ERROR
is returned,
-.B pcap_geterr(3PCAP)
+.BR pcap_geterr (3PCAP)
or
-.B pcap_perror(3PCAP)
+.BR pcap_perror (3PCAP)
may be called with
.I p
as an argument to fetch or display the error text.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_statustostr.3pcap b/pcap_statustostr.3pcap
index 9c2057ae..c679e362 100644
--- a/pcap_statustostr.3pcap
+++ b/pcap_statustostr.3pcap
@@ -31,11 +31,11 @@ const char *pcap_statustostr(int error);
.ft
.fi
.SH DESCRIPTION
-.B pcap_statustostr()
+.BR pcap_statustostr ()
converts a
.B PCAP_ERROR_
or
.B PCAP_WARNING_
value returned by a libpcap routine to an error string.
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_strerror.3pcap b/pcap_strerror.3pcap
index a5775f42..dedfa406 100644
--- a/pcap_strerror.3pcap
+++ b/pcap_strerror.3pcap
@@ -31,10 +31,10 @@ const char *pcap_strerror(int error);
.ft
.fi
.SH DESCRIPTION
-.B pcap_strerror()
+.BR pcap_strerror ()
is provided in case
.BR strerror (3)
isn't available. It returns an error message string corresponding to
.IR error .
.SH SEE ALSO
-pcap(3PCAP)
+.BR pcap (3PCAP)
diff --git a/pcap_tstamp_type_name_to_val.3pcap b/pcap_tstamp_type_name_to_val.3pcap
index fdcc6c6d..f60516e7 100644
--- a/pcap_tstamp_type_name_to_val.3pcap
+++ b/pcap_tstamp_type_name_to_val.3pcap
@@ -33,11 +33,11 @@ int pcap_tstamp_type_name_to_val(const char *name);
.ft
.fi
.SH DESCRIPTION
-.B pcap_tstamp_type_name_to_val()
+.BR pcap_tstamp_type_name_to_val ()
translates a time stamp type name to the corresponding time stamp type
value. The translation is case-insensitive.
.SH RETURN VALUE
-.B pcap_tstamp_type_name_to_val()
+.BR pcap_tstamp_type_name_to_val ()
returns time stamp type value on success and
.B PCAP_ERROR
on failure.
@@ -45,4 +45,5 @@ on failure.
.PP
This function became available in libpcap release 1.2.1.
.SH SEE ALSO
-pcap(3PCAP), pcap_tstamp_type_val_to_name(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_tstamp_type_val_to_name (3PCAP)
diff --git a/pcap_tstamp_type_val_to_name.3pcap b/pcap_tstamp_type_val_to_name.3pcap
index 9374f489..5958e810 100644
--- a/pcap_tstamp_type_val_to_name.3pcap
+++ b/pcap_tstamp_type_val_to_name.3pcap
@@ -34,13 +34,13 @@ const char *pcap_tstamp_type_val_to_description(int tstamp_type);
.ft
.fi
.SH DESCRIPTION
-.B pcap_tstamp_type_val_to_name()
+.BR pcap_tstamp_type_val_to_name ()
translates a time stamp type value to the corresponding time stamp type
name.
.B NULL
is returned on failure.
.PP
-.B pcap_tstamp_type_val_to_description()
+.BR pcap_tstamp_type_val_to_description ()
translates a time stamp type value to a short description of that time
stamp type.
.B NULL
@@ -49,4 +49,5 @@ is returned on failure.
.PP
These functions became available in libpcap release 1.2.1.
.SH SEE ALSO
-pcap(3PCAP), pcap_tstamp_type_name_to_val(3PCAP)
+.BR pcap (3PCAP),
+.BR pcap_tstamp_type_name_to_val (3PCAP)
diff --git a/portability.h b/portability.h
index 543846e8..d606368d 100644
--- a/portability.h
+++ b/portability.h
@@ -52,7 +52,7 @@ extern "C" {
#if defined(_MSC_VER) || defined(__MINGW32__)
/*
* strncat_s() is supported at least back to Visual
- * Studio 2005.
+ * Studio 2005; we require Visual Studio 2015 or later.
*/
#define pcap_strlcat(x, y, z) \
strncat_s((x), (z), (y), _TRUNCATE)
@@ -70,7 +70,7 @@ extern "C" {
#if defined(_MSC_VER) || defined(__MINGW32__)
/*
* strncpy_s() is supported at least back to Visual
- * Studio 2005.
+ * Studio 2005; we require Visual Studio 2015 or later.
*/
#define pcap_strlcpy(x, y, z) \
strncpy_s((x), (z), (y), _TRUNCATE)
@@ -83,8 +83,6 @@ extern "C" {
#endif
#ifdef _MSC_VER
- #define isascii __isascii
-
/*
* If <crtdbg.h> has been included, and _DEBUG is defined, and
* __STDC__ is zero, <crtdbg.h> will define strdup() to call
@@ -97,43 +95,9 @@ extern "C" {
#endif
/*
- * On Windows, snprintf(), with that name and with C99 behavior - i.e.,
- * guaranteeing that the formatted string is null-terminated - didn't
- * appear until Visual Studio 2015. Prior to that, the C runtime had
- * only _snprintf(), which *doesn't* guarantee that the string is
- * null-terminated if it is truncated due to the buffer being too
- * small. We therefore can't just define snprintf to be _snprintf
- * and define vsnprintf to be _vsnprintf, as we're relying on null-
- * termination of strings in all cases.
- *
- * We also want to allow this to be built with versions of Visual Studio
- * prior to VS 2015, so we can't rely on snprintf() being present.
- *
- * And we want to make sure that, if we support plugins in the future,
- * a routine with C99 snprintf() behavior will be available to them.
- * We also don't want it to collide with the C library snprintf() if
- * there is one.
- *
- * So we make pcap_snprintf() and pcap_vsnprintf() available, either by
- * #defining them to be snprintf or vsnprintf, respectively, or by
- * defining our own versions and exporting them.
- */
-#ifdef HAVE_SNPRINTF
-#define pcap_snprintf snprintf
-#else
-extern int pcap_snprintf(char *, size_t, PCAP_FORMAT_STRING(const char *), ...)
- PCAP_PRINTFLIKE(3, 4);
-#endif
-
-#ifdef HAVE_VSNPRINTF
-#define pcap_vsnprintf vsnprintf
-#else
-extern int pcap_vsnprintf(char *, size_t, const char *, va_list ap);
-#endif
-
-/*
- * We also want asprintf(), for some cases where we use it to construct
- * dynamically-allocated variable-length strings.
+ * We want asprintf(), for some cases where we use it to construct
+ * dynamically-allocated variable-length strings; it's present on
+ * some, but not all, platforms.
*/
#ifdef HAVE_ASPRINTF
#define pcap_asprintf asprintf
diff --git a/rpcap-protocol.c b/rpcap-protocol.c
index 692f7c5c..0cdc0ba3 100644
--- a/rpcap-protocol.c
+++ b/rpcap-protocol.c
@@ -61,6 +61,8 @@
*
* \param sock: the socket we are currently using.
*
+ * \param ssl: if compiled with openssl, the optional ssl handler to use with the above socket.
+ *
* \param ver: the protocol version we want to put in the reply.
*
* \param errcode: a integer which tells the other party the type of error
@@ -78,7 +80,7 @@
* error message is returned in the 'errbuf' variable.
*/
int
-rpcap_senderror(SOCKET sock, uint8 ver, unsigned short errcode, const char *error, char *errbuf)
+rpcap_senderror(SOCKET sock, SSL *ssl, uint8 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 */
@@ -99,7 +101,7 @@ rpcap_senderror(SOCKET sock, uint8 ver, unsigned short errcode, const char *erro
RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE))
return -1;
- if (sock_send(sock, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) < 0)
+ if (sock_send(sock, ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) < 0)
return -1;
return 0;
diff --git a/rpcap-protocol.h b/rpcap-protocol.h
index 8ae8b62d..a69cf802 100644
--- a/rpcap-protocol.h
+++ b/rpcap-protocol.h
@@ -259,7 +259,7 @@ struct rpcap_findalldevs_ifaddr
struct rpcap_openreply
{
int32 linktype; /* Link type */
- int32 tzoff; /* Timezone offset */
+ int32 tzoff; /* Timezone offset - not used by newer clients */
};
/* Format of the message that starts a remote capture (startcap command) */
@@ -287,10 +287,14 @@ struct rpcap_startcapreply
*/
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 this packet (off wire) */
+ 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) */
};
@@ -302,7 +306,7 @@ struct rpcap_filter
uint32 nitems; /* Number of items contained into the filter (e.g. BPF instructions for BPF filters) */
};
-/* Structure that keeps a single BPF instuction; it is repeated 'ninsn' times according to the 'rpcap_filterbpf' header */
+/* 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 */
@@ -346,17 +350,17 @@ struct rpcap_sampling
*/
#define RPCAP_MSG_IS_REPLY 0x080 /* Flag indicating a reply */
-#define RPCAP_MSG_ERROR 1 /* Message that keeps an error notification */
-#define RPCAP_MSG_FINDALLIF_REQ 2 /* Request to list all the remote interfaces */
-#define RPCAP_MSG_OPEN_REQ 3 /* Request to open a remote device */
-#define RPCAP_MSG_STARTCAP_REQ 4 /* Request to start a capture on a remote device */
-#define RPCAP_MSG_UPDATEFILTER_REQ 5 /* Send a compiled filter into the remote device */
-#define RPCAP_MSG_CLOSE 6 /* Close the connection with the remote peer */
-#define RPCAP_MSG_PACKET 7 /* This is a 'data' message, which carries a network packet */
-#define RPCAP_MSG_AUTH_REQ 8 /* Message that keeps the authentication parameters */
-#define RPCAP_MSG_STATS_REQ 9 /* It requires to have network statistics */
-#define RPCAP_MSG_ENDCAP_REQ 10 /* Stops the current capture, keeping the device open */
-#define RPCAP_MSG_SETSAMPLING_REQ 11 /* Set sampling parameters */
+#define RPCAP_MSG_ERROR 0x01 /* Message that keeps an error notification */
+#define RPCAP_MSG_FINDALLIF_REQ 0x02 /* Request to list all the remote interfaces */
+#define RPCAP_MSG_OPEN_REQ 0x03 /* Request to open a remote device */
+#define RPCAP_MSG_STARTCAP_REQ 0x04 /* Request to start a capture on a remote device */
+#define RPCAP_MSG_UPDATEFILTER_REQ 0x05 /* Send a compiled filter into the remote device */
+#define RPCAP_MSG_CLOSE 0x06 /* Close the connection with the remote peer */
+#define RPCAP_MSG_PACKET 0x07 /* This is a 'data' message, which carries a network packet */
+#define RPCAP_MSG_AUTH_REQ 0x08 /* Message that keeps the authentication parameters */
+#define RPCAP_MSG_STATS_REQ 0x09 /* It requires to have network statistics */
+#define RPCAP_MSG_ENDCAP_REQ 0x0A /* Stops the current capture, keeping the device open */
+#define RPCAP_MSG_SETSAMPLING_REQ 0x0B /* Set sampling parameters */
#define RPCAP_MSG_FINDALLIF_REPLY (RPCAP_MSG_FINDALLIF_REQ | RPCAP_MSG_IS_REPLY) /* Keeps the list of all the remote interfaces */
#define RPCAP_MSG_OPEN_REPLY (RPCAP_MSG_OPEN_REQ | RPCAP_MSG_IS_REPLY) /* The remote device has been opened correctly */
@@ -415,9 +419,10 @@ 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, uint8 ver, uint16 errcode, const char *error, char *errbuf);
+extern int rpcap_senderror(SOCKET sock, SSL *ssl, uint8 ver, uint16 errcode, const char *error, char *errbuf);
#endif
diff --git a/rpcapd/CMakeLists.txt b/rpcapd/CMakeLists.txt
index 1821c856..f2bd12dc 100644
--- a/rpcapd/CMakeLists.txt
+++ b/rpcapd/CMakeLists.txt
@@ -50,8 +50,8 @@ if(WIN32 OR ((CMAKE_USE_PTHREADS_INIT OR PTHREADS_FOUND) AND HAVE_CRYPT))
if(WIN32)
set(RPCAPD_EXTRA_SOURCES
win32-svc.c
+ ${pcap_SOURCE_DIR}/charconv.c
${pcap_SOURCE_DIR}/missing/getopt.c
- ${pcap_SOURCE_DIR}/missing/win_snprintf.c
rpcapd.rc)
include_directories(${pcap_SOURCE_DIR}/rpcapd ${pcap_SOURCE_DIR}/missing)
endif(WIN32)
@@ -63,6 +63,7 @@ if(WIN32 OR ((CMAKE_USE_PTHREADS_INIT OR PTHREADS_FOUND) AND HAVE_CRYPT))
rpcapd.c
${pcap_SOURCE_DIR}/rpcap-protocol.c
${pcap_SOURCE_DIR}/sockutils.c
+ ${pcap_SOURCE_DIR}/sslutils.c
${pcap_SOURCE_DIR}/fmtutils.c
${RPCAPD_EXTRA_SOURCES}
)
@@ -71,6 +72,11 @@ if(WIN32 OR ((CMAKE_USE_PTHREADS_INIT OR PTHREADS_FOUND) AND HAVE_CRYPT))
set_target_properties(rpcapd PROPERTIES COMPILE_FLAGS ${C_ADDITIONAL_FLAGS})
endif()
+ if(NOT "${SANITIZER_FLAGS}" STREQUAL "")
+ set_target_properties(rpcapd PROPERTIES
+ LINK_FLAGS "${SANITIZER_FLAGS}")
+ endif()
+
#
# By default, build rpcapd universal with the appropriate set of
# architectures for the OS on which we're doing the build.
@@ -129,11 +135,15 @@ if(WIN32 OR ((CMAKE_USE_PTHREADS_INIT OR PTHREADS_FOUND) AND HAVE_CRYPT))
set(MANFILE_EXPAND rpcapd-config.manfile.in)
- if(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
- install(TARGETS rpcapd DESTINATION bin/amd64)
- else(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
- install(TARGETS rpcapd DESTINATION bin)
- endif(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
+ if(NOT MSVC)
+ install(TARGETS rpcapd DESTINATION sbin)
+ else(NOT MSVC)
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ install(TARGETS rpcapd DESTINATION bin/amd64)
+ else(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ install(TARGETS rpcapd DESTINATION bin)
+ endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ endif(NOT MSVC)
# On UN*X, and on Windows when not using MSVC, generate process man
# pages and arrange that they be installed.
diff --git a/rpcapd/Makefile.in b/rpcapd/Makefile.in
index 88e632a2..32906790 100644
--- a/rpcapd/Makefile.in
+++ b/rpcapd/Makefile.in
@@ -38,6 +38,7 @@ mandir = @mandir@
# VPATH
srcdir = @srcdir@
+top_srcdir = @top_srcdir@
VPATH = @srcdir@
#
@@ -84,7 +85,7 @@ SRC = daemon.c \
log.c \
rpcapd.c
-OBJ = $(SRC:.c=.o) ../rpcap-protocol.o ../sockutils.o ../fmtutils.o
+OBJ = $(SRC:.c=.o) ../rpcap-protocol.o ../sockutils.o ../fmtutils.o ../sslutils.o
PUBHDR =
HDR = $(PUBHDR) log.h
@@ -138,4 +139,4 @@ tags: $(TAGFILES)
ctags -wtd $(TAGFILES)
depend:
- ../$(MKDEP) -c "$(CC)" -m "$(DEPENDENCY_CFLAG)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC)
+ $(MKDEP) -c "$(CC)" -m "$(DEPENDENCY_CFLAG)" -s "$(srcdir)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC)
diff --git a/rpcapd/daemon.c b/rpcapd/daemon.c
index 209dba22..620dec31 100644
--- a/rpcapd/daemon.c
+++ b/rpcapd/daemon.c
@@ -39,6 +39,7 @@
#include <errno.h> // for the errno variable
#include <stdlib.h> // for malloc(), free(), ...
#include <string.h> // for strlen(), ...
+#include <limits.h> // for INT_MAX
#ifdef _WIN32
#include <process.h> // for threads
@@ -64,6 +65,11 @@
#include "daemon.h"
#include "log.h"
+#ifdef HAVE_OPENSSL
+#include <openssl/ssl.h>
+#include "sslutils.h"
+#endif
+
//
// Timeout, in seconds, when we're waiting for a client to send us an
// authentication request; if they don't send us a request within that
@@ -90,6 +96,7 @@
struct daemon_slpars
{
SOCKET sockctrl; //!< SOCKET ID of the control connection
+ SSL *ssl; //!< Optional SSL handler for the controlling sockets
int isactive; //!< Not null if the daemon has to run in active mode
int nullAuthAllowed; //!< '1' if we permit NULL authentication, '0' otherwise
};
@@ -105,6 +112,7 @@ struct daemon_slpars
struct session {
SOCKET sockctrl;
SOCKET sockdata;
+ SSL *ctrl_ssl, *data_ssl; // optional SSL handlers for sockctrl and sockdata.
uint8 protocol_version;
pcap_t *fp;
unsigned int TotCapt;
@@ -117,7 +125,7 @@ struct session {
};
// Locally defined functions
-static int daemon_msg_err(SOCKET sockctrl, uint32 plen);
+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_AuthUserPwd(char *username, char *password, char *errbuf);
@@ -128,13 +136,13 @@ static int daemon_msg_open_req(uint8 ver, struct daemon_slpars *pars,
uint32 plen, char *source, size_t sourcelen);
static int daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars,
uint32 plen, char *source, struct session **sessionp,
- struct rpcap_sampling *samp_param);
+ struct rpcap_sampling *samp_param, int uses_ssl);
static int daemon_msg_endcap_req(uint8 ver, struct daemon_slpars *pars,
struct session *session);
static int daemon_msg_updatefilter_req(uint8 ver, struct daemon_slpars *pars,
struct session *session, uint32 plen);
-static int daemon_unpackapplyfilter(SOCKET sockctrl, struct session *session, uint32 *plenp, char *errbuf);
+static int daemon_unpackapplyfilter(SOCKET sockctrl, SSL *, struct session *session, uint32 *plenp, char *errbuf);
static int daemon_msg_stats_req(uint8 ver, struct daemon_slpars *pars,
struct session *session, uint32 plen, struct pcap_stat *stats,
@@ -151,21 +159,69 @@ static void *daemon_thrdatamain(void *ptr);
static void noop_handler(int sign);
#endif
-static int rpcapd_recv_msg_header(SOCKET sock, struct rpcap_header *headerp);
-static int rpcapd_recv(SOCKET sock, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf);
-static int rpcapd_discard(SOCKET sock, uint32 len);
+static 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 void session_close(struct session *);
+//
+// TLS record layer header; used when processing the first message from
+// 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
+ // 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
+};
+
+#define TLS_RECORD_HEADER_LEN 5 // Don't use sizeof in case it's padded
+
+#define TLS_RECORD_TYPE_ALERT 21
+#define TLS_RECORD_TYPE_HANDSHAKE 22
+
+//
+// TLS alert message.
+//
+struct tls_alert {
+ uint8 alert_level;
+ uint8 alert_description;
+};
+
+#define TLS_ALERT_LEN 2
+
+#define TLS_ALERT_LEVEL_FATAL 2
+#define TLS_ALERT_HANDSHAKE_FAILURE 40
+
static int is_url(const char *source);
+/*
+ * Maximum sizes for fixed-bit-width values.
+ */
+#ifndef UINT16_MAX
+#define UINT16_MAX 65535U
+#endif
+
+#ifndef UINT32_MAX
+#define UINT32_MAX 4294967295U
+#endif
+
int
daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
- int nullAuthAllowed)
+ int nullAuthAllowed, int uses_ssl)
{
+ uint8 first_octet;
+ struct tls_record_header tls_header;
+ struct tls_alert tls_alert;
struct daemon_slpars pars; // service loop parameters
char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
char errmsgbuf[PCAP_ERRBUF_SIZE + 1]; // buffer for errors to send to the client
int host_port_check_status;
+ SSL *ssl = NULL;
int nrecv;
struct rpcap_header header; // RPCAP message general header
uint32 plen; // payload length from header
@@ -192,8 +248,177 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
*errbuf = 0; // Initialize errbuf
+ //
+ // Peek into the socket to determine whether the client sent us
+ // a TLS handshake message or a non-TLS rpcapd message.
+ //
+ // The first byte of an rpcapd request is the version number;
+ // the first byte of a TLS handshake message is 22. The
+ // first request to an rpcapd server must be an authentication
+ // request or a close request, and must have a version number
+ // of 0, so it will be possible to distinguish between an
+ // initial plaintext request to a server and an initial TLS
+ // handshake message.
+ //
+ nrecv = sock_recv(sockctrl, NULL, (char *)&first_octet, 1,
+ SOCK_EOF_ISNT_ERROR|SOCK_MSG_PEEK, errbuf, PCAP_ERRBUF_SIZE);
+ if (nrecv == -1)
+ {
+ // Fatal error.
+ rpcapd_log(LOGPRIO_ERROR, "Peek from client failed: %s", errbuf);
+ goto end;
+ }
+ if (nrecv == 0)
+ {
+ // Client closed the connection.
+ goto end;
+ }
+
+#ifdef HAVE_OPENSSL
+ //
+ // We have to upgrade to TLS as soon as possible, so that the
+ // whole protocol goes through the encrypted tunnel, including
+ // early error messages.
+ //
+ // Even in active mode, the other end has to initiate the TLS
+ // handshake as we still are the server as far as TLS is concerned,
+ // so we don't check isactive.
+ //
+ if (uses_ssl)
+ {
+ //
+ // We're expecting a TLS handshake message. If this
+ // isn't one, assume it's a non-TLS rpcapd message.
+ //
+ // The first octet of a TLS handshake is
+ // TLS_RECORD_TYPE_HANDSHAKE.
+ //
+ if (first_octet != TLS_RECORD_TYPE_HANDSHAKE)
+ {
+ //
+ // We assume this is a non-TLS rpcapd message.
+ //
+ // Read the message header from the client.
+ //
+ nrecv = rpcapd_recv_msg_header(sockctrl, NULL, &header);
+ if (nrecv == -1)
+ {
+ // Fatal error.
+ goto end;
+ }
+ if (nrecv == -2)
+ {
+ // Client closed the connection.
+ goto end;
+ }
+ plen = header.plen;
+
+ // Discard the rest of the message.
+ if (rpcapd_discard(sockctrl, NULL, plen) == -1)
+ {
+ // Network error.
+ goto end;
+ }
+
+ //
+ // Send an authentication error, indicating
+ // that we require TLS.
+ //
+ if (rpcap_senderror(sockctrl, NULL, header.ver,
+ PCAP_ERR_TLS_REQUIRED,
+ "TLS is required by this server", errbuf) == -1)
+ {
+ // That failed; log a message and give up.
+ rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
+ goto end;
+ }
+
+ // Shut the session down.
+ goto end;
+ }
+ ssl = ssl_promotion(1, sockctrl, errbuf, PCAP_ERRBUF_SIZE);
+ if (! ssl)
+ {
+ rpcapd_log(LOGPRIO_ERROR, "TLS handshake on control connection failed: %s",
+ errbuf);
+ goto end;
+ }
+ }
+ else
+#endif
+ {
+ //
+ // We're expecting a non-TLS rpcapd message. If this
+ // looks, instead, like a TLS handshake message, send
+ // a TLS handshake_failed alert.
+ //
+ // The first octet of a TLS handshake is
+ // TLS_RECORD_TYPE_HANDSHAKE.
+ //
+ if (first_octet == TLS_RECORD_TYPE_HANDSHAKE)
+ {
+ //
+ // TLS handshake.
+ // Read the record header.
+ //
+ nrecv = sock_recv(sockctrl, ssl, (char *) &tls_header,
+ sizeof tls_header, SOCK_RECEIVEALL_YES|SOCK_EOF_ISNT_ERROR,
+ errbuf, PCAP_ERRBUF_SIZE);
+ if (nrecv == -1)
+ {
+ // Network error.
+ rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf);
+ goto end;
+ }
+ if (nrecv == 0)
+ {
+ // Immediate EOF
+ goto end;
+ }
+ plen = (tls_header.length_hi << 8) | tls_header.length_lo;
+
+ // Discard the rest of the message.
+ if (rpcapd_discard(sockctrl, NULL, plen) == -1)
+ {
+ // Network error.
+ goto end;
+ }
+
+ //
+ // Send a TLS handshake failure alert.
+ // Use the same version the client sent us.
+ //
+ tls_header.type = TLS_RECORD_TYPE_ALERT;
+ tls_header.length_hi = 0;
+ tls_header.length_lo = TLS_ALERT_LEN;
+
+ if (sock_send(sockctrl, NULL, (char *) &tls_header,
+ TLS_RECORD_HEADER_LEN, errbuf, PCAP_ERRBUF_SIZE) == -1)
+ {
+ // That failed; log a message and give up.
+ rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
+ goto end;
+ }
+
+ tls_alert.alert_level = TLS_ALERT_LEVEL_FATAL;
+ tls_alert.alert_description = TLS_ALERT_HANDSHAKE_FAILURE;
+ if (sock_send(sockctrl, NULL, (char *) &tls_alert,
+ TLS_ALERT_LEN, errbuf, PCAP_ERRBUF_SIZE) == -1)
+ {
+ // That failed; log a message and give up.
+ rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
+ goto end;
+ }
+ //
+ // Give up anyway.
+ //
+ goto end;
+ }
+ }
+
// Set parameters structure
pars.sockctrl = sockctrl;
+ pars.ssl = ssl;
pars.isactive = isactive; // active mode
pars.nullAuthAllowed = nullAuthAllowed;
@@ -225,7 +450,7 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
&fromlen) == -1)
{
sock_geterror("getpeername()", errmsgbuf, PCAP_ERRBUF_SIZE);
- if (rpcap_senderror(pars.sockctrl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1)
+ 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;
}
@@ -248,7 +473,7 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
//
// Sorry, we can't let you in.
//
- if (rpcap_senderror(pars.sockctrl, 0, PCAP_ERR_HOSTNOAUTH, errmsgbuf, errbuf) == -1)
+ if (rpcap_senderror(pars.sockctrl, pars.ssl, 0, PCAP_ERR_HOSTNOAUTH, errmsgbuf, errbuf) == -1)
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
goto end;
}
@@ -295,11 +520,11 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
FD_SET(pars.sockctrl, &rfds);
- retval = select(pars.sockctrl + 1, &rfds, NULL, NULL, &tv);
+ retval = select((int)pars.sockctrl + 1, &rfds, NULL, NULL, &tv);
if (retval == -1)
{
sock_geterror("select() failed", errmsgbuf, PCAP_ERRBUF_SIZE);
- if (rpcap_senderror(pars.sockctrl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1)
+ 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;
}
@@ -308,7 +533,7 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
// So, this was a fake connection. Drop it down
if (retval == 0)
{
- if (rpcap_senderror(pars.sockctrl, 0, PCAP_ERR_INITTIMEOUT, "The RPCAP initial timeout has expired", errbuf) == -1)
+ if (rpcap_senderror(pars.sockctrl, pars.ssl, 0, PCAP_ERR_INITTIMEOUT, "The RPCAP initial timeout has expired", errbuf) == -1)
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
goto end;
}
@@ -317,7 +542,7 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
//
// Read the message header from the client.
//
- nrecv = rpcapd_recv_msg_header(pars.sockctrl, &header);
+ nrecv = rpcapd_recv_msg_header(pars.sockctrl, pars.ssl, &header);
if (nrecv == -1)
{
// Fatal error.
@@ -340,7 +565,7 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
//
// Send it back to them with their version.
//
- if (rpcap_senderror(pars.sockctrl, header.ver,
+ if (rpcap_senderror(pars.sockctrl, pars.ssl, header.ver,
PCAP_ERR_WRONGVER,
"RPCAP version in requests in the authentication phase must be 0",
errbuf) == -1)
@@ -352,7 +577,7 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
// Discard the rest of the message and drop the
// connection.
- (void)rpcapd_discard(pars.sockctrl, plen);
+ (void)rpcapd_discard(pars.sockctrl, pars.ssl, plen);
goto end;
}
@@ -385,7 +610,7 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
// Discard the rest of the message, if
// there is anything more.
//
- (void)rpcapd_discard(pars.sockctrl, plen);
+ (void)rpcapd_discard(pars.sockctrl, pars.ssl, plen);
// We're done with this client.
goto end;
@@ -397,7 +622,7 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
// an error message rather than a "let
// me log in" message, indicating that
// we're not allowed to connect to them?
- (void)daemon_msg_err(pars.sockctrl, plen);
+ (void)daemon_msg_err(pars.sockctrl, pars.ssl, plen);
goto end;
case RPCAP_MSG_FINDALLIF_REQ:
@@ -414,20 +639,21 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
msg_type_string = rpcap_msg_type_string(header.type);
if (msg_type_string != NULL)
{
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "%s request sent before authentication was completed", msg_type_string);
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "%s request sent before authentication was completed", msg_type_string);
}
else
{
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message of type %u sent before authentication was completed", header.type);
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message of type %u sent before authentication was completed", header.type);
}
- if (rpcap_senderror(pars.sockctrl, header.ver,
- PCAP_ERR_WRONGMSG, errmsgbuf, errbuf) == -1)
+ if (rpcap_senderror(pars.sockctrl, pars.ssl,
+ header.ver, PCAP_ERR_WRONGMSG,
+ errmsgbuf, errbuf) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
goto end;
}
// Discard the rest of the message.
- if (rpcapd_discard(pars.sockctrl, plen) == -1)
+ if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
{
// Network error.
goto end;
@@ -449,20 +675,21 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
msg_type_string = rpcap_msg_type_string(header.type);
if (msg_type_string != NULL)
{
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message %s received from client", msg_type_string);
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message %s received from client", msg_type_string);
}
else
{
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type);
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type);
}
- if (rpcap_senderror(pars.sockctrl, header.ver,
- PCAP_ERR_WRONGMSG, errmsgbuf, errbuf) == -1)
+ if (rpcap_senderror(pars.sockctrl, pars.ssl,
+ header.ver, PCAP_ERR_WRONGMSG,
+ errmsgbuf, errbuf) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
goto end;
}
// Discard the rest of the message.
- if (rpcapd_discard(pars.sockctrl, plen) == -1)
+ if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
{
// Fatal error.
goto end;
@@ -473,15 +700,16 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
//
// Unknown message type.
//
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type);
- if (rpcap_senderror(pars.sockctrl, header.ver,
- PCAP_ERR_WRONGMSG, errmsgbuf, errbuf) == -1)
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type);
+ if (rpcap_senderror(pars.sockctrl, pars.ssl,
+ header.ver, PCAP_ERR_WRONGMSG,
+ errmsgbuf, errbuf) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
goto end;
}
// Discard the rest of the message.
- if (rpcapd_discard(pars.sockctrl, plen) == -1)
+ if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
{
// Fatal error.
goto end;
@@ -519,7 +747,7 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
//
// Be carefully: the capture can have been started, but an error occurred (so session != NULL, but
// sockdata is 0
- if ((!pars.isactive) && ((session == NULL) || ((session != NULL) && (session->sockdata == 0))))
+ if ((!pars.isactive) && (session == NULL || session->sockdata == 0))
{
// Check for the initial timeout
FD_ZERO(&rfds);
@@ -528,13 +756,17 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
tv.tv_usec = 0;
FD_SET(pars.sockctrl, &rfds);
-
- retval = select(pars.sockctrl + 1, &rfds, NULL, NULL, &tv);
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ retval = 1;
+#else
+ retval = select((int)pars.sockctrl + 1, &rfds, NULL, NULL, &tv);
+#endif
if (retval == -1)
{
sock_geterror("select() failed", errmsgbuf, PCAP_ERRBUF_SIZE);
- if (rpcap_senderror(pars.sockctrl, 0,
- PCAP_ERR_NETW, errmsgbuf, errbuf) == -1)
+ 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;
}
@@ -543,8 +775,8 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
// So, this was a fake connection. Drop it down
if (retval == 0)
{
- if (rpcap_senderror(pars.sockctrl, 0,
- PCAP_ERR_INITTIMEOUT,
+ if (rpcap_senderror(pars.sockctrl, pars.ssl,
+ 0, PCAP_ERR_INITTIMEOUT,
"The RPCAP initial timeout has expired",
errbuf) == -1)
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -555,7 +787,7 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
//
// Read the message header from the client.
//
- nrecv = rpcapd_recv_msg_header(pars.sockctrl, &header);
+ nrecv = rpcapd_recv_msg_header(pars.sockctrl, pars.ssl, &header);
if (nrecv == -1)
{
// Fatal error.
@@ -581,7 +813,7 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
// so they don't reject it as having the wrong
// version.
//
- if (rpcap_senderror(pars.sockctrl,
+ if (rpcap_senderror(pars.sockctrl, pars.ssl,
header.ver, PCAP_ERR_WRONGVER,
"RPCAP version in message isn't supported by the server",
errbuf) == -1)
@@ -592,7 +824,7 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
}
// Discard the rest of the message.
- (void)rpcapd_discard(pars.sockctrl, plen);
+ (void)rpcapd_discard(pars.sockctrl, pars.ssl, plen);
// Give up on them.
goto end;
}
@@ -601,7 +833,7 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
{
case RPCAP_MSG_ERROR: // The other endpoint reported an error
{
- (void)daemon_msg_err(pars.sockctrl, plen);
+ (void)daemon_msg_err(pars.sockctrl, pars.ssl, plen);
// Do nothing; just exit; the error code is already into the errbuf
// XXX - actually exit....
break;
@@ -647,7 +879,7 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
{
// They never told us what device
// to capture on!
- if (rpcap_senderror(pars.sockctrl,
+ if (rpcap_senderror(pars.sockctrl, pars.ssl,
header.ver,
PCAP_ERR_STARTCAPTURE,
"No capture device was specified",
@@ -658,7 +890,7 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
goto end;
}
- if (rpcapd_discard(pars.sockctrl, plen) == -1)
+ if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
{
goto end;
}
@@ -666,7 +898,8 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
}
if (daemon_msg_startcap_req(header.ver, &pars,
- plen, source, &session, &samp_param) == -1)
+ plen, source, &session, &samp_param,
+ uses_ssl) == -1)
{
// Fatal error; a message has
// been logged, so just give up.
@@ -689,8 +922,9 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
}
else
{
- if (rpcap_senderror(pars.sockctrl,
- header.ver, PCAP_ERR_UPDATEFILTER,
+ if (rpcap_senderror(pars.sockctrl, pars.ssl,
+ header.ver,
+ PCAP_ERR_UPDATEFILTER,
"Device not opened. Cannot update filter",
errbuf) == -1)
{
@@ -757,8 +991,9 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
}
else
{
- rpcap_senderror(pars.sockctrl,
- header.ver, PCAP_ERR_ENDCAPTURE,
+ rpcap_senderror(pars.sockctrl, pars.ssl,
+ header.ver,
+ PCAP_ERR_ENDCAPTURE,
"Device not opened. Cannot close the capture",
errbuf);
}
@@ -784,7 +1019,8 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
// get to reauthenticate.
//
rpcapd_log(LOGPRIO_INFO, "The client sent an RPCAP_MSG_AUTH_REQ message after authentication was completed");
- if (rpcap_senderror(pars.sockctrl, header.ver,
+ if (rpcap_senderror(pars.sockctrl, pars.ssl,
+ header.ver,
PCAP_ERR_WRONGMSG,
"RPCAP_MSG_AUTH_REQ request sent after authentication was completed",
errbuf) == -1)
@@ -793,7 +1029,7 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
goto end;
}
// Discard the rest of the message.
- if (rpcapd_discard(pars.sockctrl, plen) == -1)
+ if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
{
// Fatal error.
goto end;
@@ -816,21 +1052,22 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
if (msg_type_string != NULL)
{
rpcapd_log(LOGPRIO_INFO, "The client sent a %s server-to-client message", msg_type_string);
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message %s received from client", msg_type_string);
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message %s received from client", msg_type_string);
}
else
{
rpcapd_log(LOGPRIO_INFO, "The client sent a server-to-client message of type %u", header.type);
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type);
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type);
}
- if (rpcap_senderror(pars.sockctrl, header.ver,
- PCAP_ERR_WRONGMSG, errmsgbuf, errbuf) == -1)
+ if (rpcap_senderror(pars.sockctrl, pars.ssl,
+ header.ver, PCAP_ERR_WRONGMSG,
+ errmsgbuf, errbuf) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
goto end;
}
// Discard the rest of the message.
- if (rpcapd_discard(pars.sockctrl, plen) == -1)
+ if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
{
// Fatal error.
goto end;
@@ -842,15 +1079,16 @@ daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
// Unknown message type.
//
rpcapd_log(LOGPRIO_INFO, "The client sent a message of type %u", header.type);
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type);
- if (rpcap_senderror(pars.sockctrl, header.ver,
- PCAP_ERR_WRONGMSG, errbuf, errmsgbuf) == -1)
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type);
+ if (rpcap_senderror(pars.sockctrl, pars.ssl,
+ header.ver, PCAP_ERR_WRONGMSG,
+ errbuf, errmsgbuf) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
goto end;
}
// Discard the rest of the message.
- if (rpcapd_discard(pars.sockctrl, plen) == -1)
+ if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
{
// Fatal error.
goto end;
@@ -870,6 +1108,21 @@ end:
session = NULL;
}
+ if (passiveClients) {
+ free(passiveClients);
+ }
+ //
+ // Finish using the SSL handle for the control socket, if we
+ // have an SSL connection, and close the control socket.
+ //
+#ifdef HAVE_OPENSSL
+ if (ssl)
+ {
+ // Finish using the SSL handle for the socket.
+ // This must be done *before* the socket is closed.
+ ssl_finish(ssl);
+ }
+#endif
sock_close(sockctrl, NULL, 0);
// Print message and return
@@ -882,7 +1135,7 @@ end:
* This handles the RPCAP_MSG_ERR message.
*/
static int
-daemon_msg_err(SOCKET sockctrl, uint32 plen)
+daemon_msg_err(SOCKET sockctrl, SSL *ssl, uint32 plen)
{
char errbuf[PCAP_ERRBUF_SIZE];
char remote_errbuf[PCAP_ERRBUF_SIZE];
@@ -893,7 +1146,7 @@ daemon_msg_err(SOCKET sockctrl, uint32 plen)
* Message is too long; just read as much of it as we
* can into the buffer provided, and discard the rest.
*/
- if (sock_recv(sockctrl, remote_errbuf, PCAP_ERRBUF_SIZE - 1,
+ if (sock_recv(sockctrl, ssl, remote_errbuf, PCAP_ERRBUF_SIZE - 1,
SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
PCAP_ERRBUF_SIZE) == -1)
{
@@ -901,7 +1154,7 @@ daemon_msg_err(SOCKET sockctrl, uint32 plen)
rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf);
return -1;
}
- if (rpcapd_discard(sockctrl, plen - (PCAP_ERRBUF_SIZE - 1)) == -1)
+ if (rpcapd_discard(sockctrl, ssl, plen - (PCAP_ERRBUF_SIZE - 1)) == -1)
{
// Network error.
return -1;
@@ -919,7 +1172,7 @@ daemon_msg_err(SOCKET sockctrl, uint32 plen)
}
else
{
- if (sock_recv(sockctrl, remote_errbuf, plen,
+ if (sock_recv(sockctrl, ssl, remote_errbuf, plen,
SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
PCAP_ERRBUF_SIZE) == -1)
{
@@ -971,7 +1224,7 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen)
int sendbufidx = 0; // index which keeps the number of bytes currently buffered
struct rpcap_authreply *authreply; // authentication reply message
- status = rpcapd_recv(pars->sockctrl, (char *) &auth, sizeof(struct rpcap_auth), &plen, errmsgbuf);
+ status = rpcapd_recv(pars->sockctrl, pars->ssl, (char *) &auth, sizeof(struct rpcap_auth), &plen, errmsgbuf);
if (status == -1)
{
return -1;
@@ -988,10 +1241,10 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen)
if (!pars->nullAuthAllowed)
{
// Send the client an error reply.
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE,
"Authentication failed; NULL authentication not permitted.");
- if (rpcap_senderror(pars->sockctrl, 0,
- PCAP_ERR_AUTH_FAILED, errmsgbuf, errbuf) == -1)
+ if (rpcap_senderror(pars->sockctrl, pars->ssl,
+ 0, PCAP_ERR_AUTH_FAILED, errmsgbuf, errbuf) == -1)
{
// That failed; log a message and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1015,7 +1268,7 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen)
PCAP_ERRBUF_SIZE, errno, "malloc() failed");
goto error;
}
- status = rpcapd_recv(pars->sockctrl, username, usernamelen, &plen, errmsgbuf);
+ status = rpcapd_recv(pars->sockctrl, pars->ssl, username, usernamelen, &plen, errmsgbuf);
if (status == -1)
{
free(username);
@@ -1037,7 +1290,7 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen)
free(username);
goto error;
}
- status = rpcapd_recv(pars->sockctrl, passwd, passwdlen, &plen, errmsgbuf);
+ status = rpcapd_recv(pars->sockctrl, pars->ssl, passwd, passwdlen, &plen, errmsgbuf);
if (status == -1)
{
free(username);
@@ -1060,8 +1313,8 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen)
//
free(username);
free(passwd);
- if (rpcap_senderror(pars->sockctrl, 0,
- PCAP_ERR_AUTH_FAILED, errmsgbuf, errbuf) == -1)
+ if (rpcap_senderror(pars->sockctrl, pars->ssl,
+ 0, PCAP_ERR_AUTH_FAILED, errmsgbuf, errbuf) == -1)
{
// That failed; log a message and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1088,10 +1341,10 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen)
}
default:
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE,
"Authentication type not recognized.");
- if (rpcap_senderror(pars->sockctrl, 0,
- PCAP_ERR_AUTH_TYPE_NOTSUP, errmsgbuf, errbuf) == -1)
+ if (rpcap_senderror(pars->sockctrl, pars->ssl,
+ 0, PCAP_ERR_AUTH_TYPE_NOTSUP, errmsgbuf, errbuf) == -1)
{
// That failed; log a message and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1122,15 +1375,15 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen)
authreply->maxvers = RPCAP_MAX_VERSION;
// Send the reply.
- if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
{
- // That failed; log a messsage and give up.
+ // That failed; log a message and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
return -1;
}
// Check if all the data has been read; if not, discard the data in excess
- if (rpcapd_discard(pars->sockctrl, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
{
return -1;
}
@@ -1138,8 +1391,8 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen)
return 0;
error:
- if (rpcap_senderror(pars->sockctrl, 0, PCAP_ERR_AUTH, errmsgbuf,
- errbuf) == -1)
+ if (rpcap_senderror(pars->sockctrl, pars->ssl, 0, PCAP_ERR_AUTH,
+ errmsgbuf, errbuf) == -1)
{
// That failed; log a message and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1148,7 +1401,7 @@ error:
error_noreply:
// Check if all the data has been read; if not, discard the data in excess
- if (rpcapd_discard(pars->sockctrl, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
{
return -1;
}
@@ -1184,7 +1437,7 @@ daemon_AuthUserPwd(char *username, char *password, char *errbuf)
if (LogonUser(username, ".", password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &Token) == 0)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
error = GetLastError();
if (error != ERROR_LOGON_FAILURE)
{
@@ -1201,7 +1454,7 @@ daemon_AuthUserPwd(char *username, char *password, char *errbuf)
// I didn't test it.
if (ImpersonateLoggedOnUser(Token) == 0)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
pcap_fmt_errmsg_for_win32_err(errmsgbuf, PCAP_ERRBUF_SIZE,
GetLastError(), "ImpersonateLoggedOnUser() failed");
rpcapd_log(LOGPRIO_ERROR, "%s", errmsgbuf);
@@ -1216,7 +1469,7 @@ daemon_AuthUserPwd(char *username, char *password, char *errbuf)
/*
* See
*
- * http://www.unixpapa.com/incnote/passwd.html
+ * https://www.unixpapa.com/incnote/passwd.html
*
* We use the Solaris/Linux shadow password authentication if
* we have getspnam(), otherwise we just do traditional
@@ -1243,7 +1496,7 @@ daemon_AuthUserPwd(char *username, char *password, char *errbuf)
// This call is needed to get the uid
if ((user = getpwnam(username)) == NULL)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
return -1;
}
@@ -1251,7 +1504,7 @@ daemon_AuthUserPwd(char *username, char *password, char *errbuf)
// This call is needed to get the password; otherwise 'x' is returned
if ((usersp = getspnam(username)) == NULL)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
return -1;
}
user_password = usersp->sp_pwdp;
@@ -1279,7 +1532,7 @@ daemon_AuthUserPwd(char *username, char *password, char *errbuf)
if (crypt_password == NULL)
{
error = errno;
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
if (error == 0)
{
// It didn't set errno.
@@ -1294,7 +1547,7 @@ daemon_AuthUserPwd(char *username, char *password, char *errbuf)
}
if (strcmp(user_password, crypt_password) != 0)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed");
return -1;
}
@@ -1324,6 +1577,21 @@ daemon_AuthUserPwd(char *username, char *password, char *errbuf)
}
+/*
+ * Make sure that the reply length won't overflow 32 bits if we add the
+ * specified amount to it. If it won't, add that amount to it.
+ *
+ * We check whether replylen + itemlen > UINT32_MAX, but subtract itemlen
+ * from both sides, to prevent overflow.
+ */
+#define CHECK_AND_INCREASE_REPLY_LEN(itemlen) \
+ if (replylen > UINT32_MAX - (itemlen)) { \
+ pcap_strlcpy(errmsgbuf, "Reply length doesn't fit in 32 bits", \
+ sizeof (errmsgbuf)); \
+ goto error; \
+ } \
+ replylen += (uint32)(itemlen)
+
static int
daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen)
{
@@ -1339,7 +1607,7 @@ daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen)
uint16 nif = 0; // counts the number of interface listed
// Discard the rest of the message; there shouldn't be any payload.
- if (rpcapd_discard(pars->sockctrl, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
{
// Network error.
return -1;
@@ -1351,7 +1619,8 @@ daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen)
if (alldevs == NULL)
{
- if (rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_NOREMOTEIF,
+ if (rpcap_senderror(pars->sockctrl, pars->ssl, ver,
+ PCAP_ERR_NOREMOTEIF,
"No interfaces found! Make sure libpcap/WinPcap is properly installed"
" and you have the right to access to the remote device.",
errbuf) == -1)
@@ -1369,13 +1638,30 @@ daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen)
{
nif++;
- if (d->description)
- replylen += strlen(d->description);
- if (d->name)
- replylen += strlen(d->name);
+ if (d->description) {
+ size_t stringlen = strlen(d->description);
+ if (stringlen > UINT16_MAX) {
+ pcap_strlcpy(errmsgbuf,
+ "Description length doesn't fit in 16 bits",
+ sizeof (errmsgbuf));
+ goto error;
+ }
+ CHECK_AND_INCREASE_REPLY_LEN(stringlen);
+ }
+ if (d->name) {
+ size_t stringlen = strlen(d->name);
+ if (stringlen > UINT16_MAX) {
+ pcap_strlcpy(errmsgbuf,
+ "Name length doesn't fit in 16 bits",
+ sizeof (errmsgbuf));
+ goto error;
+ }
+ CHECK_AND_INCREASE_REPLY_LEN(stringlen);
+ }
- replylen += sizeof(struct rpcap_findalldevs_if);
+ CHECK_AND_INCREASE_REPLY_LEN(sizeof(struct rpcap_findalldevs_if));
+ uint16_t naddrs = 0;
for (address = d->addresses; address != NULL; address = address->next)
{
/*
@@ -1387,7 +1673,14 @@ daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen)
#ifdef AF_INET6
case AF_INET6:
#endif
- replylen += (sizeof(struct rpcap_sockaddr) * 4);
+ CHECK_AND_INCREASE_REPLY_LEN(sizeof(struct rpcap_sockaddr) * 4);
+ if (naddrs == UINT16_MAX) {
+ pcap_strlcpy(errmsgbuf,
+ "Number of interfaces doesn't fit in 16 bits",
+ sizeof (errmsgbuf));
+ goto error;
+ }
+ naddrs++;
break;
default:
@@ -1396,7 +1689,7 @@ daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen)
}
}
- // RPCAP findalldevs command
+ // RPCAP findalldevs reply
if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
&sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf,
PCAP_ERRBUF_SIZE) == -1)
@@ -1418,10 +1711,18 @@ daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen)
memset(findalldevs_if, 0, sizeof(struct rpcap_findalldevs_if));
- if (d->description) ldescr = (short) strlen(d->description);
- else ldescr = 0;
- if (d->name) lname = (short) strlen(d->name);
- else lname = 0;
+ /*
+ * We've already established that the string lengths
+ * fit in 16 bits.
+ */
+ if (d->description)
+ ldescr = (uint16) strlen(d->description);
+ else
+ ldescr = 0;
+ if (d->name)
+ lname = (uint16) strlen(d->name);
+ else
+ lname = 0;
findalldevs_if->desclen = htons(ldescr);
findalldevs_if->namelen = htons(lname);
@@ -1506,7 +1807,7 @@ daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen)
pcap_freealldevs(alldevs);
// Send a final command that says "now send it!"
- if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
return -1;
@@ -1518,8 +1819,8 @@ error:
if (alldevs)
pcap_freealldevs(alldevs);
- if (rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_FINDALLIF,
- errmsgbuf, errbuf) == -1)
+ if (rpcap_senderror(pars->sockctrl, pars->ssl, ver,
+ PCAP_ERR_FINDALLIF, errmsgbuf, errbuf) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
return -1;
@@ -1545,11 +1846,11 @@ daemon_msg_open_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
if (plen > sourcelen - 1)
{
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Source string too long");
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Source string too long");
goto error;
}
- nread = sock_recv(pars->sockctrl, source, plen,
+ nread = sock_recv(pars->sockctrl, pars->ssl, source, plen,
SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE);
if (nread == -1)
{
@@ -1563,7 +1864,7 @@ daemon_msg_open_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
// If so, reject it.
if (is_url(source))
{
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Source string refers to a remote device");
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Source string refers to a remote device");
goto error;
}
@@ -1592,13 +1893,20 @@ daemon_msg_open_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
memset(openreply, 0, sizeof(struct rpcap_openreply));
openreply->linktype = htonl(pcap_datalink(fp));
- openreply->tzoff = 0; /* This is always 0 for live captures */
+ /*
+ * This is always 0 for live captures; we no longer support it
+ * as something we read from capture files and supply to
+ * clients, but we have to send it over the wire, as open
+ * replies are expected to have 8 bytes of payload by
+ * existing clients.
+ */
+ openreply->tzoff = 0;
// We're done with the pcap_t.
pcap_close(fp);
// Send the reply.
- if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
return -1;
@@ -1606,7 +1914,7 @@ daemon_msg_open_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
return 0;
error:
- if (rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_OPEN,
+ if (rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_OPEN,
errmsgbuf, errbuf) == -1)
{
// That failed; log a message and give up.
@@ -1615,7 +1923,7 @@ error:
}
// Check if all the data has been read; if not, discard the data in excess
- if (rpcapd_discard(pars->sockctrl, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
{
return -1;
}
@@ -1629,7 +1937,7 @@ error:
static int
daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
char *source, struct session **sessionp,
- struct rpcap_sampling *samp_param _U_)
+ struct rpcap_sampling *samp_param _U_, int uses_ssl)
{
char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client
@@ -1654,7 +1962,7 @@ daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
addrinfo = NULL;
- status = rpcapd_recv(pars->sockctrl, (char *) &startcapreq,
+ status = rpcapd_recv(pars->sockctrl, pars->ssl, (char *) &startcapreq,
sizeof(struct rpcap_startcapreq), &plen, errmsgbuf);
if (status == -1)
{
@@ -1667,15 +1975,25 @@ daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
startcapreq.flags = ntohs(startcapreq.flags);
+ // Check that the client does not ask for UDP is the server has been asked
+ // to enforce encryption, as SSL is not supported yet with UDP:
+ if (uses_ssl && (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_DGRAM))
+ {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "SSL not supported with UDP forward of remote packets");
+ goto error;
+ }
+
// Create a session structure
session = malloc(sizeof(struct session));
if (session == NULL)
{
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Can't allocate session structure");
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Can't allocate session structure");
goto error;
}
session->sockdata = INVALID_SOCKET;
+ session->ctrl_ssl = session->data_ssl = NULL;
// We don't have a thread yet.
session->have_thread = 0;
//
@@ -1737,7 +2055,7 @@ daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
// Now we have to create a new socket to send packets
if (serveropen_dp) // Data connection is opened by the server toward the client
{
- pcap_snprintf(portdata, sizeof portdata, "%d", ntohs(startcapreq.portdata));
+ snprintf(portdata, sizeof portdata, "%d", ntohs(startcapreq.portdata));
// Get the name of the other peer (needed to connect to that specific network address)
if (getnameinfo((struct sockaddr *) &saddr, saddrlen, peerhost,
@@ -1787,10 +2105,11 @@ daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
// Needed to send an error on the ctrl connection
session->sockctrl = pars->sockctrl;
+ session->ctrl_ssl = pars->ssl;
session->protocol_version = ver;
// Now I can set the filter
- ret = daemon_unpackapplyfilter(pars->sockctrl, session, &plen, errmsgbuf);
+ ret = daemon_unpackapplyfilter(pars->sockctrl, pars->ssl, session, &plen, errmsgbuf);
if (ret == -1)
{
// Fatal error. A message has been logged; just give up.
@@ -1825,7 +2144,7 @@ daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
startcapreply->portdata = htons(port);
}
- if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
{
// That failed; log a message and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1854,13 +2173,30 @@ daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
session->sockdata = socktemp;
}
+ SSL *ssl = NULL;
+ if (uses_ssl)
+ {
+#ifdef HAVE_OPENSSL
+ /* In both active or passive cases, wait for the client to initiate the
+ * TLS handshake. Yes during that time the control socket will not be
+ * served, but the same was true from the above call to accept(). */
+ ssl = ssl_promotion(1, session->sockdata, errbuf, PCAP_ERRBUF_SIZE);
+ if (! ssl)
+ {
+ rpcapd_log(LOGPRIO_ERROR, "TLS handshake failed: %s", errbuf);
+ goto error;
+ }
+#endif
+ }
+ session->data_ssl = ssl;
+
// Now we have to create a new thread to receive packets
#ifdef _WIN32
session->thread = (HANDLE)_beginthreadex(NULL, 0, daemon_thrdatamain,
(void *) session, 0, NULL);
if (session->thread == 0)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error creating the data thread");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error creating the data thread");
goto error;
}
#else
@@ -1876,7 +2212,7 @@ daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
session->have_thread = 1;
// Check if all the data has been read; if not, discard the data in excess
- if (rpcapd_discard(pars->sockctrl, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
goto fatal_error;
*sessionp = session;
@@ -1898,8 +2234,8 @@ error:
free(session);
}
- if (rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_STARTCAPTURE,
- errmsgbuf, errbuf) == -1)
+ if (rpcap_senderror(pars->sockctrl, pars->ssl, ver,
+ PCAP_ERR_STARTCAPTURE, errmsgbuf, errbuf) == -1)
{
// That failed; log a message and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1907,7 +2243,7 @@ error:
}
// Check if all the data has been read; if not, discard the data in excess
- if (rpcapd_discard(pars->sockctrl, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
{
// Network error.
return -1;
@@ -1942,7 +2278,7 @@ daemon_msg_endcap_req(uint8 ver, struct daemon_slpars *pars,
rpcap_createhdr(&header, ver, RPCAP_MSG_ENDCAP_REPLY, 0, 0);
- if (sock_send(pars->sockctrl, (char *) &header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_send(pars->sockctrl, pars->ssl, (char *) &header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
{
// That failed; log a message and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1970,7 +2306,7 @@ daemon_msg_endcap_req(uint8 ver, struct daemon_slpars *pars,
#define RPCAP_BPF_MAXINSNS 8192
static int
-daemon_unpackapplyfilter(SOCKET sockctrl, struct session *session, uint32 *plenp, char *errmsgbuf)
+daemon_unpackapplyfilter(SOCKET sockctrl, SSL *ctrl_ssl, struct session *session, uint32 *plenp, char *errmsgbuf)
{
int status;
struct rpcap_filter filter;
@@ -1979,7 +2315,7 @@ daemon_unpackapplyfilter(SOCKET sockctrl, struct session *session, uint32 *plenp
struct bpf_program bf_prog;
unsigned int i;
- status = rpcapd_recv(sockctrl, (char *) &filter,
+ status = rpcapd_recv(sockctrl, ctrl_ssl, (char *) &filter,
sizeof(struct rpcap_filter), plenp, errmsgbuf);
if (status == -1)
{
@@ -1994,13 +2330,13 @@ daemon_unpackapplyfilter(SOCKET sockctrl, struct session *session, uint32 *plenp
if (ntohs(filter.filtertype) != RPCAP_UPDATEFILTER_BPF)
{
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Only BPF/NPF filters are currently supported");
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Only BPF/NPF filters are currently supported");
return -2;
}
if (bf_prog.bf_len > RPCAP_BPF_MAXINSNS)
{
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE,
"Filter program is larger than the maximum size of %u instructions",
RPCAP_BPF_MAXINSNS);
return -2;
@@ -2017,7 +2353,7 @@ daemon_unpackapplyfilter(SOCKET sockctrl, struct session *session, uint32 *plenp
for (i = 0; i < bf_prog.bf_len; i++)
{
- status = rpcapd_recv(sockctrl, (char *) &insn,
+ status = rpcapd_recv(sockctrl, ctrl_ssl, (char *) &insn,
sizeof(struct rpcap_filterbpf_insn), plenp, errmsgbuf);
if (status == -1)
{
@@ -2036,15 +2372,18 @@ daemon_unpackapplyfilter(SOCKET sockctrl, struct session *session, uint32 *plenp
bf_insn++;
}
+ //
+ // XXX - pcap_setfilter() should do the validation for us.
+ //
if (bpf_validate(bf_prog.bf_insns, bf_prog.bf_len) == 0)
{
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "The filter contains bogus instructions");
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "The filter contains bogus instructions");
return -2;
}
if (pcap_setfilter(session->fp, &bf_prog))
{
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "RPCAP error: %s", pcap_geterr(session->fp));
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "RPCAP error: %s", pcap_geterr(session->fp));
return -2;
}
@@ -2060,7 +2399,7 @@ daemon_msg_updatefilter_req(uint8 ver, struct daemon_slpars *pars,
int ret; // status of daemon_unpackapplyfilter()
struct rpcap_header header; // keeps the answer to the updatefilter command
- ret = daemon_unpackapplyfilter(pars->sockctrl, session, &plen, errmsgbuf);
+ ret = daemon_unpackapplyfilter(pars->sockctrl, pars->ssl, session, &plen, errmsgbuf);
if (ret == -1)
{
// Fatal error. A message has been logged; just give up.
@@ -2073,7 +2412,7 @@ daemon_msg_updatefilter_req(uint8 ver, struct daemon_slpars *pars,
}
// Check if all the data has been read; if not, discard the data in excess
- if (rpcapd_discard(pars->sockctrl, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
{
// Network error.
return -1;
@@ -2082,9 +2421,9 @@ daemon_msg_updatefilter_req(uint8 ver, struct daemon_slpars *pars,
// A response is needed, otherwise the other host does not know that everything went well
rpcap_createhdr(&header, ver, RPCAP_MSG_UPDATEFILTER_REPLY, 0, 0);
- if (sock_send(pars->sockctrl, (char *) &header, sizeof (struct rpcap_header), pcap_geterr(session->fp), PCAP_ERRBUF_SIZE))
+ if (sock_send(pars->sockctrl, pars->ssl, (char *) &header, sizeof (struct rpcap_header), pcap_geterr(session->fp), PCAP_ERRBUF_SIZE))
{
- // That failed; log a messsage and give up.
+ // That failed; log a message and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
return -1;
}
@@ -2092,11 +2431,11 @@ daemon_msg_updatefilter_req(uint8 ver, struct daemon_slpars *pars,
return 0;
error:
- if (rpcapd_discard(pars->sockctrl, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
{
return -1;
}
- rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_UPDATEFILTER,
+ rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_UPDATEFILTER,
errmsgbuf, NULL);
return 0;
@@ -2115,7 +2454,7 @@ daemon_msg_setsampling_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
struct rpcap_sampling rpcap_samp;
int status;
- status = rpcapd_recv(pars->sockctrl, (char *) &rpcap_samp, sizeof(struct rpcap_sampling), &plen, errmsgbuf);
+ status = rpcapd_recv(pars->sockctrl, pars->ssl, (char *) &rpcap_samp, sizeof(struct rpcap_sampling), &plen, errmsgbuf);
if (status == -1)
{
return -1;
@@ -2132,14 +2471,14 @@ daemon_msg_setsampling_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
// A response is needed, otherwise the other host does not know that everything went well
rpcap_createhdr(&header, ver, RPCAP_MSG_SETSAMPLING_REPLY, 0, 0);
- if (sock_send(pars->sockctrl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_send(pars->sockctrl, pars->ssl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
{
- // That failed; log a messsage and give up.
+ // That failed; log a message and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
return -1;
}
- if (rpcapd_discard(pars->sockctrl, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
{
return -1;
}
@@ -2147,7 +2486,7 @@ daemon_msg_setsampling_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
return 0;
error:
- if (rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_SETSAMPLING,
+ if (rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_SETSAMPLING,
errmsgbuf, errbuf) == -1)
{
// That failed; log a message and give up.
@@ -2156,7 +2495,7 @@ error:
}
// Check if all the data has been read; if not, discard the data in excess
- if (rpcapd_discard(pars->sockctrl, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
{
return -1;
}
@@ -2176,7 +2515,7 @@ daemon_msg_stats_req(uint8 ver, struct daemon_slpars *pars,
struct rpcap_stats *netstats; // statistics sent on the network
// Checks that the header does not contain other data; if so, discard it
- if (rpcapd_discard(pars->sockctrl, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1)
{
// Network error.
return -1;
@@ -2199,7 +2538,7 @@ daemon_msg_stats_req(uint8 ver, struct daemon_slpars *pars,
{
if (pcap_stats(session->fp, stats) == -1)
{
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "%s", pcap_geterr(session->fp));
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "%s", pcap_geterr(session->fp));
goto error;
}
@@ -2220,7 +2559,7 @@ daemon_msg_stats_req(uint8 ver, struct daemon_slpars *pars,
}
// Send the packet
- if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
return -1;
@@ -2229,7 +2568,7 @@ daemon_msg_stats_req(uint8 ver, struct daemon_slpars *pars,
return 0;
error:
- rpcap_senderror(pars->sockctrl, ver, PCAP_ERR_GETSTATS,
+ rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_GETSTATS,
errmsgbuf, NULL);
return 0;
}
@@ -2288,7 +2627,21 @@ daemon_thrdatamain(void *ptr)
//
// So we don't need to make sure that sendbufsize will overflow.
//
+ // However, we *do* need to make sure its value fits in an int,
+ // because sock_send() can't send more than INT_MAX bytes (it could
+ // do so on 64-bit UN*Xes, but can't do so on Windows, not even
+ // 64-bit Windows, as the send() buffer size argument is an int
+ // in Winsock).
+ //
sendbufsize = sizeof(struct rpcap_header) + sizeof(struct rpcap_pkthdr) + pcap_snapshot(session->fp);
+ if (sendbufsize > INT_MAX)
+ {
+ rpcapd_log(LOGPRIO_ERROR,
+ "Buffer size for this child thread would be larger than %d",
+ INT_MAX);
+ sendbuf = NULL; // we haven't allocated a buffer, so nothing to free
+ goto error;
+ }
sendbuf = (char *) malloc (sendbufsize);
if (sendbuf == NULL)
{
@@ -2335,7 +2688,7 @@ daemon_thrdatamain(void *ptr)
// Bufferize the general header
if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
- &sendbufidx, sendbufsize, SOCKBUF_CHECKONLY, errbuf,
+ &sendbufidx, (int)sendbufsize, SOCKBUF_CHECKONLY, errbuf,
PCAP_ERRBUF_SIZE) == -1)
{
rpcapd_log(LOGPRIO_ERROR,
@@ -2352,7 +2705,7 @@ daemon_thrdatamain(void *ptr)
// Bufferize the pkt header
if (sock_bufferize(NULL, sizeof(struct rpcap_pkthdr), NULL,
- &sendbufidx, sendbufsize, SOCKBUF_CHECKONLY, errbuf,
+ &sendbufidx, (int)sendbufsize, SOCKBUF_CHECKONLY, errbuf,
PCAP_ERRBUF_SIZE) == -1)
{
rpcapd_log(LOGPRIO_ERROR,
@@ -2364,12 +2717,16 @@ daemon_thrdatamain(void *ptr)
net_pkt_header->caplen = htonl(pkt_header->caplen);
net_pkt_header->len = htonl(pkt_header->len);
net_pkt_header->npkt = htonl(++(session->TotCapt));
- net_pkt_header->timestamp_sec = htonl(pkt_header->ts.tv_sec);
- net_pkt_header->timestamp_usec = htonl(pkt_header->ts.tv_usec);
+ //
+ // 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);
// Bufferize the pkt data
if (sock_bufferize((char *) pkt_data, pkt_header->caplen,
- sendbuf, &sendbufidx, sendbufsize, SOCKBUF_BUFFERIZE,
+ sendbuf, &sendbufidx, (int)sendbufsize, SOCKBUF_BUFFERIZE,
errbuf, PCAP_ERRBUF_SIZE) == -1)
{
rpcapd_log(LOGPRIO_ERROR,
@@ -2381,7 +2738,7 @@ daemon_thrdatamain(void *ptr)
// Send the packet
// If the client dropped the connection, don't report an
// error, just quit.
- status = sock_send(session->sockdata, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE);
+ status = sock_send(session->sockdata, session->data_ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE);
if (status < 0)
{
if (status == -1)
@@ -2412,8 +2769,8 @@ daemon_thrdatamain(void *ptr)
// The latter just means that the client told us to stop
// capturing, so there's no error to report.
//
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error reading the packets: %s", pcap_geterr(session->fp));
- rpcap_senderror(session->sockctrl, session->protocol_version,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error reading the packets: %s", pcap_geterr(session->fp));
+ rpcap_senderror(session->sockctrl, session->ctrl_ssl, session->protocol_version,
PCAP_ERR_READEX, errbuf, NULL);
}
@@ -2502,6 +2859,7 @@ daemon_seraddr(struct sockaddr_storage *sockaddrin, struct rpcap_sockaddr *socka
*/
void sleep_secs(int secs)
{
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
#ifdef _WIN32
Sleep(secs*1000);
#else
@@ -2513,18 +2871,19 @@ void sleep_secs(int secs)
while (secs_remaining != 0)
secs_remaining = sleep(secs_remaining);
#endif
+#endif
}
/*
* Read the header of a message.
*/
static int
-rpcapd_recv_msg_header(SOCKET sock, struct rpcap_header *headerp)
+rpcapd_recv_msg_header(SOCKET sock, SSL *ssl, struct rpcap_header *headerp)
{
int nread;
char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
- nread = sock_recv(sock, (char *) headerp, sizeof(struct rpcap_header),
+ nread = sock_recv(sock, ssl, (char *) headerp, sizeof(struct rpcap_header),
SOCK_RECEIVEALL_YES|SOCK_EOF_ISNT_ERROR, errbuf, PCAP_ERRBUF_SIZE);
if (nread == -1)
{
@@ -2551,7 +2910,7 @@ rpcapd_recv_msg_header(SOCKET sock, struct rpcap_header *headerp)
* error.
*/
static int
-rpcapd_recv(SOCKET sock, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf)
+rpcapd_recv(SOCKET sock, SSL *ssl, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf)
{
int nread;
char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
@@ -2559,10 +2918,10 @@ rpcapd_recv(SOCKET sock, char *buffer, size_t toread, uint32 *plen, char *errmsg
if (toread > *plen)
{
// Tell the client and continue.
- pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message payload is too short");
+ snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message payload is too short");
return -2;
}
- nread = sock_recv(sock, buffer, toread,
+ nread = sock_recv(sock, ssl, buffer, toread,
SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE);
if (nread == -1)
{
@@ -2580,13 +2939,13 @@ rpcapd_recv(SOCKET sock, char *buffer, size_t toread, uint32 *plen, char *errmsg
* error.
*/
static int
-rpcapd_discard(SOCKET sock, uint32 len)
+rpcapd_discard(SOCKET sock, SSL *ssl, uint32 len)
{
char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
if (len != 0)
{
- if (sock_discard(sock, len, errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_discard(sock, ssl, len, errbuf, PCAP_ERRBUF_SIZE) == -1)
{
// Network error.
rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf);
@@ -2669,6 +3028,16 @@ static void session_close(struct session *session)
#endif
}
+#ifdef HAVE_OPENSSL
+ if (session->data_ssl)
+ {
+ // Finish using the SSL handle for the socket.
+ // This must be done *before* the socket is closed.
+ ssl_finish(session->data_ssl);
+ session->data_ssl = NULL;
+ }
+#endif
+
if (session->sockdata != INVALID_SOCKET)
{
sock_close(session->sockdata, NULL, 0);
diff --git a/rpcapd/daemon.h b/rpcapd/daemon.h
index 74e17da5..dbbdb62c 100644
--- a/rpcapd/daemon.h
+++ b/rpcapd/daemon.h
@@ -33,13 +33,19 @@
#ifndef __DAEMON_H__
#define __DAEMON_H__
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "sslutils.h"
+
//
// Returns 1 if the client closed the control connection explicitly, 0
// otherwise; the return value is used only by callers that call us
// for active mode.
//
int daemon_serviceloop(SOCKET sockctrl, int isactive, char *passiveClients,
- int nullAuthAllowed);
+ int nullAuthAllowed, int uses_ssl);
void sleep_secs(int secs);
diff --git a/rpcapd/fileconf.c b/rpcapd/fileconf.c
index 2f15c014..b79dda18 100644
--- a/rpcapd/fileconf.c
+++ b/rpcapd/fileconf.c
@@ -39,7 +39,6 @@
#include <stdio.h>
#include <string.h>
-#include <ctype.h>
#include <signal.h>
#include <pcap.h> // for PCAP_ERRBUF_SIZE
@@ -59,6 +58,16 @@
static char *skipws(char *ptr);
+/*
+ * Locale-independent version checks for alphabetical and alphanumerical
+ * characters that also can handle being handed a char value that might
+ * be negative.
+ */
+#define FILECONF_ISALPHA(c) \
+ (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
+#define FILECONF_ISALNUM(c) \
+ (FILECONF_ISALPHA(c) || ((c) >= '0' && (c) <= '9'))
+
void fileconf_read(void)
{
FILE *fp;
@@ -135,8 +144,7 @@ void fileconf_read(void)
// Is the next character alphabetic? If not,
// this isn't a valid parameter name.
//
- if (!isascii((unsigned char)*ptr) ||
- !isalpha((unsigned char)*ptr))
+ if (FILECONF_ISALPHA(*ptr))
{
rpcapd_log(LOGPRIO_ERROR,
"%s, line %u doesn't have a valid parameter name",
@@ -150,8 +158,7 @@ void fileconf_read(void)
// That's the name of the parameter being set.
//
param = ptr;
- while (isascii((unsigned char)*ptr) &&
- (isalnum((unsigned char)*ptr) || *ptr == '-' || *ptr == '_'))
+ while (FILECONF_ISALNUM(*ptr) || *ptr == '-' || *ptr == '_')
ptr++;
//
@@ -234,13 +241,15 @@ void fileconf_read(void)
ptr += toklen; // skip to the terminator
if (toklen == 0)
{
- if (isascii((unsigned char)*ptr) &&
- (isspace((unsigned char)*ptr) || *ptr == '#' || *ptr == '\0'))
+ if (*ptr == ' ' || *ptr == '\t' ||
+ *ptr == '\r' || *ptr == '\n' ||
+ *ptr == '#' || *ptr == '\0')
{
//
// The first character it saw
// was a whitespace character
- // or a comment character.
+ // or a comment character,
+ // or we ran out of characters.
// This means that there's
// no value.
//
@@ -498,8 +507,7 @@ int fileconf_save(const char *savefile)
fprintf(fp, "# Hosts which are allowed to connect to this server (passive mode)\n");
fprintf(fp, "# Format: PassiveClient = <name or address>\n\n");
- strncpy(temphostlist, hostlist, MAX_HOST_LIST);
- temphostlist[MAX_HOST_LIST] = 0;
+ pcap_strlcpy(temphostlist, hostlist, sizeof (temphostlist));
token = pcap_strtok_r(temphostlist, RPCAP_HOSTLIST_SEP, &lasts);
while(token != NULL)
@@ -548,7 +556,7 @@ int fileconf_save(const char *savefile)
//
static char *skipws(char *ptr)
{
- while (isascii((unsigned char)*ptr) && isspace((unsigned char)*ptr)) {
+ while (*ptr == ' ' || *ptr == '\t' || *ptr == '\r' || *ptr == '\n') {
if (*ptr == '\r' || *ptr == '\n')
return NULL;
*ptr++ = '\0';
diff --git a/rpcapd/log.c b/rpcapd/log.c
index 7b5fee57..f26c145e 100644
--- a/rpcapd/log.c
+++ b/rpcapd/log.c
@@ -229,7 +229,7 @@ static void rpcapd_vlog_systemlog(log_priority priority, const char *message,
*/
char logbuf[1024+1];
- pcap_vsnprintf(logbuf, sizeof logbuf, message, ap);
+ vsnprintf(logbuf, sizeof logbuf, message, ap);
syslog(syslog_priority, "%s", logbuf);
#endif
}
diff --git a/rpcapd/org.tcpdump.rpcapd.plist b/rpcapd/org.tcpdump.rpcapd.plist
index db3223a7..b0e24398 100644
--- a/rpcapd/org.tcpdump.rpcapd.plist
+++ b/rpcapd/org.tcpdump.rpcapd.plist
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Disabled</key>
diff --git a/rpcapd/rpcapd-config.manfile.in b/rpcapd/rpcapd-config.manfile.in
index 1a87529d..267b48e5 100644
--- a/rpcapd/rpcapd-config.manfile.in
+++ b/rpcapd/rpcapd-config.manfile.in
@@ -21,7 +21,7 @@
.SH NAME
rpcapd-config \- rpcapd configuration file format
.SH DESCRIPTION
-An
+An
.B rpcapd
configuration file allows parameters to be set for
.BR rpcapd (@MAN_ADMIN_COMMANDS@).
@@ -42,7 +42,7 @@ are:
.TP
.B ActiveClient
.I value
-is a host name or IP addresse, followed by a comma,
+is a host name or IP address, followed by a comma,
semicolon, or space, followed by a port name and address or
.BR DEFAULT .
.B DEFAULT
@@ -54,7 +54,7 @@ should connect in active mode.
.TP
.B PassiveClient
.I value
-is a host name or IP addresse, followed by a comma,
+is a host name or IP address, followed by a comma,
semicolon, or space, followed by a port name and address or
.BR DEFAULT .
.B DEFAULT
@@ -75,4 +75,4 @@ means that null authentication is permitted;
.B No
means that it is not permitted.
.SH SEE ALSO
-rpcapd(@MAN_ADMIN_COMMANDS@)
+.BR rpcapd (@MAN_ADMIN_COMMANDS@)
diff --git a/rpcapd/rpcapd.c b/rpcapd/rpcapd.c
index 430acdc8..b91a401e 100644
--- a/rpcapd/rpcapd.c
+++ b/rpcapd/rpcapd.c
@@ -39,6 +39,7 @@
#include <errno.h> // for the errno variable
#include <string.h> // for strtok, etc
#include <stdlib.h> // for malloc(), free(), ...
+#include <stdio.h> // for fprintf(), stderr, FILE etc
#include <pcap.h> // for PCAP_ERRBUF_SIZE
#include <signal.h> // for signal()
@@ -53,6 +54,10 @@
#include "daemon.h" // the true main() method of this daemon
#include "log.h"
+#ifdef HAVE_OPENSSL
+#include "sslutils.h"
+#endif
+
#ifdef _WIN32
#include <process.h> // for thread stuff
#include "win32-svc.h" // for Win32 service stuff
@@ -86,6 +91,7 @@ static HANDLE state_change_event; //!< event to signal that a state change shou
#endif
static volatile sig_atomic_t shutdown_server; //!< '1' if the server is to shut down
static volatile sig_atomic_t reread_config; //!< '1' if the server is to re-read its configuration
+static int uses_ssl; //!< '1' to use TLS over the data socket
extern char *optarg; // for getopt()
@@ -112,7 +118,7 @@ static unsigned __stdcall main_passive_serviceloop_thread(void *ptr);
/*!
\brief Prints the usage screen if it is launched in console mode.
*/
-static void printusage(void)
+static void printusage(FILE * f)
{
const char *usagetext =
"USAGE:"
@@ -145,14 +151,23 @@ static void printusage(void)
" -i run in inetd mode (UNIX only)\n\n"
#endif
" -D log debugging messages\n\n"
+#ifdef HAVE_OPENSSL
+ " -S encrypt all communication with SSL (implements rpcaps://)\n"
+ " -C enable compression\n"
+ " -K <pem_file> uses the SSL private key in this file (default: key.pem)\n"
+ " -X <pem_file> uses the certificate from this file (default: cert.pem)\n"
+#endif
" -s <config_file> save the current configuration to file\n\n"
" -f <config_file> load the current configuration from file; all switches\n"
" specified from the command line are ignored\n\n"
" -h print this help screen\n\n";
- (void)fprintf(stderr, "RPCAPD, a remote packet capture daemon.\n"
- "Compiled with %s\n\n", pcap_lib_version());
- printf("%s", usagetext);
+ (void)fprintf(f, "RPCAPD, a remote packet capture daemon.\n"
+ "Compiled with %s\n", pcap_lib_version());
+#if defined(HAVE_OPENSSL) && defined(SSLEAY_VERSION)
+ (void)fprintf(f, "Compiled with %s\n", SSLeay_version(SSLEAY_VERSION));
+#endif
+ (void)fprintf(f, "\n%s", usagetext);
}
@@ -172,6 +187,9 @@ int main(int argc, char *argv[])
#ifndef _WIN32
struct sigaction action;
#endif
+#ifdef HAVE_OPENSSL
+ int enable_compression = 0;
+#endif
savefile[0] = 0;
loadfile[0] = 0;
@@ -180,8 +198,8 @@ int main(int argc, char *argv[])
// Initialize errbuf
memset(errbuf, 0, sizeof(errbuf));
- strncpy(address, RPCAP_DEFAULT_NETADDR, MAX_LINE);
- strncpy(port, RPCAP_DEFAULT_NETPORT, MAX_LINE);
+ pcap_strlcpy(address, RPCAP_DEFAULT_NETADDR, sizeof (address));
+ pcap_strlcpy(port, RPCAP_DEFAULT_NETPORT, sizeof (port));
// Prepare to open a new server socket
memset(&mainhints, 0, sizeof(struct addrinfo));
@@ -191,7 +209,15 @@ int main(int argc, char *argv[])
mainhints.ai_socktype = SOCK_STREAM;
// Getting the proper command line options
- while ((retval = getopt(argc, argv, "b:dDhip:4l:na:s:f:v")) != -1)
+# ifdef HAVE_OPENSSL
+# define SSL_CLOPTS "SK:X:C"
+# else
+# define SSL_CLOPTS ""
+# endif
+
+# define CLOPTS "b:dDhip:4l:na:s:f:v" SSL_CLOPTS
+
+ while ((retval = getopt(argc, argv, CLOPTS)) != -1)
{
switch (retval)
{
@@ -200,10 +226,10 @@ int main(int argc, char *argv[])
rpcapd_log_set(log_to_systemlog, log_debug_messages);
break;
case 'b':
- strncpy(address, optarg, MAX_LINE);
+ pcap_strlcpy(address, optarg, sizeof (address));
break;
case 'p':
- strncpy(port, optarg, MAX_LINE);
+ pcap_strlcpy(port, optarg, sizeof (port));
break;
case '4':
mainhints.ai_family = PF_INET; // IPv4 server only
@@ -215,7 +241,7 @@ int main(int argc, char *argv[])
break;
case 'i':
#ifdef _WIN32
- printusage();
+ printusage(stderr);
exit(1);
#else
isrunbyinetd = 1;
@@ -231,7 +257,7 @@ int main(int argc, char *argv[])
break;
case 'l':
{
- strncpy(hostlist, optarg, sizeof(hostlist));
+ pcap_strlcpy(hostlist, optarg, sizeof(hostlist));
break;
}
case 'a':
@@ -246,12 +272,12 @@ int main(int argc, char *argv[])
{
tmpport = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
- pcap_strlcpy(activelist[i].address, tmpaddress, MAX_LINE);
+ pcap_strlcpy(activelist[i].address, tmpaddress, sizeof (activelist[i].address));
if ((tmpport == NULL) || (strcmp(tmpport, "DEFAULT") == 0)) // the user choose a custom port
- pcap_strlcpy(activelist[i].port, RPCAP_DEFAULT_NETPORT_ACTIVE, MAX_LINE);
+ pcap_strlcpy(activelist[i].port, RPCAP_DEFAULT_NETPORT_ACTIVE, sizeof (activelist[i].port));
else
- pcap_strlcpy(activelist[i].port, tmpport, MAX_LINE);
+ pcap_strlcpy(activelist[i].port, tmpport, sizeof (activelist[i].port));
tmpaddress = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
@@ -266,13 +292,27 @@ int main(int argc, char *argv[])
break;
}
case 'f':
- pcap_strlcpy(loadfile, optarg, MAX_LINE);
+ pcap_strlcpy(loadfile, optarg, sizeof (loadfile));
break;
case 's':
- pcap_strlcpy(savefile, optarg, MAX_LINE);
+ pcap_strlcpy(savefile, optarg, sizeof (savefile));
break;
+#ifdef HAVE_OPENSSL
+ case 'S':
+ uses_ssl = 1;
+ break;
+ case 'C':
+ enable_compression = 1;
+ break;
+ case 'K':
+ ssl_set_keyfile(optarg);
+ break;
+ case 'X':
+ ssl_set_certfile(optarg);
+ break;
+#endif
case 'h':
- printusage();
+ printusage(stdout);
exit(0);
/*NOTREACHED*/
default:
@@ -289,6 +329,16 @@ int main(int argc, char *argv[])
}
#endif
+ //
+ // We want UTF-8 error messages.
+ //
+ if (pcap_init(PCAP_CHAR_ENC_UTF_8, errbuf) == -1)
+ {
+ rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
+ exit(-1);
+ }
+ pcap_fmt_set_encoding(PCAP_CHAR_ENC_UTF_8);
+
if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
@@ -302,7 +352,7 @@ int main(int argc, char *argv[])
if (loadfile[0])
fileconf_read();
-#ifdef WIN32
+#ifdef _WIN32
//
// Create a handle to signal the main loop to tell it to do
// something.
@@ -342,6 +392,17 @@ int main(int argc, char *argv[])
signal(SIGPIPE, SIG_IGN);
#endif
+# ifdef HAVE_OPENSSL
+ if (uses_ssl) {
+ if (ssl_init_once(1, enable_compression, errbuf, PCAP_ERRBUF_SIZE) < 0)
+ {
+ rpcapd_log(LOGPRIO_ERROR, "Can't initialize SSL: %s",
+ errbuf);
+ exit(2);
+ }
+ }
+# endif
+
#ifndef _WIN32
if (isrunbyinetd)
{
@@ -399,7 +460,7 @@ int main(int argc, char *argv[])
exit(0);
}
(void)daemon_serviceloop(sockctrl, 0, hostlist_copy,
- nullAuthAllowed);
+ nullAuthAllowed, uses_ssl);
//
// Nothing more to do.
@@ -454,7 +515,7 @@ int main(int argc, char *argv[])
//
// If this call succeeds, it is blocking on Win32
//
- if (svc_start() != 1)
+ if (!svc_start())
rpcapd_log(LOGPRIO_DEBUG, "Unable to start the service");
// When the previous call returns, the entire application has to be stopped.
@@ -918,8 +979,8 @@ accept_connections(void)
//
// Did an error occur?
//
- if (network_events.iErrorCode[FD_ACCEPT_BIT] != 0)
- {
+ if (network_events.iErrorCode[FD_ACCEPT_BIT] != 0)
+ {
//
// Yes - report it and keep going.
//
@@ -1100,7 +1161,7 @@ accept_connection(SOCKET listen_sock)
break;
}
- // The accept() call can return this error when a signal is catched
+ // The accept() call can return this error when a signal is caught
// In this case, we have simply to ignore this error code
// Stevens, pg 124
#ifdef _WIN32
@@ -1236,7 +1297,7 @@ accept_connection(SOCKET listen_sock)
exit(0);
}
(void)daemon_serviceloop(sockctrl, 0, hostlist_copy,
- nullAuthAllowed);
+ nullAuthAllowed, uses_ssl);
exit(0);
}
@@ -1300,7 +1361,7 @@ main_active(void *ptr)
{
rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error connecting to host %s, port %s, using protocol %s",
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error connecting to host %s, port %s, using protocol %s",
activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4":
(hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
@@ -1324,10 +1385,10 @@ main_active(void *ptr)
// daemon_serviceloop() will free the copy.
//
activeclose = daemon_serviceloop(sockctrl, 1,
- hostlist_copy, nullAuthAllowed);
+ hostlist_copy, nullAuthAllowed, uses_ssl);
}
- // If the connection is closed by the user explicitely, don't try to connect to it again
+ // If the connection is closed by the user explicitly, don't try to connect to it again
// just exit the program
if (activeclose == 1)
break;
@@ -1352,7 +1413,7 @@ unsigned __stdcall main_passive_serviceloop_thread(void *ptr)
// told by the client to close.
//
(void)daemon_serviceloop(params.sockctrl, 0, params.hostlist,
- nullAuthAllowed);
+ nullAuthAllowed, uses_ssl);
return 0;
}
diff --git a/rpcapd/rpcapd.manadmin.in b/rpcapd/rpcapd.manadmin.in
index 0a9d4e03..ea6046e4 100644
--- a/rpcapd/rpcapd.manadmin.in
+++ b/rpcapd/rpcapd.manadmin.in
@@ -30,7 +30,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.TH RPCAPD @MAN_ADMIN_COMMANDS@ "April 20, 2018"
+.TH RPCAPD @MAN_ADMIN_COMMANDS@ "13 January 2019"
.SH NAME
rpcapd \- capture daemon to be controlled by a remote libpcap application
.SH SYNOPSIS
@@ -69,10 +69,25 @@ rpcapd
] [
.B \-s
.I config_file
-] [
+]
+[
.B \-f
.I config_file
]
+[
+.B \-S
+]
+.br
+.ti +8
+[
+.B \-K
+.I ssl_keyfile
+] [
+.B \-X
+.I ssl_certfile
+] [
+.B \-C
+]
.br
.ad
.SH DESCRIPTION
@@ -84,7 +99,9 @@ Rpcapd can run in two modes: passive mode (default) and active mode.
.LP
In passive mode, the client (e.g., a network sniffer) connects to
.BR rpcapd .
-It then sends hem the appropriate commands to start the capture.
+The client then sends the appropriate commands to
+.B rpcapd
+to start the capture.
.LP
In active mode,
.B rpcapd
@@ -103,26 +120,34 @@ establishing the connection, the protocol continues its job in almost
the same way in both active and passive mode.
.SH Configuration file
.LP
-The user can create a configuration file in the same folder of the
+The user can create a configuration file in the same directory as the
executable, and put the configuration commands in there. In order for
-rpcapd to execute the commands, you have to restart it on Win32, i.e.
-the initialization file is parsed only at the beginning). The UNIX
-version of rpcapd will reread the configuration file when receiving a
-HUP signel. In that case, all the existing connections remain in place,
+.B 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
+will reread the configuration file upon receiving a
+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 rpcapd with the requested parameters plus "-s filename".
+they can launch
+.B rpcapd
+with the desired flags plus
+.BR "-s filename" .
Rpcapd will parse all the parameters and save them into the specified
configuration file.
.SH Installing rpcapd on Win32
.LP
The remote daemon is installed automatically when installing WinPcap.
-The installation process places the rpcapd file into the WinPcap folder.
+The installation process places the
+.B 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
services list and it creates a new item (Remote Packet Capture Protocol
-v.0 (experimental) ). To avoid security problems, the service is
+v.0 (experimental)). To avoid security problems, the service is
inactive and it has to be started manually (control panel -
administrative tools - services - start).
.LP
@@ -134,7 +159,9 @@ flag (in order to make it run as a service) and the
flag.
.SH Starting rpcapd on Win32
.LP
-The rpcapd executable can be launched directly, i.e. it can run in the
+The
+.B rpcapd
+executable can be launched directly, i.e. it can run in the
foreground as well (not as a daemon/service). The procedure is quite
simple: you have to invoke the executable from the command line with all
the requested parameters except for the
@@ -178,7 +205,7 @@ Only allow hosts specified in the
argument to connect to this server.
.I host_list
is a list of host names or IP addresses, separated by commas.
-We suggest that you use use host names rather than literal IP addresses
+We suggest that you use host names rather than literal IP addresses
in order to avoid problems with different address families.
.TP
.B \-n
@@ -202,8 +229,8 @@ is specified,
it accepts passive connections as well.
.TP
.B \-d
-Run in daemon mode (UNIX only) or as a service (Win32 only)
-Warning (Win32): this switch is provided automatically when
+Run in daemon mode (UNIX only) or as a service (Win32 only).
+Warning (Win32): this flag is specified automatically when
the service is started from the control panel.
.TP
.B \-i
@@ -222,12 +249,37 @@ in the format specified by
Load the current configuration from
.I config_file
in the format specified by
-.BR rpcapd-config (@MAN_FILE_FORMATS@);
-all switches specified from the command line are ignored.
+.BR rpcapd-config (@MAN_FILE_FORMATS@)
+and ignore all flags specified on the command line.
.TP
.B \-h
Print this help screen.
+.LP
+If
+.B rpcapd
+was compiled with SSL support, the following options are also
+available:
+.TP
+.B \-S
+Require that SSL be used on connections.
+.TP
+.B \-C
+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
+With SSL enabled, use
+.I ssl_keyfile
+as the SSL key file.
+.TP
+.B \-X
+.I ssl_certfile
+With SSL enabled, use
+.I ssl_certfile
+as the SSL certificate file.
.br
.ad
.SH "SEE ALSO"
-pcap(3PCAP), rpcapd-config(@MAN_FILE_FORMATS@)
+.BR pcap (3PCAP),
+.BR rpcapd-config (@MAN_FILE_FORMATS@)
diff --git a/rpcapd/win32-svc.c b/rpcapd/win32-svc.c
index 3a19910d..49b6804b 100644
--- a/rpcapd/win32-svc.c
+++ b/rpcapd/win32-svc.c
@@ -38,15 +38,18 @@
#include "fileconf.h"
#include "log.h"
+#include "win32-svc.h" // for Win32 service stuff
+
static SERVICE_STATUS_HANDLE service_status_handle;
static SERVICE_STATUS service_status;
static void WINAPI svc_main(DWORD argc, char **argv);
+static void WINAPI svc_control_handler(DWORD Opcode);
static void update_svc_status(DWORD state, DWORD progress_indicator);
-int svc_start(void)
+BOOL svc_start(void)
{
- int rc;
+ BOOL rc;
SERVICE_TABLE_ENTRY ste[] =
{
{ PROGRAM_NAME, svc_main },
@@ -65,7 +68,8 @@ int svc_start(void)
return rc; // FALSE if this is not started as a service
}
-void WINAPI svc_control_handler(DWORD Opcode)
+static void WINAPI
+svc_control_handler(DWORD Opcode)
{
switch(Opcode)
{
@@ -130,7 +134,8 @@ void WINAPI svc_control_handler(DWORD Opcode)
return;
}
-void WINAPI svc_main(DWORD argc, char **argv)
+static void WINAPI
+svc_main(DWORD argc, char **argv)
{
service_status_handle = RegisterServiceCtrlHandler(PROGRAM_NAME, svc_control_handler);
diff --git a/rpcapd/win32-svc.h b/rpcapd/win32-svc.h
index 3f511d2c..60b25ecf 100644
--- a/rpcapd/win32-svc.h
+++ b/rpcapd/win32-svc.h
@@ -30,4 +30,4 @@
*
*/
-int svc_start(void);
+BOOL svc_start(void);
diff --git a/savefile.c b/savefile.c
index 5b1e14cf..d04b917a 100644
--- a/savefile.c
+++ b/savefile.c
@@ -54,22 +54,22 @@
#include "sf-pcap.h"
#include "sf-pcapng.h"
#include "pcap-common.h"
+#include "charconv.h"
#ifdef _WIN32
/*
- * These aren't exported on Windows, because they would only work if both
+ * This isn't exported on Windows, because it would only work if both
* WinPcap/Npcap and the code using it were to use the Universal CRT; otherwise,
* a FILE structure in WinPcap/Npcap and a FILE structure in the code using it
* could be different if they're using different versions of the C runtime.
*
- * Instead, pcap/pcap.h defines them as macros that wrap the hopen versions,
- * with the wrappers calling _fileno() and _get_osfhandle() themselves,
- * so that they convert the appropriate CRT version's FILE structure to
+ * Instead, pcap/pcap.h defines it as a macro that wraps the hopen version,
+ * with the wrapper calling _fileno() and _get_osfhandle() themselves,
+ * so that it convert the appropriate CRT version's FILE structure to
* a HANDLE (which is OS-defined, not CRT-defined, and is part of the Win32
* and Win64 ABIs).
*/
static pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *, u_int, char *);
-static pcap_t *pcap_fopen_offline(FILE *, char *);
#endif
/*
@@ -106,7 +106,7 @@ sf_setnonblock(pcap_t *p, int nonblock _U_)
* as it would have to handle reading partial packets and
* keeping the state of the read.)
*/
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Savefiles cannot be put into non-blocking mode");
return (-1);
}
@@ -114,40 +114,40 @@ sf_setnonblock(pcap_t *p, int nonblock _U_)
static int
sf_stats(pcap_t *p, struct pcap_stat *ps _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Statistics aren't available from savefiles");
return (-1);
}
#ifdef _WIN32
static struct pcap_stat *
-sf_stats_ex(pcap_t *p, int *size)
+sf_stats_ex(pcap_t *p, int *size _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Statistics aren't available from savefiles");
return (NULL);
}
static int
-sf_setbuff(pcap_t *p, int dim)
+sf_setbuff(pcap_t *p, int dim _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The kernel buffer size cannot be set while reading from a file");
return (-1);
}
static int
-sf_setmode(pcap_t *p, int mode)
+sf_setmode(pcap_t *p, int mode _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"impossible to set mode while reading from a file");
return (-1);
}
static int
-sf_setmintocopy(pcap_t *p, int size)
+sf_setmintocopy(pcap_t *p, int size _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The mintocopy parameter cannot be set while reading from a file");
return (-1);
}
@@ -155,7 +155,7 @@ sf_setmintocopy(pcap_t *p, int size)
static HANDLE
sf_getevent(pcap_t *pcap)
{
- (void)pcap_snprintf(pcap->errbuf, sizeof(pcap->errbuf),
+ (void)snprintf(pcap->errbuf, sizeof(pcap->errbuf),
"The read event cannot be retrieved while reading from a file");
return (INVALID_HANDLE_VALUE);
}
@@ -164,7 +164,7 @@ static int
sf_oid_get_request(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_,
size_t *lenp _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"An OID get request cannot be performed on a file");
return (PCAP_ERROR);
}
@@ -173,13 +173,13 @@ static int
sf_oid_set_request(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
size_t *lenp _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"An OID set request cannot be performed on a file");
return (PCAP_ERROR);
}
static u_int
-sf_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue, int sync)
+sf_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue _U_, int sync _U_)
{
pcap_strlcpy(p->errbuf, "Sending packets isn't supported on savefiles",
PCAP_ERRBUF_SIZE);
@@ -187,38 +187,38 @@ sf_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue, int sync)
}
static int
-sf_setuserbuffer(pcap_t *p, int size)
+sf_setuserbuffer(pcap_t *p, int size _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The user buffer cannot be set when reading from a file");
return (-1);
}
static int
-sf_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks)
+sf_live_dump(pcap_t *p, char *filename _U_, int maxsize _U_, int maxpacks _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Live packet dumping cannot be performed when reading from a file");
return (-1);
}
static int
-sf_live_dump_ended(pcap_t *p, int sync)
+sf_live_dump_ended(pcap_t *p, int sync _U_)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
return (-1);
}
static PAirpcapHandle
-sf_get_airpcap_handle(pcap_t *pcap)
+sf_get_airpcap_handle(pcap_t *pcap _U_)
{
return (NULL);
}
#endif
static int
-sf_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
+sf_inject(pcap_t *p, const void *buf _U_, int size _U_)
{
pcap_strlcpy(p->errbuf, "Sending packets isn't supported on savefiles",
PCAP_ERRBUF_SIZE);
@@ -232,7 +232,7 @@ sf_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
static int
sf_setdirection(pcap_t *p, pcap_direction_t d _U_)
{
- pcap_snprintf(p->errbuf, sizeof(p->errbuf),
+ snprintf(p->errbuf, sizeof(p->errbuf),
"Setting direction is not supported on savefiles");
return (-1);
}
@@ -247,6 +247,94 @@ sf_cleanup(pcap_t *p)
pcap_freecode(&p->fcode);
}
+#ifdef _WIN32
+/*
+ * Wrapper for fopen() and _wfopen().
+ *
+ * If we're in UTF-8 mode, map the pathname from UTF-8 to UTF-16LE and
+ * call _wfopen().
+ *
+ * If we're not, just use fopen(); that'll treat it as being in the
+ * local code page.
+ */
+FILE *
+charset_fopen(const char *path, const char *mode)
+{
+ wchar_t *utf16_path;
+#define MAX_MODE_LEN 16
+ wchar_t utf16_mode[MAX_MODE_LEN+1];
+ int i;
+ char c;
+ FILE *fp;
+ int save_errno;
+
+ if (pcap_utf_8_mode) {
+ /*
+ * Map from UTF-8 to UTF-16LE.
+ * Fail if there are invalid characters in the input
+ * string, rather than converting them to REPLACEMENT
+ * CHARACTER; the latter is appropriate for strings
+ * to be displayed to the user, but for file names
+ * you just want the attempt to open the file to fail.
+ */
+ utf16_path = cp_to_utf_16le(CP_UTF8, path,
+ MB_ERR_INVALID_CHARS);
+ if (utf16_path == NULL) {
+ /*
+ * Error. Assume errno has been set.
+ *
+ * XXX - what about Windows errors?
+ */
+ return (NULL);
+ }
+
+ /*
+ * Now convert the mode to UTF-16LE as well.
+ * We assume the mode is ASCII, and that
+ * it's short, so that's easy.
+ */
+ for (i = 0; (c = *mode) != '\0'; i++, mode++) {
+ if (c > 0x7F) {
+ /* Not an ASCII character; fail with EINVAL. */
+ free(utf16_path);
+ errno = EINVAL;
+ return (NULL);
+ }
+ if (i >= MAX_MODE_LEN) {
+ /* The mode string is longer than we allow. */
+ free(utf16_path);
+ errno = EINVAL;
+ return (NULL);
+ }
+ utf16_mode[i] = c;
+ }
+ utf16_mode[i] = '\0';
+
+ /*
+ * OK, we have UTF-16LE strings; hand them to
+ * _wfopen().
+ */
+ fp = _wfopen(utf16_path, utf16_mode);
+
+ /*
+ * Make sure freeing the UTF-16LE string doesn't
+ * overwrite the error code we got from _wfopen().
+ */
+ save_errno = errno;
+ free(utf16_path);
+ errno = save_errno;
+
+ return (fp);
+ } else {
+ /*
+ * This takes strings in the local code page as an
+ * argument.
+ */
+ return (fopen(path, mode));
+ }
+}
+#endif
+
pcap_t *
pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision,
char *errbuf)
@@ -255,13 +343,18 @@ pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision,
pcap_t *p;
if (fname == NULL) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"A null pointer was supplied as the file name");
return (NULL);
}
if (fname[0] == '-' && fname[1] == '\0')
{
fp = stdin;
+ if (stdin == NULL) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "The standard input is not open");
+ return (NULL);
+ }
#if defined(_WIN32) || defined(MSDOS)
/*
* We're reading from the standard input, so put it in binary
@@ -272,12 +365,16 @@ pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision,
}
else {
/*
+ * Use charset_fopen(); on Windows, it tests whether we're
+ * in "local code page" or "UTF-8" mode, and treats the
+ * pathname appropriately, and on other platforms, it just
+ * wraps fopen().
+ *
* "b" is supported as of C90, so *all* UN*Xes should
- * support it, even though it does nothing. It's
- * required on Windows, as the file is a binary file
- * and must be read in binary mode.
+ * support it, even though it does nothing. For MS-DOS,
+ * we again need it.
*/
- fp = fopen(fname, "rb");
+ fp = charset_fopen(fname, "rb");
if (fp == NULL) {
pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
errno, "%s", fname);
@@ -382,6 +479,19 @@ pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision,
int err;
/*
+ * Fail if we were passed a NULL fp.
+ *
+ * That shouldn't happen if we're opening with a path name, but
+ * it could happen if buggy code is opening with a FILE * and
+ * didn't bother to make sure the FILE * isn't null.
+ */
+ if (fp == NULL) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Null FILE * pointer provided to savefile open routine");
+ return (NULL);
+ }
+
+ /*
* Read the first 4 bytes of the file; the network analyzer dump
* file formats we support (pcap and pcapng), and several other
* formats we might support in the future (such as snoop, DOS and
@@ -394,8 +504,8 @@ pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision,
pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
errno, "error reading dump file");
} else {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "truncated dump file; tried to read %" PRIsize " file header bytes, only got %" PRIsize,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "truncated dump file; tried to read %zu file header bytes, only got %zu",
sizeof(magic), amt_read);
}
return (NULL);
@@ -421,7 +531,7 @@ pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision,
/*
* Well, who knows what this mess is....
*/
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format");
return (NULL);
found:
@@ -471,6 +581,11 @@ found:
p->oneshot_callback = pcap_oneshot;
/*
+ * Default breakloop operation.
+ */
+ p->breakloop_op = pcap_breakloop_common;
+
+ /*
* Savefiles never require special BPF code generation.
*/
p->bpf_codegen_flags = 0;
@@ -480,15 +595,19 @@ found:
return (p);
}
-#ifdef _WIN32
-static
-#endif
+/*
+ * This isn't needed on Windows; we #define pcap_fopen_offline() as
+ * a wrapper around pcap_hopen_offline(), and we don't call it from
+ * inside this file, so it's unused.
+ */
+#ifndef _WIN32
pcap_t *
pcap_fopen_offline(FILE *fp, char *errbuf)
{
return (pcap_fopen_offline_with_tstamp_precision(fp,
PCAP_TSTAMP_PRECISION_MICRO, errbuf));
}
+#endif
/*
* Read packets from a capture file, and call the callback for each
@@ -531,7 +650,7 @@ pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
}
if ((fcode = p->fcode.bf_insns) == NULL ||
- bpf_filter(fcode, data, h.len, h.caplen)) {
+ pcap_filter(fcode, data, h.len, h.caplen)) {
(*callback)(user, &h, data);
if (++n >= cnt && cnt > 0)
break;
diff --git a/scanner.l b/scanner.l
index effcf815..06b9acc1 100644
--- a/scanner.l
+++ b/scanner.l
@@ -85,7 +85,6 @@
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-#include <ctype.h>
#include <string.h>
#include "pcap-int.h"
@@ -147,8 +146,7 @@ void pcap_set_column(int, yyscan_t);
#include "os-proto.h"
#endif
-static int stoi(char *);
-static inline int xdtoi(int);
+static int stou(char *, YYSTYPE *, compiler_state_t *);
/*
* Disable diagnostics in the code generated by Flex.
@@ -339,6 +337,8 @@ len|length return LEN;
inbound return INBOUND;
outbound return OUTBOUND;
+ifindex return IFINDEX;
+
vlan return VLAN;
mpls return MPLS;
pppoed return PPPOED;
@@ -393,7 +393,7 @@ hsls return HSLS;
">>" return RSH;
${B} { yylval->s = sdup(yyextra, yytext); return AID; }
{MAC} { yylval->s = sdup(yyextra, yytext); return EID; }
-{N} { yylval->i = stoi((char *)yytext); return NUM; }
+{N} { return stou(yytext, yylval, yyextra); }
({N}\.{N})|({N}\.{N}\.{N})|({N}\.{N}\.{N}\.{N}) {
yylval->s = sdup(yyextra, (char *)yytext); return HID; }
{V6} {
@@ -416,62 +416,66 @@ ${B} { yylval->s = sdup(yyextra, yytext); return AID; }
return HID6;
}
{B}:+({B}:+)+ { bpf_set_error(yyextra, "bogus ethernet address %s", yytext); yylval->s = NULL; return EID; }
-icmptype { yylval->i = 0; return NUM; }
-icmpcode { yylval->i = 1; return NUM; }
-icmp-echoreply { yylval->i = 0; return NUM; }
-icmp-unreach { yylval->i = 3; return NUM; }
-icmp-sourcequench { yylval->i = 4; return NUM; }
-icmp-redirect { yylval->i = 5; return NUM; }
-icmp-echo { yylval->i = 8; return NUM; }
-icmp-routeradvert { yylval->i = 9; return NUM; }
-icmp-routersolicit { yylval->i = 10; return NUM; }
-icmp-timxceed { yylval->i = 11; return NUM; }
-icmp-paramprob { yylval->i = 12; return NUM; }
-icmp-tstamp { yylval->i = 13; return NUM; }
-icmp-tstampreply { yylval->i = 14; return NUM; }
-icmp-ireq { yylval->i = 15; return NUM; }
-icmp-ireqreply { yylval->i = 16; return NUM; }
-icmp-maskreq { yylval->i = 17; return NUM; }
-icmp-maskreply { yylval->i = 18; return NUM; }
-
-icmp6type { yylval->i = 0; return NUM; }
-icmp6code { yylval->i = 1; return NUM; }
-
-icmp6-echo { yylval->i = 128; return NUM; }
-icmp6-echoreply { yylval->i = 129; return NUM; }
-icmp6-multicastlistenerquery { yylval->i = 130; return NUM; }
-icmp6-multicastlistenerreportv1 { yylval->i = 131; return NUM; }
-icmp6-multicastlistenerdone { yylval->i = 132; return NUM; }
-icmp6-routersolicit { yylval->i = 133; return NUM; }
-icmp6-routeradvert { yylval->i = 134; return NUM; }
-icmp6-neighborsolicit { yylval->i = 135; return NUM; }
-icmp6-neighboradvert { yylval->i = 136; return NUM; }
-icmp6-redirect { yylval->i = 137; return NUM; }
-icmp6-routerrenum { yylval->i = 138; return NUM; }
-icmp6-nodeinformationquery { yylval->i = 139; return NUM; }
-icmp6-nodeinformationresponse { yylval->i = 140; return NUM; }
-icmp6-ineighbordiscoverysolicit { yylval->i = 141; return NUM; }
-icmp6-ineighbordiscoveryadvert { yylval->i = 142; return NUM; }
-icmp6-multicastlistenerreportv2 { yylval->i = 143; return NUM; }
-icmp6-homeagentdiscoveryrequest { yylval->i = 144; return NUM; }
-icmp6-homeagentdiscoveryreply { yylval->i = 145; return NUM; }
-icmp6-mobileprefixsolicit { yylval->i = 146; return NUM; }
-icmp6-mobileprefixadvert { yylval->i = 147; return NUM; }
-icmp6-certpathsolicit { yylval->i = 148; return NUM; }
-icmp6-certpathadvert { yylval->i = 149; return NUM; }
-icmp6-multicastrouteradvert { yylval->i = 151; return NUM; }
-icmp6-multicastroutersolicit { yylval->i = 152; return NUM; }
-icmp6-multicastrouterterm { yylval->i = 153; return NUM; }
-
-tcpflags { yylval->i = 13; return NUM; }
-tcp-fin { yylval->i = 0x01; return NUM; }
-tcp-syn { yylval->i = 0x02; return NUM; }
-tcp-rst { yylval->i = 0x04; return NUM; }
-tcp-push { yylval->i = 0x08; return NUM; }
-tcp-ack { yylval->i = 0x10; return NUM; }
-tcp-urg { yylval->i = 0x20; return NUM; }
-tcp-ece { yylval->i = 0x40; return NUM; }
-tcp-cwr { yylval->i = 0x80; return NUM; }
+icmptype { yylval->h = 0; return NUM; }
+icmpcode { yylval->h = 1; return NUM; }
+icmp-echoreply { yylval->h = 0; return NUM; }
+icmp-unreach { yylval->h = 3; return NUM; }
+icmp-sourcequench { yylval->h = 4; return NUM; }
+icmp-redirect { yylval->h = 5; return NUM; }
+icmp-echo { yylval->h = 8; return NUM; }
+icmp-routeradvert { yylval->h = 9; return NUM; }
+icmp-routersolicit { yylval->h = 10; return NUM; }
+icmp-timxceed { yylval->h = 11; return NUM; }
+icmp-paramprob { yylval->h = 12; return NUM; }
+icmp-tstamp { yylval->h = 13; return NUM; }
+icmp-tstampreply { yylval->h = 14; return NUM; }
+icmp-ireq { yylval->h = 15; return NUM; }
+icmp-ireqreply { yylval->h = 16; return NUM; }
+icmp-maskreq { yylval->h = 17; return NUM; }
+icmp-maskreply { yylval->h = 18; return NUM; }
+
+icmp6type { yylval->h = 0; return NUM; }
+icmp6code { yylval->h = 1; return NUM; }
+
+icmp6-destinationunreach { yylval->h = 1; return NUM; }
+icmp6-packettoobig { yylval->h = 2; return NUM; }
+icmp6-timeexceeded { yylval->h = 3; return NUM; }
+icmp6-parameterproblem { yylval->h = 4; return NUM; }
+icmp6-echo { yylval->h = 128; return NUM; }
+icmp6-echoreply { yylval->h = 129; return NUM; }
+icmp6-multicastlistenerquery { yylval->h = 130; return NUM; }
+icmp6-multicastlistenerreportv1 { yylval->h = 131; return NUM; }
+icmp6-multicastlistenerdone { yylval->h = 132; return NUM; }
+icmp6-routersolicit { yylval->h = 133; return NUM; }
+icmp6-routeradvert { yylval->h = 134; return NUM; }
+icmp6-neighborsolicit { yylval->h = 135; return NUM; }
+icmp6-neighboradvert { yylval->h = 136; return NUM; }
+icmp6-redirect { yylval->h = 137; return NUM; }
+icmp6-routerrenum { yylval->h = 138; return NUM; }
+icmp6-nodeinformationquery { yylval->h = 139; return NUM; }
+icmp6-nodeinformationresponse { yylval->h = 140; return NUM; }
+icmp6-ineighbordiscoverysolicit { yylval->h = 141; return NUM; }
+icmp6-ineighbordiscoveryadvert { yylval->h = 142; return NUM; }
+icmp6-multicastlistenerreportv2 { yylval->h = 143; return NUM; }
+icmp6-homeagentdiscoveryrequest { yylval->h = 144; return NUM; }
+icmp6-homeagentdiscoveryreply { yylval->h = 145; return NUM; }
+icmp6-mobileprefixsolicit { yylval->h = 146; return NUM; }
+icmp6-mobileprefixadvert { yylval->h = 147; return NUM; }
+icmp6-certpathsolicit { yylval->h = 148; return NUM; }
+icmp6-certpathadvert { yylval->h = 149; return NUM; }
+icmp6-multicastrouteradvert { yylval->h = 151; return NUM; }
+icmp6-multicastroutersolicit { yylval->h = 152; return NUM; }
+icmp6-multicastrouterterm { yylval->h = 153; return NUM; }
+
+tcpflags { yylval->h = 13; return NUM; }
+tcp-fin { yylval->h = 0x01; return NUM; }
+tcp-syn { yylval->h = 0x02; return NUM; }
+tcp-rst { yylval->h = 0x04; return NUM; }
+tcp-push { yylval->h = 0x08; return NUM; }
+tcp-ack { yylval->h = 0x10; return NUM; }
+tcp-urg { yylval->h = 0x20; return NUM; }
+tcp-ece { yylval->h = 0x40; return NUM; }
+tcp-cwr { yylval->h = 0x80; return NUM; }
[A-Za-z0-9]([-_.A-Za-z0-9]*[.A-Za-z0-9])? {
yylval->s = sdup(yyextra, (char *)yytext); return ID; }
"\\"[^ !()\n\t]+ { yylval->s = sdup(yyextra, (char *)yytext + 1); return ID; }
@@ -483,40 +487,110 @@ tcp-cwr { yylval->i = 0x80; return NUM; }
*/
DIAG_ON_FLEX
-/* Hex digit to integer. */
-static inline int
-xdtoi(int c)
-{
- if (isdigit(c))
- return c - '0';
- else if (islower(c))
- return c - 'a' + 10;
- else
- return c - 'A' + 10;
-}
-
/*
- * Convert string to integer. Just like atoi(), but checks for
+ * 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
-stoi(char *s)
+stou(char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
{
- int base = 10;
- int n = 0;
-
+ bpf_u_int32 n = 0;
+ unsigned int digit;
+ char *s = yytext_arg;
+
+ /*
+ * yytext_arg 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') {
- s += 2;
- base = 16;
- }
- else {
- base = 8;
+ /*
+ * Begins with 0x or 0X, so hex.
+ * Guaranteed to be all hex digits following the
+ * prefix, so anything that's not 0-9 or a-f is
+ * A-F.
+ */
+ s += 2; /* skip the prefix */
+ while ((digit = *s++) != '\0') {
+ if (digit >= '0' && digit <= '9')
+ digit = digit - '0';
+ else if (digit >= 'a' && digit <= 'f')
+ digit = digit - 'a' + 10;
+ else
+ digit = digit - 'A' + 10;
+
+ /*
+ * Check for overflow.
+ */
+ if (n > 0xFFFFFFFU) {
+ /*
+ * We have more than 28 bits of
+ * number, and are about to
+ * 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;
+ }
+ n = (n << 4) + digit;
+ }
+ } else {
+ /*
+ * Begins with 0, but not 0x or 0X, so octal.
+ * Guaranteed to be all *decimal* digits following
+ * the prefix, so we need to catch 8 and 9 and
+ * report an error.
+ */
s += 1;
+ while ((digit = *s++) != '\0') {
+ 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;
+ }
+ if (n > 03777777777U) {
+ /*
+ * We have more than 29 bits of
+ * number, and are about to add
+ * 3 more; that won't fit in
+ * 32 bits.
+ */
+ bpf_set_error(yyextra_arg,
+ "number %s overflows 32 bits",
+ yytext_arg);
+ return LEX_ERROR;
+ }
+ n = (n << 3) + digit;
+ }
+ }
+ } else {
+ /*
+ * Decimal.
+ */
+ while ((digit = *s++) != '\0') {
+ digit = digit - '0';
+#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;
+ }
+ n = (n * 10) + digit;
}
}
- while (*s)
- n = n * base + xdtoi(*s++);
- return n;
+ yylval_arg->h = n;
+ return NUM;
}
diff --git a/sf-pcap.c b/sf-pcap.c
index 60c73a89..d8443e98 100644
--- a/sf-pcap.c
+++ b/sf-pcap.c
@@ -194,8 +194,8 @@ pcap_check_header(const uint8_t *magic, FILE *fp, u_int precision, char *errbuf,
pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
errno, "error reading dump file");
} else {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "truncated dump file; tried to read %" PRIsize " file header bytes, only got %" PRIsize,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "truncated dump file; tried to read %zu file header bytes, only got %zu",
sizeof(hdr), amt_read);
}
*err = 1;
@@ -215,7 +215,7 @@ pcap_check_header(const uint8_t *magic, FILE *fp, u_int precision, char *errbuf,
}
if (hdr.version_major < PCAP_VERSION_MAJOR) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"archaic pcap savefile format");
*err = 1;
return (NULL);
@@ -229,7 +229,7 @@ pcap_check_header(const uint8_t *magic, FILE *fp, u_int precision, char *errbuf,
hdr.version_minor <= PCAP_VERSION_MINOR) ||
(hdr.version_major == 543 &&
hdr.version_minor == 0))) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"unsupported pcap savefile version %u.%u",
hdr.version_major, hdr.version_minor);
*err = 1;
@@ -240,7 +240,7 @@ pcap_check_header(const uint8_t *magic, FILE *fp, u_int precision, char *errbuf,
* OK, this is a good pcap file.
* Allocate a pcap_t for it.
*/
- p = pcap_open_offline_common(errbuf, sizeof (struct pcap_sf));
+ p = PCAP_OPEN_OFFLINE_COMMON(errbuf, struct pcap_sf);
if (p == NULL) {
/* Allocation failed. */
*err = 1;
@@ -249,7 +249,6 @@ pcap_check_header(const uint8_t *magic, FILE *fp, u_int precision, char *errbuf,
p->swapped = swapped;
p->version_major = hdr.version_major;
p->version_minor = hdr.version_minor;
- p->tzoff = hdr.thiszone;
p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype));
p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype);
p->snapshot = pcap_adjust_snapshot(p->linktype, hdr.snaplen);
@@ -292,7 +291,7 @@ pcap_check_header(const uint8_t *magic, FILE *fp, u_int precision, char *errbuf,
ps->scale_type = PASS_THROUGH;
} else {
/*
- * The file has microoseconds, the user
+ * The file has microseconds, the user
* wants nanoseconds; scale the
* precision up.
*/
@@ -301,7 +300,7 @@ pcap_check_header(const uint8_t *magic, FILE *fp, u_int precision, char *errbuf,
break;
default:
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"unknown time stamp resolution %u", precision);
free(p);
*err = 1;
@@ -404,7 +403,7 @@ pcap_check_header(const uint8_t *magic, FILE *fp, u_int precision, char *errbuf,
p->bufsize = 2048;
p->buffer = malloc(p->bufsize);
if (p->buffer == NULL) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
free(p);
*err = 1;
return (NULL);
@@ -425,7 +424,7 @@ grow_buffer(pcap_t *p, u_int bufsize)
bigger_buffer = realloc(p->buffer, bufsize);
if (bigger_buffer == NULL) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "out of memory");
return (0);
}
p->buffer = bigger_buffer;
@@ -462,8 +461,8 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
return (-1);
} else {
if (amt_read != 0) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "truncated dump file; tried to read %" PRIsize " header bytes, only got %" PRIsize,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "truncated dump file; tried to read %zu header bytes, only got %zu",
ps->hdrsize, amt_read);
return (-1);
}
@@ -546,11 +545,11 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
* below.)
*/
if (hdr->caplen > (bpf_u_int32)p->snapshot) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"invalid packet capture length %u, bigger than "
"snaplen of %d", hdr->caplen, p->snapshot);
} else {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"invalid packet capture length %u, bigger than "
"maximum of %u", hdr->caplen,
max_snaplen_for_dlt(p->linktype));
@@ -622,8 +621,8 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
* that would fail because we got EOF before
* the read finished.
*/
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "truncated dump file; tried to read %u captured bytes, only got %" PRIsize,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "truncated dump file; tried to read %u captured bytes, only got %zu",
p->snapshot, amt_read);
}
return (-1);
@@ -646,8 +645,8 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
PCAP_ERRBUF_SIZE, errno,
"error reading dump file");
} else {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "truncated dump file; tried to read %u captured bytes, only got %" PRIsize,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "truncated dump file; tried to read %u captured bytes, only got %zu",
hdr->caplen, bytes_read);
}
return (-1);
@@ -673,7 +672,7 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
new_bufsize = hdr->caplen;
/*
- * http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+ * https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
*/
new_bufsize--;
new_bufsize |= new_bufsize >> 1;
@@ -698,8 +697,8 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
PCAP_ERRBUF_SIZE, errno,
"error reading dump file");
} else {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "truncated dump file; tried to read %u captured bytes, only got %" PRIsize,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "truncated dump file; tried to read %u captured bytes, only got %zu",
hdr->caplen, amt_read);
}
return (-1);
@@ -714,7 +713,7 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
}
static int
-sf_write_header(pcap_t *p, FILE *fp, int linktype, int thiszone, int snaplen)
+sf_write_header(pcap_t *p, FILE *fp, int linktype, int snaplen)
{
struct pcap_file_header hdr;
@@ -722,9 +721,15 @@ sf_write_header(pcap_t *p, FILE *fp, int linktype, int thiszone, int snaplen)
hdr.version_major = PCAP_VERSION_MAJOR;
hdr.version_minor = PCAP_VERSION_MINOR;
- hdr.thiszone = thiszone;
- hdr.snaplen = snaplen;
+ /*
+ * https://www.tcpdump.org/manpages/pcap-savefile.5.txt states:
+ * thiszone: 4-byte time zone offset; this is always 0.
+ * sigfigs: 4-byte number giving the accuracy of time stamps
+ * in the file; this is always 0.
+ */
+ hdr.thiszone = 0;
hdr.sigfigs = 0;
+ hdr.snaplen = snaplen;
hdr.linktype = linktype;
if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1)
@@ -743,8 +748,12 @@ pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
struct pcap_sf_pkthdr sf_hdr;
f = (FILE *)user;
- sf_hdr.ts.tv_sec = h->ts.tv_sec;
- sf_hdr.ts.tv_usec = h->ts.tv_usec;
+ /*
+ * Better not try writing pcap files after
+ * 2038-01-19 03:14:07 UTC; switch to pcapng.
+ */
+ sf_hdr.ts.tv_sec = (bpf_int32)h->ts.tv_sec;
+ sf_hdr.ts.tv_usec = (bpf_int32)h->ts.tv_usec;
sf_hdr.caplen = h->caplen;
sf_hdr.len = h->len;
/* XXX we should check the return status */
@@ -769,7 +778,7 @@ pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname)
else
setvbuf(f, NULL, _IONBF, 0);
#endif
- if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) {
+ if (sf_write_header(p, f, linktype, p->snapshot) == -1) {
pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
errno, "Can't write to %s", fname);
if (f != stdout)
@@ -793,14 +802,14 @@ pcap_dump_open(pcap_t *p, const char *fname)
* link-layer type, so we can't use it.
*/
if (!p->activated) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"%s: not-yet-activated pcap_t passed to pcap_dump_open",
fname);
return (NULL);
}
linktype = dlt_to_linktype(p->linktype);
if (linktype == -1) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"%s: link-layer type %d isn't supported in savefiles",
fname, p->linktype);
return (NULL);
@@ -808,7 +817,7 @@ pcap_dump_open(pcap_t *p, const char *fname)
linktype |= p->linktype_ext;
if (fname == NULL) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"A null pointer was supplied as the file name");
return NULL;
}
@@ -822,7 +831,7 @@ pcap_dump_open(pcap_t *p, const char *fname)
* required on Windows, as the file is a binary file
* and must be written in binary mode.
*/
- f = fopen(fname, "wb");
+ f = charset_fopen(fname, "wb");
if (f == NULL) {
pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
errno, "%s", fname);
@@ -875,7 +884,7 @@ pcap_dump_fopen(pcap_t *p, FILE *f)
linktype = dlt_to_linktype(p->linktype);
if (linktype == -1) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"stream: link-layer type %d isn't supported in savefiles",
p->linktype);
return (NULL);
@@ -895,14 +904,14 @@ pcap_dump_open_append(pcap_t *p, const char *fname)
linktype = dlt_to_linktype(p->linktype);
if (linktype == -1) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"%s: link-layer type %d isn't supported in savefiles",
fname, linktype);
return (NULL);
}
if (fname == NULL) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"A null pointer was supplied as the file name");
return NULL;
}
@@ -922,7 +931,7 @@ pcap_dump_open_append(pcap_t *p, const char *fname)
* even though it does nothing. It's required on Windows, as the
* file is a binary file and must be read in binary mode.
*/
- f = fopen(fname, "ab+");
+ f = charset_fopen(fname, "ab+");
if (f == NULL) {
pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
errno, "%s", fname);
@@ -955,7 +964,7 @@ pcap_dump_open_append(pcap_t *p, const char *fname)
(void)fclose(f);
return (NULL);
} else if (feof(f) && amt_read > 0) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"%s: truncated pcap file header", fname);
(void)fclose(f);
return (NULL);
@@ -991,7 +1000,7 @@ pcap_dump_open_append(pcap_t *p, const char *fname)
case TCPDUMP_MAGIC:
if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_MICRO) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"%s: different time stamp precision, cannot append to file", fname);
(void)fclose(f);
return (NULL);
@@ -1000,7 +1009,7 @@ pcap_dump_open_append(pcap_t *p, const char *fname)
case NSEC_TCPDUMP_MAGIC:
if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_NANO) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"%s: different time stamp precision, cannot append to file", fname);
(void)fclose(f);
return (NULL);
@@ -1009,7 +1018,7 @@ pcap_dump_open_append(pcap_t *p, const char *fname)
case SWAPLONG(TCPDUMP_MAGIC):
case SWAPLONG(NSEC_TCPDUMP_MAGIC):
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"%s: different byte order, cannot append to file", fname);
(void)fclose(f);
return (NULL);
@@ -1018,13 +1027,13 @@ pcap_dump_open_append(pcap_t *p, const char *fname)
case SWAPLONG(KUZNETZOV_TCPDUMP_MAGIC):
case NAVTEL_TCPDUMP_MAGIC:
case SWAPLONG(NAVTEL_TCPDUMP_MAGIC):
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"%s: not a pcap file to which we can append", fname);
(void)fclose(f);
return (NULL);
default:
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"%s: not a pcap file", fname);
(void)fclose(f);
return (NULL);
@@ -1035,20 +1044,20 @@ pcap_dump_open_append(pcap_t *p, const char *fname)
*/
if (ph.version_major != PCAP_VERSION_MAJOR ||
ph.version_minor != PCAP_VERSION_MINOR) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"%s: version is %u.%u, cannot append to file", fname,
ph.version_major, ph.version_minor);
(void)fclose(f);
return (NULL);
}
if ((bpf_u_int32)linktype != ph.linktype) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"%s: different linktype, cannot append to file", fname);
(void)fclose(f);
return (NULL);
}
if ((bpf_u_int32)p->snapshot != ph.snaplen) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"%s: different snaplen, cannot append to file", fname);
(void)fclose(f);
return (NULL);
@@ -1057,7 +1066,7 @@ pcap_dump_open_append(pcap_t *p, const char *fname)
/*
* A header isn't present; attempt to write it.
*/
- if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) {
+ if (sf_write_header(p, f, linktype, p->snapshot) == -1) {
pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
errno, "Can't write to %s", fname);
(void)fclose(f);
diff --git a/sf-pcapng.c b/sf-pcapng.c
index afaeb056..f7f413d3 100644
--- a/sf-pcapng.c
+++ b/sf-pcapng.c
@@ -197,6 +197,7 @@ typedef enum {
* Per-interface information.
*/
struct pcap_ng_if {
+ uint32_t snaplen; /* snapshot length */
uint64_t tsresol; /* time stamp resolution */
tstamp_scale_type_t scale_type; /* how to scale */
uint64_t scale_factor; /* time stamp scale factor for power-of-10 tsresol */
@@ -265,8 +266,8 @@ read_bytes(FILE *fp, void *buf, size_t bytes_to_read, int fail_on_eof,
} else {
if (amt_read == 0 && !fail_on_eof)
return (0); /* EOF */
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "truncated pcapng dump file; tried to read %" PRIsize " bytes, only got %" PRIsize,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "truncated pcapng dump file; tried to read %zu bytes, only got %zu",
bytes_to_read, amt_read);
}
return (-1);
@@ -301,8 +302,8 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf)
*/
if (bhdr.total_length < sizeof(struct block_header) +
sizeof(struct block_trailer)) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "block in pcapng dump file has a length of %u < %" PRIsize,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "block in pcapng dump file has a length of %u < %zu",
bhdr.total_length,
sizeof(struct block_header) + sizeof(struct block_trailer));
return (-1);
@@ -315,8 +316,8 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf)
/*
* No. Report that as an error.
*/
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "block in pcapng dump file has a length of %u that is not a multiple of 4" PRIsize,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "block in pcapng dump file has a length of %u that is not a multiple of 4",
bhdr.total_length);
return (-1);
}
@@ -332,13 +333,13 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf)
void *bigger_buffer;
if (bhdr.total_length > ps->max_blocksize) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcapng block size %u > maximum %u", bhdr.total_length,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcapng block size %u > maximum %u", bhdr.total_length,
ps->max_blocksize);
return (-1);
}
bigger_buffer = realloc(p->buffer, bhdr.total_length);
if (bigger_buffer == NULL) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
return (-1);
}
p->buffer = bigger_buffer;
@@ -369,7 +370,7 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf)
/*
* No.
*/
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"block total length in header and trailer don't match");
return (-1);
}
@@ -394,7 +395,7 @@ get_from_block_data(struct block_cursor *cursor, size_t chunk_size,
* the block data.
*/
if (cursor->data_remaining < chunk_size) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"block of type %u in pcapng dump file is too short",
cursor->block_type);
return (NULL);
@@ -495,7 +496,7 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, uint64_t *tsresol,
case OPT_ENDOFOPT:
if (opthdr->option_length != 0) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Interface Description Block has opt_endofopt option with length %u != 0",
opthdr->option_length);
return (-1);
@@ -504,13 +505,13 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, uint64_t *tsresol,
case IF_TSRESOL:
if (opthdr->option_length != 1) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Interface Description Block has if_tsresol option with length %u != 1",
opthdr->option_length);
return (-1);
}
if (saw_tsresol) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Interface Description Block has more than one if_tsresol option");
return (-1);
}
@@ -527,7 +528,7 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, uint64_t *tsresol,
* Resolution is too high; 2^-{res}
* won't fit in a 64-bit value.
*/
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Interface Description Block if_tsresol option resolution 2^-%u is too high",
tsresol_shift);
return (-1);
@@ -547,7 +548,7 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, uint64_t *tsresol,
* the largest 64-bit unsigned
* value is ~1.8*10^19).
*/
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Interface Description Block if_tsresol option resolution 10^-%u is too high",
tsresol_opt);
return (-1);
@@ -561,13 +562,13 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, uint64_t *tsresol,
case IF_TSOFFSET:
if (opthdr->option_length != 8) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Interface Description Block has if_tsoffset option with length %u != 8",
opthdr->option_length);
return (-1);
}
if (saw_tsoffset) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Interface Description Block has more than one if_tsoffset option");
return (-1);
}
@@ -587,7 +588,8 @@ done:
}
static int
-add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf)
+add_interface(pcap_t *p, struct interface_description_block *idbp,
+ struct block_cursor *cursor, char *errbuf)
{
struct pcap_ng_sf *ps;
uint64_t tsresol;
@@ -644,7 +646,7 @@ add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf)
* possible 32-bit power of 2, as we do
* size doubling.
*/
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"more than %u interfaces in the file",
0x80000000U);
return (0);
@@ -675,7 +677,7 @@ add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf)
* (unsigned) value divided by
* sizeof (struct pcap_ng_if).
*/
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"more than %u interfaces in the file",
0xFFFFFFFFU / ((u_int)sizeof (struct pcap_ng_if)));
return (0);
@@ -687,7 +689,7 @@ add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf)
* We ran out of memory.
* Give up.
*/
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"out of memory for per-interface information (%u interfaces)",
ps->ifcount);
return (0);
@@ -696,6 +698,8 @@ add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf)
ps->ifaces = new_ifaces;
}
+ ps->ifaces[ps->ifcount - 1].snaplen = idbp->snaplen;
+
/*
* Set the default time stamp resolution and offset.
*/
@@ -858,8 +862,8 @@ pcap_ng_check_header(const uint8_t *magic, FILE *fp, u_int precision,
*/
if (total_length < sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer) ||
(total_length > BT_SHB_INSANE_MAX)) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "Section Header Block in pcapng dump file has invalid length %" PRIsize " < _%u_ < %u (BT_SHB_INSANE_MAX)",
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "Section Header Block in pcapng dump file has invalid length %zu < _%u_ < %u (BT_SHB_INSANE_MAX)",
sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer),
total_length,
BT_SHB_INSANE_MAX);
@@ -872,7 +876,7 @@ pcap_ng_check_header(const uint8_t *magic, FILE *fp, u_int precision,
* OK, this is a good pcapng file.
* Allocate a pcap_t for it.
*/
- p = pcap_open_offline_common(errbuf, sizeof (struct pcap_ng_sf));
+ p = PCAP_OPEN_OFFLINE_COMMON(errbuf, struct pcap_ng_sf);
if (p == NULL) {
/* Allocation failed. */
*err = 1;
@@ -895,7 +899,7 @@ pcap_ng_check_header(const uint8_t *magic, FILE *fp, u_int precision,
break;
default:
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"unknown time stamp resolution %u", precision);
free(p);
*err = 1;
@@ -925,7 +929,7 @@ pcap_ng_check_header(const uint8_t *magic, FILE *fp, u_int precision,
p->bufsize = total_length;
p->buffer = malloc(p->bufsize);
if (p->buffer == NULL) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
free(p);
*err = 1;
return (NULL);
@@ -961,7 +965,7 @@ pcap_ng_check_header(const uint8_t *magic, FILE *fp, u_int precision,
/* currently only SHB version 1.0 is supported */
if (! (shbp->major_version == PCAP_NG_VERSION_MAJOR &&
shbp->minor_version == PCAP_NG_VERSION_MINOR)) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"unsupported pcapng savefile version %u.%u",
shbp->major_version, shbp->minor_version);
goto fail;
@@ -984,7 +988,7 @@ pcap_ng_check_header(const uint8_t *magic, FILE *fp, u_int precision,
status = read_block(fp, p, &cursor, errbuf);
if (status == 0) {
/* EOF - no IDB in this file */
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"the capture file has no Interface Description Blocks");
goto fail;
}
@@ -1013,7 +1017,7 @@ pcap_ng_check_header(const uint8_t *magic, FILE *fp, u_int precision,
/*
* Try to add this interface.
*/
- if (!add_interface(p, &cursor, errbuf))
+ if (!add_interface(p, idbp, &cursor, errbuf))
goto fail;
goto done;
@@ -1026,7 +1030,7 @@ pcap_ng_check_header(const uint8_t *magic, FILE *fp, u_int precision,
* not valid, as we don't know what link-layer
* encapsulation the packet has.
*/
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"the capture file has a packet block before any Interface Description Blocks");
goto fail;
@@ -1039,7 +1043,6 @@ pcap_ng_check_header(const uint8_t *magic, FILE *fp, u_int precision,
}
done:
- p->tzoff = 0; /* XXX - not used in pcap */
p->linktype = linktype_to_dlt(idbp->linktype);
p->snapshot = pcap_adjust_snapshot(p->linktype, idbp->snaplen);
p->linktype_ext = 0;
@@ -1231,7 +1234,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
* interfaces?
*/
if (p->linktype != idbp->linktype) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"an interface has a type %u different from the type of the first interface",
idbp->linktype);
return (-1);
@@ -1243,8 +1246,8 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
*/
if ((bpf_u_int32)p->snapshot !=
pcap_adjust_snapshot(p->linktype, idbp->snaplen)) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "an interface has a snapshot length %u different from the type of the first interface",
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "an interface has a snapshot length %u different from the snapshot length of the first interface",
idbp->snaplen);
return (-1);
}
@@ -1252,7 +1255,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
/*
* Try to add this interface.
*/
- if (!add_interface(p, &cursor, p->errbuf))
+ if (!add_interface(p, idbp, &cursor, p->errbuf))
return (-1);
break;
@@ -1295,7 +1298,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
/*
* Byte order changes.
*/
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"the file has sections with different byte orders");
return (-1);
@@ -1303,7 +1306,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
/*
* Not a valid SHB.
*/
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"the file has a section with a bad byte order magic field");
return (-1);
}
@@ -1313,7 +1316,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
* we handle.
*/
if (shbp->major_version != PCAP_NG_VERSION_MAJOR) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"unknown pcapng savefile major version number %u",
shbp->major_version);
return (-1);
@@ -1347,14 +1350,14 @@ found:
/*
* Yes. Fail.
*/
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"a packet arrived on interface %u, but there's no Interface Description Block for that interface",
interface_id);
return (-1);
}
if (hdr->caplen > (bpf_u_int32)p->snapshot) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"invalid packet capture length %u, bigger than "
"snaplen of %d", hdr->caplen, p->snapshot);
return (-1);
diff --git a/sockutils.c b/sockutils.c
index d3e94649..c1ec9a5a 100644
--- a/sockutils.c
+++ b/sockutils.c
@@ -56,11 +56,7 @@
#include <errno.h> /* for the errno variable */
#include <stdio.h> /* for the stderr file */
#include <stdlib.h> /* for malloc() and free() */
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#else
-#define INT_MAX 2147483647
-#endif
+#include <limits.h> /* for INT_MAX */
#include "pcap-int.h"
@@ -71,7 +67,7 @@
/*
* Winsock initialization.
*
- * Ask for WinSock 2.2.
+ * Ask for Winsock 2.2.
*/
#define WINSOCK_MAJOR_VERSION 2
#define WINSOCK_MINOR_VERSION 2
@@ -124,8 +120,31 @@ static int sock_ismcastaddr(const struct sockaddr *saddr);
* *
****************************************************/
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+const uint8_t *fuzzBuffer;
+size_t fuzzSize;
+size_t fuzzPos;
+
+void sock_initfuzz(const uint8_t *Data, size_t Size) {
+ fuzzPos = 0;
+ fuzzSize = Size;
+ fuzzBuffer = Data;
+}
+
+static int fuzz_recv(char *bufp, int remaining) {
+ if (remaining > fuzzSize - fuzzPos) {
+ remaining = fuzzSize - fuzzPos;
+ }
+ if (fuzzPos < fuzzSize) {
+ memcpy(bufp, fuzzBuffer + fuzzPos, remaining);
+ }
+ fuzzPos += remaining;
+ return remaining;
+}
+#endif
+
/*
- * Format an error message given an errno value (UN*X) or a WinSock error
+ * 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)
@@ -201,7 +220,7 @@ int sock_init(char *errbuf, int errbuflen)
WINSOCK_MINOR_VERSION), &wsaData) != 0)
{
if (errbuf)
- pcap_snprintf(errbuf, errbuflen, "Failed to initialize Winsock\n");
+ snprintf(errbuf, errbuflen, "Failed to initialize Winsock\n");
WSACleanup();
@@ -271,7 +290,7 @@ static int sock_ismcastaddr(const struct sockaddr *saddr)
*
* In case of a server socket, the function calls socket(), bind() and listen().
*
- * This function is usually preceeded by the sock_initaddress().
+ * This function is usually preceded by the sock_initaddress().
*
* \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
@@ -375,7 +394,7 @@ SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf,
(char *)&on, sizeof (int)) == -1)
{
if (errbuf)
- pcap_snprintf(errbuf, errbuflen, "setsockopt(IPV6_V6ONLY)");
+ snprintf(errbuf, errbuflen, "setsockopt(IPV6_V6ONLY)");
closesocket(sock);
return INVALID_SOCKET;
}
@@ -419,7 +438,9 @@ SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf,
*/
while (tempaddrinfo)
{
-
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ break;
+#endif
if (connect(sock, tempaddrinfo->ai_addr, (int) tempaddrinfo->ai_addrlen) == -1)
{
size_t msglen;
@@ -436,7 +457,7 @@ SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf,
/* Returns the numeric address of the host that triggered the error */
sock_getascii_addrport((struct sockaddr_storage *) tempaddrinfo->ai_addr, TmpBuffer, sizeof(TmpBuffer), NULL, 0, NI_NUMERICHOST, TmpBuffer, sizeof(TmpBuffer));
- pcap_snprintf(errbufptr, bufspaceleft,
+ snprintf(errbufptr, bufspaceleft,
"Is the server properly installed on %s? %s", TmpBuffer, SocketErrorMessage);
/* In case more then one 'connect' fails, we manage to keep all the error messages */
@@ -527,52 +548,52 @@ get_gai_errstring(char *errbuf, int errbuflen, const char *prefix, int err,
char hostport[PCAP_ERRBUF_SIZE];
if (hostname != NULL && portname != NULL)
- pcap_snprintf(hostport, PCAP_ERRBUF_SIZE, "%s:%s",
+ snprintf(hostport, PCAP_ERRBUF_SIZE, "%s:%s",
hostname, portname);
else if (hostname != NULL)
- pcap_snprintf(hostport, PCAP_ERRBUF_SIZE, "%s",
+ snprintf(hostport, PCAP_ERRBUF_SIZE, "%s",
hostname);
else if (portname != NULL)
- pcap_snprintf(hostport, PCAP_ERRBUF_SIZE, ":%s",
+ snprintf(hostport, PCAP_ERRBUF_SIZE, ":%s",
portname);
else
- pcap_snprintf(hostport, PCAP_ERRBUF_SIZE, "<no host or port!>");
+ snprintf(hostport, PCAP_ERRBUF_SIZE, "<no host or port!>");
switch (err)
{
#ifdef EAI_ADDRFAMILY
case EAI_ADDRFAMILY:
- pcap_snprintf(errbuf, errbuflen,
+ snprintf(errbuf, errbuflen,
"%sAddress family for %s not supported",
prefix, hostport);
break;
#endif
case EAI_AGAIN:
- pcap_snprintf(errbuf, errbuflen,
+ snprintf(errbuf, errbuflen,
"%s%s could not be resolved at this time",
prefix, hostport);
break;
case EAI_BADFLAGS:
- pcap_snprintf(errbuf, errbuflen,
+ snprintf(errbuf, errbuflen,
"%sThe ai_flags parameter for looking up %s had an invalid value",
prefix, hostport);
break;
case EAI_FAIL:
- pcap_snprintf(errbuf, errbuflen,
+ snprintf(errbuf, errbuflen,
"%sA non-recoverable error occurred when attempting to resolve %s",
prefix, hostport);
break;
case EAI_FAMILY:
- pcap_snprintf(errbuf, errbuflen,
+ snprintf(errbuf, errbuflen,
"%sThe address family for looking up %s was not recognized",
prefix, hostport);
break;
case EAI_MEMORY:
- pcap_snprintf(errbuf, errbuflen,
+ snprintf(errbuf, errbuflen,
"%sOut of memory trying to allocate storage when looking up %s",
prefix, hostport);
break;
@@ -589,26 +610,26 @@ get_gai_errstring(char *errbuf, int errbuflen, const char *prefix, int err,
*/
#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME
case EAI_NODATA:
- pcap_snprintf(errbuf, errbuflen,
+ snprintf(errbuf, errbuflen,
"%sNo address associated with %s",
prefix, hostport);
break;
#endif
case EAI_NONAME:
- pcap_snprintf(errbuf, errbuflen,
+ snprintf(errbuf, errbuflen,
"%sThe host name %s couldn't be resolved",
prefix, hostport);
break;
case EAI_SERVICE:
- pcap_snprintf(errbuf, errbuflen,
+ snprintf(errbuf, errbuflen,
"%sThe service value specified when looking up %s as not recognized for the socket type",
prefix, hostport);
break;
case EAI_SOCKTYPE:
- pcap_snprintf(errbuf, errbuflen,
+ snprintf(errbuf, errbuflen,
"%sThe socket type specified when looking up %s as not recognized",
prefix, hostport);
break;
@@ -618,15 +639,15 @@ get_gai_errstring(char *errbuf, int errbuflen, const char *prefix, int err,
/*
* Assumed to be UN*X.
*/
- pcap_snprintf(errbuf, errbuflen,
- "%sAn error occurred when looking up %s: %s",
- prefix, hostport, pcap_strerror(errno));
+ pcap_fmt_errmsg_for_errno(errbuf, errbuflen, errno,
+ "%sAn error occurred when looking up %s",
+ prefix, hostport);
break;
#endif
#ifdef EAI_BADHINTS
case EAI_BADHINTS:
- pcap_snprintf(errbuf, errbuflen,
+ snprintf(errbuf, errbuflen,
"%sInvalid value for hints when looking up %s",
prefix, hostport);
break;
@@ -634,7 +655,7 @@ get_gai_errstring(char *errbuf, int errbuflen, const char *prefix, int err,
#ifdef EAI_PROTOCOL
case EAI_PROTOCOL:
- pcap_snprintf(errbuf, errbuflen,
+ snprintf(errbuf, errbuflen,
"%sResolved protocol when looking up %s is unknown",
prefix, hostport);
break;
@@ -642,14 +663,14 @@ get_gai_errstring(char *errbuf, int errbuflen, const char *prefix, int err,
#ifdef EAI_OVERFLOW
case EAI_OVERFLOW:
- pcap_snprintf(errbuf, errbuflen,
+ snprintf(errbuf, errbuflen,
"%sArgument buffer overflow when looking up %s",
prefix, hostport);
break;
#endif
default:
- pcap_snprintf(errbuf, errbuflen,
+ snprintf(errbuf, errbuflen,
"%sgetaddrinfo() error %d when looking up %s",
prefix, err, hostport);
break;
@@ -726,7 +747,7 @@ int sock_initaddress(const char *host, const char *port,
((*addrinfo)->ai_family != PF_INET6))
{
if (errbuf)
- pcap_snprintf(errbuf, errbuflen, "getaddrinfo(): socket type not supported");
+ snprintf(errbuf, errbuflen, "getaddrinfo(): socket type not supported");
freeaddrinfo(*addrinfo);
*addrinfo = NULL;
return -1;
@@ -739,7 +760,7 @@ int sock_initaddress(const char *host, const char *port,
(sock_ismcastaddr((*addrinfo)->ai_addr) == 0))
{
if (errbuf)
- pcap_snprintf(errbuf, errbuflen, "getaddrinfo(): multicast addresses are not valid when using TCP streams");
+ snprintf(errbuf, errbuflen, "getaddrinfo(): multicast addresses are not valid when using TCP streams");
freeaddrinfo(*addrinfo);
*addrinfo = NULL;
return -1;
@@ -775,7 +796,7 @@ int sock_initaddress(const char *host, const char *port,
* '-2' if we got one of those errors.
* For errors, an error message is returned in the 'errbuf' variable.
*/
-int sock_send(SOCKET sock, const char *buffer, size_t size,
+int sock_send(SOCKET sock, SSL *ssl _U_NOSSL_, const char *buffer, size_t size,
char *errbuf, int errbuflen)
{
int remaining;
@@ -785,7 +806,7 @@ int sock_send(SOCKET sock, const char *buffer, size_t size,
{
if (errbuf)
{
- pcap_snprintf(errbuf, errbuflen,
+ snprintf(errbuf, errbuflen,
"Can't send more than %u bytes with sock_send",
INT_MAX);
}
@@ -794,6 +815,13 @@ int sock_send(SOCKET sock, const char *buffer, size_t size,
remaining = (int)size;
do {
+#ifdef HAVE_OPENSSL
+ if (ssl) return ssl_send(ssl, buffer, remaining, errbuf, errbuflen);
+#endif
+
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ nsent = remaining;
+#else
#ifdef MSG_NOSIGNAL
/*
* Send with MSG_NOSIGNAL, so that we don't get SIGPIPE
@@ -805,6 +833,7 @@ int sock_send(SOCKET sock, const char *buffer, size_t size,
#else
nsent = send(sock, buffer, remaining, 0);
#endif
+#endif //FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if (nsent == -1)
{
@@ -912,7 +941,7 @@ int sock_bufferize(const char *buffer, int size, char *tempbuf, int *offset, int
if ((*offset + size) > totsize)
{
if (errbuf)
- pcap_snprintf(errbuf, errbuflen, "Not enough space in the temporary send buffer.");
+ snprintf(errbuf, errbuflen, "Not enough space in the temporary send buffer.");
return -1;
}
@@ -970,9 +999,10 @@ int sock_bufferize(const char *buffer, int size, char *tempbuf, int *offset, int
* The error message is returned in the 'errbuf' variable.
*/
-int sock_recv(SOCKET sock, void *buffer, size_t size, int flags,
- char *errbuf, int errbuflen)
+int sock_recv(SOCKET sock, SSL *ssl _U_NOSSL_, void *buffer, size_t size,
+ int flags, char *errbuf, int errbuflen)
{
+ int recv_flags = 0;
char *bufp = buffer;
int remaining;
ssize_t nread;
@@ -985,13 +1015,16 @@ int sock_recv(SOCKET sock, void *buffer, size_t size, int flags,
{
if (errbuf)
{
- pcap_snprintf(errbuf, errbuflen,
+ snprintf(errbuf, errbuflen,
"Can't read more than %u bytes with sock_recv",
INT_MAX);
}
return -1;
}
+ if (flags & SOCK_MSG_PEEK)
+ recv_flags |= MSG_PEEK;
+
bufp = (char *) buffer;
remaining = (int) size;
@@ -1000,7 +1033,22 @@ int sock_recv(SOCKET sock, void *buffer, size_t size, int flags,
* Win32.
*/
for (;;) {
- nread = recv(sock, bufp, remaining, 0);
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ nread = fuzz_recv(bufp, remaining);
+#elif defined(HAVE_OPENSSL)
+ if (ssl)
+ {
+ /*
+ * XXX - what about MSG_PEEK?
+ */
+ nread = ssl_recv(ssl, bufp, remaining, errbuf, errbuflen);
+ if (nread == -2) return -1;
+ }
+ else
+ nread = recv(sock, bufp, remaining, recv_flags);
+#else
+ nread = recv(sock, bufp, remaining, recv_flags);
+#endif
if (nread == -1)
{
@@ -1024,7 +1072,7 @@ int sock_recv(SOCKET sock, void *buffer, size_t size, int flags,
*/
if (errbuf)
{
- pcap_snprintf(errbuf, errbuflen,
+ snprintf(errbuf, errbuflen,
"The other host terminated the connection.");
}
return -1;
@@ -1058,7 +1106,7 @@ int sock_recv(SOCKET sock, void *buffer, size_t size, int flags,
*
* Returns the size of the datagram on success or -1 on error.
*/
-int sock_recv_dgram(SOCKET sock, void *buffer, size_t size,
+int sock_recv_dgram(SOCKET sock, SSL *ssl _U_NOSSL_, void *buffer, size_t size,
char *errbuf, int errbuflen)
{
ssize_t nread;
@@ -1075,20 +1123,29 @@ int sock_recv_dgram(SOCKET sock, void *buffer, size_t size,
{
if (errbuf)
{
- pcap_snprintf(errbuf, errbuflen,
+ snprintf(errbuf, errbuflen,
"Can't read more than %u bytes with sock_recv_dgram",
INT_MAX);
}
return -1;
}
+#ifdef HAVE_OPENSSL
+ // TODO: DTLS
+ if (ssl)
+ {
+ snprintf(errbuf, errbuflen, "DTLS not implemented yet");
+ return -1;
+ }
+#endif
+
/*
* This should be a datagram socket, so we should get the
* entire datagram in one recv() or recvmsg() call, and
* don't need to loop.
*/
#ifdef _WIN32
- nread = recv(sock, buffer, size, 0);
+ nread = recv(sock, buffer, (int)size, 0);
if (nread == SOCKET_ERROR)
{
/*
@@ -1132,7 +1189,11 @@ int sock_recv_dgram(SOCKET sock, void *buffer, size_t size,
#ifdef HAVE_STRUCT_MSGHDR_MSG_FLAGS
message.msg_flags = 0;
#endif
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ nread = fuzz_recv(buffer, size);
+#else
nread = recvmsg(sock, &message, 0);
+#endif
if (nread == -1)
{
if (errno == EINTR)
@@ -1154,7 +1215,7 @@ int sock_recv_dgram(SOCKET sock, void *buffer, size_t size,
* Report this as an error, as the Microsoft documentation
* implies we'd do in a similar case on Windows.
*/
- pcap_snprintf(errbuf, errbuflen, "recv(): Message too long");
+ snprintf(errbuf, errbuflen, "recv(): Message too long");
return -1;
}
#endif /* HAVE_STRUCT_MSGHDR_MSG_FLAGS */
@@ -1192,7 +1253,7 @@ int sock_recv_dgram(SOCKET sock, void *buffer, size_t size,
* \return '0' if everything is fine, '-1' if some errors occurred.
* The error message is returned in the 'errbuf' variable.
*/
-int sock_discard(SOCKET sock, int size, char *errbuf, int errbuflen)
+int sock_discard(SOCKET sock, SSL *ssl, int size, char *errbuf, int errbuflen)
{
#define TEMP_BUF_SIZE 32768
@@ -1208,7 +1269,7 @@ int sock_discard(SOCKET sock, int size, char *errbuf, int errbuflen)
*/
while (size > TEMP_BUF_SIZE)
{
- if (sock_recv(sock, buffer, TEMP_BUF_SIZE, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1)
+ if (sock_recv(sock, ssl, buffer, TEMP_BUF_SIZE, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1)
return -1;
size -= TEMP_BUF_SIZE;
@@ -1220,7 +1281,7 @@ int sock_discard(SOCKET sock, int size, char *errbuf, int errbuflen)
*/
if (size)
{
- if (sock_recv(sock, buffer, size, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1)
+ if (sock_recv(sock, ssl, buffer, size, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1)
return -1;
}
@@ -1358,7 +1419,7 @@ int sock_check_hostlist(char *hostlist, const char *sep, struct sockaddr_storage
* the host wasn't in the list.
*/
if (errbuf)
- pcap_snprintf(errbuf, errbuflen, "The host is not in the allowed host list. Connection refused.");
+ snprintf(errbuf, errbuflen, "The host is not in the allowed host list. Connection refused.");
return -1;
}
}
@@ -1628,7 +1689,7 @@ int sock_present2network(const char *address, struct sockaddr_storage *sockaddr,
freeaddrinfo(addrinfo);
if (errbuf)
- pcap_snprintf(errbuf, errbuflen, "More than one socket requested; using the first one returned");
+ snprintf(errbuf, errbuflen, "More than one socket requested; using the first one returned");
return -2;
}
diff --git a/sockutils.h b/sockutils.h
index 8a45b3df..e748662e 100644
--- a/sockutils.h
+++ b/sockutils.h
@@ -52,6 +52,8 @@
#define closesocket(a) close(a)
#endif
+#include "sslutils.h" // for SSL type, whatever that turns out to be
+
/*
* MingW headers include this definition, but only for Windows XP and above.
* MSDN states that this function is available for most versions on Windows.
@@ -104,6 +106,8 @@ int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD,
#define SOCK_EOF_ISNT_ERROR 0x00000000 /* Return 0 on EOF */
#define SOCK_EOF_IS_ERROR 0x00000002 /* Return an error on EOF */
+#define SOCK_MSG_PEEK 0x00000004 /* Return data but leave it in the socket queue */
+
/*
* \}
*/
@@ -128,17 +132,17 @@ void sock_geterror(const char *caller, char *errbuf, int errbufsize);
int sock_initaddress(const char *address, const char *port,
struct addrinfo *hints, struct addrinfo **addrinfo,
char *errbuf, int errbuflen);
-int sock_recv(SOCKET sock, void *buffer, size_t size, int receiveall,
+int sock_recv(SOCKET sock, SSL *, void *buffer, size_t size, int receiveall,
char *errbuf, int errbuflen);
-int sock_recv_dgram(SOCKET sock, void *buffer, size_t size,
+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);
int sock_close(SOCKET sock, char *errbuf, int errbuflen);
-int sock_send(SOCKET sock, const char *buffer, size_t size,
+int sock_send(SOCKET sock, SSL *, const char *buffer, size_t size,
char *errbuf, int errbuflen);
int sock_bufferize(const char *buffer, int size, char *tempbuf, int *offset, int totsize, int checkonly, char *errbuf, int errbuflen);
-int sock_discard(SOCKET sock, int size, char *errbuf, int errbuflen);
+int sock_discard(SOCKET sock, SSL *, int size, char *errbuf, int errbuflen);
int sock_check_hostlist(char *hostlist, const char *sep, struct sockaddr_storage *from, char *errbuf, int errbuflen);
int sock_cmpaddr(struct sockaddr_storage *first, struct sockaddr_storage *second);
diff --git a/sslutils.c b/sslutils.c
new file mode 100644
index 00000000..7274cc34
--- /dev/null
+++ b/sslutils.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2002 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_OPENSSL
+#include <stdlib.h>
+
+#include "portability.h"
+
+#include "sslutils.h"
+
+static const char *ssl_keyfile = ""; //!< file containing the private key in PEM format
+static const char *ssl_certfile = ""; //!< file containing the server's certificate in PEM format
+static const char *ssl_rootfile = ""; //!< file containing the list of CAs trusted by the client
+// TODO: a way to set ssl_rootfile from the command line, or an envvar?
+
+// TODO: lock?
+static SSL_CTX *ctx;
+
+void ssl_set_certfile(const char *certfile)
+{
+ ssl_certfile = certfile;
+}
+
+void ssl_set_keyfile(const char *keyfile)
+{
+ ssl_keyfile = keyfile;
+}
+
+int ssl_init_once(int is_server, int enable_compression, char *errbuf, size_t errbuflen)
+{
+ static int inited = 0;
+ if (inited) return 0;
+
+ SSL_library_init();
+ SSL_load_error_strings();
+ OpenSSL_add_ssl_algorithms();
+ if (enable_compression)
+ SSL_COMP_get_compression_methods();
+
+ SSL_METHOD const *meth =
+ is_server ? SSLv23_server_method() : SSLv23_client_method();
+ ctx = SSL_CTX_new(meth);
+ if (! ctx)
+ {
+ snprintf(errbuf, errbuflen, "Cannot get a new SSL context: %s", ERR_error_string(ERR_get_error(), NULL));
+ goto die;
+ }
+
+ SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
+
+ if (is_server)
+ {
+ char const *certfile = ssl_certfile[0] ? ssl_certfile : "cert.pem";
+ if (1 != SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))
+ {
+ snprintf(errbuf, errbuflen, "Cannot read certificate file %s: %s", certfile, ERR_error_string(ERR_get_error(), NULL));
+ goto die;
+ }
+
+ char const *keyfile = ssl_keyfile[0] ? ssl_keyfile : "key.pem";
+ if (1 != SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))
+ {
+ snprintf(errbuf, errbuflen, "Cannot read private key file %s: %s", keyfile, ERR_error_string(ERR_get_error(), NULL));
+ goto die;
+ }
+ }
+ else
+ {
+ if (ssl_rootfile[0])
+ {
+ if (! SSL_CTX_load_verify_locations(ctx, ssl_rootfile, 0))
+ {
+ snprintf(errbuf, errbuflen, "Cannot read CA list from %s", ssl_rootfile);
+ goto die;
+ }
+ }
+ else
+ {
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
+ }
+ }
+
+#if 0
+ if (! RAND_load_file(RANDOM, 1024*1024))
+ {
+ snprintf(errbuf, errbuflen, "Cannot init random");
+ goto die;
+ }
+
+ if (is_server)
+ {
+ SSL_CTX_set_session_id_context(ctx, (void *)&s_server_session_id_context, sizeof(s_server_session_id_context));
+ }
+#endif
+
+ inited = 1;
+ return 0;
+
+die:
+ return -1;
+}
+
+SSL *ssl_promotion(int is_server, SOCKET s, char *errbuf, size_t errbuflen)
+{
+ if (ssl_init_once(is_server, 1, errbuf, errbuflen) < 0) {
+ return NULL;
+ }
+
+ SSL *ssl = SSL_new(ctx); // TODO: also a DTLS context
+ SSL_set_fd(ssl, (int)s);
+
+ if (is_server) {
+ if (SSL_accept(ssl) <= 0) {
+ snprintf(errbuf, errbuflen, "SSL_accept(): %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return NULL;
+ }
+ } else {
+ if (SSL_connect(ssl) <= 0) {
+ snprintf(errbuf, errbuflen, "SSL_connect(): %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return NULL;
+ }
+ }
+
+ return ssl;
+}
+
+// Finish using an SSL handle; shut down the connection and free the
+// handle.
+void ssl_finish(SSL *ssl)
+{
+ //
+ // We won't be using this again, so we can just send the
+ // shutdown alert and free up the handle, and have our
+ // caller close the socket.
+ //
+ // XXX - presumably, if the connection is shut down on
+ // our side, either our peer won't have a problem sending
+ // their shutdown alert or will not treat such a problem
+ // as an error. If this causes errors to be reported,
+ // fix that as appropriate.
+ //
+ SSL_shutdown(ssl);
+ SSL_free(ssl);
+}
+
+// Same return value as sock_send:
+// 0 on OK, -1 on error but closed connection (-2).
+int ssl_send(SSL *ssl, char const *buffer, int size, char *errbuf, size_t errbuflen)
+{
+ int status = SSL_write(ssl, buffer, size);
+ if (status > 0)
+ {
+ // "SSL_write() will only return with success, when the complete contents (...) has been written."
+ return 0;
+ }
+ else
+ {
+ int ssl_err = SSL_get_error(ssl, status); // TODO: does it pop the error?
+ if (ssl_err == SSL_ERROR_ZERO_RETURN)
+ {
+ return -2;
+ }
+ else if (ssl_err == SSL_ERROR_SYSCALL)
+ {
+#ifndef _WIN32
+ if (errno == ECONNRESET || errno == EPIPE) return -2;
+#endif
+ }
+ snprintf(errbuf, errbuflen, "SSL_write(): %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+}
+
+// Returns the number of bytes read, or -1 on syserror, or -2 on SSL error.
+int ssl_recv(SSL *ssl, char *buffer, int size, char *errbuf, size_t errbuflen)
+{
+ int status = SSL_read(ssl, buffer, size);
+ if (status <= 0)
+ {
+ int ssl_err = SSL_get_error(ssl, status);
+ if (ssl_err == SSL_ERROR_ZERO_RETURN)
+ {
+ return 0;
+ }
+ else if (ssl_err == SSL_ERROR_SYSCALL)
+ {
+ return -1;
+ }
+ else
+ {
+ // Should not happen
+ snprintf(errbuf, errbuflen, "SSL_read(): %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -2;
+ }
+ }
+ else
+ {
+ return status;
+ }
+}
+
+#endif // HAVE_OPENSSL
diff --git a/sslutils.h b/sslutils.h
new file mode 100644
index 00000000..6316364e
--- /dev/null
+++ b/sslutils.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2002 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __SSLUTILS_H__
+#define __SSLUTILS_H__
+
+#ifdef HAVE_OPENSSL
+#include "pcap/socket.h" // for SOCKET
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+/*
+ * Utility functions
+ */
+
+void ssl_set_certfile(const char *certfile);
+void ssl_set_keyfile(const char *keyfile);
+int ssl_init_once(int is_server, int enable_compression, char *errbuf, size_t errbuflen);
+SSL *ssl_promotion(int is_server, SOCKET s, char *errbuf, size_t errbuflen);
+void ssl_finish(SSL *ssl);
+int ssl_send(SSL *, char const *buffer, int size, char *errbuf, size_t errbuflen);
+int ssl_recv(SSL *, char *buffer, int size, char *errbuf, size_t errbuflen);
+
+// The SSL parameters are used
+#define _U_NOSSL_
+
+#else // HAVE_OPENSSL
+
+// This saves us from a lot of ifdefs:
+#define SSL void const
+
+// The SSL parameters are unused
+#define _U_NOSSL_ _U_
+
+#endif // HAVE_OPENSSL
+
+#endif // __SSLUTILS_H__
diff --git a/testprogs/.gitignore b/testprogs/.gitignore
index b9178b4e..b57c7bb4 100644
--- a/testprogs/.gitignore
+++ b/testprogs/.gitignore
@@ -7,7 +7,9 @@ capturetest
can_set_rfmon_test
filtertest
findalldevstest
+findalldevstest-perf
opentest
reactivatetest
selpolltest
threadsignaltest
+writecaptest
diff --git a/testprogs/BPF/1.txt b/testprogs/BPF/1.txt
index 66086952..733651e6 100644
--- a/testprogs/BPF/1.txt
+++ b/testprogs/BPF/1.txt
@@ -1,2 +1,2 @@
-# common block merging, same block elimination, result propogation
+# common block merging, same block elimination, result propagation
host 192.168.1.1
diff --git a/testprogs/CMakeLists.txt b/testprogs/CMakeLists.txt
index b8ef9b7d..bf573613 100644
--- a/testprogs/CMakeLists.txt
+++ b/testprogs/CMakeLists.txt
@@ -19,6 +19,10 @@ macro(add_test_executable _executable)
target_link_libraries(${_executable}
${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES})
endif(WIN32)
+ if(NOT "${LINKER_FLAGS}" STREQUAL "")
+ set_target_properties(${_executable} PROPERTIES
+ LINK_FLAGS "${LINKER_FLAGS}")
+ endif()
add_dependencies(testprogs ${_executable})
endmacro()
@@ -26,8 +30,10 @@ add_test_executable(can_set_rfmon_test)
add_test_executable(capturetest)
add_test_executable(filtertest)
add_test_executable(findalldevstest)
+add_test_executable(findalldevstest-perf)
add_test_executable(opentest)
add_test_executable(reactivatetest)
+add_test_executable(writecaptest)
if(NOT WIN32)
add_test_executable(selpolltest)
@@ -38,3 +44,5 @@ add_test_executable(threadsignaltest ${CMAKE_THREAD_LIBS_INIT})
if(NOT WIN32)
add_test_executable(valgrindtest)
endif()
+
+add_subdirectory(fuzz)
diff --git a/testprogs/Makefile.in b/testprogs/Makefile.in
index ec0a4720..43af561e 100644
--- a/testprogs/Makefile.in
+++ b/testprogs/Makefile.in
@@ -38,6 +38,7 @@ mandir = @mandir@
# VPATH
srcdir = @srcdir@
+top_srcdir = @top_srcdir@
VPATH = @srcdir@
#
@@ -79,14 +80,16 @@ INSTALL_DATA = @INSTALL_DATA@
$(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c
SRC = @VALGRINDTEST_SRC@ \
- capturetest.c \
can_set_rfmon_test.c \
+ capturetest.c \
filtertest.c \
+ findalldevstest-perf.c \
findalldevstest.c \
opentest.c \
reactivatetest.c \
selpolltest.c \
- threadsignaltest.c
+ threadsignaltest.c \
+ writecaptest.c
TESTS = $(SRC:.c=)
@@ -109,6 +112,9 @@ filtertest: $(srcdir)/filtertest.c ../libpcap.a
findalldevstest: $(srcdir)/findalldevstest.c ../libpcap.a
$(CC) $(FULL_CFLAGS) -I. -L. -o findalldevstest $(srcdir)/findalldevstest.c ../libpcap.a $(EXTRA_NETWORK_LIBS) $(LIBS)
+findalldevstest-perf: $(srcdir)/findalldevstest-perf.c ../libpcap.a
+ $(CC) $(FULL_CFLAGS) -I. -L. -o findalldevstest-perf $(srcdir)/findalldevstest-perf.c ../libpcap.a $(EXTRA_NETWORK_LIBS) $(LIBS)
+
opentest: $(srcdir)/opentest.c ../libpcap.a
$(CC) $(FULL_CFLAGS) -I. -L. -o opentest $(srcdir)/opentest.c ../libpcap.a $(LIBS)
@@ -124,6 +130,9 @@ threadsignaltest: $(srcdir)/threadsignaltest.c ../libpcap.a
valgrindtest: $(srcdir)/valgrindtest.c ../libpcap.a
$(CC) $(FULL_CFLAGS) -I. -L. -o valgrindtest $(srcdir)/valgrindtest.c ../libpcap.a $(LIBS)
+writecaptest: $(srcdir)/writecaptest.c ../libpcap.a
+ $(CC) $(FULL_CFLAGS) -I. -L. -o writecaptest $(srcdir)/writecaptest.c ../libpcap.a $(LIBS)
+
clean:
rm -f $(CLEANFILES)
rm -rf *.dSYM
@@ -141,4 +150,4 @@ tags: $(TAGFILES)
ctags -wtd $(TAGFILES)
depend:
- ../$(MKDEP) -c "$(CC)" -m "$(DEPENDENCY_CFLAG)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC)
+ $(MKDEP) -c "$(CC)" -m "$(DEPENDENCY_CFLAG)" -s "$(srcdir)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC)
diff --git a/testprogs/can_set_rfmon_test.c b/testprogs/can_set_rfmon_test.c
index f6188ba1..96816f9b 100644
--- a/testprogs/can_set_rfmon_test.c
+++ b/testprogs/can_set_rfmon_test.c
@@ -70,7 +70,6 @@ main(int argc, char **argv)
else
error("%s: pcap_can_set_rfmon failed: %s", argv[1],
pcap_statustostr(status));
- return 1;
}
printf("%s: Monitor mode %s be set\n", argv[1], status ? "can" : "cannot");
return 0;
diff --git a/testprogs/capturetest.c b/testprogs/capturetest.c
index d625cb4a..4eadd336 100644
--- a/testprogs/capturetest.c
+++ b/testprogs/capturetest.c
@@ -38,6 +38,9 @@ The Regents of the University of California. All rights reserved.\n";
#include <unistd.h>
#endif
#include <errno.h>
+#ifndef _WIN32
+ #include <signal.h>
+#endif
#include <sys/types.h>
#include <pcap.h>
@@ -58,6 +61,37 @@ static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2);
static char *copy_argv(char **);
static pcap_t *pd;
+#ifndef _WIN32
+static int breaksigint = 0;
+#endif
+
+#ifndef _WIN32
+static void
+sigint_handler(int signum _U_)
+{
+ if (breaksigint)
+ pcap_breakloop(pd);
+}
+#endif
+
+#ifdef _WIN32
+/*
+ * We don't have UN*X-style signals, so we don't have anything to test.
+ */
+#define B_OPTION ""
+#define R_OPTION ""
+#define S_OPTION ""
+#else
+/*
+ * We do have UN*X-style signals (we assume that "not Windows" means "UN*X").
+ */
+#define B_OPTION "b"
+#define R_OPTION "r"
+#define S_OPTION "s"
+#endif
+
+#define COMMAND_OPTIONS B_OPTION "i:mn" R_OPTION S_OPTION "t:"
+#define USAGE_OPTIONS "-" B_OPTION "mn" R_OPTION S_OPTION
int
main(int argc, char **argv)
@@ -69,6 +103,10 @@ main(int argc, char **argv)
int timeout = 1000;
int immediate = 0;
int nonblock = 0;
+#ifndef _WIN32
+ int sigrestart = 0;
+ int catchsigint = 0;
+#endif
pcap_if_t *devlist;
bpf_u_int32 localnet, netmask;
struct bpf_program fcode;
@@ -83,9 +121,15 @@ main(int argc, char **argv)
program_name = argv[0];
opterr = 0;
- while ((op = getopt(argc, argv, "i:mnt:")) != -1) {
+ while ((op = getopt(argc, argv, COMMAND_OPTIONS)) != -1) {
switch (op) {
+#ifndef _WIN32
+ case 'b':
+ breaksigint = 1;
+ break;
+#endif
+
case 'i':
device = optarg;
break;
@@ -98,6 +142,16 @@ main(int argc, char **argv)
nonblock = 1;
break;
+#ifndef _WIN32
+ case 'r':
+ sigrestart = 1;
+ break;
+
+ case 's':
+ catchsigint = 1;
+ break;
+#endif
+
case 't':
longarg = strtol(optarg, &p, 10);
if (p == optarg || *p != '\0') {
@@ -132,6 +186,28 @@ main(int argc, char **argv)
pcap_freealldevs(devlist);
}
*ebuf = '\0';
+
+#ifndef _WIN32
+ /*
+ * If we were told to catch SIGINT, do so.
+ */
+ if (catchsigint) {
+ struct sigaction action;
+
+ action.sa_handler = sigint_handler;
+ sigemptyset(&action.sa_mask);
+
+ /*
+ * Should SIGINT interrupt, or restart, system calls?
+ */
+ action.sa_flags = sigrestart ? SA_RESTART : 0;
+
+ if (sigaction(SIGINT, &action, NULL) == -1)
+ error("Can't catch SIGINT: %s\n",
+ strerror(errno));
+ }
+#endif
+
pd = pcap_create(device, ebuf);
if (pd == NULL)
error("%s", ebuf);
@@ -188,6 +264,10 @@ main(int argc, char **argv)
if (status != 0) {
printf("%d packets seen, %d packets counted after pcap_dispatch returns\n",
status, packet_count);
+ struct pcap_stat ps;
+ pcap_stats(pd, &ps);
+ printf("%d ps_recv, %d ps_drop, %d ps_ifdrop\n",
+ ps.ps_recv, ps.ps_drop, ps.ps_ifdrop);
}
}
if (status == -2) {
@@ -197,13 +277,14 @@ main(int argc, char **argv)
* Print an extra newline, just in case.
*/
putchar('\n');
+ printf("Broken out of loop from SIGINT handler\n");
}
(void)fflush(stdout);
if (status == -1) {
/*
* Error. Report it.
*/
- (void)fprintf(stderr, "%s: pcap_loop: %s\n",
+ (void)fprintf(stderr, "%s: pcap_dispatch: %s\n",
program_name, pcap_geterr(pd));
}
pcap_close(pd);
@@ -223,7 +304,7 @@ countme(u_char *user, const struct pcap_pkthdr *h _U_, const u_char *sp _U_)
static void
usage(void)
{
- (void)fprintf(stderr, "Usage: %s [ -mn ] [ -i interface ] [ -t timeout] [expression]\n",
+ (void)fprintf(stderr, "Usage: %s [ " USAGE_OPTIONS " ] [ -i interface ] [ -t timeout] [expression]\n",
program_name);
exit(1);
}
@@ -271,7 +352,7 @@ static char *
copy_argv(register char **argv)
{
register char **p;
- register u_int len = 0;
+ register size_t len = 0;
char *buf;
char *src, *dst;
diff --git a/testprogs/filtertest.c b/testprogs/filtertest.c
index 7e2d6d6e..440b550d 100644
--- a/testprogs/filtertest.c
+++ b/testprogs/filtertest.c
@@ -36,6 +36,7 @@ The Regents of the University of California. All rights reserved.\n";
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
+#include <limits.h>
#ifdef _WIN32
#include "getopt.h"
#include "unix.h"
@@ -56,6 +57,8 @@ The Regents of the University of California. All rights reserved.\n";
#include "pcap/funcattrs.h"
+#define MAXIMUM_SNAPLEN 262144
+
#ifdef BDEBUG
/*
* We have pcap_set_optimizer_debug() and pcap_set_print_dot_graph() in
@@ -99,11 +102,21 @@ read_infile(char *fname)
if (fstat(fd, &buf) < 0)
error("can't stat %s: %s", fname, pcap_strerror(errno));
+ /*
+ * _read(), on Windows, has an unsigned int byte count and an
+ * int return value, so we can't handle a file bigger than
+ * INT_MAX - 1 bytes (and have no reason to do so; a filter *that*
+ * big will take forever to compile). (The -1 is for the '\0' at
+ * the end of the string.)
+ */
+ if (buf.st_size > INT_MAX - 1)
+ error("%s is larger than %d bytes; that's too large", fname,
+ INT_MAX - 1);
cp = malloc((u_int)buf.st_size + 1);
if (cp == NULL)
error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
fname, pcap_strerror(errno));
- cc = read(fd, cp, (u_int)buf.st_size);
+ cc = (int)read(fd, cp, (u_int)buf.st_size);
if (cc < 0)
error("read %s: %s", fname, pcap_strerror(errno));
if (cc != buf.st_size)
@@ -163,7 +176,7 @@ static char *
copy_argv(register char **argv)
{
register char **p;
- register u_int len = 0;
+ register size_t len = 0;
char *buf;
char *src, *dst;
@@ -196,10 +209,12 @@ main(int argc, char **argv)
char *cp;
int op;
int dflag;
+#ifdef BDEBUG
int gflag;
+#endif
char *infile;
int Oflag;
- long snaplen;
+ int snaplen;
char *p;
int dlt;
int have_fcode = 0;
@@ -214,11 +229,13 @@ main(int argc, char **argv)
#endif /* _WIN32 */
dflag = 1;
+#ifdef BDEBUG
gflag = 0;
+#endif
infile = NULL;
Oflag = 1;
- snaplen = 68;
+ snaplen = MAXIMUM_SNAPLEN;
if ((cp = strrchr(argv[0], '/')) != NULL)
program_name = cp + 1;
@@ -272,13 +289,19 @@ main(int argc, char **argv)
case 's': {
char *end;
+ long long_snaplen;
- snaplen = strtol(optarg, &end, 0);
+ long_snaplen = strtol(optarg, &end, 0);
if (optarg == end || *end != '\0'
- || snaplen < 0 || snaplen > 65535)
+ || long_snaplen < 0
+ || long_snaplen > MAXIMUM_SNAPLEN)
error("invalid snaplen %s", optarg);
- else if (snaplen == 0)
- snaplen = 65535;
+ else {
+ if (snaplen == 0)
+ snaplen = MAXIMUM_SNAPLEN;
+ else
+ snaplen = (int)long_snaplen;
+ }
break;
}
diff --git a/testprogs/findalldevstest-perf.c b/testprogs/findalldevstest-perf.c
new file mode 100644
index 00000000..40875666
--- /dev/null
+++ b/testprogs/findalldevstest-perf.c
@@ -0,0 +1,100 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#ifdef _WIN32
+ #include <winsock2.h>
+ #include <ws2tcpip.h>
+ #include <windows.h>
+#else
+ #include <unistd.h>
+ #include <sys/resource.h>
+#endif
+
+#include <pcap.h>
+
+#include "varattrs.h"
+#include "pcap/funcattrs.h"
+
+#ifdef _WIN32
+#include "portability.h"
+#endif
+
+int main(int argc _U_, char **argv _U_)
+{
+ pcap_if_t *alldevs;
+ int exit_status = 0;
+ char errbuf[PCAP_ERRBUF_SIZE+1];
+#ifdef _WIN32
+ FILETIME start_ktime, start_utime, end_ktime, end_utime;
+ FILETIME dummy1, dummy2;
+ ULARGE_INTEGER start_kticks, end_kticks, start_uticks, end_uticks;
+ ULONGLONG ktime, utime, tottime;
+#else
+ struct rusage start_rusage, end_rusage;
+ struct timeval ktime, utime, tottime;
+#endif
+
+#ifdef _WIN32
+ if (!GetProcessTimes(GetCurrentProcess(), &dummy1, &dummy2,
+ &start_ktime, &start_utime))
+ {
+ fprintf(stderr, "GetProcessTimes() fails at start\n");
+ exit(1);
+ }
+ start_kticks.LowPart = start_ktime.dwLowDateTime;
+ start_kticks.HighPart = start_ktime.dwHighDateTime;
+ start_uticks.LowPart = start_utime.dwLowDateTime;
+ start_uticks.HighPart = start_utime.dwHighDateTime;
+#else
+ if (getrusage(RUSAGE_SELF, &start_rusage) == -1) {
+ fprintf(stderr, "getrusage() fails at start\n");
+ exit(1);
+ }
+#endif
+ for (int i = 0; i < 500; i++)
+ {
+ if (pcap_findalldevs(&alldevs, errbuf) == -1)
+ {
+ fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf);
+ exit(1);
+ }
+ pcap_freealldevs(alldevs);
+ }
+
+#ifdef _WIN32
+ if (!GetProcessTimes(GetCurrentProcess(), &dummy1, &dummy2,
+ &end_ktime, &end_utime))
+ {
+ fprintf(stderr, "GetProcessTimes() fails at end\n");
+ exit(1);
+ }
+ end_kticks.LowPart = end_ktime.dwLowDateTime;
+ end_kticks.HighPart = end_ktime.dwHighDateTime;
+ end_uticks.LowPart = end_utime.dwLowDateTime;
+ end_uticks.HighPart = end_utime.dwHighDateTime;
+ ktime = end_kticks.QuadPart - start_kticks.QuadPart;
+ utime = end_uticks.QuadPart - start_uticks.QuadPart;
+ tottime = ktime + utime;
+ printf("Total CPU secs: kernel %g, user %g, total %g\n",
+ ((double)ktime) / 10000000.0,
+ ((double)utime) / 10000000.0,
+ ((double)tottime) / 10000000.0);
+#else
+ if (getrusage(RUSAGE_SELF, &end_rusage) == -1) {
+ fprintf(stderr, "getrusage() fails at end\n");
+ exit(1);
+ }
+ timersub(&end_rusage.ru_stime, &start_rusage.ru_stime, &ktime);
+ timersub(&end_rusage.ru_utime, &start_rusage.ru_utime, &utime);
+ timeradd(&ktime, &utime, &tottime);
+ printf("Total CPU secs: kernel %g, user %g, total %g\n",
+ (double)ktime.tv_sec + ((double)ktime.tv_usec / 1000000.0),
+ (double)utime.tv_sec + ((double)utime.tv_usec / 1000000.0),
+ (double)tottime.tv_sec + ((double)tottime.tv_usec / 1000000.0));
+#endif
+ exit(exit_status);
+}
diff --git a/testprogs/findalldevstest.c b/testprogs/findalldevstest.c
index e535e254..092fd045 100644
--- a/testprogs/findalldevstest.c
+++ b/testprogs/findalldevstest.c
@@ -19,6 +19,7 @@
#include <pcap.h>
+#include "varattrs.h"
#include "pcap/funcattrs.h"
static int ifprint(pcap_if_t *d);
@@ -94,7 +95,11 @@ getpass(const char *prompt)
}
#endif
+#ifdef ENABLE_REMOTE
int main(int argc, char **argv)
+#else
+int main(int argc _U_, char **argv _U_)
+#endif
{
pcap_if_t *alldevs;
pcap_if_t *d;
@@ -152,8 +157,24 @@ int main(int argc, char **argv)
{
if (pcap_lookupnet(alldevs->name, &net, &mask, errbuf) < 0)
{
- fprintf(stderr,"Error in pcap_lookupnet: %s\n",errbuf);
- exit_status = 2;
+ /*
+ * XXX - this doesn't distinguish between "a real error
+ * occurred" and "this interface doesn't *have* an IPv4
+ * address". The latter shouldn't be treated as an error.
+ *
+ * We look for the interface name, followed by a colon and
+ * a space, and, if we find it,w e see if what follows it
+ * is "no IPv4 address assigned".
+ */
+ size_t devnamelen = strlen(alldevs->name);
+ if (strncmp(errbuf, alldevs->name, devnamelen) == 0 &&
+ strncmp(errbuf + devnamelen, ": ", 2) == 0 &&
+ strcmp(errbuf + devnamelen + 2, "no IPv4 address assigned") == 0)
+ printf("Preferred device is not on an IPv4 network\n");
+ else {
+ fprintf(stderr,"Error in pcap_lookupnet: %s\n",errbuf);
+ exit_status = 2;
+ }
}
else
{
diff --git a/testprogs/fuzz/CMakeLists.txt b/testprogs/fuzz/CMakeLists.txt
new file mode 100644
index 00000000..67250cca
--- /dev/null
+++ b/testprogs/fuzz/CMakeLists.txt
@@ -0,0 +1,43 @@
+add_executable(fuzz_pcap onefile.c fuzz_pcap.c)
+target_link_libraries(fuzz_pcap ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES})
+if(NOT "${SANITIZER_FLAGS}" STREQUAL "")
+ set_target_properties(fuzz_pcap PROPERTIES
+ LINK_FLAGS "${SANITIZER_FLAGS}")
+endif()
+
+add_executable(fuzz_filter onefile.c fuzz_filter.c)
+target_link_libraries(fuzz_filter ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES})
+if(NOT "${SANITIZER_FLAGS}" STREQUAL "")
+ set_target_properties(fuzz_filter PROPERTIES
+ LINK_FLAGS "${SANITIZER_FLAGS}")
+endif()
+
+add_executable(fuzz_both onefile.c fuzz_both.c)
+target_link_libraries(fuzz_both ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES})
+if(NOT "${SANITIZER_FLAGS}" STREQUAL "")
+ set_target_properties(fuzz_both PROPERTIES
+ LINK_FLAGS "${SANITIZER_FLAGS}")
+endif()
+
+if(ENABLE_REMOTE AND "$ENV{CFLAGS}" MATCHES "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION")
+add_executable(fuzz_rclient onefile.c fuzz_rclient.c)
+target_link_libraries(fuzz_rclient ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES})
+if(NOT "${SANITIZER_FLAGS}" STREQUAL "")
+ set_target_properties(fuzz_rclient PROPERTIES
+ LINK_FLAGS "${SANITIZER_FLAGS}")
+endif()
+
+add_executable(fuzz_rserver onefile.c fuzz_rserver.c ../../rpcapd/daemon.c)
+check_function_exists(crypt HAVE_CRYPT_IN_SYSTEM_LIBRARIES)
+if(HAVE_CRYPT_IN_SYSTEM_LIBRARIES)
+ set(HAVE_CRYPT TRUE)
+else(HAVE_CRYPT_IN_SYSTEM_LIBRARIES)
+ set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} crypt)
+endif(HAVE_CRYPT_IN_SYSTEM_LIBRARIES)
+target_link_libraries(fuzz_rserver ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES})
+
+if(NOT "${SANITIZER_FLAGS}" STREQUAL "")
+ set_target_properties(fuzz_rserver PROPERTIES
+ LINK_FLAGS "${SANITIZER_FLAGS}")
+endif()
+endif(ENABLE_REMOTE AND "$ENV{CFLAGS}" MATCHES "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION")
diff --git a/testprogs/fuzz/fuzz_both.c b/testprogs/fuzz/fuzz_both.c
new file mode 100644
index 00000000..59e3d404
--- /dev/null
+++ b/testprogs/fuzz/fuzz_both.c
@@ -0,0 +1,101 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include <pcap/pcap.h>
+
+FILE * outfile = NULL;
+
+static int bufferToFile(const char * name, const uint8_t *Data, size_t Size) {
+ FILE * fd;
+ if (remove(name) != 0) {
+ if (errno != ENOENT) {
+ printf("failed remove, errno=%d\n", errno);
+ return -1;
+ }
+ }
+ fd = fopen(name, "wb");
+ if (fd == NULL) {
+ printf("failed open, errno=%d\n", errno);
+ return -2;
+ }
+ if (fwrite (Data, 1, Size, fd) != Size) {
+ fclose(fd);
+ return -3;
+ }
+ fclose(fd);
+ return 0;
+}
+
+void fuzz_openFile(const char * name) {
+ if (outfile != NULL) {
+ fclose(outfile);
+ }
+ outfile = fopen(name, "w");
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ pcap_t * pkts;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ const u_char *pkt;
+ struct pcap_pkthdr *header;
+ int r;
+ size_t filterSize;
+ char * filter;
+ struct bpf_program bpf;
+
+
+ //initialize output file
+ if (outfile == NULL) {
+ outfile = fopen("/dev/null", "w");
+ if (outfile == NULL) {
+ return 0;
+ }
+ }
+
+ if (Size < 1) {
+ return 0;
+ }
+ filterSize = Data[0];
+ if (Size < 1+filterSize || filterSize == 0) {
+ return 0;
+ }
+
+ //rewrite buffer to a file as libpcap does not have buffer inputs
+ if (bufferToFile("/tmp/fuzz.pcap", Data+1+filterSize, Size-(1+filterSize)) < 0) {
+ return 0;
+ }
+
+ //initialize structure
+ pkts = pcap_open_offline("/tmp/fuzz.pcap", errbuf);
+ if (pkts == NULL) {
+ fprintf(outfile, "Couldn't open pcap file %s\n", errbuf);
+ return 0;
+ }
+
+ filter = malloc(filterSize);
+ memcpy(filter, Data+1, filterSize);
+ //null terminate string
+ filter[filterSize-1] = 0;
+
+ if (pcap_compile(pkts, &bpf, filter, 1, PCAP_NETMASK_UNKNOWN) == 0) {
+ //loop over packets
+ r = pcap_next_ex(pkts, &header, &pkt);
+ while (r > 0) {
+ //checks filter
+ fprintf(outfile, "packet length=%d/%d filter=%d\n",header->caplen, header->len, pcap_offline_filter(&bpf, header, pkt));
+ r = pcap_next_ex(pkts, &header, &pkt);
+ }
+ //close structure
+ pcap_close(pkts);
+ pcap_freecode(&bpf);
+ }
+ else {
+ pcap_close(pkts);
+ }
+ free(filter);
+
+ return 0;
+}
diff --git a/testprogs/fuzz/fuzz_both.options b/testprogs/fuzz/fuzz_both.options
new file mode 100644
index 00000000..0824b19f
--- /dev/null
+++ b/testprogs/fuzz/fuzz_both.options
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = 65535
diff --git a/testprogs/fuzz/fuzz_filter.c b/testprogs/fuzz/fuzz_filter.c
new file mode 100644
index 00000000..de350672
--- /dev/null
+++ b/testprogs/fuzz/fuzz_filter.c
@@ -0,0 +1,43 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <pcap/pcap.h>
+
+void fuzz_openFile(const char * name){
+ //do nothing
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ pcap_t * pkts;
+ struct bpf_program bpf;
+ char * filter;
+
+ //we need at least 1 byte for linktype
+ if (Size < 1) {
+ return 0;
+ }
+
+ //initialize structure snaplen = 65535
+ pkts = pcap_open_dead(Data[Size-1], 0xFFFF);
+ if (pkts == NULL) {
+ printf("pcap_open_dead failed\n");
+ return 0;
+ }
+ filter = malloc(Size);
+ memcpy(filter, Data, Size);
+ //null terminate string
+ filter[Size-1] = 0;
+
+ if (pcap_compile(pkts, &bpf, filter, 1, PCAP_NETMASK_UNKNOWN) == 0) {
+ pcap_setfilter(pkts, &bpf);
+ pcap_close(pkts);
+ pcap_freecode(&bpf);
+ }
+ else {
+ pcap_close(pkts);
+ }
+ free(filter);
+
+ return 0;
+}
diff --git a/testprogs/fuzz/fuzz_filter.options b/testprogs/fuzz/fuzz_filter.options
new file mode 100644
index 00000000..9fda93fc
--- /dev/null
+++ b/testprogs/fuzz/fuzz_filter.options
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = 4096
diff --git a/testprogs/fuzz/fuzz_pcap.c b/testprogs/fuzz/fuzz_pcap.c
new file mode 100644
index 00000000..fba5312f
--- /dev/null
+++ b/testprogs/fuzz/fuzz_pcap.c
@@ -0,0 +1,80 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <pcap/pcap.h>
+
+FILE * outfile = NULL;
+
+static int bufferToFile(const char * name, const uint8_t *Data, size_t Size) {
+ FILE * fd;
+ if (remove(name) != 0) {
+ if (errno != ENOENT) {
+ printf("failed remove, errno=%d\n", errno);
+ return -1;
+ }
+ }
+ fd = fopen(name, "wb");
+ if (fd == NULL) {
+ printf("failed open, errno=%d\n", errno);
+ return -2;
+ }
+ if (fwrite (Data, 1, Size, fd) != Size) {
+ fclose(fd);
+ return -3;
+ }
+ fclose(fd);
+ return 0;
+}
+
+void fuzz_openFile(const char * name) {
+ if (outfile != NULL) {
+ fclose(outfile);
+ }
+ outfile = fopen(name, "w");
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ pcap_t * pkts;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ const u_char *pkt;
+ struct pcap_pkthdr *header;
+ struct pcap_stat stats;
+ int r;
+
+ //initialize output file
+ if (outfile == NULL) {
+ outfile = fopen("/dev/null", "w");
+ if (outfile == NULL) {
+ return 0;
+ }
+ }
+
+ //rewrite buffer to a file as libpcap does not have buffer inputs
+ if (bufferToFile("/tmp/fuzz.pcap", Data, Size) < 0) {
+ return 0;
+ }
+
+ //initialize structure
+ pkts = pcap_open_offline("/tmp/fuzz.pcap", errbuf);
+ if (pkts == NULL) {
+ fprintf(outfile, "Couldn't open pcap file %s\n", errbuf);
+ return 0;
+ }
+
+ //loop over packets
+ r = pcap_next_ex(pkts, &header, &pkt);
+ while (r > 0) {
+ //TODO pcap_offline_filter
+ fprintf(outfile, "packet length=%d/%d\n",header->caplen, header->len);
+ r = pcap_next_ex(pkts, &header, &pkt);
+ }
+ if (pcap_stats(pkts, &stats) == 0) {
+ fprintf(outfile, "number of packets=%d\n", stats.ps_recv);
+ }
+ //close structure
+ pcap_close(pkts);
+
+ return 0;
+}
diff --git a/testprogs/fuzz/fuzz_pcap.options b/testprogs/fuzz/fuzz_pcap.options
new file mode 100644
index 00000000..0824b19f
--- /dev/null
+++ b/testprogs/fuzz/fuzz_pcap.options
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = 65535
diff --git a/testprogs/fuzz/fuzz_rclient.c b/testprogs/fuzz/fuzz_rclient.c
new file mode 100644
index 00000000..b5a6a91a
--- /dev/null
+++ b/testprogs/fuzz/fuzz_rclient.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <pcap/pcap.h>
+
+FILE * outfile = NULL;
+struct pcap_rmtauth auth;
+
+void fuzz_openFile(const char * name) {
+ if (outfile != NULL) {
+ fclose(outfile);
+ }
+ outfile = fopen(name, "w");
+ auth.type = RPCAP_RMTAUTH_PWD;
+ auth.username = "user";
+ auth.password = "pass";
+}
+
+void sock_initfuzz(const uint8_t *Data, size_t Size);
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ pcap_t * pkts;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ const u_char *pkt;
+ struct pcap_pkthdr *header;
+ struct pcap_stat stats;
+ int r;
+
+ //initialization
+ if (outfile == NULL) {
+ fuzz_openFile("/dev/null");
+ }
+
+ sock_initfuzz(Data, Size);
+ //initialize structure
+ pkts = pcap_open("rpcap://127.0.0.1/fuzz.pcap", 0, 0, 1000, &auth, errbuf);
+ if (pkts == NULL) {
+ fprintf(outfile, "Couldn't open pcap file %s\n", errbuf);
+ return 0;
+ }
+
+ //loop over packets
+ r = pcap_next_ex(pkts, &header, &pkt);
+ while (r > 0) {
+ fprintf(outfile, "packet length=%d/%d\n",header->caplen, header->len);
+ r = pcap_next_ex(pkts, &header, &pkt);
+ }
+ if (pcap_stats(pkts, &stats) == 0) {
+ fprintf(outfile, "number of packets=%d\n", stats.ps_recv);
+ }
+ //close structure
+ pcap_close(pkts);
+
+ return 0;
+}
diff --git a/testprogs/fuzz/fuzz_rserver.c b/testprogs/fuzz/fuzz_rserver.c
new file mode 100644
index 00000000..c79a3736
--- /dev/null
+++ b/testprogs/fuzz/fuzz_rserver.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include <pcap/pcap.h>
+
+FILE * outfile = NULL;
+
+void fuzz_openFile(const char * name) {
+ if (outfile != NULL) {
+ fclose(outfile);
+ }
+ outfile = fopen(name, "w");
+}
+
+typedef enum {
+ LOGPRIO_DEBUG,
+ LOGPRIO_INFO,
+ LOGPRIO_WARNING,
+ LOGPRIO_ERROR
+} log_priority;
+
+void rpcapd_log(log_priority priority, const char *message, ...)
+{
+ va_list ap;
+
+ va_start(ap, message);
+ fprintf(outfile, "rpcapd[%d]:", priority);
+ vfprintf(outfile, message, ap);
+ putc('\n', outfile);
+ va_end(ap);
+}
+
+void sock_initfuzz(const uint8_t *Data, size_t Size);
+int daemon_serviceloop(int sockctrl, int isactive, char *passiveClients, int nullAuthAllowed, int uses_ssl);
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ int sock;
+
+ //initialization
+ if (outfile == NULL) {
+ fuzz_openFile("/dev/null");
+ }
+
+ sock_initfuzz(Data, Size);
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock == INVALID_SOCKET) {
+ abort();
+ }
+ //dummy socket, active, null auth allowed, no ssl
+ daemon_serviceloop(sock, 1, malloc(0), 1, 0);
+
+ return 0;
+}
diff --git a/testprogs/fuzz/onefile.c b/testprogs/fuzz/onefile.c
new file mode 100644
index 00000000..690a63bd
--- /dev/null
+++ b/testprogs/fuzz/onefile.c
@@ -0,0 +1,54 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+void fuzz_openFile(const char * name);
+
+int main(int argc, char** argv)
+{
+ FILE * fp;
+ uint8_t *Data;
+ size_t Size;
+
+ if (argc == 3) {
+ fuzz_openFile(argv[2]);
+ } else if (argc != 2) {
+ return 1;
+ }
+ //opens the file, get its size, and reads it into a buffer
+ fp = fopen(argv[1], "rb");
+ if (fp == NULL) {
+ return 2;
+ }
+ if (fseek(fp, 0L, SEEK_END) != 0) {
+ fclose(fp);
+ return 2;
+ }
+ Size = ftell(fp);
+ if (Size == (size_t) -1) {
+ fclose(fp);
+ return 2;
+ }
+ if (fseek(fp, 0L, SEEK_SET) != 0) {
+ fclose(fp);
+ return 2;
+ }
+ Data = malloc(Size);
+ if (Data == NULL) {
+ fclose(fp);
+ return 2;
+ }
+ if (fread(Data, Size, 1, fp) != 1) {
+ fclose(fp);
+ free(Data);
+ return 2;
+ }
+
+ //launch fuzzer
+ LLVMFuzzerTestOneInput(Data, Size);
+ free(Data);
+ fclose(fp);
+ return 0;
+}
+
diff --git a/testprogs/opentest.c b/testprogs/opentest.c
index bad38eb0..a441dda1 100644
--- a/testprogs/opentest.c
+++ b/testprogs/opentest.c
@@ -45,7 +45,7 @@ The Regents of the University of California. All rights reserved.\n";
#include "portability.h"
#endif
-#define MAXIMUM_SNAPLEN 65535
+#define MAXIMUM_SNAPLEN 262144
static char *program_name;
@@ -81,7 +81,7 @@ main(int argc, char **argv)
switch (op) {
case 'i':
- device = optarg;
+ device = strdup(optarg);
break;
case 'I':
@@ -95,13 +95,19 @@ main(int argc, char **argv)
case 's': {
char *end;
+ long long_snaplen;
- snaplen = strtol(optarg, &end, 0);
+ long_snaplen = strtol(optarg, &end, 0);
if (optarg == end || *end != '\0'
- || snaplen < 0 || snaplen > MAXIMUM_SNAPLEN)
+ || long_snaplen < 0
+ || long_snaplen > MAXIMUM_SNAPLEN)
error("invalid snaplen %s", optarg);
- else if (snaplen == 0)
- snaplen = MAXIMUM_SNAPLEN;
+ else {
+ if (snaplen == 0)
+ snaplen = MAXIMUM_SNAPLEN;
+ else
+ snaplen = (int)long_snaplen;
+ }
break;
}
@@ -186,6 +192,7 @@ main(int argc, char **argv)
else
printf("%s opened successfully\n", device);
}
+ free(device);
pcap_close(pd);
exit(status < 0 ? 1 : 0);
}
diff --git a/testprogs/reactivatetest.c b/testprogs/reactivatetest.c
index d7f3e322..a9c987aa 100644
--- a/testprogs/reactivatetest.c
+++ b/testprogs/reactivatetest.c
@@ -51,7 +51,6 @@ main(void)
if (pd == NULL) {
error("Neither lo0 nor lo could be opened: %s",
ebuf);
- return 2;
}
}
status = pcap_activate(pd);
diff --git a/testprogs/selpolltest.c b/testprogs/selpolltest.c
index 329281dc..569c8294 100644
--- a/testprogs/selpolltest.c
+++ b/testprogs/selpolltest.c
@@ -69,13 +69,13 @@ main(int argc, char **argv)
register int op;
bpf_u_int32 localnet, netmask;
register char *cp, *cmdbuf, *device;
- int doselect, dopoll, dotimeout, dononblock;
+ int doselect, dopoll, dotimeout, dononblock, quiet;
const char *mechanism;
struct bpf_program fcode;
char ebuf[PCAP_ERRBUF_SIZE];
pcap_if_t *devlist;
int selectable_fd;
- struct timeval *required_timeout;
+ const struct timeval *required_timeout;
int status;
int packet_count;
@@ -85,13 +85,14 @@ main(int argc, char **argv)
mechanism = NULL;
dotimeout = 0;
dononblock = 0;
+ quiet = 0;
if ((cp = strrchr(argv[0], '/')) != NULL)
program_name = cp + 1;
else
program_name = argv[0];
opterr = 0;
- while ((op = getopt(argc, argv, "i:sptn")) != -1) {
+ while ((op = getopt(argc, argv, "i:sptnq")) != -1) {
switch (op) {
case 'i':
@@ -116,6 +117,10 @@ main(int argc, char **argv)
dononblock = 1;
break;
+ case 'q':
+ quiet = 1;
+ break;
+
default:
usage();
/* NOTREACHED */
@@ -196,6 +201,7 @@ main(int argc, char **argv)
for (;;) {
fd_set setread, setexcept;
struct timeval seltimeout;
+ struct timeval *timeoutp;
FD_ZERO(&setread);
if (selectable_fd != -1) {
@@ -203,6 +209,7 @@ main(int argc, char **argv)
FD_ZERO(&setexcept);
FD_SET(selectable_fd, &setexcept);
}
+ required_timeout = pcap_get_required_select_timeout(pd);
if (dotimeout) {
seltimeout.tv_sec = 0;
if (required_timeout != NULL &&
@@ -210,37 +217,34 @@ main(int argc, char **argv)
seltimeout.tv_usec = required_timeout->tv_usec;
else
seltimeout.tv_usec = 1000;
- status = select(selectable_fd + 1, &setread,
- NULL, &setexcept, &seltimeout);
+ timeoutp = &seltimeout;
} else if (required_timeout != NULL) {
seltimeout = *required_timeout;
- status = select(selectable_fd + 1, &setread,
- NULL, &setexcept, &seltimeout);
+ timeoutp = &seltimeout;
} else {
- status = select((selectable_fd == -1) ?
- 0 : selectable_fd + 1, &setread,
- NULL, &setexcept, NULL);
+ timeoutp = NULL;
}
+ status = select((selectable_fd == -1) ?
+ 0 : selectable_fd + 1, &setread, NULL, &setexcept,
+ timeoutp);
if (status == -1) {
printf("Select returns error (%s)\n",
strerror(errno));
} else {
- if (selectable_fd == -1) {
- if (status != 0)
- printf("Select returned a descriptor\n");
- } else {
+ if (!quiet) {
if (status == 0)
printf("Select timed out: ");
- else
+ else{
printf("Select returned a descriptor: ");
- if (FD_ISSET(selectable_fd, &setread))
- printf("readable, ");
- else
- printf("not readable, ");
- if (FD_ISSET(selectable_fd, &setexcept))
- printf("exceptional condition\n");
- else
- printf("no exceptional condition\n");
+ if (FD_ISSET(selectable_fd, &setread))
+ printf("readable, ");
+ else
+ printf("not readable, ");
+ if (FD_ISSET(selectable_fd, &setexcept))
+ printf("exceptional condition\n");
+ else
+ printf("no exceptional condition\n");
+ }
}
packet_count = 0;
status = pcap_dispatch(pd, -1, countme,
@@ -268,11 +272,12 @@ main(int argc, char **argv)
fd.fd = selectable_fd;
fd.events = POLLIN;
+ required_timeout = pcap_get_required_select_timeout(pd);
if (dotimeout)
polltimeout = 1;
else if (required_timeout != NULL &&
required_timeout->tv_usec >= 1000)
- polltimeout = required_timeout->tv_usec/1000;
+ polltimeout = (int)(required_timeout->tv_usec/1000);
else
polltimeout = -1;
status = poll(&fd, (selectable_fd == -1) ? 0 : 1, polltimeout);
@@ -280,10 +285,7 @@ main(int argc, char **argv)
printf("Poll returns error (%s)\n",
strerror(errno));
} else {
- if (selectable_fd == -1) {
- if (status != 0)
- printf("Poll returned a descriptor\n");
- } else {
+ if (!quiet) {
if (status == 0)
printf("Poll timed out\n");
else {
@@ -349,7 +351,7 @@ main(int argc, char **argv)
/*
* Error. Report it.
*/
- (void)fprintf(stderr, "%s: pcap_loop: %s\n",
+ (void)fprintf(stderr, "%s: pcap_dispatch: %s\n",
program_name, pcap_geterr(pd));
}
pcap_close(pd);
@@ -367,7 +369,7 @@ countme(u_char *user, const struct pcap_pkthdr *h _U_, const u_char *sp _U_)
static void
usage(void)
{
- (void)fprintf(stderr, "Usage: %s [ -sptn ] [ -i interface ] [expression]\n",
+ (void)fprintf(stderr, "Usage: %s [ -sptnq ] [ -i interface ] [expression]\n",
program_name);
exit(1);
}
@@ -415,7 +417,7 @@ static char *
copy_argv(register char **argv)
{
register char **p;
- register u_int len = 0;
+ register size_t len = 0;
char *buf;
char *src, *dst;
diff --git a/testprogs/threadsignaltest.c b/testprogs/threadsignaltest.c
index a60bb495..c9ade76f 100644
--- a/testprogs/threadsignaltest.c
+++ b/testprogs/threadsignaltest.c
@@ -157,7 +157,7 @@ capture_thread_func(THREAD_FUNC_ARG_TYPE arg)
} else
printf("No packets seen by pcap_dispatch\n");
}
- if (status == -2) {
+ if (status == PCAP_ERROR_BREAK) {
/*
* We got interrupted, so perhaps we didn't
* manage to finish a line we were printing.
@@ -167,11 +167,11 @@ capture_thread_func(THREAD_FUNC_ARG_TYPE arg)
printf("Loop got broken\n");
}
(void)fflush(stdout);
- if (status == -1) {
+ if (status == PCAP_ERROR) {
/*
* Error. Report it.
*/
- (void)fprintf(stderr, "%s: pcap_loop: %s\n",
+ (void)fprintf(stderr, "%s: pcap_dispatch: %s\n",
program_name, pcap_geterr(pd));
}
return 0;
@@ -182,7 +182,7 @@ main(int argc, char **argv)
{
register int op;
register char *cp, *cmdbuf, *device;
- int immediate = 0;
+ int do_wakeup = 1;
pcap_if_t *devlist;
bpf_u_int32 localnet, netmask;
struct bpf_program fcode;
@@ -200,13 +200,17 @@ main(int argc, char **argv)
program_name = argv[0];
opterr = 0;
- while ((op = getopt(argc, argv, "i:")) != -1) {
+ while ((op = getopt(argc, argv, "i:n")) != -1) {
switch (op) {
case 'i':
device = optarg;
break;
+ case 'n':
+ do_wakeup = 0;
+ break;
+
default:
usage();
/* NOTREACHED */
@@ -229,12 +233,6 @@ main(int argc, char **argv)
if (status != 0)
error("%s: pcap_set_snaplen failed: %s",
device, pcap_statustostr(status));
- if (immediate) {
- status = pcap_set_immediate_mode(pd, 1);
- if (status != 0)
- error("%s: pcap_set_immediate_mode failed: %s",
- device, pcap_statustostr(status));
- }
status = pcap_set_timeout(pd, 5*60*1000);
if (status != 0)
error("%s: pcap_set_timeout failed: %s",
@@ -280,21 +278,39 @@ main(int argc, char **argv)
error("Can't create capture thread: %s", strerror(status));
#endif
sleep_secs(60);
+ printf("Doing pcap_breakloop()\n");
pcap_breakloop(pd);
+ if (do_wakeup) {
+ /*
+ * Force a wakeup in the capture thread.
+ *
+ * On some platforms, with some devices,, pcap_breakloop()
+ * can't do that itself. On Windows, poke the device's
+ * event handle; on UN*X, send a SIGUSR1 to the thread.
+ */
+#ifdef _WIN32
+ printf("Setting event\n");
+ if (!SetEvent(pcap_getevent(pd)))
+ error("Can't set event for pcap_t: %s",
+ win32_strerror(GetLastError()));
+#else
+ printf("Sending SIGUSR1\n");
+ status = pthread_kill(capture_thread, SIGUSR1);
+ if (status != 0)
+ warning("Can't interrupt capture thread: %s",
+ strerror(status));
+#endif
+ }
+
+ /*
+ * Now wait for the capture thread to terminate.
+ */
#ifdef _WIN32
- printf("Setting event\n");
- if (!SetEvent(pcap_getevent(pd)))
- error("Can't set event for pcap_t: %s",
- win32_strerror(GetLastError()));
if (WaitForSingleObject(capture_thread, INFINITE) == WAIT_FAILED)
error("Wait for thread termination failed: %s",
win32_strerror(GetLastError()));
CloseHandle(capture_thread);
#else
- printf("Sending SIGUSR1\n");
- status = pthread_kill(capture_thread, SIGUSR1);
- if (status != 0)
- warning("Can't interrupt capture thread: %s", strerror(status));
status = pthread_join(capture_thread, &retval);
if (status != 0)
error("Wait for thread termination failed: %s",
@@ -317,7 +333,7 @@ countme(u_char *user, const struct pcap_pkthdr *h _U_, const u_char *sp _U_)
static void
usage(void)
{
- (void)fprintf(stderr, "Usage: %s [ -m ] [ -i interface ] [ -t timeout] [expression]\n",
+ (void)fprintf(stderr, "Usage: %s [ -n ] [ -i interface ] [ expression ]\n",
program_name);
exit(1);
}
@@ -365,7 +381,7 @@ static char *
copy_argv(register char **argv)
{
register char **p;
- register u_int len = 0;
+ register size_t len = 0;
char *buf;
char *src, *dst;
diff --git a/testprogs/valgrindtest.c b/testprogs/valgrindtest.c
index 104ef6a9..058b18be 100644
--- a/testprogs/valgrindtest.c
+++ b/testprogs/valgrindtest.c
@@ -59,6 +59,7 @@ The Regents of the University of California. All rights reserved.\n";
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
+#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
@@ -99,6 +100,23 @@ The Regents of the University of California. All rights reserved.\n";
#endif
+/*
+ * Squelch a warning.
+ *
+ * We include system headers to be able to directly set the filter to
+ * a program with uninitialized content, to make sure what we're testing
+ * is Valgrind's checking of the system call to set the filter, and we
+ * 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
+ * avoid the warnings, as the preprocessor doesn't know that u_short is
+ * just unsigned short).
+ *
+ * So we undefine BPF_STMT and BPF_JUMP to avoid the warning.
+ */
+#undef BPF_STMT
+#undef BPF_JUMP
#include <pcap.h>
static char *program_name;
@@ -132,11 +150,21 @@ read_infile(char *fname)
if (fstat(fd, &buf) < 0)
error("can't stat %s: %s", fname, pcap_strerror(errno));
+ /*
+ * _read(), on Windows, has an unsigned int byte count and an
+ * int return value, so we can't handle a file bigger than
+ * INT_MAX - 1 bytes (and have no reason to do so; a filter *that*
+ * big will take forever to compile). (The -1 is for the '\0' at
+ * the end of the string.)
+ */
+ if (buf.st_size > INT_MAX - 1)
+ error("%s is larger than %d bytes; that's too large", fname,
+ INT_MAX - 1);
cp = malloc((u_int)buf.st_size + 1);
if (cp == NULL)
error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
fname, pcap_strerror(errno));
- cc = read(fd, cp, (u_int)buf.st_size);
+ cc = (int)read(fd, cp, (u_int)buf.st_size);
if (cc < 0)
error("read %s: %s", fname, pcap_strerror(errno));
if (cc != buf.st_size)
@@ -196,7 +224,7 @@ static char *
copy_argv(register char **argv)
{
register char **p;
- register u_int len = 0;
+ register size_t len = 0;
char *buf;
char *src, *dst;
@@ -421,7 +449,7 @@ usage(void)
(void)fprintf(stderr, "%s, with %s\n", program_name,
pcap_lib_version());
(void)fprintf(stderr,
- "Usage: %s [-aI] [ -F file ] [ -I interface ] [ expression ]\n",
+ "Usage: %s [-aI] [ -F file ] [ -i interface ] [ expression ]\n",
program_name);
exit(1);
}
diff --git a/testprogs/visopts.py b/testprogs/visopts.py
index 03aa804e..80c14639 100755
--- a/testprogs/visopts.py
+++ b/testprogs/visopts.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-This program parse the output from pcap_compile() to visualize the CFG after
+This program parses the output from pcap_compile() to visualize the CFG after
each optimize phase.
Usage guide:
@@ -15,23 +15,24 @@ Usage guide:
testprogs/filtertest -g EN10MB host 192.168.1.1 > a.txt
3. Send a.txt to this program's standard input
cat a.txt | testprogs/visopts.py
+ (Graphviz must be installed)
4. Step 2&3 can be merged:
testprogs/filtertest -g EN10MB host 192.168.1.1 | testprogs/visopts.py
5. The standard output is something like this:
generated files under directory: /tmp/visopts-W9ekBw
the directory will be removed when this programs finished.
open this link: http://localhost:39062/expr1.html
-6. Using open link at the 3rd line `http://localhost:39062/expr1.html'
+6. Open the URL at the 3rd line in a browser.
Note:
-1. The CFG is translated to SVG an document, expr1.html embeded them as external
- document. If you open expr1.html as local file using file:// protocol, some
- browsers will deny such requests so the web pages will not shown properly.
- For chrome, you can run it using following command to avoid this:
+1. The CFG is translated to SVG images, expr1.html embeds them as external
+ documents. If you open expr1.html as local file using file:// protocol, some
+ browsers will deny such requests so the web page will not work properly.
+ For Chrome, you can run it using the following command to avoid this:
chromium --disable-web-security
- That's why this program start a localhost http server.
-2. expr1.html use jquery from http://ajax.googleapis.com, so you need internet
- access to show the web page.
+ That's why this program starts a localhost HTTP server.
+2. expr1.html uses jQuery from https://ajax.googleapis.com, so it needs Internet
+ access to work.
"""
import sys, os
@@ -52,7 +53,7 @@ html_template = string.Template("""
}
</style>
- <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"/></script>
+ <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';
@@ -142,7 +143,7 @@ html_template = string.Template("""
}
function load_left(index) {
var url = gurl(index);
- var frag = "<embed id='leftsvgc' type='image/svg+xml' pluginspage='http://www.adobe.com/svg/viewer/install/' src='" + url + "'/>";
+ var frag = "<embed id='leftsvgc' type='image/svg+xml' pluginspage='https://www.adobe.com/svg/viewer/install/' src='" + url + "'/>";
$$("#lsvg").html(frag);
$$("#lcomment").html(logs[index]);
$$("#lsvglink").attr("href", url);
@@ -151,7 +152,7 @@ html_template = string.Template("""
}
function load_right(index) {
var url = gurl(index);
- var frag = "<embed id='rightsvgc' type='image/svg+xml' pluginspage='http://www.adobe.com/svg/viewer/install/' src='" + url + "'/>";
+ var frag = "<embed id='rightsvgc' type='image/svg+xml' pluginspage='https://www.adobe.com/svg/viewer/install/' src='" + url + "'/>";
$$("#rsvg").html(frag);
$$("#rcomment").html(logs[index]);
$$("#rsvglink").attr("href", url);
@@ -255,7 +256,13 @@ def render_on_html(infile):
log += line
if indot == 2:
- p = subprocess.Popen(['dot', '-Tsvg'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ try:
+ p = subprocess.Popen(['dot', '-Tsvg'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ except OSError as ose:
+ print "Failed to run 'dot':", ose
+ print "(Is Graphviz installed?)"
+ exit(1)
+
svg = p.communicate(dot)[0]
with file("expr1_g%03d.svg" % (gid), "wt") as f:
f.write(svg)
@@ -296,7 +303,7 @@ def main():
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 programs finished."
+ print " the directory will be removed when this program has finished."
if not render_on_html(sys.stdin):
return 1
diff --git a/testprogs/writecaptest.c b/testprogs/writecaptest.c
new file mode 100644
index 00000000..4db532c6
--- /dev/null
+++ b/testprogs/writecaptest.c
@@ -0,0 +1,556 @@
+/*
+ * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "varattrs.h"
+
+#ifndef lint
+static const char copyright[] _U_ =
+ "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
+The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
+#ifdef _WIN32
+ #include "getopt.h"
+#else
+ #include <unistd.h>
+#endif
+#include <errno.h>
+#ifndef _WIN32
+ #include <signal.h>
+#endif
+#include <sys/types.h>
+
+#include <pcap.h>
+
+#include "pcap/funcattrs.h"
+
+#ifdef _WIN32
+ #include "portability.h"
+#endif
+
+static char *program_name;
+
+/* Forwards */
+static void PCAP_NORETURN usage(void);
+static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2);
+static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2);
+static char *copy_argv(char **);
+
+static pcap_t *pd;
+
+#ifdef _WIN32
+static BOOL WINAPI
+stop_capture(DWORD ctrltype _U_)
+{
+ pcap_breakloop(pd);
+ return TRUE;
+}
+#else
+static void
+stop_capture(int signum _U_)
+{
+ pcap_breakloop(pd);
+}
+#endif
+
+static long
+parse_interface_number(const char *device)
+{
+ const char *p;
+ long devnum;
+ char *end;
+
+ /*
+ * Search for a colon, terminating any scheme at the beginning
+ * of the device.
+ */
+ p = strchr(device, ':');
+ if (p != NULL) {
+ /*
+ * We found it. Is it followed by "//"?
+ */
+ p++; /* skip the : */
+ if (strncmp(p, "//", 2) == 0) {
+ /*
+ * Yes. Search for the next /, at the end of the
+ * authority part of the URL.
+ */
+ p += 2; /* skip the // */
+ p = strchr(p, '/');
+ if (p != NULL) {
+ /*
+ * OK, past the / is the path.
+ */
+ device = p + 1;
+ }
+ }
+ }
+ devnum = strtol(device, &end, 10);
+ if (device != end && *end == '\0') {
+ /*
+ * It's all-numeric, but is it a valid number?
+ */
+ if (devnum <= 0) {
+ /*
+ * No, it's not an ordinal.
+ */
+ error("Invalid adapter index");
+ }
+ return (devnum);
+ } else {
+ /*
+ * It's not all-numeric; return -1, so our caller
+ * knows that.
+ */
+ return (-1);
+ }
+}
+
+static char *
+find_interface_by_number(long devnum)
+{
+ pcap_if_t *dev, *devlist;
+ long i;
+ char ebuf[PCAP_ERRBUF_SIZE];
+ char *device;
+ int status;
+
+ status = pcap_findalldevs(&devlist, ebuf);
+ if (status < 0)
+ error("%s", ebuf);
+ /*
+ * Look for the devnum-th entry in the list of devices (1-based).
+ */
+ for (i = 0, dev = devlist; i < devnum-1 && dev != NULL;
+ i++, dev = dev->next)
+ ;
+ if (dev == NULL)
+ error("Invalid adapter index");
+ device = strdup(dev->name);
+ pcap_freealldevs(devlist);
+ return (device);
+}
+
+static pcap_t *
+open_interface(const char *device, int snaplen_set, int snaplen, char *ebuf)
+{
+ pcap_t *pc;
+ int status;
+ char *cp;
+
+ pc = pcap_create(device, ebuf);
+ if (pc == NULL) {
+ /*
+ * If this failed with "No such device", that means
+ * the interface doesn't exist; return NULL, so that
+ * the caller can see whether the device name is
+ * actually an interface index.
+ */
+ if (strstr(ebuf, "No such device") != NULL)
+ return (NULL);
+ error("%s", ebuf);
+ }
+ if (snaplen_set) {
+ status = pcap_set_snaplen(pc, snaplen);
+ if (status != 0)
+ error("%s: pcap_set_snaplen failed: %s",
+ device, pcap_statustostr(status));
+ }
+ status = pcap_set_timeout(pc, 100);
+ if (status != 0)
+ error("%s: pcap_set_timeout failed: %s",
+ device, pcap_statustostr(status));
+ status = pcap_activate(pc);
+ if (status < 0) {
+ /*
+ * pcap_activate() failed.
+ */
+ cp = pcap_geterr(pc);
+ if (status == PCAP_ERROR)
+ error("%s", cp);
+ else if (status == PCAP_ERROR_NO_SUCH_DEVICE) {
+ /*
+ * Return an error for our caller to handle.
+ */
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s\n(%s)",
+ device, pcap_statustostr(status), cp);
+ } else if (status == PCAP_ERROR_PERM_DENIED && *cp != '\0')
+ error("%s: %s\n(%s)", device,
+ pcap_statustostr(status), cp);
+ else
+ error("%s: %s", device,
+ pcap_statustostr(status));
+ pcap_close(pc);
+ return (NULL);
+ } else if (status > 0) {
+ /*
+ * pcap_activate() succeeded, but it's warning us
+ * of a problem it had.
+ */
+ cp = pcap_geterr(pc);
+ if (status == PCAP_WARNING)
+ warning("%s", cp);
+ else if (status == PCAP_WARNING_PROMISC_NOTSUP &&
+ *cp != '\0')
+ warning("%s: %s\n(%s)", device,
+ pcap_statustostr(status), cp);
+ else
+ warning("%s: %s", device,
+ pcap_statustostr(status));
+ }
+ return (pc);
+}
+
+#define COMMAND_OPTIONS "DLi:s:w:y:"
+
+int
+main(int argc, char **argv)
+{
+ int op;
+ char *cp, *cmdbuf = NULL, *device, *end, *savefile = NULL;
+ int snaplen = 0;
+ int snaplen_set = 0;
+ pcap_if_t *devlist;
+ long devnum;
+ int show_interfaces = 0;
+ int show_dlt_types = 0;
+ int ndlts;
+ int *dlts;
+ bpf_u_int32 localnet, netmask;
+ struct bpf_program fcode;
+ char ebuf[PCAP_ERRBUF_SIZE];
+#ifndef _WIN32
+ struct sigaction action;
+#endif
+ int dlt;
+ const char *dlt_name = NULL;
+ int status;
+ pcap_dumper_t *pdd;
+
+ device = NULL;
+ if ((cp = strrchr(argv[0], '/')) != NULL)
+ program_name = cp + 1;
+ else
+ program_name = argv[0];
+
+ opterr = 0;
+ while ((op = getopt(argc, argv, COMMAND_OPTIONS)) != -1) {
+ switch (op) {
+
+ case 'D':
+ show_interfaces = 1;
+ break;
+
+ case 'L':
+ show_dlt_types = 1;
+ break;
+
+ case 'i':
+ device = optarg;
+ break;
+
+ case 's':
+ snaplen = (int)strtol(optarg, &end, 0);
+ if (optarg == end || *end != '\0' || snaplen < 0)
+ error("invalid snaplen %s (must be >= 0)",
+ optarg);
+ snaplen_set = 1;
+ break;
+
+ case 'w':
+ savefile = optarg;
+ break;
+
+ case 'y':
+ dlt_name = optarg;
+ break;
+
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+
+ if (show_interfaces) {
+ pcap_if_t *dev;
+ int i;
+
+ if (pcap_findalldevs(&devlist, ebuf) < 0)
+ error("%s", ebuf);
+ for (i = 0, dev = devlist; dev != NULL; i++, dev = dev->next) {
+ printf("%d.%s", i+1, dev->name);
+ if (dev->description != NULL)
+ printf(" (%s)", dev->description);
+ printf("\n");
+ }
+ pcap_freealldevs(devlist);
+ return (0);
+ }
+
+ if (device == NULL) {
+ if (pcap_findalldevs(&devlist, ebuf) == -1)
+ error("%s", ebuf);
+ if (devlist == NULL)
+ error("no interfaces available for capture");
+ device = strdup(devlist->name);
+ pcap_freealldevs(devlist);
+ }
+ if (show_dlt_types) {
+ pd = pcap_create(device, ebuf);
+ if (pd == NULL)
+ error("%s", ebuf);
+ status = pcap_activate(pd);
+ if (status < 0) {
+ /*
+ * pcap_activate() failed.
+ */
+ error("%s: %s\n(%s)", device,
+ pcap_statustostr(status), pcap_geterr(pd));
+ }
+ ndlts = pcap_list_datalinks(pd, &dlts);
+ if (ndlts < 0) {
+ /*
+ * pcap_list_datalinks() failed.
+ */
+ error("%s: %s\n(%s)", device,
+ pcap_statustostr(status), pcap_geterr(pd));
+ }
+ for (int i = 0; i < ndlts; i++) {
+ dlt_name = pcap_datalink_val_to_name(dlts[i]);
+ if (dlt_name == NULL)
+ printf("DLT %d", dlts[i]);
+ else
+ printf("%s", dlt_name);
+ printf("\n");
+ }
+ pcap_free_datalinks(dlts);
+ pcap_close(pd);
+ return 0;
+ }
+
+ if (savefile == NULL)
+ error("no savefile specified");
+
+ *ebuf = '\0';
+
+ pd = open_interface(device, snaplen_set, snaplen, ebuf);
+ if (pd == NULL) {
+ /*
+ * That failed because the interface couldn't be found.
+ *
+ * If we can get a list of interfaces, and the interface name
+ * is purely numeric, try to use it as a 1-based index
+ * in the list of interfaces.
+ */
+ devnum = parse_interface_number(device);
+ if (devnum == -1) {
+ /*
+ * It's not a number; just report
+ * the open error and fail.
+ */
+ error("%s", ebuf);
+ }
+
+ /*
+ * OK, it's a number; try to find the
+ * interface with that index, and try
+ * to open it.
+ *
+ * find_interface_by_number() exits if it
+ * couldn't be found.
+ */
+ device = find_interface_by_number(devnum);
+ pd = open_interface(device, snaplen_set, snaplen, ebuf);
+ if (pd == NULL)
+ error("%s", ebuf);
+ }
+
+ if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
+ localnet = 0;
+ netmask = 0;
+ warning("%s", ebuf);
+ }
+
+ if (dlt_name != NULL) {
+ dlt = pcap_datalink_name_to_val(dlt_name);
+ if (dlt == PCAP_ERROR)
+ error("%s isn't a valid DLT name", dlt_name);
+ if (pcap_set_datalink(pd, dlt) == PCAP_ERROR)
+ error("%s: %s", device, pcap_geterr(pd));
+ }
+
+ /*
+ * Don't set a filter unless we were given one on the
+ * command line; if capturing doesn't work, or doesn't
+ * use the snapshot length, without a filter, that's
+ * a bug.
+ */
+ if (optind < argc) {
+ cmdbuf = copy_argv(&argv[optind]);
+
+ if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0)
+ error("%s", pcap_geterr(pd));
+
+ if (pcap_setfilter(pd, &fcode) < 0)
+ error("%s", pcap_geterr(pd));
+ }
+
+ pdd = pcap_dump_open(pd, savefile);
+ if (pdd == NULL)
+ error("%s", pcap_geterr(pd));
+
+#ifdef _WIN32
+ SetConsoleCtrlHandler(stop_capture, TRUE);
+#else
+ action.sa_handler = stop_capture;
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ if (sigaction(SIGINT, &action, NULL) == -1)
+ error("Can't catch SIGINT: %s\n", strerror(errno));
+#endif
+
+ printf("Listening on %s, link-type ", device);
+ dlt = pcap_datalink(pd);
+ dlt_name = pcap_datalink_val_to_name(dlt);
+ if (dlt_name == NULL)
+ printf("DLT %d", dlt);
+ else
+ printf("%s", dlt_name);
+ printf("\n");
+ for (;;) {
+ status = pcap_dispatch(pd, -1, pcap_dump, (u_char *)pdd);
+ if (status < 0)
+ break;
+ if (status != 0) {
+ printf("%d packets seen\n", status);
+ struct pcap_stat ps;
+ pcap_stats(pd, &ps);
+ printf("%d ps_recv, %d ps_drop, %d ps_ifdrop\n",
+ ps.ps_recv, ps.ps_drop, ps.ps_ifdrop);
+ }
+ }
+ if (status == -2) {
+ /*
+ * We got interrupted, so perhaps we didn't
+ * manage to finish a line we were printing.
+ * Print an extra newline, just in case.
+ */
+ putchar('\n');
+ printf("Broken out of loop from SIGINT handler\n");
+ }
+ (void)fflush(stdout);
+ if (status == -1) {
+ /*
+ * Error. Report it.
+ */
+ (void)fprintf(stderr, "%s: pcap_dispatch: %s\n",
+ program_name, pcap_geterr(pd));
+ }
+ pcap_close(pd);
+ if (cmdbuf != NULL) {
+ pcap_freecode(&fcode);
+ free(cmdbuf);
+ }
+ exit(status == -1 ? 1 : 0);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "Usage: %s -D -L [ -i interface ] [ -s snaplen ] [ -w file ] [ -y dlt ] [expression]\n",
+ program_name);
+ exit(1);
+}
+
+/* VARARGS */
+static void
+error(const char *fmt, ...)
+{
+ va_list ap;
+
+ (void)fprintf(stderr, "%s: ", program_name);
+ va_start(ap, fmt);
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ if (*fmt) {
+ fmt += strlen(fmt);
+ if (fmt[-1] != '\n')
+ (void)fputc('\n', stderr);
+ }
+ exit(1);
+ /* NOTREACHED */
+}
+
+/* VARARGS */
+static void
+warning(const char *fmt, ...)
+{
+ va_list ap;
+
+ (void)fprintf(stderr, "%s: WARNING: ", program_name);
+ va_start(ap, fmt);
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ if (*fmt) {
+ fmt += strlen(fmt);
+ if (fmt[-1] != '\n')
+ (void)fputc('\n', stderr);
+ }
+}
+
+/*
+ * Copy arg vector into a new buffer, concatenating arguments with spaces.
+ */
+static char *
+copy_argv(register char **argv)
+{
+ register char **p;
+ register size_t len = 0;
+ char *buf;
+ char *src, *dst;
+
+ p = argv;
+ if (*p == 0)
+ return 0;
+
+ while (*p)
+ len += strlen(*p++) + 1;
+
+ buf = (char *)malloc(len);
+ if (buf == NULL)
+ error("copy_argv: malloc");
+
+ p = argv;
+ dst = buf;
+ while ((src = *p++) != NULL) {
+ while ((*dst++ = *src++) != '\0')
+ ;
+ dst[-1] = ' ';
+ }
+ dst[-1] = '\0';
+
+ return buf;
+}