mirror of
https://github.com/mfontanini/libtins
synced 2026-01-23 18:55:58 +01:00
Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37c92fcf5c | ||
|
|
18281e614d | ||
|
|
7f8644cb39 | ||
|
|
799ba2b4b6 | ||
|
|
ad0a1ca97d | ||
|
|
7607610cf9 | ||
|
|
a71a3d29ff | ||
|
|
9051197603 | ||
|
|
94e5ac2109 | ||
|
|
84cb686928 | ||
|
|
da07ad3b13 | ||
|
|
d5cba00ce0 | ||
|
|
ba9d0b34c6 | ||
|
|
f2850cc0b9 | ||
|
|
c69ea0c1fb | ||
|
|
a63387f85e | ||
|
|
df7e7b391d | ||
|
|
5d6431d2d9 | ||
|
|
a61a361eb1 | ||
|
|
9dbad2a26f | ||
|
|
aaba3dd46a | ||
|
|
2e013847d9 | ||
|
|
22e569d430 | ||
|
|
2847039ffe | ||
|
|
54ce11629c | ||
|
|
8dcfd6aae0 | ||
|
|
838a4a5cb9 | ||
|
|
e82b72e931 | ||
|
|
fdc6ccdf5c | ||
|
|
52b389afe8 | ||
|
|
552006c876 | ||
|
|
f0b32edaa9 | ||
|
|
5a901ca155 | ||
|
|
9593cf4cf6 | ||
|
|
64725e2ed9 | ||
|
|
9260f9374a | ||
|
|
2ccf50db3e | ||
|
|
e843ee7117 | ||
|
|
a192e814bf | ||
|
|
ccda631708 | ||
|
|
1552e33c67 | ||
|
|
8afc784956 | ||
|
|
5b00916f83 | ||
|
|
6b7bc76603 | ||
|
|
732c665af5 | ||
|
|
8cf367d68c | ||
|
|
d070978a54 | ||
|
|
7f30efab38 | ||
|
|
d7fed87ebb | ||
|
|
269ac164ed | ||
|
|
55edf31aa6 | ||
|
|
364782b8af | ||
|
|
d3c576f6de | ||
|
|
8d52d73968 | ||
|
|
48022d3a3f | ||
|
|
ec1634d6d8 | ||
|
|
688bb7094e | ||
|
|
928e66eb27 | ||
|
|
d80c27de29 | ||
|
|
6aac22fa74 | ||
|
|
7bc1ab41f7 | ||
|
|
068e304baa | ||
|
|
5dc7b20a43 | ||
|
|
a70ce10bed | ||
|
|
3773443fc8 | ||
|
|
1f4be63d08 | ||
|
|
6a69d1ff6c | ||
|
|
85102b4546 | ||
|
|
f188ea4d2a | ||
|
|
a75dd9e3f9 | ||
|
|
dda673cad4 | ||
|
|
8b125d31f2 | ||
|
|
67ee3e8a7d | ||
|
|
d70536f9ab | ||
|
|
97e24131c6 | ||
|
|
42b6c40433 | ||
|
|
4dcef0f15d |
9
AUTHORS
9
AUTHORS
@@ -1,9 +0,0 @@
|
||||
# Below is a list of people and organizations that have contributed source
|
||||
# code to libtins. Names are listed using the following format:
|
||||
#
|
||||
# Name/Organization <email address>
|
||||
|
||||
Matias Fontanini <matias.fontanini@gmail.com>
|
||||
Santiago Alessandri <san.lt.ss@gmail.com>
|
||||
Bruno Nery <brunonery@brunonery.com>
|
||||
Piotr Haber <piotr.haber@sens.us>
|
||||
@@ -1,4 +1,74 @@
|
||||
v3.4 - Wed Mar 9 20:24:54 PST 2016
|
||||
##### v3.5 - Sat Apr 1 09:11:58 PDT 2017
|
||||
|
||||
- Added Utils::route6_entries
|
||||
|
||||
- Allow masking IPv4/6 and hardware addresses via `operator&`
|
||||
|
||||
- Add IPv4Address::from_prefix_length
|
||||
|
||||
- Move `stream_id` into a new file and rename it `StreamIdentifier`
|
||||
|
||||
- Allow disabling TCPIP classes
|
||||
|
||||
- Properly handle out of order SACKs on `AckTracker`
|
||||
|
||||
- Move TCP data tracking into a separate class
|
||||
|
||||
- Allow constructing `StreamIdentifier` from a `Stream`
|
||||
|
||||
- Allow configuring pcap timestamp precision
|
||||
|
||||
- Allow building libtins using MinGW
|
||||
|
||||
- Allow including libtins using `add_subdirectory` via CMake
|
||||
|
||||
- Allow setting customer user data to each TCP stream
|
||||
|
||||
- Allow skipping data forward in TCP streams
|
||||
|
||||
- Allow attaching to already existing TCP streams
|
||||
|
||||
- Fix: AddressRange masks first address as well
|
||||
|
||||
- Fix: Add TINS_API to `IPv4Address::operator<<`, `DataTracker` and `AckTracker`
|
||||
|
||||
- Fix: Don't always set `key_t` to 0 on `RSNEAPOL`
|
||||
|
||||
- Fix: Handle MLDv1 properly on ICMP
|
||||
|
||||
- Fix: Make Utils::resolve_hwaddress work on Windows
|
||||
|
||||
- Fix: Interface was sometimes considered down when it was up (BSD/Linux)
|
||||
|
||||
- Fix: Don't set `Dot1Q`'s payload type if next protocol type is unknown
|
||||
|
||||
- Fix: Use recvfrom on BSD/OSX when capturing layer 3 packets
|
||||
|
||||
- Fix: Make `Timestamp::current_time` work on Windows
|
||||
|
||||
- Fix: Forward `NetworkInterface` argument when calling `PacketSender::send_l2`
|
||||
|
||||
- Fix: `Timestamp` overflow issue
|
||||
|
||||
- Fix: boost's include directories variable incorrectly used on build system
|
||||
|
||||
- Fix: Configuring auto cleanup of `Stream`'s server data not working
|
||||
|
||||
- Fix: Set `EthernetII` payload type to `UNKNOWN` if there's no inner PDU
|
||||
|
||||
- Fix: Set payload type to 0 if there's no inner PDU in `IP`, `Dot1Q` and `IPv6`
|
||||
|
||||
- Fix: Buffer length check issues on `Dot11QosData`
|
||||
|
||||
- Fix: Use AF_INET6 flag when opening L3 IPv6 socket
|
||||
|
||||
- Fix: Check expecter size properly on `DNS::extract_metadata`
|
||||
|
||||
- Fix: several unused parameter warnings
|
||||
|
||||
- Fix: CCMP decryption issue when `Dot11QoSData` has a TID != 0
|
||||
|
||||
##### v3.4 - Wed Mar 9 20:24:54 PST 2016
|
||||
|
||||
- Check the secure bit on HandshakeCapturer to detect 2nd packet
|
||||
|
||||
@@ -50,7 +120,7 @@ v3.4 - Wed Mar 9 20:24:54 PST 2016
|
||||
|
||||
- Fix invalid endian on IP fragment offset on OSX
|
||||
|
||||
v3.3 - Sun Jan 31 21:06:04 PST 2016
|
||||
##### v3.3 - Sun Jan 31 21:06:04 PST 2016
|
||||
|
||||
- Add TCP connection close example
|
||||
|
||||
@@ -215,7 +285,7 @@ immutable
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
v3.2 - Fri Mar 20 22:12:23 PST 2015
|
||||
##### v3.2 - Fri Mar 20 22:12:23 PST 2015
|
||||
|
||||
- Added include guard for config.h.
|
||||
|
||||
@@ -298,7 +368,7 @@ conversion on integral constant.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
v3.1 - Sun Aug 24 21:39:43 ART 2014
|
||||
##### v3.1 - Sun Aug 24 21:39:43 ART 2014
|
||||
|
||||
- Fixed ICMPv6 checksum error on serialization.
|
||||
|
||||
@@ -308,7 +378,7 @@ v3.1 - Sun Aug 24 21:39:43 ART 2014
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
v3.0 - Thu Aug 7 21:39:09 ART 2014
|
||||
##### v3.0 - Thu Aug 7 21:39:09 ART 2014
|
||||
|
||||
- Timestamps can now be constructed from std::chrono::duration.
|
||||
|
||||
@@ -373,7 +443,7 @@ PDU types.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
v2.0 - Thu Jan 23 11:09:38 ART 2014
|
||||
##### v2.0 - Thu Jan 23 11:09:38 ART 2014
|
||||
|
||||
- DNSResourceRecord was removed. Now DNS records are added using
|
||||
DNS::Resource.
|
||||
@@ -429,7 +499,7 @@ capture size.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
v1.2 - Mon oct 7 23:33:49 ART 2013
|
||||
##### v1.2 - Mon oct 7 23:33:49 ART 2013
|
||||
|
||||
- Added BaseSniffer::begin and BaseSniffer::end.
|
||||
|
||||
@@ -525,7 +595,7 @@ that used them.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
v0.3 - Thu Jan 31 16:47:27 ART 2013
|
||||
##### v0.3 - Thu Jan 31 16:47:27 ART 2013
|
||||
|
||||
- Added IPv6, ICMPv6 and DHCPv6 classes.
|
||||
|
||||
@@ -546,7 +616,7 @@ pseudo protocol.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
v0.2 - Sat Oct 20 11:26:40 2012
|
||||
##### v0.2 - Sat Oct 20 11:26:40 2012
|
||||
|
||||
- Added support for big endian architectures.
|
||||
|
||||
@@ -4,7 +4,7 @@ PROJECT(libtins)
|
||||
# Compile in release mode by default
|
||||
IF(NOT CMAKE_BUILD_TYPE)
|
||||
MESSAGE(STATUS "Setting build type to 'RelWithDebInfo' as none was specified.")
|
||||
SET(CMAKE_BUILD_TYPE RelWithDebInfo)
|
||||
SET(CMAKE_BUILD_TYPE RelWithDebInfo)
|
||||
ELSE(NOT CMAKE_BUILD_TYPE)
|
||||
MESSAGE(STATUS "Using specified '${CMAKE_BUILD_TYPE}' build type.")
|
||||
ENDIF(NOT CMAKE_BUILD_TYPE)
|
||||
@@ -18,11 +18,11 @@ IF(MSVC)
|
||||
ADD_DEFINITIONS("-D_SCL_SECURE_NO_WARNINGS=1")
|
||||
ADD_DEFINITIONS("-DNOGDI=1")
|
||||
ELSE()
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
|
||||
ENDIF()
|
||||
|
||||
IF(APPLE)
|
||||
# This is set to ON as of policy CMP0042
|
||||
# This is set to ON as of policy CMP0042
|
||||
SET(CMAKE_MACOSX_RPATH ON)
|
||||
ENDIF()
|
||||
|
||||
@@ -30,7 +30,7 @@ ENDIF()
|
||||
OPTION(LIBTINS_BUILD_SHARED "Build libtins as a shared library." ON)
|
||||
IF(LIBTINS_BUILD_SHARED)
|
||||
MESSAGE(
|
||||
STATUS
|
||||
STATUS
|
||||
"Build will generate a shared library. "
|
||||
"Use LIBTINS_BUILD_SHARED=0 to perform a static build"
|
||||
)
|
||||
@@ -43,14 +43,20 @@ ENDIF(LIBTINS_BUILD_SHARED)
|
||||
|
||||
# The version number.
|
||||
SET(LIBTINS_VERSION_MAJOR 3)
|
||||
SET(LIBTINS_VERSION_MINOR 4)
|
||||
SET(LIBTINS_VERSION_MINOR 5)
|
||||
SET(LIBTINS_VERSION "${LIBTINS_VERSION_MAJOR}.${LIBTINS_VERSION_MINOR}")
|
||||
|
||||
# Required Packages
|
||||
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
|
||||
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/")
|
||||
|
||||
# Allow disabling packet capture mechanism
|
||||
OPTION(LIBTINS_ENABLE_PCAP "Enable capturing packets via libpcap" ON)
|
||||
|
||||
# Look for libpcap
|
||||
FIND_PACKAGE(PCAP REQUIRED)
|
||||
IF(LIBTINS_ENABLE_PCAP)
|
||||
FIND_PACKAGE(PCAP REQUIRED)
|
||||
SET(TINS_HAVE_PCAP ON)
|
||||
ENDIF()
|
||||
|
||||
# Set some Windows specific flags
|
||||
IF(WIN32)
|
||||
@@ -59,6 +65,22 @@ IF(WIN32)
|
||||
|
||||
# Add the NOMINMAX macro to avoid Windows' min and max macros.
|
||||
ADD_DEFINITIONS(-DNOMINMAX)
|
||||
|
||||
# MinWG need some extra definitions to compile properly (WIN32 for PCAP and WIN32_WINNT version for ws2tcpip.h)
|
||||
IF(MINGW)
|
||||
ADD_DEFINITIONS(-DWIN32)
|
||||
MACRO(get_WIN32_WINNT version)
|
||||
IF (WIN32 AND CMAKE_SYSTEM_VERSION)
|
||||
SET(ver ${CMAKE_SYSTEM_VERSION})
|
||||
STRING(REPLACE "." "" ver ${ver})
|
||||
STRING(REGEX REPLACE "([0-9])" "0\\1" ver ${ver})
|
||||
SET(${version} "0x${ver}")
|
||||
ENDIF()
|
||||
ENDMACRO()
|
||||
get_WIN32_WINNT(ver)
|
||||
ADD_DEFINITIONS(-D_WIN32_WINNT=${ver})
|
||||
ENDIF(MINGW)
|
||||
|
||||
ENDIF(WIN32)
|
||||
|
||||
INCLUDE(ExternalProject)
|
||||
@@ -80,7 +102,7 @@ IF(LIBTINS_ENABLE_CXX11)
|
||||
# We only use declval and decltype on gcc/clang as VC fails to build that code,
|
||||
# at least on VC2013
|
||||
IF(HAS_CXX11_RVALUE_REFERENCES AND HAS_CXX11_FUNCTIONAL AND HAS_CXX11_CHRONO AND
|
||||
((HAS_CXX11_DECLVAL AND HAS_CXX11_DECLTYPE) OR MSVC))
|
||||
HAS_CXX11_NOEXCEPT AND ((HAS_CXX11_DECLVAL AND HAS_CXX11_DECLTYPE) OR MSVC))
|
||||
SET(TINS_HAVE_CXX11 ON)
|
||||
MESSAGE(STATUS "Enabling C++11 features")
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX11_COMPILER_FLAGS}")
|
||||
@@ -90,7 +112,7 @@ IF(LIBTINS_ENABLE_CXX11)
|
||||
ENDIF()
|
||||
ELSE(LIBTINS_ENABLE_CXX11)
|
||||
MESSAGE(
|
||||
WARNING
|
||||
WARNING
|
||||
"Disabling C++11 features. Use LIBTINS_ENABLE_CXX11=1 to enable them. "
|
||||
"Unless you are using an old compiler, you should enable this option, "
|
||||
"as it increases the library's performance")
|
||||
@@ -118,12 +140,25 @@ IF(LIBTINS_ENABLE_DOT11)
|
||||
ENDIF(LIBTINS_ENABLE_WPA2)
|
||||
ENDIF(LIBTINS_ENABLE_DOT11)
|
||||
|
||||
# Optionally enable TCPIP classes (on by default)
|
||||
OPTION(LIBTINS_ENABLE_TCPIP "Enable TCPIP classes" ON)
|
||||
IF(LIBTINS_ENABLE_TCPIP AND TINS_HAVE_CXX11)
|
||||
SET(TINS_HAVE_TCPIP ON)
|
||||
MESSAGE(STATUS "Enabling TCPIP classes")
|
||||
ELSE()
|
||||
SET(TINS_HAVE_TCPIP OFF)
|
||||
MESSAGE(STATUS "Disabling TCPIP classes")
|
||||
ENDIF()
|
||||
|
||||
# Search for libboost
|
||||
FIND_PACKAGE(Boost)
|
||||
|
||||
# Optionally enable the ACK tracker (on by default)
|
||||
OPTION(LIBTINS_ENABLE_ACK_TRACKER "Enable TCP ACK tracking support" ON)
|
||||
IF(LIBTINS_ENABLE_ACK_TRACKER AND TINS_HAVE_CXX11)
|
||||
FIND_PACKAGE(Boost)
|
||||
IF (Boost_FOUND)
|
||||
MESSAGE(STATUS "Enabling TCP ACK tracking support.")
|
||||
INCLUDE_DIRECTORIES(Boost_INCLUDE_DIRS)
|
||||
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
|
||||
SET(TINS_HAVE_ACK_TRACKER ON)
|
||||
ELSE()
|
||||
MESSAGE(WARNING "Disabling ACK tracking support as boost.icl was not found")
|
||||
@@ -134,6 +169,22 @@ ELSE()
|
||||
MESSAGE(STATUS "Disabling ACK tracking support")
|
||||
ENDIF()
|
||||
|
||||
# Optionally enable the TCP stream custom data (on by default)
|
||||
OPTION(LIBTINS_ENABLE_TCP_STREAM_CUSTOM_DATA "Enable TCP stream custom data support" ON)
|
||||
IF(LIBTINS_ENABLE_TCP_STREAM_CUSTOM_DATA AND TINS_HAVE_CXX11)
|
||||
IF (Boost_FOUND)
|
||||
MESSAGE(STATUS "Enabling TCP stream custom data support.")
|
||||
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
|
||||
SET(TINS_HAVE_TCP_STREAM_CUSTOM_DATA ON)
|
||||
ELSE()
|
||||
MESSAGE(WARNING "Disabling TCP stream custom data support as boost.any was not found")
|
||||
SET(TINS_HAVE_TCP_STREAM_CUSTOM_DATA OFF)
|
||||
ENDIF()
|
||||
ELSE()
|
||||
SET(TINS_HAVE_TCP_STREAM_CUSTOM_DATA OFF)
|
||||
MESSAGE(STATUS "Disabling TCP stream custom data support")
|
||||
ENDIF()
|
||||
|
||||
OPTION(LIBTINS_ENABLE_WPA2_CALLBACKS "Enable WPA2 callback interface" ON)
|
||||
IF(LIBTINS_ENABLE_WPA2_CALLBACKS AND TINS_HAVE_WPA2_DECRYPTION AND TINS_HAVE_CXX11)
|
||||
SET(STATUS "Enabling WPA2 callback interface")
|
||||
@@ -149,17 +200,17 @@ ENDIF(WIN32)
|
||||
|
||||
OPTION(LIBTINS_USE_PCAP_SENDPACKET "Use pcap_sendpacket to send l2 packets"
|
||||
${USE_PCAP_SENDPACKET_DEFAULT})
|
||||
IF(LIBTINS_USE_PCAP_SENDPACKET)
|
||||
IF(LIBTINS_ENABLE_PCAP AND LIBTINS_USE_PCAP_SENDPACKET)
|
||||
SET(TINS_HAVE_PACKET_SENDER_PCAP_SENDPACKET ON)
|
||||
MESSAGE(STATUS "Using pcap_sendpacket to send l2 packets.")
|
||||
ENDIF(LIBTINS_USE_PCAP_SENDPACKET)
|
||||
ENDIF()
|
||||
|
||||
# Add a target to generate API documentation using Doxygen
|
||||
FIND_PACKAGE(Doxygen QUIET)
|
||||
IF(DOXYGEN_FOUND)
|
||||
CONFIGURE_FILE(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||
@ONLY
|
||||
)
|
||||
ADD_CUSTOM_TARGET(
|
||||
@@ -210,14 +261,18 @@ ADD_CUSTOM_TARGET(uninstall
|
||||
# Add subdirectories
|
||||
# ******************
|
||||
ADD_SUBDIRECTORY(include)
|
||||
ADD_SUBDIRECTORY(examples)
|
||||
ADD_SUBDIRECTORY(src)
|
||||
IF(LIBTINS_ENABLE_PCAP)
|
||||
ADD_SUBDIRECTORY(examples)
|
||||
ELSE()
|
||||
MESSAGE(STATUS "Not building examples as pcap support is disabled")
|
||||
ENDIF()
|
||||
|
||||
# Only include googletest if the git submodule has been fetched
|
||||
IF(EXISTS "${CMAKE_SOURCE_DIR}/googletest/CMakeLists.txt")
|
||||
IF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/googletest/CMakeLists.txt")
|
||||
# Enable tests and add the test directory
|
||||
MESSAGE(STATUS "Tests have been enabled")
|
||||
SET(GOOGLETEST_ROOT ${CMAKE_SOURCE_DIR}/googletest)
|
||||
SET(GOOGLETEST_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/googletest)
|
||||
SET(GOOGLETEST_INCLUDE ${GOOGLETEST_ROOT}/googletest/include)
|
||||
SET(GOOGLETEST_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/googletest)
|
||||
SET(GOOGLETEST_LIBRARY ${GOOGLETEST_BINARY_DIR}/googletest)
|
||||
|
||||
@@ -125,23 +125,11 @@ function(cxx11_check_feature FEATURE_NAME RESULT_VAR)
|
||||
endif (NOT DEFINED ${RESULT_VAR})
|
||||
endfunction(cxx11_check_feature)
|
||||
|
||||
#cxx11_check_feature("regex" HAS_CXX11_LIB_REGEX)
|
||||
#cxx11_check_feature("__func__" HAS_CXX11_FUNC)
|
||||
#cxx11_check_feature("auto" HAS_CXX11_AUTO)
|
||||
#cxx11_check_feature("auto_ret_type" HAS_CXX11_AUTO_RET_TYPE)
|
||||
#cxx11_check_feature("class_override_final" HAS_CXX11_CLASS_OVERRIDE)
|
||||
#cxx11_check_feature("constexpr" HAS_CXX11_CONSTEXPR)
|
||||
#cxx11_check_feature("cstdint" HAS_CXX11_CSTDINT_H)
|
||||
#cxx11_check_feature("lambda" HAS_CXX11_LAMBDA)
|
||||
#cxx11_check_feature("long_long" HAS_CXX11_LONG_LONG)
|
||||
#cxx11_check_feature("nullptr" HAS_CXX11_NULLPTR)
|
||||
#cxx11_check_feature("sizeof_member" HAS_CXX11_SIZEOF_MEMBER)
|
||||
#cxx11_check_feature("static_assert" HAS_CXX11_STATIC_ASSERT)
|
||||
#cxx11_check_feature("variadic_templates" HAS_CXX11_VARIADIC_TEMPLATES)
|
||||
cxx11_check_feature("decltype" HAS_CXX11_DECLTYPE)
|
||||
cxx11_check_feature("declval" HAS_CXX11_DECLVAL)
|
||||
cxx11_check_feature("initializer_list" HAS_CXX11_INITIALIZER_LIST)
|
||||
cxx11_check_feature("rvalue-references" HAS_CXX11_RVALUE_REFERENCES)
|
||||
cxx11_check_feature("functional" HAS_CXX11_FUNCTIONAL)
|
||||
cxx11_check_feature("chrono" HAS_CXX11_CHRONO)
|
||||
cxx11_check_feature("noexcept" HAS_CXX11_NOEXCEPT)
|
||||
cxx11_check_feature("builtin-swap" HAS_GCC_BUILTIN_SWAP)
|
||||
|
||||
7
cmake/Modules/CheckCXXFeatures/cxx-test-noexcept.cpp
Normal file
7
cmake/Modules/CheckCXXFeatures/cxx-test-noexcept.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
int foo() noexcept {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
return foo();
|
||||
}
|
||||
@@ -75,6 +75,7 @@ include(CheckFunctionExists)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${PCAP_LIBRARY})
|
||||
check_function_exists(pcap_get_pfring_id HAVE_PF_RING)
|
||||
check_function_exists(pcap_set_immediate_mode HAVE_PCAP_IMMEDIATE_MODE)
|
||||
check_function_exists(pcap_set_tstamp_precision HAVE_PCAP_TIMESTAMP_PRECISION)
|
||||
set(CMAKE_REQUIRED_LIBRARIES)
|
||||
|
||||
mark_as_advanced(
|
||||
|
||||
@@ -5,6 +5,11 @@ configuration:
|
||||
platform:
|
||||
- Win32
|
||||
- x64
|
||||
environment:
|
||||
matrix:
|
||||
- compiler: vs2013
|
||||
- compiler: vs2015
|
||||
BOOST_ROOT: C:\Libraries\boost
|
||||
clone_depth: 1
|
||||
install:
|
||||
- git clone https://github.com/mfontanini/winpcap-installer.git
|
||||
@@ -18,8 +23,12 @@ install:
|
||||
before_build:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- if "%platform%"=="x64" ( set GENERATOR="Visual Studio 12 Win64" ) else ( set GENERATOR="Visual Studio 12" )
|
||||
- cmake .. -G %GENERATOR% -DPCAP_ROOT_DIR=c:\WpdPack -DLIBTINS_BUILD_SHARED=0 -DLIBTINS_ENABLE_WPA2=0
|
||||
- if "%compiler%"=="vs2013" (set VS_VERSION=12) else (set VS_VERSION=14)
|
||||
- set VS=Visual Studio %VS_VERSION%
|
||||
- if "%platform%"=="Win32" (set GENERATOR="%VS%" & set ARCH_BITS=32)
|
||||
- if "%platform%"=="x64" (set GENERATOR="%VS% Win64" & set ARCH_BITS=64)
|
||||
- set BOOST_LIBRARYDIR=C:\Libraries\boost\lib%ARCH_BITS%-msvc-%VS_VERSION%.0
|
||||
- cmake .. -G %GENERATOR% -DPCAP_ROOT_DIR=c:\WpdPack -DLIBTINS_BUILD_SHARED=0 -DLIBTINS_ENABLE_WPA2=0 -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_LIBRARYDIR="%BOOST_LIBRARYDIR%" -DBoost_USE_STATIC_LIBS="ON"
|
||||
build:
|
||||
project: C:/projects/libtins/build/libtins.sln
|
||||
verbosity: minimal
|
||||
@@ -34,11 +43,11 @@ after_build:
|
||||
- del include\tins\config.h.in
|
||||
- del include\tins\dot11\CMakeLists.txt
|
||||
- cd ..\
|
||||
- 7z a libtins-%platform%-%Configuration%.zip libtins
|
||||
- 7z a libtins-%compiler%-%platform%-%Configuration%.zip libtins
|
||||
test_script:
|
||||
- cd c:\projects\libtins\build
|
||||
- ctest -C %Configuration% -V
|
||||
deploy_script:
|
||||
- ps: Push-AppveyorArtifact "install\libtins-$env:Platform-$env:Configuration.zip"
|
||||
- ps: Push-AppveyorArtifact "install\libtins-$env:Compiler-$env:Platform-$env:Configuration.zip"
|
||||
skip_commits:
|
||||
message: /Update documentation.*/
|
||||
|
||||
@@ -56,7 +56,7 @@ bool callback(const PDU& pdu) {
|
||||
if (query.query_type() == DNS::A) {
|
||||
// Here's one! Let's add an answer.
|
||||
dns.add_answer(
|
||||
DNS::Resource(
|
||||
DNS::resource(
|
||||
query.dname(),
|
||||
"127.0.0.1",
|
||||
DNS::A,
|
||||
@@ -93,6 +93,8 @@ int main(int argc, char* argv[]) {
|
||||
// Sniff on the provided interface in promiscuos mode
|
||||
SnifferConfiguration config;
|
||||
config.set_promisc_mode(true);
|
||||
// Use immediate mode so we get the packets as fast as we can
|
||||
config.set_immediate_mode(true);
|
||||
// Only capture udp packets sent to port 53
|
||||
config.set_filter("udp and dst port 53");
|
||||
Sniffer sniffer(argv[1], config);
|
||||
|
||||
@@ -40,13 +40,30 @@ using std::vector;
|
||||
using namespace Tins;
|
||||
|
||||
int main() {
|
||||
vector<Utils::RouteEntry> entries = Utils::route_entries();
|
||||
for (size_t i = 0; i < entries.size(); ++i) {
|
||||
vector<Utils::RouteEntry> v4_entries = Utils::route_entries();
|
||||
cout << "IPv4 route table entries: " << endl
|
||||
<< "========================= " << endl;
|
||||
for (size_t i = 0; i < v4_entries.size(); ++i) {
|
||||
cout << "Entry " << setw(2) << i << ": " << endl
|
||||
<< "Interface: " << entries[i].interface << endl
|
||||
<< "Destination: " << entries[i].destination << endl
|
||||
<< "Gateway: " << entries[i].gateway << endl
|
||||
<< "Genmask: " << entries[i].mask << endl
|
||||
<< "Metric: " << entries[i].metric << endl << endl;
|
||||
<< "Interface: " << v4_entries[i].interface << endl
|
||||
<< "Destination: " << v4_entries[i].destination << endl
|
||||
<< "Gateway: " << v4_entries[i].gateway << endl
|
||||
<< "Genmask: " << v4_entries[i].mask << endl
|
||||
<< "Metric: " << v4_entries[i].metric << endl << endl;
|
||||
}
|
||||
|
||||
vector<Utils::Route6Entry> v6_entries = Utils::route6_entries();
|
||||
if (!v6_entries.empty()) {
|
||||
cout << endl
|
||||
<< "IPv6 route table entries: " << endl
|
||||
<< "========================= " << endl;
|
||||
for (size_t i = 0; i < v6_entries.size(); ++i) {
|
||||
cout << "Entry " << setw(2) << i << ": " << endl
|
||||
<< "Interface: " << v6_entries[i].interface << endl
|
||||
<< "Destination: " << v6_entries[i].destination << endl
|
||||
<< "Gateway: " << v6_entries[i].gateway << endl
|
||||
<< "Genmask: " << v6_entries[i].mask << endl
|
||||
<< "Metric: " << v6_entries[i].metric << endl << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,14 +5,14 @@
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@@ -125,10 +125,10 @@ private:
|
||||
* \brief Represents a range of addresses.
|
||||
*
|
||||
* This class provides a begin()/end() interface which allows
|
||||
* iterating through every address stored in it.
|
||||
* iterating through every address stored in it.
|
||||
*
|
||||
* Note that when iterating a range that was created using
|
||||
* operator/(IPv4Address, int) and the analog for IPv6, the
|
||||
* operator/(IPv4Address, int) and the analog for IPv6, the
|
||||
* network and broadcast addresses are discarded:
|
||||
*
|
||||
* \code
|
||||
@@ -139,12 +139,12 @@ private:
|
||||
* }
|
||||
*
|
||||
* // That's only valid for iteration, not for AddressRange<>::contains
|
||||
*
|
||||
*
|
||||
* assert(range.contains("192.168.5.0")); // works
|
||||
* assert(range.contains("192.168.5.255")); // works
|
||||
* \endcode
|
||||
*
|
||||
* Ranges created using AddressRange(address_type, address_type)
|
||||
* Ranges created using AddressRange(address_type, address_type)
|
||||
* will allow the iteration over the entire range:
|
||||
*
|
||||
* \code
|
||||
@@ -153,11 +153,11 @@ private:
|
||||
* // process 192.168.5.0-255, no addresses are discarded
|
||||
* process(addr);
|
||||
* }
|
||||
*
|
||||
*
|
||||
* assert(range.contains("192.168.5.0")); // still valid
|
||||
* assert(range.contains("192.168.5.255")); // still valid
|
||||
* \endcode
|
||||
*
|
||||
*
|
||||
*/
|
||||
template<typename Address>
|
||||
class AddressRange {
|
||||
@@ -186,10 +186,10 @@ public:
|
||||
* The range will consist of the addresses [first, last].
|
||||
*
|
||||
* If only_hosts is true, then the network and broadcast addresses
|
||||
* will not be available when iterating the range.
|
||||
* will not be available when iterating the range.
|
||||
*
|
||||
* If last < first, an std::runtime_error exception is thrown.
|
||||
*
|
||||
*
|
||||
* \param first The first address in the range.
|
||||
* \param last The last address(inclusive) in the range.
|
||||
* \param only_hosts Indicates whether only host addresses
|
||||
@@ -211,8 +211,8 @@ public:
|
||||
*/
|
||||
static AddressRange from_mask(const address_type& first, const address_type& mask) {
|
||||
return AddressRange<address_type>(
|
||||
first,
|
||||
Internals::last_address_from_mask(first, mask),
|
||||
first & mask,
|
||||
Internals::last_address_from_mask(first, mask),
|
||||
true
|
||||
);
|
||||
}
|
||||
@@ -253,15 +253,15 @@ public:
|
||||
/**
|
||||
* \brief Indicates whether this range is iterable.
|
||||
*
|
||||
* Iterable ranges are those for which there is at least one
|
||||
* Iterable ranges are those for which there is at least one
|
||||
* address that could represent a host. For IPv4 ranges, a /31 or
|
||||
* /32 ranges does not contain any, therefore it's not iterable.
|
||||
* The same is true for /127 and /128 IPv6 ranges.
|
||||
*
|
||||
* If is_iterable returns false for a range, then iterating it
|
||||
* through the iterators returned by begin() and end() is
|
||||
* undefined.
|
||||
*
|
||||
* through the iterators returned by begin() and end() is
|
||||
* undefined.
|
||||
*
|
||||
* \return bool indicating whether this range is iterable.
|
||||
*/
|
||||
bool is_iterable() const {
|
||||
|
||||
@@ -298,7 +298,7 @@ public:
|
||||
* \param sender The sender's IP address.
|
||||
* \param hw_tgt The target's hardware address.
|
||||
* \param hw_snd The sender's hardware address.
|
||||
* \return EthetnetII containing the ARP Replay.
|
||||
* \return EthernetII object containing the ARP Reply.
|
||||
*/
|
||||
static EthernetII make_arp_reply(ipaddress_type target,
|
||||
ipaddress_type sender,
|
||||
|
||||
@@ -13,13 +13,22 @@
|
||||
/* Use pcap_sendpacket to send l2 packets */
|
||||
#cmakedefine TINS_HAVE_PACKET_SENDER_PCAP_SENDPACKET
|
||||
|
||||
/* Have TCPIP classes */
|
||||
#cmakedefine TINS_HAVE_TCPIP
|
||||
|
||||
/* Have TCP ACK tracking */
|
||||
#cmakedefine TINS_HAVE_ACK_TRACKER
|
||||
|
||||
/* Have TCP stream custom data */
|
||||
#cmakedefine TINS_HAVE_TCP_STREAM_CUSTOM_DATA
|
||||
|
||||
/* Have GCC builtin swap */
|
||||
#cmakedefine TINS_HAVE_GCC_BUILTIN_SWAP
|
||||
|
||||
/* Have WPA2Decrypter callbacks */
|
||||
#cmakedefine TINS_HAVE_WPA2_CALLBACKS
|
||||
|
||||
/* Have libpcap */
|
||||
#cmakedefine TINS_HAVE_PCAP
|
||||
|
||||
#endif // TINS_CONFIG_H
|
||||
|
||||
@@ -56,6 +56,8 @@ struct smart_ptr {
|
||||
typedef std::auto_ptr<T> type;
|
||||
#endif
|
||||
};
|
||||
|
||||
template<class T> void unused(const T&) { }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,14 @@
|
||||
#include "pdu.h"
|
||||
#include "endianness.h"
|
||||
|
||||
// Undefining some macros that conflict with some symbols here.
|
||||
// Eventually, the conflicting names will be removed, but until then
|
||||
// this is the best we can do.
|
||||
// - IN is defined by winsock2.h
|
||||
// - CERT is defined by openssl
|
||||
#undef IN
|
||||
#undef CERT
|
||||
|
||||
namespace Tins {
|
||||
namespace Memory {
|
||||
|
||||
@@ -130,7 +138,7 @@ public:
|
||||
ATMA,
|
||||
NAPTR,
|
||||
KX,
|
||||
CERT,
|
||||
CERTIFICATE,
|
||||
A6,
|
||||
DNAM,
|
||||
SINK,
|
||||
@@ -144,13 +152,23 @@ public:
|
||||
DNSKEY,
|
||||
DHCID,
|
||||
NSEC3,
|
||||
NSEC3PARAM
|
||||
NSEC3PARAM,
|
||||
CERT = CERTIFICATE
|
||||
};
|
||||
|
||||
enum QueryClass {
|
||||
IN = 1,
|
||||
CH = 3,
|
||||
HS = 4,
|
||||
INTERNET = 1,
|
||||
CHAOS = 3,
|
||||
HESIOD = 4,
|
||||
/**
|
||||
* \cond
|
||||
*/
|
||||
IN = INTERNET,
|
||||
CH = CHAOS,
|
||||
HS = HESIOD,
|
||||
/**
|
||||
* \endcond
|
||||
*/
|
||||
ANY = 255
|
||||
};
|
||||
|
||||
|
||||
@@ -508,8 +508,8 @@ public:
|
||||
*/
|
||||
static Dot11* from_bytes(const uint8_t* buffer, uint32_t total_sz);
|
||||
protected:
|
||||
virtual void write_ext_header(Memory::OutputMemoryStream& stream) { }
|
||||
virtual void write_fixed_parameters(Memory::OutputMemoryStream& stream) { }
|
||||
virtual void write_ext_header(Memory::OutputMemoryStream& stream);
|
||||
virtual void write_fixed_parameters(Memory::OutputMemoryStream& stream);
|
||||
void parse_tagged_parameters(Memory::InputMemoryStream& stream);
|
||||
void add_tagged_option(OptionTypes opt, uint8_t len, const uint8_t* val);
|
||||
protected:
|
||||
|
||||
@@ -463,7 +463,8 @@ public:
|
||||
uint16_t dwell_time;
|
||||
uint8_t hop_set, hop_pattern, hop_index;
|
||||
|
||||
fh_params_set() {}
|
||||
fh_params_set()
|
||||
: dwell_time(0), hop_set(0), hop_pattern(0), hop_index(0) {}
|
||||
|
||||
fh_params_set(uint16_t dwell_time,
|
||||
uint8_t hop_set,
|
||||
@@ -482,7 +483,8 @@ public:
|
||||
uint8_t cfp_count, cfp_period;
|
||||
uint16_t cfp_max_duration, cfp_dur_remaining;
|
||||
|
||||
cf_params_set() {}
|
||||
cf_params_set()
|
||||
: cfp_count(0), cfp_period(0), cfp_max_duration(0), cfp_dur_remaining(0) {}
|
||||
|
||||
cf_params_set(uint8_t cfp_count,
|
||||
uint8_t cfp_period,
|
||||
@@ -505,7 +507,7 @@ public:
|
||||
uint8_t recovery_interval;
|
||||
channel_map_type channel_map;
|
||||
|
||||
ibss_dfs_params() {}
|
||||
ibss_dfs_params() : recovery_interval(0) {}
|
||||
|
||||
ibss_dfs_params(const address_type& addr,
|
||||
uint8_t recovery_interval,
|
||||
@@ -547,7 +549,8 @@ public:
|
||||
uint8_t flag, number_of_sets, modulus, offset;
|
||||
byte_array random_table;
|
||||
|
||||
fh_pattern_type() {}
|
||||
fh_pattern_type()
|
||||
: flag(0), number_of_sets(0), modulus(0), offset(0) {}
|
||||
|
||||
fh_pattern_type(uint8_t flag,
|
||||
uint8_t sets,
|
||||
@@ -566,7 +569,8 @@ public:
|
||||
struct channel_switch_type {
|
||||
uint8_t switch_mode, new_channel, switch_count;
|
||||
|
||||
channel_switch_type() {}
|
||||
channel_switch_type()
|
||||
: switch_mode(0), new_channel(0), switch_count(0) {}
|
||||
|
||||
channel_switch_type(uint8_t mode,
|
||||
uint8_t channel,
|
||||
@@ -583,7 +587,8 @@ public:
|
||||
uint8_t quiet_count, quiet_period;
|
||||
uint16_t quiet_duration, quiet_offset;
|
||||
|
||||
quiet_type() {}
|
||||
quiet_type()
|
||||
: quiet_count(0), quiet_period(0), quiet_duration(0), quiet_offset(0) {}
|
||||
|
||||
quiet_type(uint8_t count,
|
||||
uint8_t period,
|
||||
@@ -603,7 +608,8 @@ public:
|
||||
uint16_t available_capacity;
|
||||
uint8_t channel_utilization;
|
||||
|
||||
bss_load_type() {}
|
||||
bss_load_type()
|
||||
: station_count(0), available_capacity(0), channel_utilization(0) {}
|
||||
|
||||
bss_load_type(uint16_t count, uint8_t utilization, uint16_t capacity)
|
||||
: station_count(count), available_capacity(capacity),
|
||||
@@ -619,7 +625,8 @@ public:
|
||||
uint8_t dtim_count, dtim_period, bitmap_control;
|
||||
byte_array partial_virtual_bitmap;
|
||||
|
||||
tim_type() {}
|
||||
tim_type()
|
||||
: dtim_count(0), dtim_period(0), bitmap_control(0) {}
|
||||
|
||||
tim_type(uint8_t count,
|
||||
uint8_t period,
|
||||
|
||||
@@ -45,6 +45,9 @@ public:
|
||||
|
||||
exception_base(const std::string& message)
|
||||
: std::runtime_error(message) { }
|
||||
|
||||
exception_base(const char* message)
|
||||
: std::runtime_error(message) { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -52,10 +55,7 @@ public:
|
||||
*/
|
||||
class option_not_found : public exception_base {
|
||||
public:
|
||||
// try to avoid allocations by doing this.
|
||||
const char* what() const throw() {
|
||||
return "Option not found";
|
||||
}
|
||||
option_not_found() : exception_base("Option not found") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -63,9 +63,7 @@ public:
|
||||
*/
|
||||
class malformed_packet : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "Malformed packet";
|
||||
}
|
||||
malformed_packet() : exception_base("Malformed packet") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -73,9 +71,7 @@ public:
|
||||
*/
|
||||
class serialization_error : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "Serialization error";
|
||||
}
|
||||
serialization_error() : exception_base("Serialization error") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -83,9 +79,7 @@ public:
|
||||
*/
|
||||
class pdu_not_found : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "PDU not found";
|
||||
}
|
||||
pdu_not_found() : exception_base("PDU not found") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -94,9 +88,7 @@ public:
|
||||
*/
|
||||
class invalid_interface : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "Invalid interface";
|
||||
}
|
||||
invalid_interface() : exception_base("Invalid interface") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -105,9 +97,7 @@ public:
|
||||
*/
|
||||
class invalid_address : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "Invalid address";
|
||||
}
|
||||
invalid_address() : exception_base("Invalid address") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -115,9 +105,7 @@ public:
|
||||
*/
|
||||
class field_not_present : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "Field not present";
|
||||
}
|
||||
field_not_present() : exception_base("Field not present") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -153,9 +141,7 @@ public:
|
||||
*/
|
||||
class invalid_socket_type : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "The provided socket type is invalid";
|
||||
}
|
||||
invalid_socket_type() : exception_base("The provided socket type is invalid") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -164,9 +150,7 @@ public:
|
||||
*/
|
||||
class unknown_link_type : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "The sniffed link layer PDU type is unknown";
|
||||
}
|
||||
unknown_link_type() : exception_base("The sniffed link layer PDU type is unknown") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -174,9 +158,7 @@ public:
|
||||
*/
|
||||
class malformed_option : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "Malformed option";
|
||||
}
|
||||
malformed_option() : exception_base("Malformed option") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -184,9 +166,7 @@ public:
|
||||
*/
|
||||
class bad_tins_cast : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "Bad Tins cast";
|
||||
}
|
||||
bad_tins_cast() : exception_base("Bad Tins cast") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -195,9 +175,7 @@ public:
|
||||
*/
|
||||
class protocol_disabled : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "Protocol disabled";
|
||||
}
|
||||
protocol_disabled() : exception_base("Protocol disabled") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -206,9 +184,7 @@ public:
|
||||
*/
|
||||
class feature_disabled : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "Feature disabled";
|
||||
}
|
||||
feature_disabled() : exception_base("Feature disabled") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -217,9 +193,7 @@ public:
|
||||
*/
|
||||
class option_payload_too_large : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "Option payload too large";
|
||||
}
|
||||
option_payload_too_large() : exception_base("Option payload too large") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -248,9 +222,7 @@ public:
|
||||
*/
|
||||
class pdu_not_serializable : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "PDU not serializable";
|
||||
}
|
||||
pdu_not_serializable() : exception_base("PDU not serializable") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -258,9 +230,7 @@ public:
|
||||
*/
|
||||
class pcap_open_failed : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "Failed to create pcap handle";
|
||||
}
|
||||
pcap_open_failed() : exception_base("Failed to create pcap handle") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -269,9 +239,7 @@ public:
|
||||
*/
|
||||
class unsupported_function : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "Function is not supported on this OS";
|
||||
}
|
||||
unsupported_function() : exception_base("Function is not supported on this OS") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -279,9 +247,7 @@ public:
|
||||
*/
|
||||
class invalid_domain_name : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "Invalid domain name";
|
||||
}
|
||||
invalid_domain_name() : exception_base("Invalid domain name") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -289,9 +255,7 @@ public:
|
||||
*/
|
||||
class stream_not_found : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "Stream not found";
|
||||
}
|
||||
stream_not_found() : exception_base("Stream not found") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -299,9 +263,7 @@ public:
|
||||
*/
|
||||
class callback_not_set : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "Callback not set";
|
||||
}
|
||||
callback_not_set() : exception_base("Callback not set") { }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -309,9 +271,7 @@ public:
|
||||
*/
|
||||
class invalid_packet : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "Invalid packet";
|
||||
}
|
||||
invalid_packet() : exception_base("Invalid packet") { }
|
||||
};
|
||||
|
||||
namespace Crypto {
|
||||
@@ -321,9 +281,7 @@ namespace WPA2 {
|
||||
*/
|
||||
class invalid_handshake : public exception_base {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "Invalid WPA2 handshake";
|
||||
}
|
||||
invalid_handshake() : exception_base("Invalid WPA2 handshake") { }
|
||||
};
|
||||
} // WPA2
|
||||
} // Crypto
|
||||
|
||||
@@ -249,13 +249,27 @@ public:
|
||||
bool operator<(const HWAddress& rhs) const {
|
||||
return std::lexicographical_compare(begin(), end(), rhs.begin(), rhs.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Apply a mask to this address
|
||||
*
|
||||
* \param mask The mask to be applied
|
||||
* \return The result of applying the mask to this address
|
||||
*/
|
||||
HWAddress operator&(const HWAddress& mask) const {
|
||||
HWAddress<n> output = *this;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
output[i] = output[i] & mask[i];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves the size of this address.
|
||||
*
|
||||
* This effectively returns the address_size constant.
|
||||
*/
|
||||
const size_t size() const {
|
||||
size_t size() const {
|
||||
return address_size;
|
||||
}
|
||||
|
||||
@@ -299,6 +313,15 @@ public:
|
||||
storage_type operator[](size_t i) const {
|
||||
return begin()[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves the i-th storage_type in this address.
|
||||
*
|
||||
* \param i The element to retrieve.
|
||||
*/
|
||||
storage_type& operator[](size_t i) {
|
||||
return begin()[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Writes this HWAddress in hex-notation to a std::ostream.
|
||||
|
||||
@@ -507,7 +507,9 @@ private:
|
||||
bool are_extensions_allowed() const;
|
||||
|
||||
icmp_header header_;
|
||||
uint32_t orig_timestamp_or_address_mask_, recv_timestamp_, trans_timestamp_;
|
||||
uint32_t orig_timestamp_or_address_mask_;
|
||||
uint32_t recv_timestamp_;
|
||||
uint32_t trans_timestamp_;
|
||||
ICMPExtensionsStructure extensions_;
|
||||
};
|
||||
|
||||
|
||||
@@ -251,8 +251,8 @@ public:
|
||||
uint8_t prefix_len;
|
||||
small_uint<1> A, L;
|
||||
uint32_t valid_lifetime,
|
||||
preferred_lifetime,
|
||||
reserved2;
|
||||
preferred_lifetime,
|
||||
reserved2;
|
||||
ipaddress_type prefix;
|
||||
|
||||
prefix_info_type(uint8_t prefix_len = 0,
|
||||
@@ -262,7 +262,7 @@ public:
|
||||
uint32_t preferred_lifetime = 0,
|
||||
const ipaddress_type& prefix = ipaddress_type())
|
||||
: prefix_len(prefix_len), A(A), L(L), valid_lifetime(valid_lifetime),
|
||||
preferred_lifetime(preferred_lifetime), prefix(prefix) { }
|
||||
preferred_lifetime(preferred_lifetime), reserved2(0), prefix(prefix) { }
|
||||
|
||||
static prefix_info_type from_option(const option& opt);
|
||||
};
|
||||
@@ -1115,6 +1115,17 @@ public:
|
||||
ICMPv6* clone() const {
|
||||
return new ICMPv6(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Indicates whether to use MLDv2
|
||||
*
|
||||
* If this is set to true, then MLDv2 will be used rather than MLDv1 when
|
||||
* serializing Multicast Listener Discovery messages. By default,
|
||||
* MLDv2 will be used.
|
||||
*
|
||||
* \param value The value to set
|
||||
*/
|
||||
void use_mldv2(bool value);
|
||||
|
||||
// ****************************************************************
|
||||
// Option setters
|
||||
@@ -1590,6 +1601,7 @@ private:
|
||||
multicast_listener_query_message_fields mlqm_;
|
||||
sources_list sources_;
|
||||
ICMPExtensionsStructure extensions_;
|
||||
bool use_mldv2_;
|
||||
};
|
||||
|
||||
} // Tins
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "constants.h"
|
||||
#include "pdu.h"
|
||||
#include "hw_address.h"
|
||||
#include "macros.h"
|
||||
|
||||
/**
|
||||
* \cond
|
||||
@@ -108,6 +109,7 @@ private:
|
||||
|
||||
void skip_line(std::istream& input);
|
||||
bool from_hex(const std::string& str, uint32_t& result);
|
||||
bool from_hex(const std::string& str, std::string& result);
|
||||
|
||||
template<bool, typename T = void>
|
||||
struct enable_if {
|
||||
@@ -123,8 +125,10 @@ PDU* pdu_from_flag(Constants::Ethernet::e flag, const uint8_t* buffer,
|
||||
uint32_t size, bool rawpdu_on_no_match = true);
|
||||
PDU* pdu_from_flag(Constants::IP::e flag, const uint8_t* buffer,
|
||||
uint32_t size, bool rawpdu_on_no_match = true);
|
||||
#ifdef TINS_HAVE_PCAP
|
||||
PDU* pdu_from_dlt_flag(int flag, const uint8_t* buffer,
|
||||
uint32_t size, bool rawpdu_on_no_match = true);
|
||||
#endif // TINS_HAVE_PCAP
|
||||
PDU* pdu_from_flag(PDU::PDUType type, const uint8_t* buffer, uint32_t size);
|
||||
|
||||
Constants::Ethernet::e pdu_flag_to_ether_type(PDU::PDUType flag);
|
||||
@@ -133,7 +137,7 @@ Constants::IP::e pdu_flag_to_ip_type(PDU::PDUType flag);
|
||||
PDU::PDUType ip_type_to_pdu_flag(Constants::IP::e flag);
|
||||
|
||||
uint32_t get_padded_icmp_inner_pdu_size(const PDU* inner_pdu, uint32_t pad_alignment);
|
||||
void try_parse_icmp_extensions(Memory::InputMemoryStream& stream,
|
||||
void try_parse_icmp_extensions(Memory::InputMemoryStream& stream,
|
||||
uint32_t payload_length, ICMPExtensionsStructure& extensions);
|
||||
|
||||
template<typename T>
|
||||
@@ -229,10 +233,10 @@ template <typename T, typename P, typename=void>
|
||||
struct accepts_type : std::false_type { };
|
||||
|
||||
template <typename T, typename P>
|
||||
struct accepts_type<T, P,
|
||||
struct accepts_type<T, P,
|
||||
typename std::enable_if<
|
||||
std::is_same< decltype( std::declval<T>()(std::declval<P>()) ), bool>::value
|
||||
>::type
|
||||
>::type
|
||||
> : std::true_type { };
|
||||
|
||||
// use enable_if to invoke the Packet&& version of the sniff_loop handler if possible - otherwise fail to old behavior
|
||||
|
||||
@@ -53,6 +53,13 @@ public:
|
||||
*/
|
||||
static const IPv4Address broadcast;
|
||||
|
||||
/**
|
||||
* \brief Constructs an IPv4 address from a prefix length
|
||||
*
|
||||
* \param prefix_length The length of the prefix
|
||||
*/
|
||||
static IPv4Address from_prefix_length(uint32_t prefix_length);
|
||||
|
||||
/**
|
||||
* \brief Constructor taking a const char*.
|
||||
*
|
||||
@@ -123,9 +130,17 @@ public:
|
||||
* \param rhs The address to be compared.
|
||||
* \return bool indicating whether this address is less-than rhs.
|
||||
*/
|
||||
bool operator< (const IPv4Address& rhs) const {
|
||||
bool operator<(const IPv4Address& rhs) const {
|
||||
return ip_addr_ < rhs.ip_addr_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Apply a mask to this address
|
||||
*
|
||||
* \param mask The mask to be applied
|
||||
* \return The result of applying the mask to this address
|
||||
*/
|
||||
IPv4Address operator&(const IPv4Address& mask) const;
|
||||
|
||||
/**
|
||||
* \brief Returns true if this is a private IPv4 address.
|
||||
@@ -176,7 +191,7 @@ public:
|
||||
* \param addr The IPv4Address to be written.
|
||||
* \return std::stream& pointing to output.
|
||||
*/
|
||||
friend std::ostream& operator<<(std::ostream& output, const IPv4Address& addr);
|
||||
TINS_API friend std::ostream& operator<<(std::ostream& output, const IPv4Address& addr);
|
||||
private:
|
||||
uint32_t ip_to_int(const char* ip);
|
||||
|
||||
|
||||
@@ -89,6 +89,15 @@ public:
|
||||
NO_NEXT_HEADER = 59
|
||||
};
|
||||
|
||||
/**
|
||||
* The values used to identify Hop-By-Hop Options and Destination Options.
|
||||
*/
|
||||
enum OptionType {
|
||||
PAD_1 = 0,
|
||||
PAD_N = 1,
|
||||
JUMBO_PAYLOAD = 0xC2,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Extracts metadata for this protocol based on the buffer provided
|
||||
*
|
||||
|
||||
@@ -55,6 +55,13 @@ public:
|
||||
*/
|
||||
typedef const uint8_t* const_iterator;
|
||||
|
||||
/**
|
||||
* \brief Constructs an IPv6 address from a prefix length
|
||||
*
|
||||
* \param prefix_length The length of the prefix
|
||||
*/
|
||||
static IPv6Address from_prefix_length(uint32_t prefix_length);
|
||||
|
||||
/**
|
||||
* \brief Default constructor.
|
||||
* Initializes this IPv6 address to "::"
|
||||
@@ -199,6 +206,13 @@ public:
|
||||
friend std::ostream& operator<<(std::ostream& os, const IPv6Address& addr) {
|
||||
return os << addr.to_string();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Applies a mask to an address
|
||||
*/
|
||||
TINS_API friend IPv6Address operator&(const IPv6Address& lhs, const IPv6Address& rhs);
|
||||
|
||||
private:
|
||||
void init(const char* addr);
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include <stdint.h>
|
||||
#include "macros.h"
|
||||
#include "pdu.h"
|
||||
#include "macros.h"
|
||||
#include "endianness.h"
|
||||
|
||||
namespace Tins {
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
#define TINS_LIKELY(x) (x)
|
||||
#define TINS_UNLIKELY(x) (x)
|
||||
#else
|
||||
// Not Vistual Studio. Assume this is gcc compatible
|
||||
// Not Visual Studio. Assume this is gcc compatible
|
||||
#define TINS_BEGIN_PACK
|
||||
#define TINS_END_PACK __attribute__((packed))
|
||||
#define TINS_PACKED(DECLARATION) DECLARATION __attribute__((packed))
|
||||
|
||||
@@ -32,9 +32,12 @@
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include "data_link_type.h"
|
||||
#include "macros.h"
|
||||
|
||||
#ifdef TINS_HAVE_PCAP
|
||||
|
||||
#include "data_link_type.h"
|
||||
|
||||
namespace Tins {
|
||||
|
||||
class PDU;
|
||||
@@ -154,6 +157,9 @@ private:
|
||||
mutable bpf_program filter_;
|
||||
std::string string_filter_;
|
||||
};
|
||||
|
||||
} // Tins
|
||||
|
||||
#endif // TINS_HAVE_PCAP
|
||||
|
||||
#endif // TINS_OFFLINE_PACKET_FILTER_H
|
||||
|
||||
@@ -399,7 +399,8 @@ private:
|
||||
PDU* recv_match_loop(const std::vector<int>& sockets,
|
||||
PDU& pdu,
|
||||
struct sockaddr* link_addr,
|
||||
uint32_t addrlen);
|
||||
uint32_t addrlen,
|
||||
bool is_layer_3);
|
||||
|
||||
std::vector<int> sockets_;
|
||||
#ifndef _WIN32
|
||||
|
||||
@@ -33,11 +33,13 @@
|
||||
#include "utils.h"
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
#include <pcap.h>
|
||||
#include "data_link_type.h"
|
||||
#include "macros.h"
|
||||
#include "cxxstd.h"
|
||||
|
||||
#ifdef TINS_HAVE_PCAP
|
||||
#include <pcap.h>
|
||||
#include "data_link_type.h"
|
||||
|
||||
struct timeval;
|
||||
|
||||
namespace Tins {
|
||||
@@ -220,6 +222,9 @@ private:
|
||||
pcap_t* handle_;
|
||||
pcap_dumper_t* dumper_;
|
||||
};
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
#endif // TINS_HAVE_PCAP
|
||||
|
||||
#endif // TINS_PACKET_WRITER_H
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
#include "macros.h"
|
||||
#include "cxxstd.h"
|
||||
#include "exceptions.h"
|
||||
#include "macros.h"
|
||||
|
||||
/** \brief The Tins namespace.
|
||||
*/
|
||||
@@ -354,7 +353,7 @@ public:
|
||||
*/
|
||||
template<typename T>
|
||||
const T* find_pdu(PDUType type = T::pdu_flag) const {
|
||||
return const_cast<PDU*>(this)->find_pdu<T>();
|
||||
return const_cast<PDU*>(this)->find_pdu<T>(type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -382,7 +381,7 @@ public:
|
||||
*/
|
||||
template<typename T>
|
||||
const T& rfind_pdu(PDUType type = T::pdu_flag) const {
|
||||
return const_cast<PDU*>(this)->rfind_pdu<T>();
|
||||
return const_cast<PDU*>(this)->rfind_pdu<T>(type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -434,9 +433,7 @@ public:
|
||||
* \param ptr The pointer to the buffer.
|
||||
* \param total_sz The size of the buffer.
|
||||
*/
|
||||
virtual bool matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool matches_response(const uint8_t* ptr, uint32_t total_sz) const;
|
||||
|
||||
/**
|
||||
* \brief Check whether this PDU matches the specified flag.
|
||||
@@ -486,7 +483,7 @@ protected:
|
||||
*
|
||||
* \param parent The parent PDU.
|
||||
*/
|
||||
virtual void prepare_for_serialize(const PDU* parent) { }
|
||||
virtual void prepare_for_serialize(const PDU* parent);
|
||||
|
||||
/**
|
||||
* \brief Serializes this PDU and propagates this action to child PDUs.
|
||||
|
||||
@@ -333,8 +333,10 @@ public:
|
||||
PDUOption(option_type opt = option_type(),
|
||||
size_t length = 0,
|
||||
const data_type* data = 0)
|
||||
: option_(opt), size_(static_cast<uint16_t>(length)) {
|
||||
set_payload_contents(data, data + (data ? length : 0));
|
||||
: option_(opt), size_(static_cast<uint16_t>(length)), real_size_(0) {
|
||||
if (data != 0) {
|
||||
set_payload_contents(data, data + length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
#include "pdu.h"
|
||||
#include "macros.h"
|
||||
|
||||
// This class is only available if pcap is enabled
|
||||
#ifdef TINS_HAVE_PCAP
|
||||
|
||||
namespace Tins {
|
||||
|
||||
/**
|
||||
@@ -111,4 +114,6 @@ private:
|
||||
|
||||
} // Tins
|
||||
|
||||
#endif // TINS_HAVE_PCAP
|
||||
|
||||
#endif // TINS_PKTAP_H
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
#include "endianness.h"
|
||||
#include "small_uint.h"
|
||||
|
||||
#ifdef TINS_HAVE_PCAP
|
||||
|
||||
namespace Tins {
|
||||
|
||||
/**
|
||||
@@ -135,6 +137,9 @@ private:
|
||||
ppi_header header_;
|
||||
byte_array data_;
|
||||
};
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
#endif // TINS_HAVE_PCAP
|
||||
|
||||
#endif // TINS_PPI_H
|
||||
|
||||
@@ -506,10 +506,21 @@ private:
|
||||
radiotap_hdr radio_;
|
||||
// present fields...
|
||||
uint64_t tsft_;
|
||||
uint16_t channel_type_, channel_freq_, rx_flags_, signal_quality_, tx_flags_;
|
||||
uint16_t channel_type_;
|
||||
uint16_t channel_freq_;
|
||||
uint16_t rx_flags_;
|
||||
uint16_t signal_quality_;
|
||||
uint16_t tx_flags_;
|
||||
mcs_type mcs_;
|
||||
uint8_t antenna_, flags_, rate_, channel_, max_power_, db_signal_, data_retries_;
|
||||
int8_t dbm_signal_, dbm_noise_;
|
||||
uint8_t antenna_;
|
||||
uint8_t flags_;
|
||||
uint8_t rate_;
|
||||
uint8_t channel_;
|
||||
uint8_t max_power_;
|
||||
uint8_t db_signal_;
|
||||
uint8_t data_retries_;
|
||||
int8_t dbm_signal_;
|
||||
int8_t dbm_noise_;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,6 @@
|
||||
#ifndef TINS_SNIFFER_H
|
||||
#define TINS_SNIFFER_H
|
||||
|
||||
|
||||
#include <pcap.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
@@ -44,6 +42,10 @@
|
||||
#include "exceptions.h"
|
||||
#include "internals.h"
|
||||
|
||||
#ifdef TINS_HAVE_PCAP
|
||||
|
||||
#include <pcap.h>
|
||||
|
||||
namespace Tins {
|
||||
class SnifferIterator;
|
||||
class SnifferConfiguration;
|
||||
@@ -350,14 +352,11 @@ private:
|
||||
friend class SnifferConfiguration;
|
||||
|
||||
void set_snap_len(unsigned snap_len);
|
||||
|
||||
void set_buffer_size(unsigned buffer_size);
|
||||
|
||||
void set_promisc_mode(bool promisc_enabled);
|
||||
|
||||
void set_rfmon(bool rfmon_enabled);
|
||||
|
||||
void set_immediate_mode(bool enabled);
|
||||
void set_timestamp_precision(int value);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -586,6 +585,12 @@ public:
|
||||
* \param enabled The immediate mode option value.
|
||||
*/
|
||||
void set_immediate_mode(bool enabled);
|
||||
|
||||
/**
|
||||
* Sets the timestamp precision value
|
||||
* \param value The timestamp option value.
|
||||
*/
|
||||
void set_timestamp_precision(int value);
|
||||
protected:
|
||||
friend class Sniffer;
|
||||
friend class FileSniffer;
|
||||
@@ -596,7 +601,8 @@ protected:
|
||||
RFMON = 4,
|
||||
PACKET_FILTER = 8,
|
||||
IMMEDIATE_MODE = 16,
|
||||
DIRECTION = 32
|
||||
DIRECTION = 32,
|
||||
TIMESTAMP_PRECISION = 64,
|
||||
};
|
||||
|
||||
void configure_sniffer_pre_activation(Sniffer& sniffer) const;
|
||||
@@ -613,6 +619,7 @@ protected:
|
||||
bool rfmon_;
|
||||
bool immediate_mode_;
|
||||
pcap_direction_t direction_;
|
||||
int timestamp_precision_;
|
||||
};
|
||||
|
||||
template <typename Functor>
|
||||
@@ -640,4 +647,6 @@ void Tins::BaseSniffer::sniff_loop(Functor function, uint32_t max_packets) {
|
||||
|
||||
} // Tins
|
||||
|
||||
#endif // TINS_HAVE_PCAP
|
||||
|
||||
#endif // TINS_SNIFFER_H
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
#include <vector>
|
||||
#include <boost/icl/interval_set.hpp>
|
||||
#include "../macros.h"
|
||||
|
||||
namespace Tins {
|
||||
|
||||
@@ -48,7 +49,7 @@ namespace TCPIP {
|
||||
*
|
||||
* The interval represented by this range is a closed interval [first, last].
|
||||
*/
|
||||
class AckedRange {
|
||||
class TINS_API AckedRange {
|
||||
public:
|
||||
typedef boost::icl::discrete_interval<uint32_t> interval_type;
|
||||
|
||||
@@ -90,7 +91,7 @@ private:
|
||||
/**
|
||||
* \brief Allows tracking acknowledged intervals in a TCP stream
|
||||
*/
|
||||
class AckTracker {
|
||||
class TINS_API AckTracker {
|
||||
public:
|
||||
/**
|
||||
* The type used to store ACKed intervals
|
||||
|
||||
162
include/tins/tcp_ip/data_tracker.h
Normal file
162
include/tins/tcp_ip/data_tracker.h
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_TCP_IP_DATA_TRACKER_H
|
||||
#define TINS_TCP_IP_DATA_TRACKER_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <stdint.h>
|
||||
#include "../config.h"
|
||||
#include "../macros.h"
|
||||
|
||||
#ifdef TINS_HAVE_TCPIP
|
||||
|
||||
namespace Tins {
|
||||
namespace TCPIP {
|
||||
|
||||
/**
|
||||
* \class DataTracker
|
||||
*
|
||||
* Stores and tracks data in a TCP stream, reassembling segments, handling
|
||||
* out of order packets, etc.
|
||||
*/
|
||||
class TINS_API DataTracker {
|
||||
public:
|
||||
/**
|
||||
* The type used to store the payload
|
||||
*/
|
||||
typedef std::vector<uint8_t> payload_type;
|
||||
|
||||
/**
|
||||
* The type used to store the buffered payload
|
||||
*/
|
||||
typedef std::map<uint32_t, payload_type> buffered_payload_type;
|
||||
|
||||
/**
|
||||
* Default constructs an instance
|
||||
*/
|
||||
DataTracker();
|
||||
|
||||
/**
|
||||
* \brief Constructs an instance using the given sequence number as the initial one
|
||||
*
|
||||
* \param seq_number The sequence number to use
|
||||
*/
|
||||
DataTracker(uint32_t seq_number);
|
||||
|
||||
/**
|
||||
* \brief Processes the given payload
|
||||
*
|
||||
* This will buffer the given data on the payload buffer or store it on the
|
||||
* buffered payload map, depending the sequence number given.
|
||||
*
|
||||
* This method returns true iff any data was added to the payload buffer. That is
|
||||
* if this method returns true, then the size of the payload will be greater than
|
||||
* what it was before calling the function.
|
||||
*
|
||||
* \brief seq The payload's sequence number
|
||||
* \brief payload The payload to process
|
||||
* \return true iff any data was added to the payload buffer
|
||||
*/
|
||||
bool process_payload(uint32_t seq, payload_type payload);
|
||||
|
||||
/**
|
||||
* \brief Skip forward to a sequence number
|
||||
*
|
||||
* This allows to recover from packetloss, if we just do not see all packets of
|
||||
* an original stream. This recovery can only sensibly triggered from the application
|
||||
* layer.
|
||||
*
|
||||
* The method does nothing, if the sequence number is smaller or equal to the
|
||||
* current number.
|
||||
*
|
||||
* This method is particularly useful to call from an out of order callback, if
|
||||
* the application wants to skip forward to this out of order block. The application
|
||||
* will then get the normal data callback!
|
||||
*
|
||||
* The method cleans the buffer from all no longer needed fragments.
|
||||
*
|
||||
* IMPORTANT: If you call this method with a sequence number that is not exactly a
|
||||
* TCP fragment boundary, the flow will never recover from this.
|
||||
*
|
||||
* \param seq The seqeunce number to skip to.
|
||||
*/
|
||||
void advance_sequence(uint32_t seq);
|
||||
|
||||
/**
|
||||
* Retrieves the current sequence number
|
||||
*/
|
||||
uint32_t sequence_number() const;
|
||||
|
||||
/**
|
||||
* Sets the current sequence number
|
||||
*/
|
||||
void sequence_number(uint32_t seq);
|
||||
|
||||
/**
|
||||
* Retrieves the available payload (const)
|
||||
*/
|
||||
const payload_type& payload() const;
|
||||
|
||||
/**
|
||||
* Retrieves the available payload
|
||||
*/
|
||||
payload_type& payload();
|
||||
|
||||
/**
|
||||
* Retrieves the buffered payload (const)
|
||||
*/
|
||||
const buffered_payload_type& buffered_payload() const;
|
||||
|
||||
/**
|
||||
* Retrieves the buffered payload
|
||||
*/
|
||||
buffered_payload_type& buffered_payload();
|
||||
|
||||
/**
|
||||
* Retrieves the total amount of buffered bytes
|
||||
*/
|
||||
uint32_t total_buffered_bytes() const;
|
||||
private:
|
||||
void store_payload(uint32_t seq, payload_type payload);
|
||||
buffered_payload_type::iterator erase_iterator(buffered_payload_type::iterator iter);
|
||||
|
||||
payload_type payload_;
|
||||
buffered_payload_type buffered_payload_;
|
||||
uint32_t seq_number_;
|
||||
uint32_t total_buffered_bytes_;
|
||||
};
|
||||
|
||||
} // TCPIP
|
||||
} // Tins
|
||||
|
||||
#endif // TINS_HAVE_TCPIP
|
||||
|
||||
#endif // TINS_TCP_IP_DATA_TRACKER_H
|
||||
@@ -30,19 +30,19 @@
|
||||
#ifndef TINS_TCP_IP_FLOW_H
|
||||
#define TINS_TCP_IP_FLOW_H
|
||||
|
||||
#include "../cxxstd.h"
|
||||
#include "../config.h"
|
||||
|
||||
// This classes use C++11 features
|
||||
#if TINS_IS_CXX11
|
||||
#ifdef TINS_HAVE_TCPIP
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <stdint.h>
|
||||
#include "../hw_address.h"
|
||||
#include "../macros.h"
|
||||
#include "ack_tracker.h"
|
||||
#include "../hw_address.h"
|
||||
#include "data_tracker.h"
|
||||
|
||||
namespace Tins {
|
||||
|
||||
@@ -87,12 +87,12 @@ public:
|
||||
/**
|
||||
* The type used to store the payload
|
||||
*/
|
||||
typedef std::vector<uint8_t> payload_type;
|
||||
typedef DataTracker::payload_type payload_type;
|
||||
|
||||
/**
|
||||
* The type used to store the buffered payload
|
||||
*/
|
||||
typedef std::map<uint32_t, payload_type> buffered_payload_type;
|
||||
typedef DataTracker::buffered_payload_type buffered_payload_type;
|
||||
|
||||
/**
|
||||
* The type used to store the callback called when new data is available
|
||||
@@ -165,6 +165,24 @@ public:
|
||||
*/
|
||||
void process_packet(PDU& pdu);
|
||||
|
||||
/**
|
||||
* \brief Skip forward to a sequence number
|
||||
*
|
||||
* This allows to recover from packet loss, if we just do not see all packets of
|
||||
* an original stream. This recovery can only sensibly triggered from the application
|
||||
* layer.
|
||||
*
|
||||
* This method is particularly useful to call from an out of order callback, if
|
||||
* the application wants to skip forward to this out of order block. The application
|
||||
* will then get the normal data callback!
|
||||
*
|
||||
* IMPORTANT: If you call this method with a sequence number that is not exactly a
|
||||
* TCP fragment boundary, the flow will never recover from this.
|
||||
*
|
||||
* \param seq The sequence number to skip to.
|
||||
*/
|
||||
void advance_sequence(uint32_t seq);
|
||||
|
||||
/**
|
||||
* Indicates whether this flow uses IPv6 addresses
|
||||
*/
|
||||
@@ -213,7 +231,7 @@ public:
|
||||
const payload_type& payload() const;
|
||||
|
||||
/**
|
||||
* Retrieves this flow's destination port
|
||||
* Retrieves this flow's payload
|
||||
*/
|
||||
payload_type& payload();
|
||||
|
||||
@@ -297,7 +315,7 @@ public:
|
||||
private:
|
||||
// Compress all flags into just one struct using bitfields
|
||||
struct flags {
|
||||
flags() : ignore_data_packets(0), sack_permitted(0), ack_tracking(0) {
|
||||
flags() : is_v6(0), ignore_data_packets(0), sack_permitted(0), ack_tracking(0) {
|
||||
|
||||
}
|
||||
|
||||
@@ -307,15 +325,10 @@ private:
|
||||
ack_tracking:1;
|
||||
};
|
||||
|
||||
void store_payload(uint32_t seq, payload_type payload);
|
||||
buffered_payload_type::iterator erase_iterator(buffered_payload_type::iterator iter);
|
||||
void update_state(const TCP& tcp);
|
||||
void initialize();
|
||||
|
||||
payload_type payload_;
|
||||
buffered_payload_type buffered_payload_;
|
||||
uint32_t seq_number_;
|
||||
uint32_t total_buffered_bytes_;
|
||||
DataTracker data_tracker_;
|
||||
std::array<uint8_t, 16> dest_address_;
|
||||
uint16_t dest_port_;
|
||||
data_available_callback_type on_data_callback_;
|
||||
@@ -331,6 +344,6 @@ private:
|
||||
} // TCPIP
|
||||
} // TINS
|
||||
|
||||
#endif // TINS_IS_CXX11
|
||||
#endif // TINS_HAVE_TCPIP
|
||||
#endif // TINS_TCP_IP_FLOW_H
|
||||
|
||||
|
||||
@@ -30,10 +30,9 @@
|
||||
#ifndef TINS_TCP_IP_STREAM_H
|
||||
#define TINS_TCP_IP_STREAM_H
|
||||
|
||||
#include "../cxxstd.h"
|
||||
#include "../config.h"
|
||||
|
||||
// This classes use C++11 features
|
||||
#if TINS_IS_CXX11
|
||||
#ifdef TINS_HAVE_TCPIP
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
@@ -43,7 +42,11 @@
|
||||
#include <stdint.h>
|
||||
#include "../macros.h"
|
||||
#include "../hw_address.h"
|
||||
#include "../config.h"
|
||||
#include "flow.h"
|
||||
#ifdef TINS_HAVE_TCP_STREAM_CUSTOM_DATA
|
||||
#include <boost/any.hpp>
|
||||
#endif
|
||||
|
||||
namespace Tins {
|
||||
|
||||
@@ -87,6 +90,9 @@ public:
|
||||
/**
|
||||
* The type used for packet-triggered callbacks
|
||||
*
|
||||
* The second and third arguments are the sequence number and payload of the packet that
|
||||
* arrived out of order.
|
||||
*
|
||||
* /sa Flow::buffering_callback
|
||||
*/
|
||||
typedef std::function<void(Stream&,
|
||||
@@ -362,6 +368,61 @@ public:
|
||||
* \brief Indicates whether ACK number tracking is enabled for this stream
|
||||
*/
|
||||
bool ack_tracking_enabled() const;
|
||||
|
||||
#ifdef TINS_HAVE_TCP_STREAM_CUSTOM_DATA
|
||||
/**
|
||||
* \brief Create or retrieve an application-specific payload for this stream.
|
||||
*
|
||||
* The first call to this method will create user data as specified by the
|
||||
* template parameter (using a mandatory default constructor). Subsequent calls
|
||||
* have to be made with the same template parameter or the method will fail with
|
||||
* boost::bad_any_cast. In any case, the method returns a reference to the user
|
||||
* data.
|
||||
*
|
||||
* \return A reference to a user data block in the stream.
|
||||
*/
|
||||
template<typename T>
|
||||
T& user_data() {
|
||||
if (user_data_.empty()) {
|
||||
user_data_ = T();
|
||||
};
|
||||
return boost::any_cast<T&>(user_data_);
|
||||
}
|
||||
#endif // TINS_HAVE_TCP_STREAM_CUSTOM_DATA
|
||||
|
||||
/**
|
||||
* Indicates whether this is a partial stream that we attached to after it had actually started
|
||||
*/
|
||||
bool is_partial_stream() const;
|
||||
|
||||
/**
|
||||
* \brief Enables recovery mode on this stream.
|
||||
*
|
||||
* Recovery mode can be used when either a stream is having high packet loss or on partial
|
||||
* streams. On the latter case, if a stream starts with out of order packets, then the holes
|
||||
* left by them might never be filled. Enabling recovery mode right after attaching to
|
||||
* a stream allows automatic recovery so the stream will skip the out of order packets
|
||||
* and continue tracking the stream by ignoring those holes.
|
||||
*
|
||||
* The way recovery mode is, given a recovery window size, it will skip all out of order
|
||||
* packets that arrive anywhere within the window given by the sequence number at the time of
|
||||
* enabling recovery mode + the recovery window size. This is, given a stream for which the
|
||||
* client sequence number is X and a recovery window of size Y, then enabling recovery mode
|
||||
* at that point will ignore any out of order packets having sequence numbers in the range
|
||||
* (X, X+Y]. "Ignoring" here means that the actual sequence number of the corresponding Flow
|
||||
* (the client one in this case) will be set to the out of order packet's sequece number.
|
||||
* This means that if an out of order packet is captured having a sequence number X + 5 right
|
||||
* after enabling recovery mode, then the Flow's sequence number will be set to X + 5.
|
||||
*/
|
||||
void enable_recovery_mode(uint32_t recovery_window);
|
||||
|
||||
/**
|
||||
* \brief Returns true iff recovery mode is enabled
|
||||
*
|
||||
* Note that the recovery mode flag will be cleaned only after capturing an out of order
|
||||
* packet that is outside of the recovery window.
|
||||
*/
|
||||
bool is_recovery_mode_enabled() const;
|
||||
private:
|
||||
static Flow extract_client_flow(const PDU& packet);
|
||||
static Flow extract_server_flow(const PDU& packet);
|
||||
@@ -374,6 +435,16 @@ private:
|
||||
void on_server_out_of_order(const Flow& flow,
|
||||
uint32_t seq,
|
||||
const payload_type& payload);
|
||||
static void client_recovery_mode_handler(Stream& stream, uint32_t sequence_number,
|
||||
const payload_type& payload,
|
||||
uint32_t recovery_sequence_number_end,
|
||||
const stream_packet_callback_type& original_callback);
|
||||
static void server_recovery_mode_handler(Stream& stream, uint32_t sequence_number,
|
||||
const payload_type& payload,
|
||||
uint32_t recovery_sequence_number_end,
|
||||
const stream_packet_callback_type& original_callback);
|
||||
static bool recovery_mode_handler(Flow& flow, uint32_t sequence_number,
|
||||
uint32_t recovery_sequence_number_end);
|
||||
|
||||
Flow client_flow_;
|
||||
Flow server_flow_;
|
||||
@@ -388,11 +459,17 @@ private:
|
||||
timestamp_type last_seen_;
|
||||
bool auto_cleanup_client_;
|
||||
bool auto_cleanup_server_;
|
||||
bool is_partial_stream_;
|
||||
unsigned directions_recovery_mode_enabled_;
|
||||
|
||||
#ifdef TINS_HAVE_TCP_STREAM_CUSTOM_DATA
|
||||
boost::any user_data_;
|
||||
#endif // TINS_HAVE_TCP_STREAM_CUSTOM_DATA
|
||||
};
|
||||
|
||||
} // TCPIP
|
||||
} // Tins
|
||||
|
||||
#endif // TINS_IS_CXX11
|
||||
#endif // TINS_HAVE_TCPIP
|
||||
|
||||
#endif // TINS_TCP_IP_STREAM_H
|
||||
|
||||
@@ -30,13 +30,13 @@
|
||||
#ifndef TINS_TCP_IP_STREAM_FOLLOWER_H
|
||||
#define TINS_TCP_IP_STREAM_FOLLOWER_H
|
||||
|
||||
#include "../cxxstd.h"
|
||||
#include "../config.h"
|
||||
|
||||
// This classes use C++11 features
|
||||
#if TINS_IS_CXX11
|
||||
#ifdef TINS_HAVE_TCPIP
|
||||
|
||||
#include <map>
|
||||
#include "stream.h"
|
||||
#include "stream_identifier.h"
|
||||
|
||||
namespace Tins {
|
||||
|
||||
@@ -75,10 +75,15 @@ namespace TCPIP {
|
||||
class TINS_API StreamFollower {
|
||||
public:
|
||||
/**
|
||||
* \brief The type used for callbacks
|
||||
* The type used for callbacks
|
||||
*/
|
||||
typedef Stream::stream_callback_type stream_callback_type;
|
||||
|
||||
/**
|
||||
* The type used to identify streams
|
||||
*/
|
||||
typedef StreamIdentifier stream_id;
|
||||
|
||||
/**
|
||||
* Enum to indicate the reason why a stream was terminated
|
||||
*/
|
||||
@@ -95,47 +100,6 @@ public:
|
||||
*/
|
||||
typedef std::function<void(Stream&, TerminationReason)> stream_termination_callback_type;
|
||||
|
||||
/**
|
||||
* \brief Unique identifies a stream.
|
||||
*
|
||||
* This struct is used to track TCP streams. It keeps track of minimum and maximum
|
||||
* addresses/ports in a stream to match packets coming from any of the 2 endpoints
|
||||
* into the same object.
|
||||
*/
|
||||
struct stream_id {
|
||||
/**
|
||||
* The type used to store each endpoint's address
|
||||
*/
|
||||
typedef std::array<uint8_t, 16> address_type;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
stream_id();
|
||||
|
||||
/**
|
||||
* Constructs a stream_id
|
||||
*
|
||||
* \param client_addr Client's address
|
||||
* \param client_port Port's port
|
||||
* \param server_addr Server's address
|
||||
* \param server_port Server's port
|
||||
*/
|
||||
stream_id(const address_type& client_addr, uint16_t client_port,
|
||||
const address_type& server_addr, uint16_t server_port);
|
||||
|
||||
bool operator<(const stream_id& rhs) const;
|
||||
bool operator==(const stream_id& rhs) const;
|
||||
|
||||
address_type min_address;
|
||||
address_type max_address;
|
||||
uint16_t min_address_port;
|
||||
uint16_t max_address_port;
|
||||
|
||||
static address_type serialize(IPv4Address address);
|
||||
static address_type serialize(const IPv6Address& address);
|
||||
};
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
@@ -218,6 +182,25 @@ public:
|
||||
*/
|
||||
Stream& find_stream(const IPv6Address& client_addr, uint16_t client_port,
|
||||
const IPv6Address& server_addr, uint16_t server_port);
|
||||
|
||||
/**
|
||||
* \brief Indicates whether partial streams should be followed.
|
||||
*
|
||||
* Following partial streams allows capturing packets in the middle of a stream (e.g.
|
||||
* not capturing the three way handshake) and still reassembling them.
|
||||
*
|
||||
* This can cause some issues if the first packet captured is out of order, as that would
|
||||
* create a hole in the sequence number range that might never be filled. In order to
|
||||
* allow recovering successfully, there's 2 choices:
|
||||
*
|
||||
* - Skipping those holes manually by using Flow::advance_sequence.
|
||||
* - Using Stream::enable_recovery_mode. This is the easiest mechanism and can be used
|
||||
* on the new stream callback (make sure to only enable it for stream for which
|
||||
* Stream::is_partial_stream is true).
|
||||
*
|
||||
* \param value Whether following partial stream is allowed.
|
||||
*/
|
||||
void follow_partial_streams(bool value);
|
||||
private:
|
||||
typedef Stream::timestamp_type timestamp_type;
|
||||
|
||||
@@ -228,7 +211,6 @@ private:
|
||||
|
||||
typedef std::map<stream_id, Stream> streams_type;
|
||||
|
||||
static stream_id make_stream_id(const PDU& packet);
|
||||
Stream& find_stream(const stream_id& id);
|
||||
void process_packet(PDU& packet, const timestamp_type& ts);
|
||||
void cleanup_streams(const timestamp_type& now);
|
||||
@@ -246,6 +228,6 @@ private:
|
||||
} // TCPIP
|
||||
} // Tins
|
||||
|
||||
#endif // TINS_IS_CXX11
|
||||
#endif // TINS_HAVE_TCPIP
|
||||
|
||||
#endif // TINS_TCP_IP_STREAM_FOLLOWER_H
|
||||
|
||||
107
include/tins/tcp_ip/stream_identifier.h
Normal file
107
include/tins/tcp_ip/stream_identifier.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_TCP_IP_STREAM_ID_H
|
||||
#define TINS_TCP_IP_STREAM_ID_H
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#ifdef TINS_HAVE_TCPIP
|
||||
|
||||
#include <array>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Tins {
|
||||
|
||||
class PDU;
|
||||
class IPv4Address;
|
||||
class IPv6Address;
|
||||
|
||||
namespace TCPIP {
|
||||
|
||||
class Stream;
|
||||
|
||||
/**
|
||||
* \brief Uniquely identifies a stream.
|
||||
*
|
||||
* This struct is used to track TCP/UDP streams. It keeps track of minimum and maximum
|
||||
* addresses/ports in a stream to match packets coming from any of the 2 endpoints
|
||||
* into the same object.
|
||||
*
|
||||
* This struct implements operator< so it can be used as a key on std::maps
|
||||
*/
|
||||
struct StreamIdentifier {
|
||||
/**
|
||||
* The type used to store each endpoint's address
|
||||
*/
|
||||
typedef std::array<uint8_t, 16> address_type;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
StreamIdentifier();
|
||||
|
||||
/**
|
||||
* Constructs a StreamIdentifier
|
||||
*
|
||||
* \param client_addr Client's address
|
||||
* \param client_port Port's port
|
||||
* \param server_addr Server's address
|
||||
* \param server_port Server's port
|
||||
*/
|
||||
StreamIdentifier(const address_type& client_addr, uint16_t client_port,
|
||||
const address_type& server_addr, uint16_t server_port);
|
||||
|
||||
/**
|
||||
* Indicates whether this stream identifier is lower than rhs
|
||||
*/
|
||||
bool operator<(const StreamIdentifier& rhs) const;
|
||||
|
||||
/**
|
||||
* Compares this stream identifier for equality
|
||||
*/
|
||||
bool operator==(const StreamIdentifier& rhs) const;
|
||||
|
||||
address_type min_address;
|
||||
address_type max_address;
|
||||
uint16_t min_address_port;
|
||||
uint16_t max_address_port;
|
||||
|
||||
static StreamIdentifier make_identifier(const PDU& packet);
|
||||
static StreamIdentifier make_identifier(const Stream& stream);
|
||||
static address_type serialize(IPv4Address address);
|
||||
static address_type serialize(const IPv6Address& address);
|
||||
};
|
||||
|
||||
} // TCPIP
|
||||
} // Tins
|
||||
|
||||
#endif // TINS_HAVE_TCPIP
|
||||
#endif // TINS_TCP_IP_STREAM_ID_H
|
||||
|
||||
@@ -36,13 +36,16 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stdint.h>
|
||||
#include "sniffer.h"
|
||||
#include "macros.h"
|
||||
#include "tcp.h"
|
||||
#include "utils.h"
|
||||
#include "ip.h"
|
||||
#include "ip_address.h"
|
||||
|
||||
#ifdef TINS_HAVE_PCAP
|
||||
|
||||
#include "sniffer.h"
|
||||
|
||||
namespace Tins {
|
||||
class Sniffer;
|
||||
class RawPDU;
|
||||
@@ -60,10 +63,10 @@ public:
|
||||
IPv4Address client_addr, server_addr;
|
||||
uint16_t client_port, server_port;
|
||||
|
||||
StreamInfo() {}
|
||||
StreamInfo() : client_port(0), server_port(0) {}
|
||||
|
||||
StreamInfo(IPv4Address client, IPv4Address server,
|
||||
uint16_t cport, uint16_t sport);
|
||||
uint16_t cport, uint16_t sport);
|
||||
|
||||
bool operator<(const StreamInfo& rhs) const;
|
||||
};
|
||||
@@ -385,4 +388,6 @@ bool TCPStreamFollower::callback(PDU& pdu,
|
||||
|
||||
} // Tins
|
||||
|
||||
#endif // TINS_HAVE_PCAP
|
||||
|
||||
#endif // TINS_TCP_STREAM_H
|
||||
|
||||
@@ -30,21 +30,21 @@
|
||||
#ifndef TINS_TIMESTAMP_H
|
||||
#define TINS_TIMESTAMP_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include "macros.h"
|
||||
#include "cxxstd.h"
|
||||
#if TINS_IS_CXX11
|
||||
#include <chrono>
|
||||
#endif
|
||||
|
||||
struct timeval;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
/**
|
||||
* \brief Represents a packet timestamp.
|
||||
*/
|
||||
class Timestamp {
|
||||
class TINS_API Timestamp {
|
||||
public:
|
||||
#ifdef _WIN32
|
||||
typedef long seconds_type;
|
||||
@@ -57,21 +57,12 @@ public:
|
||||
/**
|
||||
* \brief Constructs a Timestamp which will hold the current time.
|
||||
*/
|
||||
static Timestamp current_time() {
|
||||
#ifdef _WIN32
|
||||
//fixme
|
||||
return Timestamp();
|
||||
#else
|
||||
timeval tv;
|
||||
gettimeofday(&tv, 0);
|
||||
return tv;
|
||||
#endif
|
||||
}
|
||||
static Timestamp current_time();
|
||||
|
||||
/**
|
||||
* Default constructs the timestamp.
|
||||
* Default constructs a timestamp.
|
||||
*/
|
||||
Timestamp() : tv() {}
|
||||
Timestamp();
|
||||
|
||||
#if TINS_IS_CXX11
|
||||
/**
|
||||
@@ -79,47 +70,42 @@ public:
|
||||
*/
|
||||
template<typename Rep, typename Period>
|
||||
Timestamp(const std::chrono::duration<Rep, Period>& ts) {
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::microseconds;
|
||||
using std::chrono::seconds;
|
||||
|
||||
tv.tv_sec = duration_cast<seconds>(ts).count();
|
||||
tv.tv_usec = duration_cast<microseconds>(
|
||||
ts - seconds(tv.tv_sec)).count();
|
||||
timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>(ts).count();
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Constructs a timestamp from a timeval object.
|
||||
* \param time_val The timeval object.
|
||||
* Constructs a timestamp from a timeval struct.
|
||||
*
|
||||
* \param time_val The timeval struct
|
||||
*/
|
||||
Timestamp(const timeval& time_val) : tv(time_val) {}
|
||||
Timestamp(const timeval& time_val);
|
||||
|
||||
/**
|
||||
* Returns the amount of seconds in this timestamp.
|
||||
*/
|
||||
seconds_type seconds() const {
|
||||
return tv.tv_sec;
|
||||
}
|
||||
seconds_type seconds() const;
|
||||
|
||||
/**
|
||||
* Returns the amount of microseconds in this timestamp.
|
||||
* \brief Returns the rest of the time in this timestamp in microseconds
|
||||
*
|
||||
* This is, after subtracting the seconds part, how many microseconds are
|
||||
* left in this timestamp
|
||||
*/
|
||||
microseconds_type microseconds() const {
|
||||
return tv.tv_usec;
|
||||
}
|
||||
microseconds_type microseconds() const;
|
||||
|
||||
#if TINS_IS_CXX11
|
||||
/**
|
||||
* Converts this Timestamp to a std::chrono::microseconds
|
||||
*/
|
||||
operator std::chrono::microseconds() const {
|
||||
return std::chrono::seconds(seconds()) +
|
||||
std::chrono::microseconds(microseconds());
|
||||
return std::chrono::microseconds(timestamp_);
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
timeval tv;
|
||||
Timestamp(uint64_t value);
|
||||
|
||||
uint64_t timestamp_;
|
||||
};
|
||||
|
||||
} // Tins
|
||||
|
||||
@@ -145,9 +145,8 @@ public:
|
||||
void sport(uint16_t new_sport);
|
||||
|
||||
/**
|
||||
* \brief Getter for the length field.
|
||||
* \brief Set the length field.
|
||||
* \param new_len The new length field.
|
||||
* \return The length field.
|
||||
*/
|
||||
void length(uint16_t new_len);
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include "ip_address.h"
|
||||
#include "ipv6_address.h"
|
||||
#include "internals.h"
|
||||
|
||||
// Fix for Windows interface define on combaseapi.h
|
||||
@@ -89,6 +90,36 @@ struct RouteEntry {
|
||||
int metric;
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct that represents an entry the IPv6 routing table
|
||||
*/
|
||||
struct Route6Entry {
|
||||
/**
|
||||
* This interface's name.
|
||||
*/
|
||||
std::string interface;
|
||||
|
||||
/**
|
||||
* This route entry's destination.
|
||||
*/
|
||||
IPv6Address destination;
|
||||
|
||||
/**
|
||||
* This route entry's subnet mask.
|
||||
*/
|
||||
IPv6Address mask;
|
||||
|
||||
/**
|
||||
* This route entry's next hop.
|
||||
*/
|
||||
IPv6Address gateway;
|
||||
|
||||
/**
|
||||
* This route entry's metric.
|
||||
*/
|
||||
int metric;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Resolves a domain name and returns its corresponding ip address.
|
||||
*
|
||||
@@ -176,6 +207,13 @@ void route_entries(ForwardIterator output);
|
||||
*/
|
||||
TINS_API std::vector<RouteEntry> route_entries();
|
||||
|
||||
/**
|
||||
* \brief Retrieves entries in the routing table.
|
||||
*
|
||||
* \return a vector which contains all of the route entries.
|
||||
*/
|
||||
TINS_API std::vector<Route6Entry> route6_entries();
|
||||
|
||||
/** \brief Returns the 32 bit crc of the given buffer.
|
||||
*
|
||||
* \param data The input buffer.
|
||||
|
||||
@@ -4,14 +4,17 @@ IF(HAVE_PCAP_IMMEDIATE_MODE)
|
||||
ADD_DEFINITIONS("-DHAVE_PCAP_IMMEDIATE_MODE=1")
|
||||
ENDIF()
|
||||
|
||||
IF(HAVE_PCAP_TIMESTAMP_PRECISION)
|
||||
ADD_DEFINITIONS("-DHAVE_PCAP_TIMESTAMP_PRECISION=1")
|
||||
ENDIF()
|
||||
|
||||
INCLUDE_DIRECTORIES(
|
||||
${LIBTINS_INCLUDE_DIR}
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
${PCAP_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
ADD_LIBRARY(
|
||||
tins ${LIBTINS_TYPE}
|
||||
set(SOURCES
|
||||
arp.cpp
|
||||
bootp.cpp
|
||||
handshake_capturer.cpp
|
||||
@@ -39,25 +42,22 @@ ADD_LIBRARY(
|
||||
loopback.cpp
|
||||
mpls.cpp
|
||||
network_interface.cpp
|
||||
offline_packet_filter.cpp
|
||||
packet_sender.cpp
|
||||
packet_writer.cpp
|
||||
ppi.cpp
|
||||
pdu.cpp
|
||||
pktap.cpp
|
||||
radiotap.cpp
|
||||
address_range.cpp
|
||||
rawpdu.cpp
|
||||
rsn_information.cpp
|
||||
sll.cpp
|
||||
snap.cpp
|
||||
sniffer.cpp
|
||||
tcp.cpp
|
||||
tcp_ip/ack_tracker.cpp
|
||||
tcp_ip/flow.cpp
|
||||
tcp_ip/data_tracker.cpp
|
||||
tcp_ip/stream.cpp
|
||||
tcp_ip/stream_follower.cpp
|
||||
tcp_stream.cpp
|
||||
tcp_ip/stream_identifier.cpp
|
||||
timestamp.cpp
|
||||
udp.cpp
|
||||
utils.cpp
|
||||
dot11/dot11_base.cpp
|
||||
@@ -70,9 +70,28 @@ ADD_LIBRARY(
|
||||
dot11/dot11_control.cpp
|
||||
)
|
||||
|
||||
SET(PCAP_DEPENDENT_SOURCES
|
||||
sniffer.cpp
|
||||
packet_writer.cpp
|
||||
pktap.cpp
|
||||
tcp_stream.cpp
|
||||
offline_packet_filter.cpp
|
||||
ppi.cpp
|
||||
)
|
||||
|
||||
IF(LIBTINS_ENABLE_PCAP)
|
||||
message(STATUS "SETTING TO ${PCAP_DEPENDENT_SOURCES}")
|
||||
SET(SOURCES ${SOURCES} ${PCAP_DEPENDENT_SOURCES})
|
||||
ENDIF()
|
||||
|
||||
ADD_LIBRARY(
|
||||
tins ${LIBTINS_TYPE}
|
||||
${SOURCES}
|
||||
)
|
||||
|
||||
TARGET_LINK_LIBRARIES(tins ${PCAP_LIBRARY} ${OPENSSL_LIBRARIES} ${LIBTINS_OS_LIBS})
|
||||
|
||||
SET_TARGET_PROPERTIES(tins PROPERTIES OUTPUT_NAME tins )
|
||||
SET_TARGET_PROPERTIES(tins PROPERTIES OUTPUT_NAME tins)
|
||||
SET_TARGET_PROPERTIES(tins PROPERTIES VERSION ${LIBTINS_VERSION} SOVERSION ${LIBTINS_VERSION} )
|
||||
|
||||
# Install instructions for this target
|
||||
|
||||
@@ -39,25 +39,14 @@ IPv4Range operator/(const IPv4Address& addr, int mask) {
|
||||
if (mask > 32) {
|
||||
throw logic_error("Prefix length cannot exceed 32");
|
||||
}
|
||||
return IPv4Range::from_mask(
|
||||
addr,
|
||||
IPv4Address(Endian::host_to_be(0xffffffff << (32 - mask)))
|
||||
);
|
||||
return IPv4Range::from_mask(addr, IPv4Address::from_prefix_length(mask));
|
||||
}
|
||||
|
||||
IPv6Range operator/(const IPv6Address& addr, int mask) {
|
||||
if (mask > 128) {
|
||||
throw std::logic_error("Prefix length cannot exceed 128");
|
||||
throw logic_error("Prefix length cannot exceed 128");
|
||||
}
|
||||
IPv6Address last_addr;
|
||||
IPv6Address::iterator it = last_addr.begin();
|
||||
while (mask > 8) {
|
||||
*it = 0xff;
|
||||
++it;
|
||||
mask -= 8;
|
||||
}
|
||||
*it = 0xff << (8 - mask);
|
||||
return IPv6Range::from_mask(addr, last_addr);
|
||||
return IPv6Range::from_mask(addr, IPv6Address::from_prefix_length(mask));
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
@@ -43,7 +43,7 @@ using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
PDU::metadata ARP::extract_metadata(const uint8_t *buffer, uint32_t total_sz) {
|
||||
PDU::metadata ARP::extract_metadata(const uint8_t* /*buffer*/, uint32_t total_sz) {
|
||||
if (TINS_UNLIKELY(total_sz < sizeof(arp_header))) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ void BootP::vend(const vend_type& newvend_) {
|
||||
vend_ = newvend_;
|
||||
}
|
||||
|
||||
void BootP::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
void BootP::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* /*parent*/) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
stream.write(bootp_);
|
||||
stream.write(vend_.begin(), vend_.end());
|
||||
|
||||
@@ -270,7 +270,7 @@ SessionKeys::SessionKeys(const ptk_type& ptk, bool is_ccmp)
|
||||
}
|
||||
|
||||
SessionKeys::SessionKeys(const RSNHandshake& hs, const pmk_type& pmk)
|
||||
: ptk_(PTK_SIZE) {
|
||||
: ptk_(PTK_SIZE), is_ccmp_(false) {
|
||||
if (pmk.size() != PMK_SIZE) {
|
||||
throw invalid_handshake();
|
||||
}
|
||||
@@ -355,6 +355,12 @@ SNAP* SessionKeys::ccmp_decrypt_unicast(const Dot11Data& dot11, RawPDU& raw) con
|
||||
counter[14] = (total_sz >> 8) & 0xff;
|
||||
counter[15] = total_sz & 0xff;
|
||||
|
||||
if (dot11.subtype() == Dot11::QOS_DATA_DATA) {
|
||||
const uint32_t offset = (dot11.from_ds() && dot11.to_ds()) ? 30 : 24;
|
||||
AAD[offset] = static_cast<const Dot11QoSData&>(dot11).qos_control() & 0x0f;
|
||||
counter[1] = AAD[offset];
|
||||
}
|
||||
|
||||
AES_encrypt(counter, MIC, &ctx);
|
||||
xor_range(MIC, AAD, MIC, 16);
|
||||
AES_encrypt(MIC, MIC, &ctx);
|
||||
|
||||
@@ -47,7 +47,7 @@ using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
PDU::metadata DHCP::extract_metadata(const uint8_t *buffer, uint32_t total_sz) {
|
||||
PDU::metadata DHCP::extract_metadata(const uint8_t* /*buffer*/, uint32_t total_sz) {
|
||||
if (TINS_UNLIKELY(total_sz < sizeof(bootp_header))) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
PDU::metadata DHCPv6::extract_metadata(const uint8_t *buffer, uint32_t total_sz) {
|
||||
PDU::metadata DHCPv6::extract_metadata(const uint8_t* /*buffer*/, uint32_t total_sz) {
|
||||
if (TINS_UNLIKELY(total_sz < 2)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
|
||||
10
src/dns.cpp
10
src/dns.cpp
@@ -51,8 +51,8 @@ using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
PDU::metadata DNS::extract_metadata(const uint8_t *buffer, uint32_t total_sz) {
|
||||
if (TINS_UNLIKELY(sizeof(dns_header))) {
|
||||
PDU::metadata DNS::extract_metadata(const uint8_t* /*buffer*/, uint32_t total_sz) {
|
||||
if (TINS_UNLIKELY(total_sz < sizeof(dns_header))) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
return metadata(total_sz, pdu_flag, PDU::UNKNOWN);
|
||||
@@ -287,8 +287,8 @@ void DNS::add_additional(const resource& resource){
|
||||
|
||||
string DNS::encode_domain_name(const string& dn) {
|
||||
string output;
|
||||
size_t last_index(0), index;
|
||||
if (!dn.empty()) {
|
||||
size_t last_index(0), index;
|
||||
while ((index = dn.find('.', last_index+1)) != string::npos) {
|
||||
output.push_back(static_cast<char>(index - last_index));
|
||||
output.append(dn.begin() + last_index, dn.begin() + index);
|
||||
@@ -386,7 +386,7 @@ uint32_t DNS::compose_name(const uint8_t* ptr, char* out_ptr) const {
|
||||
return end_ptr - start_ptr;
|
||||
}
|
||||
|
||||
void DNS::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
void DNS::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* /*parent*/) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
stream.write(header_);
|
||||
stream.write(records_data_.begin(), records_data_.end());
|
||||
@@ -605,7 +605,7 @@ bool DNS::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
// SOA record
|
||||
|
||||
DNS::soa_record::soa_record()
|
||||
: serial_(0), refresh_(0), retry_(0), expire_(0) {
|
||||
: serial_(0), refresh_(0), retry_(0), expire_(0), minimum_ttl_(0) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -67,9 +67,8 @@ Dot11::Dot11(const address_type& dst_hw_addr)
|
||||
addr1(dst_hw_addr);
|
||||
}
|
||||
|
||||
Dot11::Dot11(const dot11_header* header_ptr)
|
||||
Dot11::Dot11(const dot11_header* /*header_ptr*/)
|
||||
: header_(), options_size_(0) {
|
||||
|
||||
}
|
||||
|
||||
Dot11::Dot11(const uint8_t* buffer, uint32_t total_sz)
|
||||
@@ -78,6 +77,12 @@ Dot11::Dot11(const uint8_t* buffer, uint32_t total_sz)
|
||||
stream.read(header_);
|
||||
}
|
||||
|
||||
void Dot11::write_ext_header(Memory::OutputMemoryStream& /*stream*/) {
|
||||
}
|
||||
|
||||
void Dot11::write_fixed_parameters(Memory::OutputMemoryStream& /*stream*/) {
|
||||
}
|
||||
|
||||
void Dot11::parse_tagged_parameters(InputMemoryStream& stream) {
|
||||
if (stream) {
|
||||
while (stream.size() >= 2) {
|
||||
@@ -201,14 +206,14 @@ void Dot11::send(PacketSender& sender, const NetworkInterface& iface) {
|
||||
addr.sll_halen = 6;
|
||||
addr.sll_ifindex = iface.id();
|
||||
memcpy(&(addr.sll_addr), header_.addr1, 6);
|
||||
sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
|
||||
sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr), iface);
|
||||
#else
|
||||
sender.send_l2(*this, 0, 0, iface);
|
||||
#endif
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
void Dot11::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
void Dot11::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* /*parent*/) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
stream.write(header_);
|
||||
write_ext_header(stream);
|
||||
|
||||
@@ -196,7 +196,7 @@ uint32_t Dot11BlockAckRequest::header_size() const {
|
||||
|
||||
Dot11BlockAck::Dot11BlockAck(const address_type& dst_addr,
|
||||
const address_type& target_addr)
|
||||
: Dot11ControlTA(dst_addr, target_addr), bitmap_() {
|
||||
: Dot11ControlTA(dst_addr, target_addr), bar_control_(0), start_sequence_(0), bitmap_() {
|
||||
subtype(BLOCK_ACK);
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ Dot11QoSData::Dot11QoSData(const uint8_t* buffer, uint32_t total_sz)
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(Dot11Data::header_size());
|
||||
stream.read(qos_control_);
|
||||
if (total_sz) {
|
||||
if (stream) {
|
||||
// If the wep bit is on, then just use a RawPDU
|
||||
if (wep()) {
|
||||
inner_pdu(new Tins::RawPDU(stream.pointer(), stream.size()));
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@@ -26,7 +26,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cstring>
|
||||
#include "dot1q.h"
|
||||
@@ -39,28 +39,28 @@ using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
PDU::metadata Dot1Q::extract_metadata(const uint8_t *buffer, uint32_t total_sz) {
|
||||
PDU::metadata Dot1Q::extract_metadata(const uint8_t* /*buffer*/, uint32_t total_sz) {
|
||||
if (TINS_UNLIKELY(total_sz < sizeof(dot1q_header))) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
return metadata(sizeof(dot1q_header), pdu_flag, PDU::UNKNOWN);
|
||||
}
|
||||
|
||||
Dot1Q::Dot1Q(small_uint<12> tag_id, bool append_pad)
|
||||
Dot1Q::Dot1Q(small_uint<12> tag_id, bool append_pad)
|
||||
: header_(), append_padding_(append_pad) {
|
||||
id(tag_id);
|
||||
}
|
||||
|
||||
Dot1Q::Dot1Q(const uint8_t* buffer, uint32_t total_sz)
|
||||
Dot1Q::Dot1Q(const uint8_t* buffer, uint32_t total_sz)
|
||||
: append_padding_() {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(header_);
|
||||
|
||||
|
||||
if (stream) {
|
||||
inner_pdu(
|
||||
Internals::pdu_from_flag(
|
||||
(Constants::Ethernet::e)payload_type(),
|
||||
stream.pointer(),
|
||||
(Constants::Ethernet::e)payload_type(),
|
||||
stream.pointer(),
|
||||
stream.size()
|
||||
)
|
||||
);
|
||||
@@ -117,7 +117,12 @@ void Dot1Q::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *)
|
||||
// Set the appropriate payload type flag
|
||||
flag = Internals::pdu_flag_to_ether_type(type);
|
||||
}
|
||||
payload_type(static_cast<uint16_t>(flag));
|
||||
if (flag != Constants::Ethernet::UNKNOWN) {
|
||||
payload_type(static_cast<uint16_t>(flag));
|
||||
}
|
||||
}
|
||||
else {
|
||||
payload_type(0);
|
||||
}
|
||||
stream.write(header_);
|
||||
|
||||
@@ -154,7 +159,7 @@ bool Dot1Q::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
return inner_pdu() ? inner_pdu()->matches_response(ptr, total_sz) : true;
|
||||
}
|
||||
return false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace Tins {
|
||||
|
||||
const Dot3::address_type Dot3::BROADCAST("ff:ff:ff:ff:ff:ff");
|
||||
|
||||
PDU::metadata Dot3::extract_metadata(const uint8_t *buffer, uint32_t total_sz) {
|
||||
PDU::metadata Dot3::extract_metadata(const uint8_t* /*buffer*/, uint32_t total_sz) {
|
||||
if (TINS_UNLIKELY(total_sz < sizeof(dot3_header))) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
@@ -112,7 +112,7 @@ void Dot3::send(PacketSender& sender, const NetworkInterface& iface) {
|
||||
addr.sll_ifindex = iface.id();
|
||||
memcpy(&(addr.sll_addr), header_.dst_mac, sizeof(header_.dst_mac));
|
||||
|
||||
sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
|
||||
sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr), iface);
|
||||
#endif
|
||||
}
|
||||
#endif // !_WIN32 || TINS_HAVE_PACKET_SENDER_PCAP_SENDPACKET
|
||||
@@ -134,7 +134,7 @@ bool Dot3::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Dot3::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
void Dot3::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* /*parent*/) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
header_.length = Endian::host_to_be<uint16_t>(size() - sizeof(header_));
|
||||
stream.write(header_);
|
||||
|
||||
@@ -229,7 +229,6 @@ void RSNEAPOL::key_length(uint16_t length) {
|
||||
|
||||
void RSNEAPOL::key(const key_type& value) {
|
||||
key_ = value;
|
||||
header_.key_t = 0;
|
||||
}
|
||||
|
||||
void RSNEAPOL::key_mic(small_uint<1> flag) {
|
||||
|
||||
@@ -140,7 +140,7 @@ void EthernetII::send(PacketSender& sender, const NetworkInterface& iface) {
|
||||
addr.sll_ifindex = iface.id();
|
||||
memcpy(&(addr.sll_addr), header_.dst_mac, address_type::address_size);
|
||||
|
||||
sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
|
||||
sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr), iface);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ bool EthernetII::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void EthernetII::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
void EthernetII::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* /*parent*/) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
if (inner_pdu()) {
|
||||
Constants::Ethernet::e flag;
|
||||
@@ -179,6 +179,9 @@ void EthernetII::write_serialization(uint8_t* buffer, uint32_t total_sz, const P
|
||||
payload_type(static_cast<uint16_t>(flag));
|
||||
}
|
||||
}
|
||||
else {
|
||||
payload_type(Constants::Ethernet::UNKNOWN);
|
||||
}
|
||||
stream.write(header_);
|
||||
const uint32_t trailer = trailer_size();
|
||||
if (trailer) {
|
||||
|
||||
@@ -46,7 +46,7 @@ using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
PDU::metadata ICMP::extract_metadata(const uint8_t *buffer, uint32_t total_sz) {
|
||||
PDU::metadata ICMP::extract_metadata(const uint8_t* /*buffer*/, uint32_t total_sz) {
|
||||
if (TINS_UNLIKELY(total_sz < sizeof(icmp_header))) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
@@ -59,7 +59,8 @@ ICMP::ICMP(Flags flag)
|
||||
type(flag);
|
||||
}
|
||||
|
||||
ICMP::ICMP(const uint8_t* buffer, uint32_t total_sz) {
|
||||
ICMP::ICMP(const uint8_t* buffer, uint32_t total_sz)
|
||||
: orig_timestamp_or_address_mask_(), recv_timestamp_(), trans_timestamp_() {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(header_);
|
||||
if (type() == TIMESTAMP_REQUEST || type() == TIMESTAMP_REPLY) {
|
||||
|
||||
@@ -47,13 +47,13 @@ using Tins::Memory::OutputMemoryStream;
|
||||
namespace Tins {
|
||||
|
||||
ICMPv6::ICMPv6(Types tp)
|
||||
: options_size_(), reach_time_(0), retrans_timer_(0) {
|
||||
: options_size_(), reach_time_(0), retrans_timer_(0), mlqm_(), use_mldv2_(true) {
|
||||
memset(&header_, 0, sizeof(header_));
|
||||
type(tp);
|
||||
}
|
||||
|
||||
ICMPv6::ICMPv6(const uint8_t* buffer, uint32_t total_sz)
|
||||
: options_size_(), reach_time_(0), retrans_timer_(0) {
|
||||
: options_size_(), reach_time_(0), retrans_timer_(0), mlqm_(), use_mldv2_(true) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(header_);
|
||||
if (has_target_addr()) {
|
||||
@@ -77,12 +77,16 @@ ICMPv6::ICMPv6(const uint8_t* buffer, uint32_t total_sz)
|
||||
}
|
||||
else if (type() == MGM_QUERY) {
|
||||
stream.read(multicast_address_);
|
||||
stream.read(mlqm_);
|
||||
int sources_count = stream.read_be<uint16_t>();
|
||||
while (sources_count--) {
|
||||
ipaddress_type address;
|
||||
stream.read(address);
|
||||
sources_.push_back(address);
|
||||
// MLDv1 ends here
|
||||
use_mldv2_ = stream;
|
||||
if (stream) {
|
||||
stream.read(mlqm_);
|
||||
int sources_count = stream.read_be<uint16_t>();
|
||||
while (sources_count--) {
|
||||
ipaddress_type address;
|
||||
stream.read(address);
|
||||
sources_.push_back(address);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Retrieve options
|
||||
@@ -232,8 +236,11 @@ uint32_t ICMPv6::header_size() const {
|
||||
}
|
||||
}
|
||||
else if (type() == MGM_QUERY) {
|
||||
extra += ipaddress_type::address_size + sizeof(mlqm_) + sizeof(uint16_t) +
|
||||
ipaddress_type::address_size * sources_.size();
|
||||
extra += ipaddress_type::address_size;
|
||||
if (use_mldv2_) {
|
||||
extra += sizeof(mlqm_) + sizeof(uint16_t) +
|
||||
ipaddress_type::address_size * sources_.size();
|
||||
}
|
||||
}
|
||||
return sizeof(header_) + options_size_ + extra +
|
||||
(has_target_addr() ? ipaddress_type::address_size : 0) +
|
||||
@@ -315,12 +322,15 @@ void ICMPv6::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU*
|
||||
}
|
||||
else if (type() == MGM_QUERY) {
|
||||
stream.write(multicast_address_);
|
||||
stream.write(mlqm_);
|
||||
stream.write_be<uint16_t>(sources_.size());
|
||||
typedef sources_list::const_iterator iterator;
|
||||
for (iterator iter = sources_.begin(); iter != sources_.end(); ++iter) {
|
||||
stream.write(*iter);
|
||||
}
|
||||
// Only write this if we're using MLDv2
|
||||
if (use_mldv2_) {
|
||||
stream.write(mlqm_);
|
||||
stream.write_be<uint16_t>(sources_.size());
|
||||
typedef sources_list::const_iterator iterator;
|
||||
for (iterator iter = sources_.begin(); iter != sources_.end(); ++iter) {
|
||||
stream.write(*iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (options_type::const_iterator it = options_.begin(); it != options_.end(); ++it) {
|
||||
write_option(*it, stream);
|
||||
@@ -414,6 +424,10 @@ void ICMPv6::write_option(const option& opt, OutputMemoryStream& stream) {
|
||||
stream.write(opt.data_ptr(), opt.data_size());
|
||||
}
|
||||
|
||||
void ICMPv6::use_mldv2(bool value) {
|
||||
use_mldv2_ = value;
|
||||
}
|
||||
|
||||
const ICMPv6::option* ICMPv6::search_option(OptionTypes type) const {
|
||||
// Search for the iterator. If we found something, return it, otherwise return nullptr.
|
||||
options_type::const_iterator iter = search_option_iterator(type);
|
||||
@@ -850,7 +864,7 @@ ICMPv6::prefix_info_type ICMPv6::prefix_info_type::from_option(const option& opt
|
||||
output.A = (stream.read<uint8_t>() >> 6) & 0x1;
|
||||
output.valid_lifetime = stream.read_be<uint32_t>();
|
||||
output.preferred_lifetime = stream.read_be<uint32_t>();
|
||||
stream.skip(sizeof(uint32_t));
|
||||
output.reserved2 = stream.read_be<uint32_t>();
|
||||
output.prefix = stream.read<ICMPv6::ipaddress_type>();
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@@ -28,7 +28,9 @@
|
||||
*/
|
||||
|
||||
#include "internals.h"
|
||||
#include <pcap.h>
|
||||
#ifdef TINS_HAVE_PCAP
|
||||
#include <pcap.h>
|
||||
#endif // TINS_HAVE_PCAP
|
||||
#include "ip.h"
|
||||
#include "ethernetII.h"
|
||||
#include "ieee802_3.h"
|
||||
@@ -63,7 +65,7 @@ namespace Tins {
|
||||
namespace Internals {
|
||||
|
||||
bool from_hex(const string& str, uint32_t& result) {
|
||||
unsigned i(0);
|
||||
size_t i = 0;
|
||||
result = 0;
|
||||
while (i < str.size()) {
|
||||
uint8_t tmp;
|
||||
@@ -82,6 +84,29 @@ bool from_hex(const string& str, uint32_t& result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool from_hex(const string& str, string& result) {
|
||||
result = "";
|
||||
for (size_t i = 0; i < str.size(); i+= 2) {
|
||||
uint8_t value = 0;
|
||||
for (size_t j = i; j < i + 2 && j < str.size(); ++j) {
|
||||
if (str[j] >= 'A' && str[j] <= 'F') {
|
||||
value = (value << 4) | (str[j] - 'A' + 10);
|
||||
}
|
||||
else if (str[j] >= 'a' && str[j] <= 'f') {
|
||||
value = (value << 4) | (str[j] - 'a' + 10);
|
||||
}
|
||||
else if (str[j] >= '0' && str[j] <= '9') {
|
||||
value = (value << 4) | (str[j] - '0');
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
result.push_back(value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void skip_line(std::istream& input) {
|
||||
int c = 0;
|
||||
while (c != '\n' && input) {
|
||||
@@ -115,7 +140,7 @@ Tins::PDU* pdu_from_flag(Constants::Ethernet::e flag,
|
||||
{
|
||||
PDU* pdu = Internals::allocate<EthernetII>(
|
||||
static_cast<uint16_t>(flag),
|
||||
buffer,
|
||||
buffer,
|
||||
size
|
||||
);
|
||||
if (pdu) {
|
||||
@@ -126,8 +151,8 @@ Tins::PDU* pdu_from_flag(Constants::Ethernet::e flag,
|
||||
};
|
||||
}
|
||||
|
||||
Tins::PDU* pdu_from_flag(Constants::IP::e flag,
|
||||
const uint8_t* buffer,
|
||||
Tins::PDU* pdu_from_flag(Constants::IP::e flag,
|
||||
const uint8_t* buffer,
|
||||
uint32_t size,
|
||||
bool rawpdu_on_no_match) {
|
||||
switch (flag) {
|
||||
@@ -156,8 +181,9 @@ Tins::PDU* pdu_from_flag(Constants::IP::e flag,
|
||||
return 0;
|
||||
}
|
||||
|
||||
PDU* pdu_from_dlt_flag(int flag,
|
||||
const uint8_t* buffer,
|
||||
#ifdef TINS_HAVE_PCAP
|
||||
PDU* pdu_from_dlt_flag(int flag,
|
||||
const uint8_t* buffer,
|
||||
uint32_t size,
|
||||
bool rawpdu_on_no_match) {
|
||||
switch (flag) {
|
||||
@@ -185,6 +211,7 @@ PDU* pdu_from_dlt_flag(int flag,
|
||||
return rawpdu_on_no_match ? new RawPDU(buffer, size) : 0;
|
||||
};
|
||||
}
|
||||
#endif // TINS_HAVE_PCAP
|
||||
|
||||
Tins::PDU* pdu_from_flag(PDU::PDUType type, const uint8_t* buffer, uint32_t size) {
|
||||
switch(type) {
|
||||
@@ -315,8 +342,8 @@ uint32_t get_padded_icmp_inner_pdu_size(const PDU* inner_pdu, uint32_t pad_align
|
||||
}
|
||||
}
|
||||
|
||||
void try_parse_icmp_extensions(InputMemoryStream& stream,
|
||||
uint32_t payload_length,
|
||||
void try_parse_icmp_extensions(InputMemoryStream& stream,
|
||||
uint32_t payload_length,
|
||||
ICMPExtensionsStructure& extensions) {
|
||||
if (!stream) {
|
||||
return;
|
||||
@@ -332,7 +359,7 @@ void try_parse_icmp_extensions(InputMemoryStream& stream,
|
||||
extensions_size = stream.size() - payload_length;
|
||||
}
|
||||
else if (stream.can_read(minimum_payload)) {
|
||||
// This packet might be non-rfc compliant. In that case the length
|
||||
// This packet might be non-rfc compliant. In that case the length
|
||||
// field can contain garbage.
|
||||
extensions_ptr = stream.pointer() + minimum_payload;
|
||||
extensions_size = stream.size() - minimum_payload;
|
||||
|
||||
@@ -435,10 +435,13 @@ void IP::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* pare
|
||||
Internals::pdu_type_to_id<IP>(inner_pdu()->pdu_type())
|
||||
);
|
||||
}
|
||||
if (!is_fragmented() && new_flag != 0xff) {
|
||||
if (new_flag != 0xff) {
|
||||
protocol(new_flag);
|
||||
}
|
||||
}
|
||||
else {
|
||||
protocol(0);
|
||||
}
|
||||
|
||||
uint16_t original_frag_off = header_.frag_off;
|
||||
|
||||
@@ -447,6 +450,8 @@ void IP::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* pare
|
||||
total_sz = Endian::host_to_be<uint16_t>(total_sz);
|
||||
header_.frag_off = Endian::be_to_host(header_.frag_off);
|
||||
}
|
||||
#else
|
||||
Internals::unused(parent);
|
||||
#endif
|
||||
tot_len(total_sz);
|
||||
head_len(static_cast<uint8_t>(header_size() / sizeof(uint32_t)));
|
||||
|
||||
@@ -54,7 +54,11 @@ const AddressRange<IPv4Address> private_ranges[] = {
|
||||
|
||||
const AddressRange<IPv4Address> loopback_range = IPv4Address("127.0.0.0") / 8;
|
||||
const AddressRange<IPv4Address> multicast_range = IPv4Address("224.0.0.0") / 4;
|
||||
|
||||
|
||||
IPv4Address IPv4Address::from_prefix_length(uint32_t prefix_length) {
|
||||
return IPv4Address(Endian::host_to_be(0xffffffff << (32 - prefix_length)));
|
||||
}
|
||||
|
||||
IPv4Address::IPv4Address(uint32_t ip)
|
||||
: ip_addr_(Endian::be_to_host(ip)) {
|
||||
|
||||
@@ -139,4 +143,8 @@ bool IPv4Address::is_broadcast() const {
|
||||
return* this == broadcast;
|
||||
}
|
||||
|
||||
IPv4Address IPv4Address::operator&(const IPv4Address& mask) const {
|
||||
return IPv4Address(Endian::be_to_host(ip_addr_ & mask.ip_addr_));
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Tins {
|
||||
namespace Internals {
|
||||
|
||||
IPv4Stream::IPv4Stream()
|
||||
: received_end_(false), received_size_(), total_size_() {
|
||||
: received_end_(false), transport_proto_(0xff), received_size_(), total_size_() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
41
src/ipv6.cpp
41
src/ipv6.cpp
@@ -70,7 +70,7 @@ PDU::metadata IPv6::extract_metadata(const uint8_t *buffer, uint32_t total_sz) {
|
||||
return metadata(header_size, pdu_flag, PDU::UNKNOWN);
|
||||
}
|
||||
|
||||
IPv6::IPv6(address_type ip_dst, address_type ip_src, PDU* child)
|
||||
IPv6::IPv6(address_type ip_dst, address_type ip_src, PDU* /*child*/)
|
||||
: header_(), headers_size_(0) {
|
||||
version(6);
|
||||
dst_addr(ip_dst);
|
||||
@@ -82,6 +82,7 @@ IPv6::IPv6(const uint8_t* buffer, uint32_t total_sz)
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(header_);
|
||||
uint8_t current_header = header_.next_header;
|
||||
uint32_t actual_payload_length = payload_length();
|
||||
bool is_payload_fragmented = false;
|
||||
while (stream) {
|
||||
if (is_extension_header(current_header)) {
|
||||
@@ -93,24 +94,47 @@ IPv6::IPv6(const uint8_t* buffer, uint32_t total_sz)
|
||||
// minus one, from the next_header field.
|
||||
const uint32_t ext_size = (static_cast<uint32_t>(stream.read<uint8_t>()) + 1) * 8;
|
||||
const uint32_t payload_size = ext_size - sizeof(uint8_t) * 2;
|
||||
if (!stream.can_read(ext_size)) {
|
||||
if (!stream.can_read(payload_size)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
// minus one, from the size field
|
||||
add_ext_header(ext_header(ext_type, payload_size, stream.pointer()));
|
||||
if (actual_payload_length == 0u && current_header == HOP_BY_HOP) {
|
||||
// could be a jumbogram, look for Jumbo Payload Option
|
||||
InputMemoryStream options(stream.pointer(), payload_size);
|
||||
while (options) {
|
||||
const uint8_t opt_type = options.read<uint8_t>();
|
||||
if (opt_type == PAD_1) {
|
||||
continue;
|
||||
}
|
||||
const uint8_t opt_size = options.read<uint8_t>();
|
||||
if (opt_type == JUMBO_PAYLOAD) {
|
||||
if (opt_size != 4) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
actual_payload_length = stream.read_be<uint32_t>();
|
||||
break;
|
||||
}
|
||||
options.skip(opt_size);
|
||||
}
|
||||
}
|
||||
current_header = ext_type;
|
||||
actual_payload_length -= ext_size;
|
||||
stream.skip(payload_size);
|
||||
}
|
||||
else {
|
||||
if (!stream.can_read(actual_payload_length)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
if (is_payload_fragmented) {
|
||||
inner_pdu(new Tins::RawPDU(stream.pointer(), stream.size()));
|
||||
inner_pdu(new Tins::RawPDU(stream.pointer(), actual_payload_length));
|
||||
}
|
||||
else {
|
||||
inner_pdu(
|
||||
Internals::pdu_from_flag(
|
||||
static_cast<Constants::IP::e>(current_header),
|
||||
stream.pointer(),
|
||||
stream.size(),
|
||||
actual_payload_length,
|
||||
false
|
||||
)
|
||||
);
|
||||
@@ -119,11 +143,11 @@ IPv6::IPv6(const uint8_t* buffer, uint32_t total_sz)
|
||||
Internals::allocate<IPv6>(
|
||||
current_header,
|
||||
stream.pointer(),
|
||||
stream.size()
|
||||
actual_payload_length
|
||||
)
|
||||
);
|
||||
if (!inner_pdu()) {
|
||||
inner_pdu(new Tins::RawPDU(stream.pointer(), stream.size()));
|
||||
inner_pdu(new Tins::RawPDU(stream.pointer(), actual_payload_length));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -219,7 +243,7 @@ bool IPv6::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void IPv6::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
void IPv6::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* /*parent*/) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
if (inner_pdu()) {
|
||||
uint8_t new_flag = Internals::pdu_flag_to_ip_type(inner_pdu()->pdu_type());
|
||||
@@ -232,6 +256,9 @@ void IPv6::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* pa
|
||||
set_last_next_header(new_flag);
|
||||
}
|
||||
}
|
||||
else {
|
||||
set_last_next_header(0);
|
||||
}
|
||||
payload_length(static_cast<uint16_t>(total_sz - sizeof(header_)));
|
||||
stream.write(header_);
|
||||
for (headers_type::const_iterator it = ext_headers_.begin(); it != ext_headers_.end(); ++it) {
|
||||
|
||||
@@ -52,6 +52,18 @@ namespace Tins {
|
||||
const IPv6Address loopback_address = "::1";
|
||||
const AddressRange<IPv6Address> multicast_range = IPv6Address("ff00::") / 8;
|
||||
|
||||
IPv6Address IPv6Address::from_prefix_length(uint32_t prefix_length) {
|
||||
IPv6Address address;
|
||||
IPv6Address::iterator it = address.begin();
|
||||
while (prefix_length > 8) {
|
||||
*it = 0xff;
|
||||
++it;
|
||||
prefix_length -= 8;
|
||||
}
|
||||
*it = 0xff << (8 - prefix_length);
|
||||
return address;
|
||||
}
|
||||
|
||||
IPv6Address::IPv6Address() {
|
||||
fill(address_, address_ + address_size, 0);
|
||||
}
|
||||
@@ -120,4 +132,13 @@ bool IPv6Address::is_multicast() const {
|
||||
return multicast_range.contains(*this);
|
||||
}
|
||||
|
||||
IPv6Address operator&(const IPv6Address& lhs, const IPv6Address& rhs) {
|
||||
IPv6Address output = lhs;
|
||||
IPv6Address::iterator addr_iter = output.begin();
|
||||
for (IPv6Address::const_iterator it = rhs.begin(); it != rhs.end(); ++it, ++addr_iter) {
|
||||
*addr_iter = *addr_iter & *it;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
@@ -196,7 +196,7 @@ void LLC::clear_information_fields() {
|
||||
information_fields_.clear();
|
||||
}
|
||||
|
||||
void LLC::write_serialization(uint8_t* buffer, uint32_t total_sz, const Tins::PDU* parent) {
|
||||
void LLC::write_serialization(uint8_t* buffer, uint32_t total_sz, const Tins::PDU* /*parent*/) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
if (inner_pdu() && inner_pdu()->pdu_type() == PDU::STP) {
|
||||
dsap(0x42);
|
||||
@@ -215,7 +215,7 @@ void LLC::write_serialization(uint8_t* buffer, uint32_t total_sz, const Tins::PD
|
||||
break;
|
||||
}
|
||||
|
||||
for (field_list::const_iterator it = information_fields_.begin(); it != information_fields_.end(); it++) {
|
||||
for (field_list::const_iterator it = information_fields_.begin(); it != information_fields_.end(); ++it) {
|
||||
stream.write(it->begin(), it->end());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ struct InterfaceInfoCollector {
|
||||
if (addr->ifa_addr->sa_family == AF_LINK && addr_ptr->sdl_index == iface_id) {
|
||||
info->hw_addr = (const uint8_t*)LLADDR(addr_ptr);
|
||||
found_hw = true;
|
||||
info->is_up = info->is_up || (addr->ifa_flags & IFF_UP);
|
||||
}
|
||||
#else
|
||||
#define TINS_BROADCAST_ADDR(addr) (addr->ifa_broadaddr)
|
||||
@@ -93,6 +94,7 @@ struct InterfaceInfoCollector {
|
||||
if (addr->ifa_addr->sa_family == AF_PACKET && addr_ptr->sll_ifindex == iface_id) {
|
||||
info->hw_addr = addr_ptr->sll_addr;
|
||||
found_hw = true;
|
||||
info->is_up = info->is_up || (addr->ifa_flags & IFF_UP);
|
||||
}
|
||||
#endif
|
||||
else if (!std::strcmp(addr->ifa_name, iface_name)) {
|
||||
@@ -106,7 +108,6 @@ struct InterfaceInfoCollector {
|
||||
else {
|
||||
info->bcast_addr = 0;
|
||||
}
|
||||
info->is_up = (addr->ifa_flags & IFF_UP);
|
||||
found_ip = true;
|
||||
}
|
||||
else if (addr->ifa_addr->sa_family == AF_INET6) {
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
*/
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string.h>
|
||||
#include "offline_packet_filter.h"
|
||||
#include "pdu.h"
|
||||
#include "exceptions.h"
|
||||
@@ -64,7 +65,8 @@ void OfflinePacketFilter::init(const string& pcap_filter,
|
||||
}
|
||||
|
||||
bool OfflinePacketFilter::matches_filter(const uint8_t* buffer, uint32_t total_sz) const {
|
||||
pcap_pkthdr header = {};
|
||||
pcap_pkthdr header;
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.len = total_sz;
|
||||
header.caplen = total_sz;
|
||||
return pcap_offline_filter(&filter_, &header, buffer) != 0;
|
||||
|
||||
@@ -156,6 +156,7 @@ bool PacketSender::ether_socket_initialized(const NetworkInterface& iface) const
|
||||
#if defined(BSD) || defined(__FreeBSD_kernel__)
|
||||
return ether_socket_.count(iface.id());
|
||||
#else
|
||||
Internals::unused(iface);
|
||||
return ether_socket_ != INVALID_RAW_SOCKET;
|
||||
#endif
|
||||
}
|
||||
@@ -234,6 +235,7 @@ void PacketSender::open_l2_socket(const NetworkInterface& iface) {
|
||||
}
|
||||
ether_socket_[iface.id()] = sock;
|
||||
#else
|
||||
Internals::unused(iface);
|
||||
if (ether_socket_ == INVALID_RAW_SOCKET) {
|
||||
ether_socket_ = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
|
||||
|
||||
@@ -263,7 +265,10 @@ void PacketSender::open_l3_socket(SocketType type) {
|
||||
#else
|
||||
typedef const char* option_ptr;
|
||||
#endif
|
||||
setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL,(option_ptr)&on,sizeof(on));
|
||||
const int level = (type == IPV6_SOCKET) ? IPPROTO_IPV6 : IPPROTO_IP;
|
||||
if (setsockopt(sockfd, level, IP_HDRINCL, (option_ptr)&on, sizeof(on)) != 0) {
|
||||
throw socket_open_error(make_error_string());
|
||||
}
|
||||
|
||||
sockets_[type] = static_cast<int>(sockfd);
|
||||
}
|
||||
@@ -281,6 +286,7 @@ void PacketSender::close_socket(SocketType type, const NetworkInterface& iface)
|
||||
}
|
||||
ether_socket_.erase(it);
|
||||
#elif !defined(_WIN32)
|
||||
Internals::unused(iface);
|
||||
if (ether_socket_ == INVALID_RAW_SOCKET) {
|
||||
throw invalid_socket_type();
|
||||
}
|
||||
@@ -291,6 +297,7 @@ void PacketSender::close_socket(SocketType type, const NetworkInterface& iface)
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
Internals::unused(iface);
|
||||
if (type >= SOCKETS_END || sockets_[type] == INVALID_RAW_SOCKET) {
|
||||
throw invalid_socket_type();
|
||||
}
|
||||
@@ -351,6 +358,8 @@ void PacketSender::send_l2(PDU& pdu,
|
||||
PDU::serialization_type buffer = pdu.serialize();
|
||||
|
||||
#ifdef TINS_HAVE_PACKET_SENDER_PCAP_SENDPACKET
|
||||
Internals::unused(len_addr);
|
||||
Internals::unused(link_addr);
|
||||
open_l2_socket(iface);
|
||||
pcap_t* handle = pcap_handles_[iface];
|
||||
const int buf_size = static_cast<int>(buffer.size());
|
||||
@@ -381,7 +390,7 @@ PDU* PacketSender::recv_l2(PDU& pdu,
|
||||
const NetworkInterface& iface) {
|
||||
int sock = get_ether_socket(iface);
|
||||
vector<int> sockets(1, sock);
|
||||
return recv_match_loop(sockets, pdu, link_addr, len_addr);
|
||||
return recv_match_loop(sockets, pdu, link_addr, len_addr, false);
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
@@ -398,7 +407,7 @@ PDU* PacketSender::recv_l3(PDU& pdu,
|
||||
open_l3_socket(ICMP_SOCKET);
|
||||
sockets.push_back(sockets_[ICMP_SOCKET]);
|
||||
}
|
||||
return recv_match_loop(sockets, pdu, link_addr, len_addr);
|
||||
return recv_match_loop(sockets, pdu, link_addr, len_addr, true);
|
||||
}
|
||||
|
||||
void PacketSender::send_l3(PDU& pdu,
|
||||
@@ -417,7 +426,8 @@ void PacketSender::send_l3(PDU& pdu,
|
||||
PDU* PacketSender::recv_match_loop(const vector<int>& sockets,
|
||||
PDU& pdu,
|
||||
struct sockaddr* link_addr,
|
||||
uint32_t addrlen) {
|
||||
uint32_t addrlen,
|
||||
bool is_layer_3) {
|
||||
#ifdef _WIN32
|
||||
typedef int socket_len_type;
|
||||
typedef int recvfrom_ret_type;
|
||||
@@ -429,10 +439,13 @@ PDU* PacketSender::recv_match_loop(const vector<int>& sockets,
|
||||
struct timeval timeout, end_time;
|
||||
int read;
|
||||
#if defined(BSD) || defined(__FreeBSD_kernel__)
|
||||
bool is_bsd = true;
|
||||
// On* BSD, we need to allocate a buffer using the given size.
|
||||
vector<uint8_t> actual_buffer(buffer_size_);
|
||||
const int buffer_size = is_layer_3 ? 2048 : buffer_size_;
|
||||
vector<uint8_t> actual_buffer(buffer_size);
|
||||
uint8_t* buffer = &actual_buffer[0];
|
||||
#else
|
||||
bool is_bsd = false;
|
||||
uint8_t buffer[2048];
|
||||
const int buffer_size = 2048;
|
||||
#endif
|
||||
@@ -454,7 +467,9 @@ PDU* PacketSender::recv_match_loop(const vector<int>& sockets,
|
||||
for (vector<int>::const_iterator it = sockets.begin(); it != sockets.end(); ++it) {
|
||||
if (FD_ISSET(*it, &readfds)) {
|
||||
recvfrom_ret_type size;
|
||||
#if defined(BSD) || defined(__FreeBSD_kernel__)
|
||||
// Crappy way of only conditionally running this on BSD + layer2
|
||||
if (is_bsd && !is_layer_3) {
|
||||
#if defined(BSD) || defined(__FreeBSD_kernel__)
|
||||
size = ::read(*it, buffer, buffer_size_);
|
||||
const uint8_t* ptr = buffer;
|
||||
// We might see more than one packet
|
||||
@@ -466,13 +481,15 @@ PDU* PacketSender::recv_match_loop(const vector<int>& sockets,
|
||||
}
|
||||
ptr += BPF_WORDALIGN(bpf_header->bh_hdrlen + bpf_header->bh_caplen);
|
||||
}
|
||||
#else
|
||||
#endif // BSD
|
||||
}
|
||||
else {
|
||||
socket_len_type length = addrlen;
|
||||
size = ::recvfrom(*it, (char*)buffer, buffer_size, 0, link_addr, &length);
|
||||
if (pdu.matches_response(buffer, size)) {
|
||||
return Internals::pdu_from_flag(pdu.pdu_type(), buffer, size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <stdexcept>
|
||||
#include <string.h>
|
||||
#include "packet_writer.h"
|
||||
#include "packet.h"
|
||||
#include "pdu.h"
|
||||
@@ -71,11 +72,11 @@ void PacketWriter::write(Packet& packet) {
|
||||
|
||||
void PacketWriter::write(PDU& pdu, const struct timeval& tv) {
|
||||
PDU::serialization_type buffer = pdu.serialize();
|
||||
struct pcap_pkthdr header = {
|
||||
tv,
|
||||
static_cast<bpf_u_int32>(buffer.size()),
|
||||
static_cast<bpf_u_int32>(buffer.size())
|
||||
};
|
||||
struct pcap_pkthdr header;
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.ts = tv;
|
||||
header.caplen = static_cast<bpf_u_int32>(buffer.size());
|
||||
header.len = static_cast<bpf_u_int32>(buffer.size());
|
||||
pcap_dump((u_char*)dumper_, &header, &buffer[0]);
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,9 @@ void PDU::copy_inner_pdu(const PDU& pdu) {
|
||||
}
|
||||
}
|
||||
|
||||
void PDU::prepare_for_serialize(const PDU* /*parent*/) {
|
||||
}
|
||||
|
||||
uint32_t PDU::size() const {
|
||||
uint32_t sz = header_size() + trailer_size();
|
||||
const PDU* ptr(inner_pdu_);
|
||||
@@ -91,6 +94,10 @@ PDU* PDU::recv_response(PacketSender &, const NetworkInterface &) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool PDU::matches_response(const uint8_t* /*ptr*/, uint32_t /*total_sz*/) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void PDU::inner_pdu(PDU* next_pdu) {
|
||||
delete inner_pdu_;
|
||||
inner_pdu_ = next_pdu;
|
||||
|
||||
@@ -65,7 +65,7 @@ uint32_t PKTAP::header_size() const {
|
||||
return sizeof(header_);
|
||||
}
|
||||
|
||||
void PKTAP::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
void PKTAP::write_serialization(uint8_t* /*buffer*/, uint32_t /*total_sz*/, const PDU* /*parent*/) {
|
||||
throw pdu_not_serializable();
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ uint32_t PPI::header_size() const {
|
||||
return static_cast<uint32_t>(sizeof(header_) + data_.size());
|
||||
}
|
||||
|
||||
void PPI::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *) {
|
||||
void PPI::write_serialization(uint8_t* /*buffer*/, uint32_t /*total_sz*/, const PDU *) {
|
||||
throw pdu_not_serializable();
|
||||
}
|
||||
|
||||
|
||||
@@ -487,7 +487,7 @@ void RadioTap::send(PacketSender& sender, const NetworkInterface& iface) {
|
||||
std::copy(dot11_addr.begin(), dot11_addr.end(), addr.sll_addr);
|
||||
}
|
||||
|
||||
sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
|
||||
sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr), iface);
|
||||
#else
|
||||
sender.send_l2(*this, 0, 0, iface);
|
||||
#endif
|
||||
@@ -507,7 +507,7 @@ bool RadioTap::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void RadioTap::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
void RadioTap::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* /*parent*/) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
uint8_t* buffer_start = buffer;
|
||||
radio_.it_len = Endian::host_to_le<uint16_t>(header_size());
|
||||
|
||||
@@ -57,7 +57,7 @@ void RawPDU::payload(const payload_type& pload) {
|
||||
payload_ = pload;
|
||||
}
|
||||
|
||||
bool RawPDU::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
bool RawPDU::matches_response(const uint8_t* /*ptr*/, uint32_t /*total_sz*/) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ using Tins::Memory::OutputMemoryStream;
|
||||
namespace Tins {
|
||||
|
||||
RSNInformation::RSNInformation()
|
||||
: version_(1), capabilities_(0) {
|
||||
: version_(1), capabilities_(0), group_suite_(static_cast<CypherSuites>(0)) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ uint32_t SNAP::header_size() const {
|
||||
return sizeof(snap_);
|
||||
}
|
||||
|
||||
void SNAP::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
void SNAP::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* /*parent*/) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
if (inner_pdu()) {
|
||||
Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_type(
|
||||
|
||||
@@ -87,7 +87,7 @@ struct sniff_data {
|
||||
PDU* pdu;
|
||||
bool packet_processed;
|
||||
|
||||
sniff_data() : pdu(0), packet_processed(true) { }
|
||||
sniff_data() : tv(), pdu(0), packet_processed(true) { }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@@ -356,9 +356,23 @@ void Sniffer::set_immediate_mode(bool enabled) {
|
||||
if (pcap_set_immediate_mode(get_pcap_handle(), enabled)) {
|
||||
throw pcap_error(pcap_geterr(get_pcap_handle()));
|
||||
}
|
||||
#else
|
||||
Internals::unused(enabled);
|
||||
#endif // HAVE_PCAP_IMMEDIATE_MODE
|
||||
}
|
||||
|
||||
void Sniffer::set_timestamp_precision(int value) {
|
||||
// This function exists as of libpcap version 1.5.0.
|
||||
#ifdef HAVE_PCAP_TIMESTAMP_PRECISION
|
||||
int result = pcap_set_tstamp_precision(get_pcap_handle(), value);
|
||||
if (result == PCAP_ERROR_TSTAMP_PRECISION_NOTSUP) {
|
||||
throw pcap_error("Timestamp precision not supported");
|
||||
}
|
||||
#else
|
||||
Internals::unused(value);
|
||||
#endif // HAVE_PCAP_TIMESTAMP_PRECISION
|
||||
}
|
||||
|
||||
void Sniffer::set_rfmon(bool rfmon_enabled) {
|
||||
#ifndef _WIN32
|
||||
if (pcap_can_set_rfmon(get_pcap_handle()) == 1) {
|
||||
@@ -408,7 +422,8 @@ const unsigned SnifferConfiguration::DEFAULT_TIMEOUT = 1000;
|
||||
|
||||
SnifferConfiguration::SnifferConfiguration()
|
||||
: flags_(0), snap_len_(DEFAULT_SNAP_LEN), buffer_size_(0), timeout_(DEFAULT_TIMEOUT),
|
||||
promisc_(false), rfmon_(false), immediate_mode_(false) {
|
||||
promisc_(false), rfmon_(false), immediate_mode_(false), direction_(PCAP_D_INOUT),
|
||||
timestamp_precision_(0) {
|
||||
|
||||
}
|
||||
|
||||
@@ -427,6 +442,9 @@ void SnifferConfiguration::configure_sniffer_pre_activation(Sniffer& sniffer) co
|
||||
if ((flags_ & IMMEDIATE_MODE) != 0) {
|
||||
sniffer.set_immediate_mode(immediate_mode_);
|
||||
}
|
||||
if ((flags_ & TIMESTAMP_PRECISION) != 0) {
|
||||
sniffer.set_timestamp_precision(timestamp_precision_);
|
||||
}
|
||||
}
|
||||
|
||||
void SnifferConfiguration::configure_sniffer_pre_activation(FileSniffer& sniffer) const {
|
||||
@@ -486,6 +504,11 @@ void SnifferConfiguration::set_immediate_mode(bool enabled) {
|
||||
immediate_mode_ = enabled;
|
||||
}
|
||||
|
||||
void SnifferConfiguration::set_timestamp_precision(int value) {
|
||||
flags_ |= TIMESTAMP_PRECISION;
|
||||
timestamp_precision_ = value;
|
||||
}
|
||||
|
||||
void SnifferConfiguration::set_direction(pcap_direction_t direction) {
|
||||
direction_ = direction;
|
||||
flags_ |= DIRECTION;
|
||||
|
||||
@@ -46,6 +46,15 @@ using Tins::Internals::seq_compare;
|
||||
namespace Tins {
|
||||
namespace TCPIP {
|
||||
|
||||
uint32_t interval_start(const AckedRange::interval_type& interval) {
|
||||
if (interval.bounds() == interval_bounds::left_open()) {
|
||||
return interval.lower() + 1;
|
||||
}
|
||||
else {
|
||||
return interval.lower();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t interval_end(const AckedRange::interval_type& interval) {
|
||||
if (interval.bounds() == interval_bounds::right_open()) {
|
||||
return interval.upper() - 1;
|
||||
@@ -123,10 +132,21 @@ void AckTracker::process_sack(const vector<uint32_t>& sack) {
|
||||
// Left edge must be lower than right edge
|
||||
if (seq_compare(sack[i - 1], sack[i]) < 0) {
|
||||
AckedRange range(sack[i - 1], sack[i] - 1);
|
||||
// If this range starts after our current ack number
|
||||
if (seq_compare(range.first(), ack_number_) > 0) {
|
||||
// If this range ends after our current ack number
|
||||
if (seq_compare(range.last(), ack_number_) > 0) {
|
||||
while (range.has_next()) {
|
||||
acked_intervals_.insert(range.next());
|
||||
AckedRange::interval_type next = range.next();
|
||||
uint32_t start = interval_start(next);
|
||||
if (seq_compare(start, ack_number_) <= 0) {
|
||||
// If this interval starts before or at our ACK number
|
||||
// then we need to update our ACK number to the end of
|
||||
// this interval
|
||||
ack_number_ = interval_end(next);
|
||||
}
|
||||
else {
|
||||
// Otherwise, push the interval into the ACK set
|
||||
acked_intervals_.insert(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
187
src/tcp_ip/data_tracker.cpp
Normal file
187
src/tcp_ip/data_tracker.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tcp_ip/data_tracker.h"
|
||||
|
||||
#ifdef TINS_HAVE_TCPIP
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
using std::move;
|
||||
|
||||
using Tins::Internals::seq_compare;
|
||||
|
||||
namespace Tins {
|
||||
namespace TCPIP {
|
||||
|
||||
DataTracker::DataTracker()
|
||||
: seq_number_(0), total_buffered_bytes_(0) {
|
||||
|
||||
}
|
||||
|
||||
DataTracker::DataTracker(uint32_t seq_number)
|
||||
: seq_number_(seq_number), total_buffered_bytes_(0) {
|
||||
|
||||
}
|
||||
|
||||
bool DataTracker::process_payload(uint32_t seq, payload_type payload) {
|
||||
const uint32_t chunk_end = seq + payload.size();
|
||||
// If the end of the chunk ends before current sequence number, ignore it.
|
||||
if (seq_compare(chunk_end, seq_number_) < 0) {
|
||||
return false;
|
||||
}
|
||||
// If it starts before our sequence number, slice it
|
||||
if (seq_compare(seq, seq_number_) < 0) {
|
||||
const uint32_t diff = seq_number_ - seq;
|
||||
payload.erase(
|
||||
payload.begin(),
|
||||
payload.begin() + diff
|
||||
);
|
||||
seq = seq_number_;
|
||||
}
|
||||
bool added_some = false;
|
||||
// Store this payload
|
||||
store_payload(seq, move(payload));
|
||||
// Keep looping while the fragments seq is lower or equal to our seq
|
||||
buffered_payload_type::iterator iter = buffered_payload_.find(seq_number_);
|
||||
while (iter != buffered_payload_.end() && seq_compare(iter->first, seq_number_) <= 0) {
|
||||
// Does this fragment start before our sequence number?
|
||||
if (seq_compare(iter->first, seq_number_) < 0) {
|
||||
uint32_t fragment_end = iter->first + iter->second.size();
|
||||
int comparison = seq_compare(fragment_end, seq_number_);
|
||||
// Does it end after our sequence number?
|
||||
if (comparison > 0) {
|
||||
// Then slice it
|
||||
payload_type& payload = iter->second;
|
||||
// First update this counter
|
||||
total_buffered_bytes_ -= payload.size();
|
||||
payload.erase(
|
||||
payload.begin(),
|
||||
payload.begin() + (seq_number_ - iter->first)
|
||||
);
|
||||
store_payload(seq_number_, move(iter->second));
|
||||
iter = erase_iterator(iter);
|
||||
}
|
||||
else {
|
||||
// Otherwise, we've seen this part of the payload. Erase it.
|
||||
iter = erase_iterator(iter);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// They're equal. Add this payload.
|
||||
payload_.insert(
|
||||
payload_.end(),
|
||||
iter->second.begin(),
|
||||
iter->second.end()
|
||||
);
|
||||
seq_number_ += iter->second.size();
|
||||
iter = erase_iterator(iter);
|
||||
added_some = true;
|
||||
}
|
||||
}
|
||||
return added_some;
|
||||
}
|
||||
|
||||
void DataTracker::advance_sequence(uint32_t seq) {
|
||||
if (seq_compare(seq, seq_number_) <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto it = buffered_payload_.begin(); it != buffered_payload_.end();) {
|
||||
if (seq_compare(it->first, seq) <= 0) {
|
||||
total_buffered_bytes_ -= it->second.size();
|
||||
it = buffered_payload_.erase(it);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
seq_number_ = seq;
|
||||
}
|
||||
|
||||
uint32_t DataTracker::sequence_number() const {
|
||||
return seq_number_;
|
||||
}
|
||||
|
||||
void DataTracker::sequence_number(uint32_t seq) {
|
||||
seq_number_ = seq;
|
||||
}
|
||||
|
||||
const DataTracker::payload_type& DataTracker::payload() const {
|
||||
return payload_;
|
||||
}
|
||||
|
||||
DataTracker::payload_type& DataTracker::payload() {
|
||||
return payload_;
|
||||
}
|
||||
|
||||
const DataTracker::buffered_payload_type& DataTracker::buffered_payload() const {
|
||||
return buffered_payload_;
|
||||
}
|
||||
|
||||
DataTracker::buffered_payload_type& DataTracker::buffered_payload() {
|
||||
return buffered_payload_;
|
||||
}
|
||||
|
||||
uint32_t DataTracker::total_buffered_bytes() const {
|
||||
return total_buffered_bytes_;
|
||||
}
|
||||
|
||||
void DataTracker::store_payload(uint32_t seq, payload_type payload) {
|
||||
buffered_payload_type::iterator iter = buffered_payload_.find(seq);
|
||||
// New segment, store it
|
||||
if (iter == buffered_payload_.end()) {
|
||||
total_buffered_bytes_ += payload.size();
|
||||
buffered_payload_.insert(make_pair(seq, move(payload)));
|
||||
}
|
||||
else if (iter->second.size() < payload.size()) {
|
||||
// Increment by the diff between sizes
|
||||
total_buffered_bytes_ += (payload.size() - iter->second.size());
|
||||
// If we already have payload on this position but it's a shorter
|
||||
// chunk than the new one, replace it
|
||||
iter->second = move(payload);
|
||||
}
|
||||
}
|
||||
|
||||
DataTracker::buffered_payload_type::iterator
|
||||
DataTracker::erase_iterator(buffered_payload_type::iterator iter) {
|
||||
buffered_payload_type::iterator output = iter;
|
||||
total_buffered_bytes_ -= iter->second.size();
|
||||
++output;
|
||||
buffered_payload_.erase(iter);
|
||||
if (output == buffered_payload_.end()) {
|
||||
output = buffered_payload_.begin();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
} // TCPIP
|
||||
} // Tins
|
||||
|
||||
#endif // TINS_HAVE_TCPIP
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
#include "tcp_ip/flow.h"
|
||||
|
||||
#if TINS_IS_CXX11
|
||||
#ifdef TINS_HAVE_TCPIP
|
||||
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
@@ -61,7 +61,7 @@ namespace TCPIP {
|
||||
|
||||
Flow::Flow(const IPv4Address& dest_address, uint16_t dest_port,
|
||||
uint32_t sequence_number)
|
||||
: seq_number_(sequence_number), dest_port_(dest_port) {
|
||||
: data_tracker_(sequence_number), dest_port_(dest_port) {
|
||||
OutputMemoryStream output(dest_address_.data(), dest_address_.size());
|
||||
output.write(dest_address);
|
||||
flags_.is_v6 = false;
|
||||
@@ -70,7 +70,7 @@ Flow::Flow(const IPv4Address& dest_address, uint16_t dest_port,
|
||||
|
||||
Flow::Flow(const IPv6Address& dest_address, uint16_t dest_port,
|
||||
uint32_t sequence_number)
|
||||
: seq_number_(sequence_number), dest_port_(dest_port) {
|
||||
: data_tracker_(sequence_number), dest_port_(dest_port) {
|
||||
OutputMemoryStream output(dest_address_.data(), dest_address_.size());
|
||||
output.write(dest_address);
|
||||
flags_.is_v6 = true;
|
||||
@@ -78,7 +78,6 @@ Flow::Flow(const IPv6Address& dest_address, uint16_t dest_port,
|
||||
}
|
||||
|
||||
void Flow::initialize() {
|
||||
total_buffered_bytes_ = 0;
|
||||
state_ = UNKNOWN;
|
||||
mss_ = -1;
|
||||
}
|
||||
@@ -110,99 +109,26 @@ void Flow::process_packet(PDU& pdu) {
|
||||
return;
|
||||
}
|
||||
const uint32_t chunk_end = tcp->seq() + raw->payload_size();
|
||||
// If the end of the chunk ends after our current sequence number, process it.
|
||||
if (seq_compare(chunk_end, seq_number_) >= 0) {
|
||||
bool added_some = false;
|
||||
uint32_t seq = tcp->seq();
|
||||
// If we're going to buffer this and we have a buffering callback, execute it
|
||||
if (seq > seq_number_ && on_out_of_order_callback_) {
|
||||
on_out_of_order_callback_(*this, seq, raw->payload());
|
||||
}
|
||||
|
||||
// If it starts before our sequence number, slice it
|
||||
if (seq_compare(seq, seq_number_) < 0) {
|
||||
const uint32_t diff = seq_number_ - seq;
|
||||
raw->payload().erase(
|
||||
raw->payload().begin(),
|
||||
raw->payload().begin() + diff
|
||||
);
|
||||
seq = seq_number_;
|
||||
}
|
||||
// Store this payload
|
||||
store_payload(seq, move(raw->payload()));
|
||||
// Keep looping while the fragments seq is lower or equal to our seq
|
||||
buffered_payload_type::iterator iter = buffered_payload_.find(seq_number_);
|
||||
while (iter != buffered_payload_.end() && seq_compare(iter->first, seq_number_) <= 0) {
|
||||
// Does this fragment start before our sequence number?
|
||||
if (seq_compare(iter->first, seq_number_) < 0) {
|
||||
uint32_t fragment_end = iter->first + iter->second.size();
|
||||
int comparison = seq_compare(fragment_end, seq_number_);
|
||||
// Does it end after our sequence number?
|
||||
if (comparison > 0) {
|
||||
// Then slice it
|
||||
payload_type& payload = iter->second;
|
||||
// First update this counter
|
||||
total_buffered_bytes_ -= payload.size();
|
||||
payload.erase(
|
||||
payload.begin(),
|
||||
payload.begin() + (seq_number_ - iter->first)
|
||||
);
|
||||
store_payload(seq_number_, move(iter->second));
|
||||
iter = erase_iterator(iter);
|
||||
}
|
||||
else {
|
||||
// Otherwise, we've seen this part of the payload. Erase it.
|
||||
iter = erase_iterator(iter);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// They're equal. Add this payload.
|
||||
payload_.insert(
|
||||
payload_.end(),
|
||||
iter->second.begin(),
|
||||
iter->second.end()
|
||||
);
|
||||
seq_number_ += iter->second.size();
|
||||
iter = erase_iterator(iter);
|
||||
added_some = true;
|
||||
}
|
||||
}
|
||||
if (added_some) {
|
||||
if (on_data_callback_) {
|
||||
on_data_callback_(*this);
|
||||
}
|
||||
const uint32_t current_seq = data_tracker_.sequence_number();
|
||||
// If the end of the chunk ends before the current sequence number or
|
||||
// if we're going to buffer this and we have a buffering callback, execute it
|
||||
if (seq_compare(chunk_end, current_seq) < 0 ||
|
||||
seq_compare(tcp->seq(), current_seq) > 0){
|
||||
if (on_out_of_order_callback_) {
|
||||
on_out_of_order_callback_(*this, tcp->seq(), raw->payload());
|
||||
}
|
||||
}
|
||||
else if (on_out_of_order_callback_) {
|
||||
on_out_of_order_callback_(*this, tcp->seq(), raw->payload());
|
||||
|
||||
// can process either way, since it will abort immediately if not needed
|
||||
if (data_tracker_.process_payload(tcp->seq(), move(raw->payload()))) {
|
||||
if (on_data_callback_) {
|
||||
on_data_callback_(*this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Flow::store_payload(uint32_t seq, payload_type payload) {
|
||||
buffered_payload_type::iterator iter = buffered_payload_.find(seq);
|
||||
// New segment, store it
|
||||
if (iter == buffered_payload_.end()) {
|
||||
total_buffered_bytes_ += payload.size();
|
||||
buffered_payload_.insert(make_pair(seq, move(payload)));
|
||||
}
|
||||
else if (iter->second.size() < payload.size()) {
|
||||
// Increment by the diff between sizes
|
||||
total_buffered_bytes_ += (payload.size() - iter->second.size());
|
||||
// If we already have payload on this position but it's a shorter
|
||||
// chunk than the new one, replace it
|
||||
iter->second = move(payload);
|
||||
}
|
||||
}
|
||||
|
||||
Flow::buffered_payload_type::iterator Flow::erase_iterator(buffered_payload_type::iterator iter) {
|
||||
buffered_payload_type::iterator output = iter;
|
||||
total_buffered_bytes_ -= iter->second.size();
|
||||
++output;
|
||||
buffered_payload_.erase(iter);
|
||||
if (output == buffered_payload_.end()) {
|
||||
output = buffered_payload_.begin();
|
||||
}
|
||||
return output;
|
||||
void Flow::advance_sequence(uint32_t seq) {
|
||||
data_tracker_.advance_sequence(seq);
|
||||
}
|
||||
|
||||
void Flow::update_state(const TCP& tcp) {
|
||||
@@ -217,7 +143,6 @@ void Flow::update_state(const TCP& tcp) {
|
||||
ack_tracker_ = AckTracker(tcp.ack_seq());
|
||||
#endif // TINS_HAVE_ACK_TRACKER
|
||||
state_ = ESTABLISHED;
|
||||
seq_number_++;
|
||||
}
|
||||
else if (state_ == UNKNOWN && (tcp.flags() & TCP::SYN) != 0) {
|
||||
// This is the server's state, sending it's first SYN|ACK
|
||||
@@ -225,7 +150,7 @@ void Flow::update_state(const TCP& tcp) {
|
||||
ack_tracker_ = AckTracker(tcp.ack_seq());
|
||||
#endif // TINS_HAVE_ACK_TRACKER
|
||||
state_ = SYN_SENT;
|
||||
seq_number_ = tcp.seq();
|
||||
data_tracker_.sequence_number(tcp.seq() + 1);
|
||||
const TCP::option* mss_option = tcp.search_option(TCP::MSS);
|
||||
if (mss_option) {
|
||||
mss_ = mss_option->to<uint16_t>();
|
||||
@@ -274,7 +199,7 @@ uint16_t Flow::dport() const {
|
||||
}
|
||||
|
||||
const Flow::payload_type& Flow::payload() const {
|
||||
return payload_;
|
||||
return data_tracker_.payload();
|
||||
}
|
||||
|
||||
Flow::State Flow::state() const {
|
||||
@@ -282,23 +207,23 @@ Flow::State Flow::state() const {
|
||||
}
|
||||
|
||||
uint32_t Flow::sequence_number() const {
|
||||
return seq_number_;
|
||||
return data_tracker_.sequence_number();
|
||||
}
|
||||
|
||||
const Flow::buffered_payload_type& Flow::buffered_payload() const {
|
||||
return buffered_payload_;
|
||||
return data_tracker_.buffered_payload();
|
||||
}
|
||||
|
||||
Flow::buffered_payload_type& Flow::buffered_payload() {
|
||||
return buffered_payload_;
|
||||
return data_tracker_.buffered_payload();
|
||||
}
|
||||
|
||||
uint32_t Flow::total_buffered_bytes() const {
|
||||
return total_buffered_bytes_;
|
||||
return data_tracker_.total_buffered_bytes();
|
||||
}
|
||||
|
||||
Flow::payload_type& Flow::payload() {
|
||||
return payload_;
|
||||
return data_tracker_.payload();
|
||||
}
|
||||
|
||||
void Flow::state(State new_state) {
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
#include "tcp_ip/stream.h"
|
||||
|
||||
#if TINS_IS_CXX11
|
||||
#ifdef TINS_HAVE_TCPIP
|
||||
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
@@ -61,14 +61,16 @@ namespace TCPIP {
|
||||
Stream::Stream(PDU& packet, const timestamp_type& ts)
|
||||
: client_flow_(extract_client_flow(packet)),
|
||||
server_flow_(extract_server_flow(packet)), create_time_(ts),
|
||||
last_seen_(ts), auto_cleanup_client_(true), auto_cleanup_server_(true) {
|
||||
// Update client flow state
|
||||
client_flow().process_packet(packet);
|
||||
last_seen_(ts), auto_cleanup_client_(true), auto_cleanup_server_(true),
|
||||
is_partial_stream_(false), directions_recovery_mode_enabled_(0) {
|
||||
const EthernetII* eth = packet.find_pdu<EthernetII>();
|
||||
if (eth) {
|
||||
client_hw_addr_ = eth->src_addr();
|
||||
server_hw_addr_ = eth->dst_addr();
|
||||
}
|
||||
const TCP& tcp = packet.rfind_pdu<TCP>();
|
||||
// If this is not the first packet of a stream (SYN), then it's a partial stream
|
||||
is_partial_stream_ = tcp.flags() != TCP::SYN;
|
||||
}
|
||||
|
||||
void Stream::process_packet(PDU& packet, const timestamp_type& ts) {
|
||||
@@ -258,7 +260,7 @@ void Stream::auto_cleanup_client_data(bool value) {
|
||||
}
|
||||
|
||||
void Stream::auto_cleanup_server_data(bool value) {
|
||||
auto_cleanup_client_ = value;
|
||||
auto_cleanup_server_ = value;
|
||||
}
|
||||
|
||||
void Stream::enable_ack_tracking() {
|
||||
@@ -270,6 +272,25 @@ bool Stream::ack_tracking_enabled() const {
|
||||
return client_flow().ack_tracking_enabled() && server_flow().ack_tracking_enabled();
|
||||
}
|
||||
|
||||
bool Stream::is_partial_stream() const {
|
||||
return is_partial_stream_;
|
||||
}
|
||||
|
||||
void Stream::enable_recovery_mode(uint32_t recovery_window) {
|
||||
using namespace std::placeholders;
|
||||
client_out_of_order_callback(bind(&Stream::client_recovery_mode_handler, _1, _2, _3,
|
||||
client_flow_.sequence_number() + recovery_window,
|
||||
on_client_out_of_order_callback_));
|
||||
server_out_of_order_callback(bind(&Stream::server_recovery_mode_handler, _1, _2, _3,
|
||||
server_flow_.sequence_number() + recovery_window,
|
||||
on_server_out_of_order_callback_));
|
||||
directions_recovery_mode_enabled_ = 2;
|
||||
}
|
||||
|
||||
bool Stream::is_recovery_mode_enabled() const {
|
||||
return directions_recovery_mode_enabled_ > 0;
|
||||
}
|
||||
|
||||
void Stream::on_client_flow_data(const Flow& /*flow*/) {
|
||||
if (on_client_data_callback_) {
|
||||
on_client_data_callback_(*this);
|
||||
@@ -288,23 +309,58 @@ void Stream::on_server_flow_data(const Flow& /*flow*/) {
|
||||
}
|
||||
}
|
||||
|
||||
void Stream::on_client_out_of_order(const Flow& flow,
|
||||
uint32_t seq,
|
||||
const payload_type& payload) {
|
||||
void Stream::on_client_out_of_order(const Flow& /*flow*/, uint32_t seq, const payload_type& payload) {
|
||||
if (on_client_out_of_order_callback_) {
|
||||
on_client_out_of_order_callback_(*this, seq, payload);
|
||||
}
|
||||
}
|
||||
|
||||
void Stream::on_server_out_of_order(const Flow& flow,
|
||||
uint32_t seq,
|
||||
const payload_type& payload) {
|
||||
void Stream::on_server_out_of_order(const Flow& /*flow*/, uint32_t seq, const payload_type& payload) {
|
||||
if (on_server_out_of_order_callback_) {
|
||||
on_server_out_of_order_callback_(*this, seq, payload);
|
||||
}
|
||||
}
|
||||
|
||||
void Stream::client_recovery_mode_handler(Stream& stream, uint32_t sequence_number,
|
||||
const payload_type& payload,
|
||||
uint32_t recovery_sequence_number_end,
|
||||
const stream_packet_callback_type& original_callback) {
|
||||
if (original_callback) {
|
||||
original_callback(stream, sequence_number, payload);
|
||||
}
|
||||
if (!recovery_mode_handler(stream.client_flow(), sequence_number,
|
||||
recovery_sequence_number_end)) {
|
||||
stream.directions_recovery_mode_enabled_--;
|
||||
stream.client_out_of_order_callback(original_callback);
|
||||
}
|
||||
}
|
||||
|
||||
void Stream::server_recovery_mode_handler(Stream& stream, uint32_t sequence_number,
|
||||
const payload_type& payload,
|
||||
uint32_t recovery_sequence_number_end,
|
||||
const stream_packet_callback_type& original_callback) {
|
||||
if (original_callback) {
|
||||
original_callback(stream, sequence_number, payload);
|
||||
}
|
||||
if (!recovery_mode_handler(stream.server_flow(), sequence_number,
|
||||
recovery_sequence_number_end)) {
|
||||
stream.directions_recovery_mode_enabled_--;
|
||||
stream.server_out_of_order_callback(original_callback);
|
||||
}
|
||||
}
|
||||
|
||||
bool Stream::recovery_mode_handler(Flow& flow, uint32_t sequence_number,
|
||||
uint32_t recovery_sequence_number_end) {
|
||||
// If this packet comes after our sequence number (would create a hole), skip it
|
||||
if (sequence_number > flow.sequence_number() &&
|
||||
sequence_number <= recovery_sequence_number_end) {
|
||||
flow.advance_sequence(sequence_number);
|
||||
}
|
||||
// Return true iff we need to keep being in recovery mode
|
||||
return recovery_sequence_number_end > sequence_number;
|
||||
}
|
||||
|
||||
} // TCPIP
|
||||
} // Tins
|
||||
|
||||
#endif // TINS_IS_CXX11
|
||||
#endif // TINS_HAVE_TCPIP
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
#include "tcp_ip/stream_follower.h"
|
||||
|
||||
#if TINS_IS_CXX11
|
||||
#ifdef TINS_HAVE_TCPIP
|
||||
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
@@ -88,9 +88,8 @@ void StreamFollower::process_packet(PDU& packet, const timestamp_type& ts) {
|
||||
if (!tcp) {
|
||||
return;
|
||||
}
|
||||
stream_id identifier = make_stream_id(packet);
|
||||
stream_id identifier = stream_id::make_identifier(packet);
|
||||
streams_type::iterator iter = streams_.find(identifier);
|
||||
bool process = true;
|
||||
if (iter == streams_.end()) {
|
||||
// Start tracking if they're either SYNs or they contain data (attach
|
||||
// to an already running flow).
|
||||
@@ -103,49 +102,49 @@ void StreamFollower::process_packet(PDU& packet, const timestamp_type& ts) {
|
||||
else {
|
||||
throw callback_not_set();
|
||||
}
|
||||
if (tcp->flags() == TCP::SYN) {
|
||||
process = false;
|
||||
}
|
||||
else {
|
||||
// Otherwise, assume the connection is established
|
||||
if (tcp->flags() != TCP::SYN) {
|
||||
// assume the connection is established
|
||||
iter->second.client_flow().state(Flow::ESTABLISHED);
|
||||
iter->second.server_flow().state(Flow::ESTABLISHED);
|
||||
}
|
||||
}
|
||||
else {
|
||||
process = false;
|
||||
// no stream found and no stream was created
|
||||
if (last_cleanup_ + stream_keep_alive_ <= ts) {
|
||||
cleanup_streams(ts);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
// We'll process it if we had already seen this stream or if we just attached to
|
||||
// it and it contains payload
|
||||
if (process) {
|
||||
Stream& stream = iter->second;
|
||||
stream.process_packet(packet, ts);
|
||||
// Check for different potential termination
|
||||
size_t total_chunks = stream.client_flow().buffered_payload().size() +
|
||||
stream.server_flow().buffered_payload().size();
|
||||
uint32_t total_buffered_bytes = stream.client_flow().total_buffered_bytes() +
|
||||
stream.server_flow().total_buffered_bytes();
|
||||
bool terminate_stream = total_chunks > max_buffered_chunks_ ||
|
||||
total_buffered_bytes > max_buffered_bytes_;
|
||||
TerminationReason reason = BUFFERED_DATA;
|
||||
#ifdef TINS_HAVE_ACK_TRACKER
|
||||
if (!terminate_stream) {
|
||||
uint32_t count = 0;
|
||||
count += stream.client_flow().ack_tracker().acked_intervals().iterative_size();
|
||||
count += stream.server_flow().ack_tracker().acked_intervals().iterative_size();
|
||||
terminate_stream = count > DEFAULT_MAX_SACKED_INTERVALS;
|
||||
reason = SACKED_SEGMENTS;
|
||||
}
|
||||
#endif // TINS_HAVE_ACK_TRACKER
|
||||
if (stream.is_finished() || terminate_stream) {
|
||||
// If we're terminating the stream, execute the termination callback
|
||||
if (terminate_stream && on_stream_termination_) {
|
||||
on_stream_termination_(stream, reason);
|
||||
}
|
||||
streams_.erase(iter);
|
||||
}
|
||||
Stream& stream = iter->second;
|
||||
stream.process_packet(packet, ts);
|
||||
// Check for different potential termination
|
||||
size_t total_chunks = stream.client_flow().buffered_payload().size() +
|
||||
stream.server_flow().buffered_payload().size();
|
||||
uint32_t total_buffered_bytes = stream.client_flow().total_buffered_bytes() +
|
||||
stream.server_flow().total_buffered_bytes();
|
||||
bool terminate_stream = total_chunks > max_buffered_chunks_ ||
|
||||
total_buffered_bytes > max_buffered_bytes_;
|
||||
TerminationReason reason = BUFFERED_DATA;
|
||||
#ifdef TINS_HAVE_ACK_TRACKER
|
||||
if (!terminate_stream) {
|
||||
uint32_t count = 0;
|
||||
count += stream.client_flow().ack_tracker().acked_intervals().iterative_size();
|
||||
count += stream.server_flow().ack_tracker().acked_intervals().iterative_size();
|
||||
terminate_stream = count > DEFAULT_MAX_SACKED_INTERVALS;
|
||||
reason = SACKED_SEGMENTS;
|
||||
}
|
||||
#endif // TINS_HAVE_ACK_TRACKER
|
||||
if (stream.is_finished() || terminate_stream) {
|
||||
// If we're terminating the stream, execute the termination callback
|
||||
if (terminate_stream && on_stream_termination_) {
|
||||
on_stream_termination_(stream, reason);
|
||||
}
|
||||
streams_.erase(iter);
|
||||
}
|
||||
|
||||
if (last_cleanup_ + stream_keep_alive_ <= ts) {
|
||||
cleanup_streams(ts);
|
||||
}
|
||||
@@ -173,24 +172,6 @@ Stream& StreamFollower::find_stream(const IPv6Address& client_addr, uint16_t cli
|
||||
return find_stream(identifier);
|
||||
}
|
||||
|
||||
StreamFollower::stream_id StreamFollower::make_stream_id(const PDU& packet) {
|
||||
const TCP* tcp = packet.find_pdu<TCP>();
|
||||
if (!tcp) {
|
||||
throw invalid_packet();
|
||||
}
|
||||
if (const IP* ip = packet.find_pdu<IP>()) {
|
||||
return stream_id(stream_id::serialize(ip->src_addr()), tcp->sport(),
|
||||
stream_id::serialize(ip->dst_addr()), tcp->dport());
|
||||
}
|
||||
else if (const IPv6* ip = packet.find_pdu<IPv6>()) {
|
||||
return stream_id(stream_id::serialize(ip->src_addr()), tcp->sport(),
|
||||
stream_id::serialize(ip->dst_addr()), tcp->dport());
|
||||
}
|
||||
else {
|
||||
throw invalid_packet();
|
||||
}
|
||||
}
|
||||
|
||||
Stream& StreamFollower::find_stream(const stream_id& id) {
|
||||
streams_type::iterator iter = streams_.find(id);
|
||||
if (iter == streams_.end()) {
|
||||
@@ -201,6 +182,10 @@ Stream& StreamFollower::find_stream(const stream_id& id) {
|
||||
}
|
||||
}
|
||||
|
||||
void StreamFollower::follow_partial_streams(bool value) {
|
||||
attach_to_flows_ = value;
|
||||
}
|
||||
|
||||
void StreamFollower::cleanup_streams(const timestamp_type& now) {
|
||||
streams_type::iterator iter = streams_.begin();
|
||||
while (iter != streams_.end()) {
|
||||
@@ -218,57 +203,7 @@ void StreamFollower::cleanup_streams(const timestamp_type& now) {
|
||||
last_cleanup_ = now;
|
||||
}
|
||||
|
||||
// stream_id
|
||||
|
||||
StreamFollower::stream_id::stream_id()
|
||||
: min_address_port(0), max_address_port(0) {
|
||||
min_address.fill(0);
|
||||
max_address.fill(0);
|
||||
}
|
||||
|
||||
StreamFollower::stream_id::stream_id(const address_type& client_addr,
|
||||
uint16_t client_port,
|
||||
const address_type& server_addr,
|
||||
uint16_t server_port)
|
||||
: min_address(client_addr), max_address(server_addr), min_address_port(client_port),
|
||||
max_address_port(server_port) {
|
||||
if (min_address > max_address) {
|
||||
swap(min_address, max_address);
|
||||
swap(min_address_port, max_address_port);
|
||||
}
|
||||
else if (min_address == max_address && min_address_port > max_address_port) {
|
||||
// If the address is the same, just sort ports
|
||||
swap(min_address_port, max_address_port);
|
||||
}
|
||||
}
|
||||
|
||||
bool StreamFollower::stream_id::operator<(const stream_id& rhs) const {
|
||||
return tie(min_address, max_address, min_address_port, max_address_port) <
|
||||
tie(rhs.min_address, rhs.max_address, rhs.min_address_port, rhs.max_address_port);
|
||||
}
|
||||
|
||||
bool StreamFollower::stream_id::operator==(const stream_id& rhs) const {
|
||||
return tie(min_address, min_address_port, max_address, max_address_port) ==
|
||||
tie(rhs.min_address, rhs.min_address_port, rhs.max_address, rhs.max_address_port);
|
||||
}
|
||||
|
||||
StreamFollower::stream_id::address_type StreamFollower::stream_id::serialize(IPv4Address address) {
|
||||
address_type addr;
|
||||
OutputMemoryStream output(addr.data(), addr.size());
|
||||
addr.fill(0);
|
||||
output.write(address);
|
||||
return addr;
|
||||
}
|
||||
|
||||
StreamFollower::stream_id::address_type StreamFollower::stream_id::serialize(const IPv6Address& address) {
|
||||
address_type addr;
|
||||
OutputMemoryStream output(addr.data(), addr.size());
|
||||
addr.fill(0);
|
||||
output.write(address);
|
||||
return addr;
|
||||
}
|
||||
|
||||
} // TCPIP
|
||||
} // Tins
|
||||
|
||||
#endif // TINS_IS_CXX11
|
||||
#endif // TINS_HAVE_TCPIP
|
||||
|
||||
142
src/tcp_ip/stream_identifier.cpp
Normal file
142
src/tcp_ip/stream_identifier.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tcp_ip/stream_identifier.h"
|
||||
|
||||
#ifdef TINS_HAVE_TCPIP
|
||||
|
||||
#include <algorithm>
|
||||
#include <tuple>
|
||||
#include "memory_helpers.h"
|
||||
#include "tcp.h"
|
||||
#include "udp.h"
|
||||
#include "ip.h"
|
||||
#include "ipv6.h"
|
||||
#include "exceptions.h"
|
||||
#include "tcp_ip/stream.h"
|
||||
|
||||
using std::swap;
|
||||
using std::tie;
|
||||
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
namespace TCPIP {
|
||||
|
||||
StreamIdentifier::StreamIdentifier()
|
||||
: min_address_port(0), max_address_port(0) {
|
||||
min_address.fill(0);
|
||||
max_address.fill(0);
|
||||
}
|
||||
|
||||
StreamIdentifier::StreamIdentifier(const address_type& client_addr,
|
||||
uint16_t client_port,
|
||||
const address_type& server_addr,
|
||||
uint16_t server_port)
|
||||
: min_address(client_addr), max_address(server_addr), min_address_port(client_port),
|
||||
max_address_port(server_port) {
|
||||
if (min_address > max_address) {
|
||||
swap(min_address, max_address);
|
||||
swap(min_address_port, max_address_port);
|
||||
}
|
||||
else if (min_address == max_address && min_address_port > max_address_port) {
|
||||
// If the address is the same, just sort ports
|
||||
swap(min_address_port, max_address_port);
|
||||
}
|
||||
}
|
||||
|
||||
bool StreamIdentifier::operator<(const StreamIdentifier& rhs) const {
|
||||
return tie(min_address, max_address, min_address_port, max_address_port) <
|
||||
tie(rhs.min_address, rhs.max_address, rhs.min_address_port, rhs.max_address_port);
|
||||
}
|
||||
|
||||
bool StreamIdentifier::operator==(const StreamIdentifier& rhs) const {
|
||||
return tie(min_address, min_address_port, max_address, max_address_port) ==
|
||||
tie(rhs.min_address, rhs.min_address_port, rhs.max_address, rhs.max_address_port);
|
||||
}
|
||||
|
||||
StreamIdentifier StreamIdentifier::make_identifier(const PDU& packet) {
|
||||
uint16_t source_port;
|
||||
uint16_t dest_port;
|
||||
// Extract source and dest ports
|
||||
if (const TCP* tcp = packet.find_pdu<TCP>()) {
|
||||
source_port = tcp->sport();
|
||||
dest_port = tcp->dport();
|
||||
}
|
||||
else if (const UDP* udp = packet.find_pdu<UDP>()) {
|
||||
source_port = udp->sport();
|
||||
dest_port = udp->dport();
|
||||
}
|
||||
else {
|
||||
throw invalid_packet();
|
||||
}
|
||||
// Extract layer 3 and build the identifier
|
||||
if (const IP* ip = packet.find_pdu<IP>()) {
|
||||
return StreamIdentifier(serialize(ip->src_addr()), source_port,
|
||||
serialize(ip->dst_addr()), dest_port);
|
||||
}
|
||||
else if (const IPv6* ip = packet.find_pdu<IPv6>()) {
|
||||
return StreamIdentifier(serialize(ip->src_addr()), source_port,
|
||||
serialize(ip->dst_addr()), dest_port);
|
||||
}
|
||||
else {
|
||||
throw invalid_packet();
|
||||
}
|
||||
}
|
||||
|
||||
StreamIdentifier StreamIdentifier::make_identifier(const Stream& stream) {
|
||||
if (stream.is_v6()) {
|
||||
return StreamIdentifier(serialize(stream.client_addr_v6()), stream.client_port(),
|
||||
serialize(stream.server_addr_v6()), stream.server_port());
|
||||
} else {
|
||||
return StreamIdentifier(serialize(stream.client_addr_v4()), stream.client_port(),
|
||||
serialize(stream.server_addr_v4()), stream.server_port());
|
||||
}
|
||||
}
|
||||
|
||||
StreamIdentifier::address_type StreamIdentifier::serialize(IPv4Address address) {
|
||||
address_type addr;
|
||||
OutputMemoryStream output(addr.data(), addr.size());
|
||||
addr.fill(0);
|
||||
output.write(address);
|
||||
return addr;
|
||||
}
|
||||
|
||||
StreamIdentifier::address_type StreamIdentifier::serialize(const IPv6Address& address) {
|
||||
address_type addr;
|
||||
OutputMemoryStream output(addr.data(), addr.size());
|
||||
addr.fill(0);
|
||||
output.write(address);
|
||||
return addr;
|
||||
}
|
||||
|
||||
} // TCPIP
|
||||
} // Tins
|
||||
|
||||
#endif // TINS_HAVE_TCPIP
|
||||
@@ -156,7 +156,7 @@ void TCPStream::safe_insert(fragments_type& frags, uint32_t seq, RawPDU* raw) {
|
||||
}
|
||||
|
||||
bool TCPStream::generic_process(uint32_t& my_seq,
|
||||
uint32_t& other_seq,
|
||||
uint32_t& /*other_seq*/,
|
||||
payload_type& pload,
|
||||
fragments_type& frags,
|
||||
TCP* tcp) {
|
||||
|
||||
84
src/timestamp.cpp
Normal file
84
src/timestamp.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include "timestamp.h"
|
||||
|
||||
namespace Tins {
|
||||
|
||||
const int MICROSECONDS_IN_SECOND = 1000000;
|
||||
|
||||
Timestamp Timestamp::current_time() {
|
||||
#ifdef _WIN32
|
||||
FILETIME file_time;
|
||||
GetSystemTimeAsFileTime(&file_time);
|
||||
uint64_t timestamp = file_time.dwHighDateTime;
|
||||
timestamp = timestamp << 32;
|
||||
timestamp |= file_time.dwLowDateTime;
|
||||
// Convert to microseconds
|
||||
timestamp /= 10;
|
||||
// Change the epoch to POSIX epoch
|
||||
timestamp -= 11644473600000000ULL;
|
||||
return Timestamp(timestamp);
|
||||
#else
|
||||
timeval tv;
|
||||
gettimeofday(&tv, 0);
|
||||
return tv;
|
||||
#endif
|
||||
}
|
||||
|
||||
Timestamp::Timestamp()
|
||||
: timestamp_(0) {
|
||||
|
||||
}
|
||||
|
||||
Timestamp::Timestamp(const timeval& time_val) {
|
||||
timestamp_ = static_cast<uint64_t>(time_val.tv_sec) * MICROSECONDS_IN_SECOND
|
||||
+ time_val.tv_usec;
|
||||
}
|
||||
|
||||
Timestamp::Timestamp(uint64_t value)
|
||||
: timestamp_(value) {
|
||||
|
||||
}
|
||||
|
||||
Timestamp::seconds_type Timestamp::seconds() const {
|
||||
return static_cast<seconds_type>(timestamp_ / MICROSECONDS_IN_SECOND);
|
||||
}
|
||||
|
||||
Timestamp::microseconds_type Timestamp::microseconds() const {
|
||||
return timestamp_ % MICROSECONDS_IN_SECOND;
|
||||
}
|
||||
|
||||
} // Tins
|
||||
@@ -43,7 +43,7 @@ using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
PDU::metadata UDP::extract_metadata(const uint8_t *buffer, uint32_t total_sz) {
|
||||
PDU::metadata UDP::extract_metadata(const uint8_t* /*buffer*/, uint32_t total_sz) {
|
||||
if (TINS_UNLIKELY(total_sz < sizeof(udp_header))) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
|
||||
221
src/utils.cpp
221
src/utils.cpp
@@ -54,8 +54,8 @@
|
||||
#endif
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <iphlpapi.h>
|
||||
#undef interface
|
||||
#endif
|
||||
#include "utils.h"
|
||||
@@ -110,7 +110,7 @@ addrinfo* resolve_domain(const string& to_resolve, int family) {
|
||||
}
|
||||
|
||||
#if defined(BSD) || defined(__FreeBSD_kernel__)
|
||||
vector<char> query_route_table() {
|
||||
vector<char> query_route_table(int family) {
|
||||
int mib[6];
|
||||
vector<char> buf;
|
||||
size_t len;
|
||||
@@ -118,7 +118,7 @@ vector<char> query_route_table() {
|
||||
mib[0] = CTL_NET;
|
||||
mib[1] = AF_ROUTE;
|
||||
mib[2] = 0;
|
||||
mib[3] = AF_INET;
|
||||
mib[3] = family;
|
||||
mib[4] = NET_RT_DUMP;
|
||||
mib[5] = 0;
|
||||
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
|
||||
@@ -133,20 +133,19 @@ vector<char> query_route_table() {
|
||||
return buf;
|
||||
}
|
||||
|
||||
template<typename ForwardIterator>
|
||||
void parse_header(struct rt_msghdr* rtm, ForwardIterator iter) {
|
||||
void parse_header(struct rt_msghdr* rtm, vector<sockaddr*>& addrs) {
|
||||
char* ptr = (char *)(rtm + 1);
|
||||
sockaddr* sa = 0;
|
||||
|
||||
for (int i = 0; i < RTAX_MAX; i++) {
|
||||
if (rtm->rtm_addrs & (1 << i)) {
|
||||
// Iterate from RTA_DST (0) to RTA_NETMASK (2)
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
sockaddr* sa = 0;
|
||||
if ((rtm->rtm_addrs & (1 << i)) != 0) {
|
||||
sa = (struct sockaddr *)ptr;
|
||||
ptr += sa->sa_len;
|
||||
if (sa->sa_family == 0) {
|
||||
sa = 0;
|
||||
}
|
||||
}
|
||||
*iter++ = sa;
|
||||
addrs[i] = sa;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -173,16 +172,29 @@ IPv6Address resolve_domain6(const string& to_resolve) {
|
||||
HWAddress<6> resolve_hwaddr(const NetworkInterface& iface,
|
||||
IPv4Address ip,
|
||||
PacketSender& sender) {
|
||||
IPv4Address my_ip;
|
||||
NetworkInterface::Info info(iface.addresses());
|
||||
EthernetII packet = ARP::make_arp_request(ip, info.ip_addr, info.hw_addr);
|
||||
Internals::smart_ptr<PDU>::type response(sender.send_recv(packet, iface));
|
||||
if (response.get()) {
|
||||
const ARP* arp_resp = response->find_pdu<ARP>();
|
||||
if (arp_resp) {
|
||||
return arp_resp->sender_hw_addr();
|
||||
#ifdef _WIN32
|
||||
// On Windows, use SendARP
|
||||
IPAddr source;
|
||||
IPAddr dest;
|
||||
ULONG hw_address[2];
|
||||
ULONG address_length = 6;
|
||||
source = static_cast<uint32_t>(info.ip_addr);
|
||||
dest = static_cast<uint32_t>(ip);
|
||||
if (SendARP(dest, source, &hw_address, &address_length) == NO_ERROR && address_length == 6) {
|
||||
return HWAddress<6>((const uint8_t*)hw_address);
|
||||
}
|
||||
}
|
||||
#else
|
||||
// On other platforms, just do the ARP resolution ourselves
|
||||
EthernetII packet = ARP::make_arp_request(ip, info.ip_addr, info.hw_addr);
|
||||
Internals::smart_ptr<PDU>::type response(sender.send_recv(packet, iface));
|
||||
if (response.get()) {
|
||||
const ARP* arp_resp = response->find_pdu<ARP>();
|
||||
if (arp_resp) {
|
||||
return arp_resp->sender_hw_addr();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
throw runtime_error("Could not resolve hardware address");
|
||||
}
|
||||
|
||||
@@ -191,35 +203,111 @@ HWAddress<6> resolve_hwaddr(IPv4Address ip, PacketSender& sender) {
|
||||
}
|
||||
|
||||
#if defined(BSD) || defined(__FreeBSD_kernel__)
|
||||
|
||||
vector<RouteEntry> route_entries() {
|
||||
vector<RouteEntry> output;
|
||||
vector<char> buffer = query_route_table();
|
||||
vector<char> buffer = query_route_table(AF_INET);
|
||||
char* next = &buffer[0], *end = &buffer[buffer.size()];
|
||||
rt_msghdr* rtm;
|
||||
vector<sockaddr*> sa(RTAX_MAX);
|
||||
vector<sockaddr*> sa(32);
|
||||
char iface_name[IF_NAMESIZE];
|
||||
while (next < end) {
|
||||
rtm = (rt_msghdr*)next;
|
||||
parse_header(rtm, sa.begin());
|
||||
if (sa[RTAX_DST] && sa[RTAX_GATEWAY] && if_indextoname(rtm->rtm_index, iface_name)) {
|
||||
RouteEntry entry;
|
||||
entry.destination = IPv4Address(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr.s_addr);
|
||||
entry.gateway = IPv4Address(((struct sockaddr_in *)sa[RTAX_GATEWAY])->sin_addr.s_addr);
|
||||
if (sa[RTAX_GENMASK]) {
|
||||
entry.mask = IPv4Address(((struct sockaddr_in *)sa[RTAX_GENMASK])->sin_addr.s_addr);
|
||||
// Filter:
|
||||
// * RTF_STATIC (only manually added routes)
|
||||
if ((rtm->rtm_flags & (RTF_STATIC)) != 0) {
|
||||
parse_header(rtm, sa);
|
||||
if (sa[RTAX_DST] && sa[RTAX_GATEWAY] && if_indextoname(rtm->rtm_index, iface_name)) {
|
||||
RouteEntry entry;
|
||||
entry.destination = IPv4Address(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr.s_addr);
|
||||
entry.gateway = IPv4Address(((struct sockaddr_in *)sa[RTAX_GATEWAY])->sin_addr.s_addr);
|
||||
if (sa[RTAX_NETMASK]) {
|
||||
entry.mask = IPv4Address(((struct sockaddr_in *)sa[RTAX_NETMASK])->sin_addr.s_addr);
|
||||
}
|
||||
entry.interface = iface_name;
|
||||
entry.metric = 0;
|
||||
output.push_back(entry);
|
||||
}
|
||||
else {
|
||||
entry.mask = IPv4Address(uint32_t());
|
||||
}
|
||||
entry.interface = iface_name;
|
||||
entry.metric = 0;
|
||||
output.push_back(entry);
|
||||
}
|
||||
next += rtm->rtm_msglen;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
vector<Route6Entry> route6_entries() {
|
||||
vector<Route6Entry> output;
|
||||
vector<char> buffer = query_route_table(AF_INET6);
|
||||
char* next = &buffer[0], *end = &buffer[buffer.size()];
|
||||
rt_msghdr* rtm;
|
||||
vector<sockaddr*> sa(9);
|
||||
char iface_name[IF_NAMESIZE];
|
||||
while (next < end) {
|
||||
rtm = (rt_msghdr*)next;
|
||||
// Filter protocol-cloned entries
|
||||
bool process_entry = true;
|
||||
// These were removed in recent versions of FreeBSD
|
||||
#if defined(RTF_WASCLONED) && defined(RTF_PRCLONING)
|
||||
process_entry = (rtm->rtm_flags & RTF_WASCLONED) == 0 ||
|
||||
(rtm->rtm_flags & RTF_PRCLONING) == 0;
|
||||
#endif
|
||||
if (process_entry) {
|
||||
parse_header(rtm, sa);
|
||||
if (sa[RTAX_DST] && sa[RTAX_GATEWAY] && if_indextoname(rtm->rtm_index, iface_name)) {
|
||||
Route6Entry entry;
|
||||
entry.destination = IPv6Address(((struct sockaddr_in6 *)sa[RTAX_DST])->sin6_addr.s6_addr);
|
||||
entry.gateway = IPv6Address(((struct sockaddr_in6 *)sa[RTAX_GATEWAY])->sin6_addr.s6_addr);
|
||||
int prefix_length = 0;
|
||||
if (sa[RTAX_NETMASK]) {
|
||||
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa[RTAX_NETMASK];
|
||||
for (size_t i = 0; i < 16; ++i) {
|
||||
uint8_t this_byte = sin->sin6_addr.s6_addr[i];
|
||||
// Stop when we find a zero byte
|
||||
if (this_byte == 0) {
|
||||
break;
|
||||
}
|
||||
switch (this_byte) {
|
||||
case 0xff:
|
||||
prefix_length += 8;
|
||||
break;
|
||||
case 0xfe:
|
||||
prefix_length += 7;
|
||||
break;
|
||||
case 0xfc:
|
||||
prefix_length += 6;
|
||||
break;
|
||||
case 0xf8:
|
||||
prefix_length += 5;
|
||||
break;
|
||||
case 0xf0:
|
||||
prefix_length += 4;
|
||||
break;
|
||||
case 0xe0:
|
||||
prefix_length += 3;
|
||||
break;
|
||||
case 0xc0:
|
||||
prefix_length += 2;
|
||||
break;
|
||||
case 0x80:
|
||||
prefix_length += 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
entry.mask = IPv6Address::from_prefix_length(prefix_length);
|
||||
entry.interface = iface_name;
|
||||
entry.metric = 0;
|
||||
output.push_back(entry);
|
||||
}
|
||||
}
|
||||
next += rtm->rtm_msglen;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
vector<RouteEntry> route_entries() {
|
||||
vector<RouteEntry> output;
|
||||
MIB_IPFORWARDTABLE* table;
|
||||
@@ -244,7 +332,34 @@ vector<RouteEntry> route_entries() {
|
||||
}
|
||||
return output;
|
||||
}
|
||||
#else
|
||||
|
||||
vector<Route6Entry> route6_entries() {
|
||||
vector<Route6Entry> output;
|
||||
MIB_IPFORWARD_TABLE2* table;
|
||||
GetIpForwardTable2(AF_INET6, &table);
|
||||
for (ULONG i = 0; i < table->NumEntries; i++) {
|
||||
MIB_IPFORWARD_ROW2* row = &table->Table[i];
|
||||
if (true) {
|
||||
try {
|
||||
Route6Entry entry;
|
||||
entry.interface = NetworkInterface::from_index(row->InterfaceIndex).name();
|
||||
entry.destination = IPv6Address(row->DestinationPrefix.Prefix.Ipv6.sin6_addr.s6_addr);
|
||||
entry.mask = IPv6Address::from_prefix_length(row->DestinationPrefix.PrefixLength);
|
||||
entry.gateway = IPv6Address(row->NextHop.Ipv6.sin6_addr.s6_addr);
|
||||
entry.metric = row->Metric;
|
||||
output.push_back(entry);
|
||||
}
|
||||
catch (invalid_interface&) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
FreeMibTable(table);
|
||||
return output;
|
||||
}
|
||||
|
||||
#else // GNU/LINUX
|
||||
|
||||
vector<RouteEntry> route_entries() {
|
||||
using namespace Tins::Internals;
|
||||
vector<RouteEntry> output;
|
||||
@@ -271,6 +386,44 @@ vector<RouteEntry> route_entries() {
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
vector<Route6Entry> route6_entries() {
|
||||
using namespace Tins::Internals;
|
||||
vector<Route6Entry> output;
|
||||
ifstream input("/proc/net/ipv6_route");
|
||||
string destination, mask_length, metric, next_hop, dummy, flags;
|
||||
Route6Entry entry;
|
||||
while (input >> destination >> mask_length) {
|
||||
string temporary;
|
||||
uint32_t temporary_int;
|
||||
for (unsigned i(0); i < 2; ++i) {
|
||||
input >> dummy;
|
||||
}
|
||||
input >> next_hop;
|
||||
input >> metric;
|
||||
for (unsigned i(0); i < 2; ++i) {
|
||||
input >> dummy;
|
||||
}
|
||||
input >> flags >> entry.interface;
|
||||
from_hex(destination, temporary);
|
||||
entry.destination = IPv6Address((const uint8_t*)&temporary[0]);
|
||||
from_hex(mask_length, temporary_int);
|
||||
entry.mask = IPv6Address::from_prefix_length(temporary_int);
|
||||
from_hex(next_hop, temporary);
|
||||
entry.gateway = IPv6Address((const uint8_t*)&temporary[0]);
|
||||
from_hex(metric, temporary_int);
|
||||
entry.metric = temporary_int;
|
||||
// Process flags
|
||||
from_hex(flags, temporary_int);
|
||||
// Skip:
|
||||
// * 0x01000000 -> cache entries
|
||||
if ((temporary_int & 0x01000000) == 0) {
|
||||
output.push_back(entry);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool gateway_from_ip(IPv4Address ip, IPv4Address& gw_addr) {
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tests)
|
||||
INCLUDE_DIRECTORIES(${gtest_INCLUDE_DIRS})
|
||||
ADD_SUBDIRECTORY(src)
|
||||
ADD_SUBDIRECTORY(src)
|
||||
|
||||
IF (ENABLE_ACTIVE_TESTS AND LIBTINS_ENABLE_PCAP)
|
||||
ADD_SUBDIRECTORY(active_tests)
|
||||
ENDIF()
|
||||
1
tests/active_tests/CMakeLists.txt
Normal file
1
tests/active_tests/CMakeLists.txt
Normal file
@@ -0,0 +1 @@
|
||||
add_subdirectory(src)
|
||||
83
tests/active_tests/include/active_test.h
Normal file
83
tests/active_tests/include/active_test.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_ACTIVE_TEST_H
|
||||
#define TINS_ACTIVE_TEST_H
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include "tins/packet_sender.h"
|
||||
#include "configuration.h"
|
||||
#include "packet_capturer.h"
|
||||
|
||||
namespace Tins {
|
||||
|
||||
class PDU;
|
||||
|
||||
} // Tins
|
||||
|
||||
class TestFailed : public std::runtime_error {
|
||||
public:
|
||||
TestFailed(const std::string& message) : std::runtime_error(message) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
class ActiveTest {
|
||||
public:
|
||||
using PacketSenderPtr = std::shared_ptr<Tins::PacketSender>;
|
||||
using ConfigurationPtr = std::shared_ptr<Configuration>;
|
||||
|
||||
ActiveTest(const PacketSenderPtr& packet_sender,
|
||||
const ConfigurationPtr& configuration);
|
||||
|
||||
virtual ~ActiveTest() = default;
|
||||
|
||||
void execute();
|
||||
std::string log_prefix() const;
|
||||
bool matches_packet(const Tins::PDU& pdu) const;
|
||||
bool is_enabled() const;
|
||||
void validate(PacketCapturer::PacketStorage& packets);
|
||||
virtual std::string name() const = 0;
|
||||
protected:
|
||||
Tins::PacketSender& packet_sender();
|
||||
const Tins::PacketSender& packet_sender() const;
|
||||
Configuration& configuration();
|
||||
const Configuration& configuration() const;
|
||||
virtual bool test_matches_packet(const Tins::PDU& pdu) const = 0;
|
||||
virtual void execute_test() = 0;
|
||||
virtual void validate_packet(const Tins::PDU& pdu) = 0;
|
||||
void disable_on_platform(Configuration::Platform platform);
|
||||
private:
|
||||
PacketSenderPtr packet_sender_;
|
||||
ConfigurationPtr configuration_;
|
||||
unsigned disabled_platforms_ = 0;
|
||||
};
|
||||
|
||||
#endif // TINS_ACTIVE_TEST_H
|
||||
68
tests/active_tests/include/active_test_runner.h
Normal file
68
tests/active_tests/include/active_test_runner.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_ACTIVE_TEST_RUNNER_H
|
||||
#define TINS_ACTIVE_TEST_RUNNER_H
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "active_test.h"
|
||||
#include "configuration.h"
|
||||
#include "packet_capturer.h"
|
||||
|
||||
class ActiveTestRunner {
|
||||
public:
|
||||
ActiveTestRunner(const Configuration& configuration);
|
||||
|
||||
template <typename T>
|
||||
void add_test();
|
||||
|
||||
bool validate_tests();
|
||||
void run();
|
||||
private:
|
||||
using ConfigurationPtr = ActiveTest::ConfigurationPtr;
|
||||
using ActiveTestPtr = std::unique_ptr<ActiveTest>;
|
||||
|
||||
template <typename... EmptyTail>
|
||||
void add_tests() { }
|
||||
|
||||
void do_run();
|
||||
|
||||
ConfigurationPtr configuration_;
|
||||
ActiveTest::PacketSenderPtr packet_sender_;
|
||||
PacketCapturer capturer_;
|
||||
std::vector<ActiveTestPtr> tests_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void ActiveTestRunner::add_test() {
|
||||
tests_.emplace_back(new T(packet_sender_, configuration_));
|
||||
}
|
||||
|
||||
#endif // TINS_ACTIVE_TEST_RUNNER_H
|
||||
62
tests/active_tests/include/configuration.h
Normal file
62
tests/active_tests/include/configuration.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_ACTIVE_TEST_CONFIGURATION_H
|
||||
#define TINS_ACTIVE_TEST_CONFIGURATION_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include "tins/network_interface.h"
|
||||
|
||||
class Configuration {
|
||||
public:
|
||||
enum Platform {
|
||||
WINDOWS = 1,
|
||||
BSD_OS = 2,
|
||||
LINUX = 4
|
||||
};
|
||||
|
||||
Configuration();
|
||||
|
||||
void interface(const Tins::NetworkInterface& interface);
|
||||
void source_port(uint16_t value);
|
||||
void destination_port(uint16_t value);
|
||||
|
||||
const Tins::NetworkInterface& interface() const;
|
||||
uint16_t source_port() const;
|
||||
uint16_t destination_port() const;
|
||||
Platform current_platform() const;
|
||||
private:
|
||||
Tins::NetworkInterface interface_;
|
||||
uint16_t source_port_ = 0;
|
||||
uint16_t destination_port_ = 0;
|
||||
Platform current_platform_;
|
||||
};
|
||||
|
||||
#endif // TINS_ACTIVE_TEST_CONFIGURATION_H
|
||||
60
tests/active_tests/include/ipv4_tests.h
Normal file
60
tests/active_tests/include/ipv4_tests.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_IPV4_TESTS_H
|
||||
#define TINS_IPV4_TESTS_H
|
||||
|
||||
#include <string>
|
||||
#include "active_test.h"
|
||||
|
||||
class IPv4SourceAddressTest : public ActiveTest {
|
||||
public:
|
||||
IPv4SourceAddressTest(const PacketSenderPtr& packet_sender,
|
||||
const ConfigurationPtr& configuration);
|
||||
|
||||
std::string name() const;
|
||||
private:
|
||||
void execute_test();
|
||||
void validate_packet(const Tins::PDU& pdu);
|
||||
bool test_matches_packet(const Tins::PDU& pdu) const;
|
||||
};
|
||||
|
||||
class IPv4FragmentationTest : public ActiveTest {
|
||||
public:
|
||||
IPv4FragmentationTest(const PacketSenderPtr& packet_sender,
|
||||
const ConfigurationPtr& configuration);
|
||||
|
||||
std::string name() const;
|
||||
private:
|
||||
void execute_test();
|
||||
void validate_packet(const Tins::PDU& pdu);
|
||||
bool test_matches_packet(const Tins::PDU& pdu) const;
|
||||
};
|
||||
|
||||
#endif // TINS_IPV4_TESTS_H
|
||||
62
tests/active_tests/include/packet_capturer.h
Normal file
62
tests/active_tests/include/packet_capturer.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_PACKET_CAPTURER_H
|
||||
#define TINS_PACKET_CAPTURER_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include "tins/sniffer.h"
|
||||
#include "configuration.h"
|
||||
|
||||
class PacketCapturer {
|
||||
public:
|
||||
using PacketPtr = std::unique_ptr<Tins::PDU>;
|
||||
using PacketStorage = std::vector<PacketPtr>;
|
||||
|
||||
PacketCapturer(const Configuration& configuration);
|
||||
|
||||
void start_capture();
|
||||
void stop_capture();
|
||||
|
||||
PacketStorage captured_packets();
|
||||
private:
|
||||
bool callback(const Tins::PDU& pdu);
|
||||
std::string make_filter(const Configuration& configuration) const;
|
||||
|
||||
std::unique_ptr<Tins::Sniffer> sniffer_;
|
||||
std::thread sniffer_thread_;
|
||||
PacketStorage storage_;
|
||||
std::atomic<bool> running_;
|
||||
};
|
||||
|
||||
#endif // TINS_PACKET_CAPTURER_H
|
||||
76
tests/active_tests/include/tcp_tests.h
Normal file
76
tests/active_tests/include/tcp_tests.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_ACTIVE_TCP_TESTS_H
|
||||
#define TINS_ACTIVE_TCP_TESTS_H
|
||||
|
||||
#include <cstdint>
|
||||
#include "active_test.h"
|
||||
#include "tins/ip_address.h"
|
||||
|
||||
class TCPSynTest : public ActiveTest {
|
||||
public:
|
||||
TCPSynTest(const PacketSenderPtr& packet_sender,
|
||||
const ConfigurationPtr& configuration,
|
||||
uint16_t target_port);
|
||||
private:
|
||||
void execute_test();
|
||||
void validate_packet(const Tins::PDU& pdu);
|
||||
bool test_matches_packet(const Tins::PDU& pdu) const;
|
||||
virtual void send_packet(Tins::PDU& pdu) = 0;
|
||||
|
||||
Tins::IPv4Address target_address_;
|
||||
uint32_t sequence_number_;
|
||||
uint16_t target_port_;
|
||||
};
|
||||
|
||||
// Sends a SYN using IP as the lowest layer
|
||||
class Layer3TCPSynTest : public TCPSynTest {
|
||||
public:
|
||||
Layer3TCPSynTest(const PacketSenderPtr& packet_sender,
|
||||
const ConfigurationPtr& configuration);
|
||||
|
||||
std::string name() const;
|
||||
private:
|
||||
void send_packet(Tins::PDU& pdu);
|
||||
};
|
||||
|
||||
// Sends a SYN using Ethernet as the lowest layer
|
||||
class Layer2TCPSynTest : public TCPSynTest {
|
||||
public:
|
||||
Layer2TCPSynTest(const PacketSenderPtr& packet_sender,
|
||||
const ConfigurationPtr& configuration);
|
||||
|
||||
std::string name() const;
|
||||
private:
|
||||
void send_packet(Tins::PDU& pdu);
|
||||
};
|
||||
|
||||
|
||||
#endif // TINS_ACTIVE_TCP_TESTS_H
|
||||
38
tests/active_tests/include/test_utils.h
Normal file
38
tests/active_tests/include/test_utils.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Matias Fontanini
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TINS_TEST_UTILS_H
|
||||
#define TINS_TEST_UTILS_H
|
||||
|
||||
#include <string>
|
||||
#include "tins/ip_address.h"
|
||||
|
||||
Tins::IPv4Address get_gateway_v4_address(const std::string& interface_name);
|
||||
|
||||
#endif // TINS_TEST_UTILS_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user