1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 18:55:58 +01:00

77 Commits
v3.4 ... v3.5

Author SHA1 Message Date
Matias Fontanini
37c92fcf5c Bump minor version 2017-04-01 09:21:33 -07:00
Matias Fontanini
18281e614d Add release notes for v3.5 2017-04-01 09:12:28 -07:00
Matias Fontanini
7f8644cb39 Merge branch 'develop' 2017-03-23 19:31:10 -07:00
Matias Fontanini
799ba2b4b6 Allow disabling pcap packet capture 2017-03-21 19:04:33 -07:00
Matias Fontanini
ad0a1ca97d Use QoS TID when building AAD for CCMP decryption
Fixes #190
2017-03-11 10:43:12 -08:00
Matias Fontanini
7607610cf9 Merge branch 'develop' 2017-01-31 21:37:41 -08:00
Kyle Fazzari
a71a3d29ff Fix -Wextra compiler warnings. (#184)
* Fix -Wextra compiler warnings.

Fix #183.

Signed-off-by: Kyle Fazzari <github@status.e4ward.com>

* Comment out unused parameters.

This is done everywhere possible instead of using Internals::unused().
Note that this involved moving some implementations into the
corresponding .cpp file.

Signed-off-by: Kyle Fazzari <github@status.e4ward.com>

* Fix warnings in tests as well.

Signed-off-by: Kyle Fazzari <github@status.e4ward.com>

* Leave IPv4Reassembler alone, it's growing.

Signed-off-by: Kyle Fazzari <github@status.e4ward.com>
2017-01-25 13:26:11 -08:00
Ed Catmur
9051197603 Use actual payload length to construct inner PDU. (#179)
Fixes #178
2017-01-16 09:36:33 -08:00
Matias Fontanini
94e5ac2109 Check expected size properly on DNS::extract_metadata
Thanks @shshzi for finding this one
2017-01-15 09:04:19 -08:00
Matias Fontanini
84cb686928 Use markdown for CHANGES file 2016-12-11 10:11:05 -08:00
Matias Fontanini
da07ad3b13 Remove AUTHORS file
This file is very outdated. Check contributions on github to
see the actual contributors.
2016-12-11 10:02:48 -08:00
Matias Fontanini
d5cba00ce0 Use immediate mode on DNS spoof example 2016-11-04 08:00:13 -07:00
Matias Fontanini
ba9d0b34c6 Fix build issue on FreeBSD 11
This fixes #174 temporarily, so at least it won't fail to build
2016-11-04 07:55:58 -07:00
Matias Fontanini
f2850cc0b9 Execute original ooo callback first on recovery mode 2016-11-01 07:35:56 -07:00
Matias Fontanini
c69ea0c1fb Keep original out of order callback on recovery mode 2016-10-30 13:08:17 -07:00
Matias Fontanini
a63387f85e Add Stream recovery mode 2016-10-30 11:38:50 -07:00
Matias Fontanini
df7e7b391d Add flag to Stream to know whether it was attached 2016-10-30 10:31:16 -07:00
Matias Fontanini
5d6431d2d9 Allow enabling attachment to partial streams 2016-10-30 10:21:58 -07:00
Matias Fontanini
a61a361eb1 Add check for noexcept when checking C++11 features 2016-10-23 11:34:10 -07:00
Matias Fontanini
9dbad2a26f Cleanup tests names and CMake script 2016-10-23 10:21:58 -07:00
Patrick Michel
aaba3dd46a Feature - Skipping ahead in TCP flows. (#163)
* Skipping forward in TCP streams, from an out-of-order callback.

- Added the ability to skip forward in a flow to a sequence number, with the intention of doing so in an out of order callback.
- Re-ordered Flow packet processing, to allow skipTo in out of order callback on stream start (flow sequence number is 0).
- Fixed missing seq_compare in flow code.

* Renamed skipTo to advance_sequence.
2016-10-23 09:47:56 -07:00
Matias Fontanini
2e013847d9 Use proper IPv6 flag when opening l3 socket
Fixes #166
2016-10-21 07:34:20 -07:00
Matias Fontanini
22e569d430 Fix buffer length check issue on Dot11QosData
Fixes #167
2016-10-18 07:24:11 -07:00
Matias Fontanini
2847039ffe Set last next protocol to 0 if no inner_pdu on IPv6 2016-09-29 07:37:46 -07:00
Matias Fontanini
54ce11629c Set payload type to 0 if no inner_pdu on Dot1Q 2016-09-29 07:37:46 -07:00
Matias Fontanini
8dcfd6aae0 Set protocol to 0 if no inner_pdu on IP 2016-09-29 07:37:46 -07:00
Patrick Michel
838a4a5cb9 Refactored code related to stream/flow initialization. (#170)
- Removed client_flow().process_packet() in Stream constructor, in favor of processing on SYN in stream follower.
- Moved +1 to seq on SYN/ACK.
2016-09-28 07:30:16 -07:00
Matias Fontanini
e82b72e931 Use relative include for config.h 2016-09-27 22:06:09 -07:00
Matias Fontanini
fdc6ccdf5c Only enable TCP stream's custom data if boost.any is found 2016-09-27 21:46:38 -07:00
Patrick Michel
52b389afe8 Allow setting custom user data to each TCP stream 2016-09-27 21:33:10 -07:00
Matias Fontanini
552006c876 Set EthernetII payload type to UNKNOWN if no inner_pdu 2016-09-27 07:47:32 -07:00
Matias Fontanini
f0b32edaa9 Use boost include paths/libs on appveyor build 2016-09-26 20:29:14 -07:00
Matias Fontanini
5a901ca155 Merge branch 'develop' 2016-09-26 19:52:12 -07:00
Jim Hague
9593cf4cf6 Correct typo preventing user buffer management for server TCP streams. (#160) 2016-08-31 09:13:43 -07:00
Huemac
64725e2ed9 Fix Cppcheck 1.75 warnings (#159)
- The scope of the variable 'last_index' & 'index' could be reduced.
- Prefer prefix ++/-- operators for non-primitive types.
2016-08-14 12:29:53 -07:00
Vikas Kumar
9260f9374a Variable Boost_INCLUDE_DIRS incorrectly used in cmake file (#158)
`s/Boost_INCLUDE_DIRS/${Boost_INCLUDE_DIRS}/ inside `INCLUDE_DIRECTORIES`
2016-08-13 13:41:25 -07:00
Sergey Kovalevich
2ccf50db3e Allow including libtins using add_subdirectory via CMake 2016-07-20 09:12:48 -07:00
ps790
e843ee7117 Added cmake compiling support for MinGW (#155)
* Added cmake compiling support for MinGW

These modificaitons allow to build Libtins on Windows with cmake directly by running 
cmake ../ -DPCAP_ROOT_DIR="PATH_TO_WpdPack" -DLIBTINS_ENABLE_WPA2=0 -DLIBTINS_BUILD_SHARED=0 -G "MinGW Makefiles"

* Update CMakeLists.txt
2016-06-24 18:00:09 -07:00
Matias Fontanini
a192e814bf Allow configuring pcap timestamp precision 2016-06-17 09:20:43 -07:00
Matias Fontanini
ccda631708 Fix timestamp integer overflow issue 2016-06-16 17:12:04 -07:00
Jacob Parker
1552e33c67 Add helper function to create StreamIdentifier from const Stream& (#152) 2016-06-07 13:19:55 -07:00
Wouter Overmeire
8afc784956 Fix typo in arp.h comment (#151) 2016-06-06 10:36:36 -07:00
Rolf Winter
5b00916f83 fixed: superfluous includes, docu (#148) 2016-05-26 09:11:48 -07:00
Matias Fontanini
6b7bc76603 Forward NetworkInterface argument when calling PacketSender::send_l2 2016-05-08 20:46:11 -07:00
Matias Fontanini
732c665af5 Fix compilation warning on VC 2016-05-08 10:34:49 -07:00
Matias Fontanini
8cf367d68c Make Timestamp::current_time work on Windows 2016-05-08 10:26:57 -07:00
Matias Fontanini
d070978a54 Add TINS_API to DataTracker and AckTracker classes 2016-05-08 09:38:52 -07:00
Matias Fontanini
7f30efab38 Fix typo in macros.h
[ci skip]
2016-05-05 12:40:11 -07:00
Matias Fontanini
d7fed87ebb Use recvfrom on BSD/OSX when capturing layer 3 packets
Fixes #147
2016-05-03 19:35:24 -07:00
Matias Fontanini
269ac164ed Use exception strings on std::runtime_error's constructor
Fixes #146
2016-05-03 14:50:28 -07:00
Matias Fontanini
55edf31aa6 Move TCP data tracking into a separate class 2016-05-03 14:50:28 -07:00
Patrick Michel
364782b8af Don't set Dot1Q's payload type if next proto type is UNKNOWN 2016-04-12 07:56:31 -07:00
Matias Fontanini
d3c576f6de Properly handle out of order SACKs on AckTracker 2016-04-03 09:39:11 -07:00
Matias Fontanini
8d52d73968 Allow disabling TCPIP classes 2016-04-02 09:35:42 -07:00
Matias Fontanini
48022d3a3f Rename and undef symbols that conflict with macro names on DNS
The undefs are a temporary fix until we get rid of the old,
conflicting, names

Fixes #141
Fixes #58
2016-04-02 09:16:28 -07:00
Matias Fontanini
ec1634d6d8 Move stream_id into a new file and rename it to StreamIdentifier 2016-03-28 21:38:43 -07:00
Matias Fontanini
688bb7094e Rename BSD enum value so it doesn't conflict with macro 2016-03-28 20:31:48 -07:00
Matias Fontanini
928e66eb27 Fix issue considering an interface down when it's up 2016-03-27 08:21:05 -07:00
Matias Fontanini
d80c27de29 Add active test for TCP over ethernet 2016-03-26 16:11:03 -07:00
Matias Fontanini
6aac22fa74 Make Utils::resolve_hwaddress work on Windows 2016-03-22 20:34:06 -07:00
Matias Fontanini
7bc1ab41f7 Add TCP and Utils::resolve_hwaddress active tests
[ci skip]
2016-03-22 19:49:26 -07:00
Matias Fontanini
068e304baa Fix active tests build issues 2016-03-20 19:01:58 -07:00
Matias Fontanini
5dc7b20a43 Add active tests for IPv4 2016-03-20 16:27:43 -07:00
Matias Fontanini
a70ce10bed Add IPv4Address::from_prefix_length 2016-03-19 16:26:00 -07:00
Matias Fontanini
3773443fc8 Allow masking IPv4/6 and HW addresses 2016-03-19 15:44:55 -07:00
Matias Fontanini
1f4be63d08 Properly handle MLDv1 on ICMP 2016-03-17 21:49:06 -07:00
Matias Fontanini
6a69d1ff6c Export proper artifacts for VS 2015 2016-03-17 21:46:56 -07:00
Matias Fontanini
85102b4546 Merge pull request #140 from asjadsyed/develop
don't set key_t to 0 when setting a key, because the two fields are unrelated
2016-03-17 21:07:15 -07:00
Asjad Syed
f188ea4d2a don't set key_t to 0 when setting a key, because the two fields are unrelated 2016-03-17 22:26:16 -04:00
Matias Fontanini
a75dd9e3f9 Add Visual Studio 2015 to appveyor build 2016-03-16 22:51:50 -07:00
Matias Fontanini
dda673cad4 Merge branch 'develop' 2016-03-16 21:01:27 -07:00
Matias Fontanini
8b125d31f2 Add TINS_API to operator<< for IPv4Address 2016-03-16 20:51:37 -07:00
Matias Fontanini
67ee3e8a7d Merge pull request #137 from stubbfel/pullrequest/first_address_from_mask
calc the complete addressrange of a network when call AddressRange::from_mask
2016-03-16 20:51:03 -07:00
stubbfel
d70536f9ab add first_address_from_mask in internals and call them from addressrange::from_mask 2016-03-16 22:28:21 +01:00
Matias Fontanini
97e24131c6 Fix issues pointed out by scan.coverity 2016-03-07 20:29:12 -08:00
Matias Fontanini
42b6c40433 Add Utils::route6_entries on OSX/BSD 2016-03-07 19:40:38 -08:00
Matias Fontanini
4dcef0f15d Add Utils::route6_entries 2016-03-06 19:18:33 -08:00
172 changed files with 3806 additions and 935 deletions

View File

@@ -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>

View File

@@ -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.

View File

@@ -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)

View File

@@ -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)

View File

@@ -0,0 +1,7 @@
int foo() noexcept {
return 0;
}
int main() {
return foo();
}

View File

@@ -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(

View File

@@ -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.*/

View File

@@ -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);

View File

@@ -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;
}
}
}

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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

View File

@@ -56,6 +56,8 @@ struct smart_ptr {
typedef std::auto_ptr<T> type;
#endif
};
template<class T> void unused(const T&) { }
}
}

View File

@@ -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
};

View File

@@ -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:

View File

@@ -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,

View File

@@ -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

View File

@@ -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.

View File

@@ -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_;
};

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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
*

View File

@@ -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);

View File

@@ -35,7 +35,6 @@
#include <stdint.h>
#include "macros.h"
#include "pdu.h"
#include "macros.h"
#include "endianness.h"
namespace Tins {

View File

@@ -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))

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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);
}
}
/**

View File

@@ -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

View File

@@ -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

View File

@@ -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_;
};
}

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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());

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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) {
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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()));

View File

@@ -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

View File

@@ -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_);

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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)));

View File

@@ -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

View File

@@ -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_() {
}

View File

@@ -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) {

View File

@@ -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

View File

@@ -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());
}
}

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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
}
}
}
}

View File

@@ -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]);
}

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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());

View File

@@ -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;
}

View File

@@ -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)) {
}

View File

@@ -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(

View File

@@ -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;

View File

@@ -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
View 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

View File

@@ -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) {

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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
View 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

View File

@@ -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();
}

View File

@@ -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) {

View File

@@ -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()

View File

@@ -0,0 +1 @@
add_subdirectory(src)

View 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

View 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

View 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

View 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

View 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

View 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

View 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