1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 02:35:57 +01:00

48 Commits
v4.3 ... master

Author SHA1 Message Date
Dave Walker
67c81199fb Update CMake minimum required version to 3.10 (#553)
CMake 4 removed compatibility with CMake versions < 3.5, and versions
between 3.5-3.10 are deprecated.

This change updates the minimum required version to 3.10 to ensure
compatibility with modern CMake versions including CMake 4.x.

This issue is affecting NixOS users (see
https://github.com/NixOS/nixpkgs/issues/450198) and will likely impact
other distributions as they upgrade to CMake 4.x.
2025-12-11 20:53:03 -08:00
James R T
fe22186623 Add RTP support (#530)
This commit adds support for the Real-time Transport Protocol (RTP) as
defined in RFC 3550. Some tests have also been added to ensure that the
RTP PDU class functionality is working as expected.

Signed-off-by: James Raphael Tiovalen <jamestiotio@gmail.com>
2024-03-31 07:46:42 -07:00
James R T
bbac2ece52 Replace remaining rfind_pdu calls to find_pdu in src directory (#527)
This commit replaces the remaining `rfind_pdu` calls to `find_pdu` in
the `src` directory. Any existing `rfind_pdu` calls in the `examples`
and `tests` directories are unmodified.

The main motivation is that conditional statements are generally more
performant than exception handling. Since `rfind_pdu` calls `find_pdu`
internally anyway, this eliminates some overhead as well.

Signed-off-by: James Raphael Tiovalen <jamestiotio@gmail.com>
2024-03-17 08:18:02 -07:00
James R T
ba9a2155ca Update VXLANTest destination port number (#528)
Based on RFC 7348, the default IANA-assigned destination UDP port number
for VXLAN is 4789, not the source port number. Update the value in the
VXLANTest class to align with the RFC.

The VXLAN implementation still allows for the destination port number to
be configurable to allow interoperability (as specified by the RFC),
such as with the Linux kernel's default value of 8472.

Signed-off-by: James Raphael Tiovalen <jamestiotio@gmail.com>
2024-03-17 08:16:31 -07:00
Cameron Miller
00619e0500 Modify conditional to have Android API version check (#526)
Co-authored-by: Cameron Miller <cameron.miller@homeaware.com>
2024-02-20 15:12:00 -08:00
Yang Bin
64da67ca56 Update tcp.h (#516)
Fix a spelling error
2023-09-19 07:04:43 -07:00
Matias Fontanini
3943700830 Bump version to 4.6 2023-08-20 09:47:49 -07:00
Matias Fontanini
142b6f62cb Add CHANGES for v4.5 2023-08-20 09:47:12 -07:00
James R T
dfd2701ee4 Add vxlan.h to CMakeLists.txt (#508) 2023-06-08 12:39:15 -07:00
James R T
850bb9b642 Add VXLAN support (#501)
This patch adds a new PDU class to support VXLAN. Several VXLAN-related
tests have also been added.

Signed-off-by: James Raphael Tiovalen <jamestiotio@gmail.com>
2023-05-03 18:21:59 -07:00
Ed Catmur
b7e61f4c76 Qualify calls to std::move (clang 15) (#488)
Co-authored-by: Ed Catmur <edward.catmur@mavensecurities.com>
2023-04-30 10:13:56 -07:00
Ed Catmur
e2a14d8898 Remove use of deprecated std::iterator (#481)
Co-authored-by: Ed Catmur <edward.catmur@mavensecurities.com>
2023-04-30 10:11:57 -07:00
Tobias Specht
ba0c820852 Add FileSniffer constructor with FILE pointer as pcap source (#499) 2023-04-30 09:44:49 -07:00
James R T
df509e7e36 Ignore IPv6 packets with payload after one with no Next Header (#500)
IPv6 data packets with payload or padded bytes received after one with
no Next Header were not being parsed correctly, resulting in NULL PDU.

This commit fixes the IPv6 parser to be compliant with RFC 2460 Section
4.7 by adding a check in the IPv6 constructor to ignore the subsequent
packets if an IPv6 packet contains no Next Header.

Signed-off-by: James Raphael Tiovalen <jamestiotio@gmail.com>
2023-04-20 21:22:01 -07:00
Ed Catmur
fa87e1b6f6 Add missing include (#497)
`<algorithm>` is needed for std::fill (error in clang-16)
2023-01-31 10:02:50 -08:00
Vasiliy Glazov
812be7966d Fix build with GCC13 (#496)
Due to changes in GCC13 need fix include.
2023-01-24 08:29:36 -08:00
Bill Willcox
f89cc9f076 Validate high order two bits of first dns label octet (#494) 2023-01-03 09:10:41 -08:00
Matias Fontanini
638bf9b34b Trigger actions on pull requests (#495) 2023-01-03 09:04:03 -08:00
mbcdev
eb997f5438 fix incorrect IP address range calculation when using /0 prefix (#484) (#486)
According to the C/C++ Standard, for shift operations, the behavior is undefined if the right operand is equal to the width of the promoted left operand.
On a 64-bit Windows machine, this causes IP addresses 0.0.0.0 and 255.255.255.255 to have the same internal representation, leading to various issues when using a /0 prefix.
2022-08-30 08:27:42 -07:00
Scott K Logan
18cbab4fc7 Use CMAKE_INSTALL_LIBDIR in CONF_CMAKE_INSTALL_DIR (#472)
On some platforms (like RedHat ones), CMAKE_INSTALL_LIBDIR is set to
`lib64` instead of `lib`. The CMake files should also be installed to
`lib64`, but because CONF_CMAKE_INSTALL_DIR is set unconditionally to
use `lib`, the proper path can't be configured.

This change makes CONF_CMAKE_INSTALL_DIR use the configured
CMAKE_INSTALL_LIBDIR value, which defaults to `lib`.
2022-05-14 11:09:58 -07:00
Scott K Logan
7cd2b2c396 Fall back to system GTest if available (#473)
Using a submodule to download and build GTest is a great approach for
most circumstances, but some may prefer to use the system-provided GTest
if it is available.

This change adds a fallback to using the system's GTest if the submodule
is absent.
2022-05-14 11:07:39 -07:00
Lattice 0
2601493752 android workaround (#471) 2022-04-24 08:44:52 -07:00
Bill Willcox
7204fbd688 dns: parser reads into garbage on misreported packet size (#468)
Co-authored-by: Bill Willcox <billwcorp@gmail.com>
2022-02-26 14:29:22 -08:00
Bill Willcox
c302e659d7 dns: bad label size interpreted as decompression pointer (#466)
Co-authored-by: Bill Willcox <billwcorp@gmail.com>
2022-02-20 15:18:00 -08:00
Matias Fontanini
54e4e4b0f4 Add github actions for ubuntu (#467) 2022-02-19 17:01:37 -08:00
Matias Fontanini
6a17e59032 Bump version to 4.5 2022-02-17 06:55:48 -08:00
Matias Fontanini
e3aedc56ed Update CHANGES.md for v4.4 2022-02-17 06:55:02 -08:00
Matias Fontanini
3b006c15db Merge pull request #458 from demiquartz/fix-macro-name-conflict
Fix conflict between variable and macro name
2022-01-30 09:04:08 -08:00
Takaaki Sato
177d0b4621 Fix conflict between variable and macro name 2021-10-31 12:03:24 +09:00
Matias Fontanini
24ac038c30 Merge pull request #448 from FlukeCorp/link-local-uses-interface
IPv6 use interface when sending to link-local dest
2021-07-22 19:23:51 -07:00
Prosper Van
a619e4ff98 IPv6 use interface when sending to link-local dest 2021-07-22 11:18:48 -07:00
Matias Fontanini
14bb185d7a Merge pull request #444 from gaya-cohen/decompression-bug-fix
Fix DNS decompression bug and add descriptive exceptions
2021-06-09 08:30:50 -07:00
Gaya Cohen
137b56d5a7 fix exception inheritance and change exception names in DNS code 2021-06-09 15:57:04 +03:00
Gaya Cohen
ed2b3c12d5 Make new exceptions inherit from malformed_packet and change exception names 2021-06-09 11:46:07 +03:00
Gaya Cohen
1650b60234 change counter variable type and add exception description comment 2021-05-24 17:04:11 +03:00
Gaya Cohen
c20c82bcb5 Fix pointer loop bug and add descriptive exceptions 2021-05-24 15:12:23 +03:00
Matias Fontanini
5858132261 Merge pull request #439 from adriancostin6/dns-comment-fix
Fix getter being labeled as setter in dns header file comments
2021-05-14 08:59:54 -07:00
Adrian Costin
16f5795243 Fix getter being labeled as setter in dns header file comments 2021-04-24 01:04:24 +03:00
Matias Fontanini
e90e377b73 Merge pull request #437 from ceerRep/master
Fix wrong address endian
2021-03-28 09:08:30 -07:00
ceerrep
222611b377 Fix wrong address endian
Host endian has been implicitly converted to big endian in "IPv4Address::operator uint32_t()"
2021-03-24 18:41:59 +08:00
Matias Fontanini
b447c664e1 Merge pull request #433 from visuve/master
Close socket when setsockopt fails
2021-03-06 11:34:51 -08:00
visuve
468159e6d2 Close socket when setsockopt fails
- Prevent resource leak
2021-03-04 23:55:29 +02:00
Matias Fontanini
cd40b232e7 Merge pull request #427 from nhutchinson-te/bsd-routing-table
Fix infinite loop when querying BSD routing table
2021-01-04 18:44:06 -08:00
Nick Hutchinson
1166094a2f Fix infinite loop when querying BSD routing table
Fix `query_route_table()` returning a buffer padded with extra '\0'
bytes because it ignored the buffer size returned by `sysctl()`.

This caused `route_entries()` / `route6_entries()` to fall into an
infinite loop, forever trying to parse a 0-length routing entry.
2021-01-04 12:02:03 +00:00
Matias Fontanini
b3d874d6a8 Merge pull request #426 from theDogOfPavlov/master
Added RFC8335 Extended echo types to headers
2020-12-29 08:52:34 -08:00
Martin O'Neal
553b1fb255 Added RFC8335 Extended Echo types 2020-12-29 08:36:30 +00:00
Martin O'Neal
94939dd0fa Added RFC8355 ICMP Extended Echo support
Added RFC8355 ICMP Extended Echo request/reply to Flags (no other changes made)
2020-12-29 08:32:29 +00:00
Matias Fontanini
0774a8dcad Bump version to 4.4 in CMakeLists.txt 2020-09-17 22:20:32 -07:00
39 changed files with 1458 additions and 74 deletions

28
.github/workflows/tests.yaml vendored Normal file
View File

@@ -0,0 +1,28 @@
name: Tests
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
Ubuntu-Tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install libpcap
run: sudo apt-get install -y libpcap-dev
- name: Initialize submodules
run: git submodule init && git submodule update
- name: Initialize build system
run: mkdir build && cd build && cmake ..
- name: Build tests
run: cmake --build build --target tests
- name: Run tests
run: ctest build

View File

@@ -1,3 +1,49 @@
##### v4.5 - Sun Aug 20 04:46:53 PM UTC 2023
- Add VXLAN support (#501)
- Add `FileSniffer` constructor taking a `FILE*` (#499).
- Remove use of deprecated `std::iterator` (#481).
- Add missing `algorithm` header include (#497).
- Validate high order two bits of first dns label octet (#494).
- Use `CMAKE_INSTALL_LIBDIR` in `CONF_CMAKE_INSTALL_DIR` (#472).
- Ignore IPv6 packets with payload after one with no Next Header (#500).
- Fix unqualified `std::move` call warnings on clang (#488).
- Fix incorrect IP address range calculation when using /0 prefix (#484) (#486).
- Fall back to system GTest if available (#473).
- Fix compilation issue on android (#471).
- Fix DNS parser reading garbage on misreported packet size (#468).
- Fix DNS parser misinterpreting bad label size (#466).
##### v4.4 - Thu Feb 17 14:41:59 UTC 2022
- Add RFC8335 extended echo types to `ICMP` and `ICMPv6` (#426)
- Handle loops in DNS name decompression (#444)
- Fix Windows' `interface` macro colliding with uses of that identifier in the code (#458)
- Sending IPv6 packets to a link-scope destination address now uses the right interface index (#448)
- Fix incorrect endian being used for ICMP's `gateway` and `address_mask` (#437)
- Socket in `PacketSender::open_l3_socket` is now closed if `setsockopt` fails (#433)
- Fix various incorrect doxygen documentation comments (#439).
- Fix infinite loop when querying the routing table in \*BSD (#427)
##### v4.3 - Fri Sep 18 03:08:33 UTC 2020
- Assign a PDUType to `Dot11ControlTA` (#420)

View File

@@ -1,4 +1,4 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.1)
CMAKE_MINIMUM_REQUIRED(VERSION 3.10)
PROJECT(libtins)
OPTION(LIBTINS_BUILD_EXAMPLES "Build examples" ON)
@@ -46,7 +46,7 @@ ENDIF(LIBTINS_BUILD_SHARED)
# The version number.
SET(TINS_VERSION_MAJOR 4)
SET(TINS_VERSION_MINOR 3)
SET(TINS_VERSION_MINOR 6)
SET(TINS_VERSION_PATCH 0)
SET(LIBTINS_VERSION "${TINS_VERSION_MAJOR}.${TINS_VERSION_MINOR}")
@@ -303,7 +303,13 @@ IF(LIBTINS_BUILD_TESTS)
ENABLE_TESTING()
ADD_SUBDIRECTORY(tests)
ELSE()
MESSAGE(STATUS "googletest git submodule is absent. Run `git submodule init && git submodule update` to get it")
FIND_PACKAGE(GTest QUIET)
IF(${GTest_FOUND})
ENABLE_TESTING()
ADD_SUBDIRECTORY(tests)
ELSE()
MESSAGE(STATUS "googletest git submodule is absent. Run `git submodule init && git submodule update` to get it")
ENDIF()
ENDIF()
ENDIF()
@@ -312,7 +318,7 @@ ENDIF()
# **********************************
if(UNIX)
set(CONF_CMAKE_INSTALL_DIR lib/cmake/libtins)
set(CONF_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/libtins")
else()
set(CONF_CMAKE_INSTALL_DIR CMake)
endif()

View File

@@ -50,7 +50,7 @@ if (NOT CMAKE_CXX_COMPILER_LOADED)
message(FATAL_ERROR "CheckCXX11Features modules only works if language CXX is enabled")
endif ()
cmake_minimum_required(VERSION 2.8.3)
cmake_minimum_required(VERSION 3.10)
#
### Check for needed compiler flags

View File

@@ -40,9 +40,13 @@ namespace Tins {
* \brief AddressRange iterator class.
*/
template<typename Address>
class AddressRangeIterator : public std::iterator<std::forward_iterator_tag, const Address> {
class AddressRangeIterator {
public:
typedef typename std::iterator<std::forward_iterator_tag, const Address>::value_type value_type;
typedef std::forward_iterator_tag iterator_category;
typedef const Address value_type;
typedef std::ptrdiff_t difference_type;
typedef const Address* pointer;
typedef const Address& reference;
struct end_iterator {

View File

@@ -652,7 +652,7 @@ public:
// Getters
/**
* \brief Setter for the id field.
* \brief Getter for the id field.
*
* \return uint16_t containing the value of the id field.
*/
@@ -661,7 +661,7 @@ public:
}
/**
* \brief Setter for the query response field.
* \brief Getter for the query response field.
*
* \return QRType containing the value of the query response
* field.
@@ -671,7 +671,7 @@ public:
}
/**
* \brief Setter for the opcode field.
* \brief Getter for the opcode field.
*
* \return uint8_t containing the value of the opcode field.
*/
@@ -680,7 +680,7 @@ public:
}
/**
* \brief Setter for the authoritative answer field.
* \brief Getter for the authoritative answer field.
*
* \return uint8_t containing the value of the authoritative
* answer field.
@@ -690,7 +690,7 @@ public:
}
/**
* \brief Setter for the truncated field.
* \brief Getter for the truncated field.
*
* \return uint8_t containing the value of the truncated field.
*/
@@ -699,7 +699,7 @@ public:
}
/**
* \brief Setter for the recursion desired field.
* \brief Getter for the recursion desired field.
*
* \return uint8_t containing the value of the recursion
* desired field.
@@ -709,7 +709,7 @@ public:
}
/**
* \brief Setter for the recursion available field.
* \brief Getter for the recursion available field.
*
* \return uint8_t containing the value of the recursion
* available field.
@@ -719,7 +719,7 @@ public:
}
/**
* \brief Setter for the z desired field.
* \brief Getter for the z desired field.
*
* \return uint8_t containing the value of the z field.
*/
@@ -728,7 +728,7 @@ public:
}
/**
* \brief Setter for the authenticated data field.
* \brief Getter for the authenticated data field.
*
* \return uint8_t containing the value of the authenticated
* data field.
@@ -738,7 +738,7 @@ public:
}
/**
* \brief Setter for the checking disabled field.
* \brief Getter for the checking disabled field.
*
* \return uint8_t containing the value of the checking
* disabled field.
@@ -748,7 +748,7 @@ public:
}
/**
* \brief Setter for the rcode field.
* \brief Getter for the rcode field.
*
* \return uint8_t containing the value of the rcode field.
*/
@@ -757,7 +757,7 @@ public:
}
/**
* \brief Setter for the questions field.
* \brief Getter for the questions field.
*
* \return uint16_t containing the value of the questions field.
*/
@@ -766,7 +766,7 @@ public:
}
/**
* \brief Setter for the answers field.
* \brief Getter for the answers field.
*
* \return uint16_t containing the value of the answers field.
*/
@@ -775,7 +775,7 @@ public:
}
/**
* \brief Setter for the authority field.
* \brief Getter for the authority field.
*
* \return uint16_t containing the value of the authority field.
*/
@@ -784,7 +784,7 @@ public:
}
/**
* \brief Setter for the additional field.
* \brief Getter for the additional field.
*
* \return uint16_t containing the value of the additional field.
*/
@@ -1034,7 +1034,8 @@ private:
uint32_t compose_name(const uint8_t* ptr, char* out_ptr) const;
void convert_records(const uint8_t* ptr,
const uint8_t* end,
resources_type& res) const;
resources_type& res,
const uint16_t rr_count) const;
void skip_to_section_end(Memory::InputMemoryStream& stream,
const uint32_t num_records) const;
void skip_to_dname_end(Memory::InputMemoryStream& stream) const;

View File

@@ -64,8 +64,26 @@ public:
class malformed_packet : public exception_base {
public:
malformed_packet() : exception_base("Malformed packet") { }
malformed_packet(const std::string& message) : exception_base(message) { }
};
/**
* \brief Exception thrown when a DNS decompression pointer is out of bounds.
*/
class dns_decompression_pointer_out_of_bounds : public malformed_packet {
public:
dns_decompression_pointer_out_of_bounds() : malformed_packet("DNS decompression: pointer out of bounds") { }
};
/**
* \brief Exception thrown when a DNS decompression pointer loops.
*/
class dns_decompression_pointer_loops : public malformed_packet {
public:
dns_decompression_pointer_loops() : malformed_packet("DNS decompression: pointer loops") { }
};
/**
* \brief Exception thrown when serializing a packet fails.
*/

View File

@@ -89,7 +89,9 @@ public:
INFO_REQUEST = 15,
INFO_REPLY = 16,
ADDRESS_MASK_REQUEST = 17,
ADDRESS_MASK_REPLY = 18
ADDRESS_MASK_REPLY = 18,
EXTENDED_ECHO_REQUEST = 42,
EXTENDED_ECHO_REPLY = 43
};
/**
@@ -318,7 +320,7 @@ public:
* \return Returns the gateway field value.
*/
address_type gateway() const {
return address_type(Endian::be_to_host(header_.un.gateway));
return address_type(header_.un.gateway);
}
/**
@@ -381,7 +383,7 @@ public:
* \return Returns the address mask value.
*/
address_type address_mask() const {
return address_type(Endian::be_to_host(orig_timestamp_or_address_mask_));
return address_type(orig_timestamp_or_address_mask_);
}
/**

View File

@@ -30,6 +30,7 @@
#ifndef TINS_ICMPV6_H
#define TINS_ICMPV6_H
#include <algorithm>
#include <vector>
#include <tins/macros.h>
#include <tins/pdu.h>
@@ -92,7 +93,9 @@ public:
MULTICAST_ROUTER_ADVERT = 151,
MULTICAST_ROUTER_SOLICIT = 152,
MULTICAST_ROUTER_TERMINATE = 153,
RPL_CONTROL_MSG = 155
RPL_CONTROL_MSG = 155,
EXTENDED_ECHO_REQUEST = 160,
EXTENDED_ECHO_REPLY = 161
};
/**

View File

@@ -33,7 +33,7 @@
#include <string>
#include <iosfwd>
#include <functional>
#include <stdint.h>
#include <cstdint>
#include <tins/cxxstd.h>
#include <tins/macros.h>

View File

@@ -65,7 +65,9 @@ class PDU;
* - Those that don't contain a link layer PDU. In this case, the
* kernel will be responsible for picking the appropriate network interface
* based on the destination address.
*
* - Exception: <a href="https://datatracker.ietf.org/doc/html/rfc2553#section-3.3">RFC2553</a>
* requires IPv6 link-scope address have a interface defined.
* .
* \par Note for Windows users:
* Sending layer 3 PDUs (without a link layer protocol) is very restricted
* on Windows (<a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms740548(v=vs.85).aspx">link</a>).

View File

@@ -180,6 +180,8 @@ public:
PKTAP,
MPLS,
DOT11_CONTROL_TA,
VXLAN,
RTP,
UNKNOWN = 999,
USER_DEFINED_PDU = 1000
};

View File

@@ -115,7 +115,7 @@ public:
* \param data The payload to use.
*/
RawPDU(payload_type&& data)
: payload_(move(data)) { }
: payload_(std::move(data)) { }
#endif // TINS_IS_CXX11
/**

328
include/tins/rtp.h Normal file
View File

@@ -0,0 +1,328 @@
#ifndef TINS_RTP_H
#define TINS_RTP_H
#include <tins/endianness.h>
#include <tins/pdu.h>
#include <tins/pdu_option.h>
#include <tins/small_uint.h>
namespace Tins {
/**
* \class RTP
* \brief Represents a RTP PDU.
*
* This class represents a RTP PDU.
*
* \sa RawPDU
*/
class TINS_API RTP : public PDU {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::RTP;
/**
* The type used to store CSRC identifiers.
*/
typedef std::vector<uint32_t> csrc_ids_type;
/**
* The type used to store extension header data.
*/
typedef std::vector<uint32_t> extension_header_data_type;
/**
* Default constructor.
*/
RTP();
/**
* \brief Constructs a RTP object from a buffer.
*
* \param data The buffer from which this PDU will be constructed.
* \param size The size of the data buffer.
*/
RTP(const uint8_t* data, uint32_t size);
/**
* \brief Getter for the version.
*/
small_uint<2> version() const { return header_.version; }
/**
* \brief Getter for the padding bit.
*/
small_uint<1> padding_bit() const { return header_.padding; }
/**
* \brief Getter for the extension bit.
*/
small_uint<1> extension_bit() const { return header_.extension; }
/**
* \brief Getter for the CSRC count.
*/
small_uint<4> csrc_count() const { return header_.csrc_count; }
/**
* \brief Getter for the marker bit.
*/
small_uint<1> marker_bit() const { return header_.marker; }
/**
* \brief Getter for the payload type.
*/
small_uint<7> payload_type() const { return header_.payload_type; }
/**
* \brief Getter for the sequence number.
*/
uint16_t sequence_number() const { return Endian::be_to_host(header_.seq_num); }
/**
* \brief Getter for the timestamp.
*/
uint32_t timestamp() const { return Endian::be_to_host(header_.timestamp); }
/**
* \brief Getter for the SSRC identifier.
*/
uint32_t ssrc_id() const { return Endian::be_to_host(header_.ssrc_id); }
/**
* \brief Getter for the CSRC identifiers.
*/
const csrc_ids_type& csrc_ids() const {
return csrc_ids_;
}
/**
* \brief Getter for the padding size.
*/
uint8_t padding_size() const { return padding_size_; }
/**
* \brief Getter for the extension header profile.
*/
uint16_t extension_profile() const { return Endian::be_to_host(ext_header_.profile); }
/**
* \brief Getter for the extension header length.
*/
uint16_t extension_length() const { return Endian::be_to_host(ext_header_.length); }
/**
* \brief Getter for the extension header data.
*/
const extension_header_data_type& extension_data() const {
return ext_data_;
}
/**
* \brief Setter for the version.
* \param version The new version.
*/
void version(small_uint<2> version) { header_.version = version; }
/**
* \brief Setter for the extension bit.
* \param extension The new extension bit.
*/
void extension_bit(small_uint<1> extension) { header_.extension = extension; }
/**
* \brief Setter for the marker bit.
* \param marker The new marker bit.
*/
void marker_bit(small_uint<1> marker) { header_.marker = marker; }
/**
* \brief Setter for the payload type.
* \param payload_type The new payload type.
*/
void payload_type(small_uint<7> payload_type) { header_.payload_type = payload_type; }
/**
* \brief Setter for the sequence number.
* \param seq_num The new sequence number.
*/
void sequence_number(uint16_t seq_num) { header_.seq_num = Endian::host_to_be(seq_num); }
/**
* \brief Setter for the timestamp.
* \param timestamp The new timestamp.
*/
void timestamp(uint32_t timestamp) { header_.timestamp = Endian::host_to_be(timestamp); }
/**
* \brief Setter for the SSRC identifier.
* \param ssrc_id The new SSRC identifier.
*/
void ssrc_id(uint32_t ssrc_id) { header_.ssrc_id = Endian::host_to_be(ssrc_id); }
/**
* \brief Setter for the padding size.
* \param size The new padding size.
*/
void padding_size(uint8_t size) {
padding_bit(size > 0);
padding_size_ = size;
}
/**
* \brief Setter for the extension header profile.
* \param profile The new extension header profile.
*/
void extension_profile(uint16_t profile) { ext_header_.profile = Endian::host_to_be(profile); }
/**
* \brief Adds a word of extension header data.
*
* The word is added after the last word of extension header data.
*
* \param value The value of the extension header data to be added.
*/
void add_extension_data(const uint32_t value);
/**
* \brief Removes a word of extension header data.
*
* If there are multiple words of extension header data of the given value,
* only the first one will be removed.
*
* \param value The value of the extension header data to be removed.
* \return true if the extension header data was removed, false otherwise.
*/
bool remove_extension_data(const uint32_t value);
/**
* \brief Searches for extension header data that matches the given value.
* \param value The extension header data to be searched.
* \return true if the extension header data was found, false otherwise.
*/
bool search_extension_data(const uint32_t value);
/**
* \brief Adds a CSRC identifier.
*
* The CSRC identifier is added after the last CSRC identifier in the extension
* header.
*
* \param csrc_id The CSRC identifier to be added
*/
void add_csrc_id(const uint32_t csrc_id);
/**
* \brief Removes a CSRC identifier.
*
* If there are multiple CSRC identifiers of the given value, only the first one
* will be removed.
*
* \param value The value of the CSRC identifier to be removed.
* \return true if the CSRC identifier was removed, false otherwise.
*/
bool remove_csrc_id(const uint32_t value);
/**
* \brief Searches for a CSRC identifier that matches the given value.
* \param value The CSRC identifier to be searched.
* \return true if the CSRC identifier was found, false otherwise.
*/
bool search_csrc_id(const uint32_t value);
/**
* \brief Returns the RTP packet's header length.
*
* This method overrides PDU::header_size.
*
* \return An uint32_t with the header's size.
* \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Returns the RTP packet's trailer length.
*
* This method overrides PDU::trailer_size.
*
* \return An uint32_t with the trailer's size.
* \sa PDU::trailer_size
*/
uint32_t trailer_size() const { return static_cast<uint32_t>(padding_size_); }
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \sa PDU::clone
*/
RTP *clone() const { return new RTP(*this); }
private:
TINS_BEGIN_PACK
struct rtp_header {
#if TINS_IS_BIG_ENDIAN
uint16_t version:2,
padding:1,
extension:1,
csrc_count:4,
marker:1,
payload_type:7;
#elif TINS_IS_LITTLE_ENDIAN
uint16_t csrc_count:4,
extension:1,
padding:1,
version:2,
payload_type:7,
marker:1;
#endif
uint16_t seq_num;
uint32_t timestamp;
uint32_t ssrc_id;
} TINS_END_PACK;
TINS_BEGIN_PACK
struct rtp_extension_header {
uint16_t profile;
uint16_t length;
} TINS_END_PACK;
void write_serialization(uint8_t* buffer, uint32_t size);
csrc_ids_type::const_iterator search_csrc_id_iterator(const uint32_t csrc_id) const;
csrc_ids_type::iterator search_csrc_id_iterator(const uint32_t csrc_id);
extension_header_data_type::const_iterator search_extension_data_iterator(const uint32_t data) const;
extension_header_data_type::iterator search_extension_data_iterator(const uint32_t data);
/**
* \brief Setter for the padding bit.
* \param padding The new padding bit.
*/
void padding_bit(small_uint<1> padding) { header_.padding = padding; }
/**
* \brief Setter for the CSRC count. Hidden from the public interface.
* \param csrc_count The new CSRC count.
*/
void csrc_count(small_uint<4> csrc_count) { header_.csrc_count = csrc_count; }
/**
* \brief Setter for the extension header length. Hidden from the public interface.
* \param length The new extension header length.
*/
void extension_length(uint16_t length) { ext_header_.length = Endian::host_to_be(length); }
rtp_header header_;
csrc_ids_type csrc_ids_;
rtp_extension_header ext_header_;
extension_header_data_type ext_data_;
uint8_t padding_size_;
};
} // Tins
#endif // TINS_RTP_H

View File

@@ -406,10 +406,17 @@ private:
*/
class TINS_API FileSniffer : public BaseSniffer {
public:
/**
* \brief Constructs an instance of FileSniffer.
* \param fp The pcap file which will be parsed.
* \param configuration A SnifferConfiguration to be used on the file.
*/
FileSniffer(FILE *fp, const SnifferConfiguration& configuration);
/**
* \brief Constructs an instance of FileSniffer.
* \param file_name The pcap file which will be parsed.
* \param filter A capture filter to be used on the file.(optional);
* \param configuration A SnifferConfiguration to be used on the file.
*/
FileSniffer(const std::string& file_name, const SnifferConfiguration& configuration);
@@ -418,9 +425,18 @@ public:
*
* \brief Constructs an instance of FileSniffer.
* \param file_name The pcap file which will be parsed.
* \param filter A capture filter to be used on the file.(optional);
* \param filter A capture filter to be used on the file. (optional)
*/
FileSniffer(const std::string& file_name, const std::string& filter = "");
/**
* \deprecated Use the constructor that takes a SnifferConfiguration instead.
*
* \brief Constructs an instance of FileSniffer.
* \param fp The pcap file which will be parsed.
* \param filter A capture filter to be used on the file. (optional)
*/
FileSniffer(FILE *fp, const std::string& filter = "");
};
template <typename T>
@@ -449,8 +465,14 @@ HandlerProxy<T> make_sniffer_handler(T* ptr,
/**
* \brief Iterates over packets sniffed by a BaseSniffer.
*/
class SnifferIterator : public std::iterator<std::forward_iterator_tag, Packet> {
class SnifferIterator {
public:
typedef std::forward_iterator_tag iterator_category;
typedef Packet value_type;
typedef std::ptrdiff_t difference_type;
typedef Packet* pointer;
typedef Packet& reference;
/**
* Constructs a SnifferIterator.
* \param sniffer The sniffer to iterate.

View File

@@ -303,7 +303,7 @@ public:
* TCP tcp = ...;
* if(tcp.has_flags(TCP::SYN | TCP::ACK)) {
* // It's a SYN+ACK, but it also possible that other flags are set!
* // it is equivalent to: (tpc.flags() & (TCP::SYN | TCP::ACK)) == (TCP::SYN | TCP::ACK)
* // it is equivalent to: (tcp.flags() & (TCP::SYN | TCP::ACK)) == (TCP::SYN | TCP::ACK)
* }
* \endcode
*

View File

@@ -78,7 +78,8 @@
#include <tins/pdu_allocator.h>
#include <tins/ipsec.h>
#include <tins/ip_reassembler.h>
#include <tins/pdu_iterator.h>
#include <tins/vxlan.h>
#include <tins/rtp.h>
#endif // TINS_TINS_H

98
include/tins/vxlan.h Normal file
View File

@@ -0,0 +1,98 @@
#ifndef TINS_VXLAN_H
#define TINS_VXLAN_H
#include <tins/pdu.h>
#include <tins/small_uint.h>
namespace Tins {
/**
* \class VXLAN
* \brief Represents a VXLAN PDU.
*
* This class represents a VXLAN PDU.
*
* \sa RawPDU
*/
class TINS_API VXLAN : public PDU {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::VXLAN;
/**
* \brief Constructs a VXLAN PDU.
*
* \param vni VXLAN Network Identifier.
*/
VXLAN(const small_uint<24> vni = 0);
/**
* \brief Constructs a VXLAN object from a buffer and adds
* the Ethernet II PDU.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
VXLAN(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Getter for the flags.
*/
uint8_t get_flags() const { return Endian::be_to_host(header_.flags) >> 24; }
/**
* \brief Getter for the VNI.
*/
small_uint<24> get_vni() const { return Endian::be_to_host(header_.vni) >> 8; }
/**
* \brief Setter for the flags.
* \param new_flags The new flags.
*/
void set_flags(uint8_t new_flags) { header_.flags = Endian::host_to_be(new_flags << 24); }
/**
* \brief Setter for the VNI.
* \param new_vni The new VNI.
*/
void set_vni(small_uint<24> new_vni) { header_.vni = Endian::host_to_be(new_vni << 8); }
/**
* \brief Returns the VXLAN frame's header length.
*
* This method overrides PDU::header_size. This size includes the
* payload and options size.
*
* \return An uint32_t with the header's size.
* \sa PDU::header_size
*/
uint32_t header_size() const { return sizeof(header_); }
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \sa PDU::clone
*/
VXLAN *clone() const { return new VXLAN(*this); }
private:
TINS_BEGIN_PACK
struct vxlan_header {
uint32_t flags;
uint32_t vni;
} TINS_END_PACK;
void write_serialization(uint8_t* buffer, uint32_t total_sz);
vxlan_header header_;
};
} // Tins
#endif // TINS_VXLAN_H

View File

@@ -54,6 +54,7 @@ set(SOURCES
radiotap.cpp
rawpdu.cpp
rsn_information.cpp
rtp.cpp
sll.cpp
snap.cpp
stp.cpp
@@ -73,6 +74,7 @@ set(SOURCES
utils/routing_utils.cpp
utils/resolve_utils.cpp
utils/pdu_utils.cpp
vxlan.cpp
)
set(HEADERS
@@ -130,6 +132,7 @@ set(HEADERS
${LIBTINS_INCLUDE_DIR}/tins/radiotap.h
${LIBTINS_INCLUDE_DIR}/tins/rawpdu.h
${LIBTINS_INCLUDE_DIR}/tins/rsn_information.h
${LIBTINS_INCLUDE_DIR}/tins/rtp.h
${LIBTINS_INCLUDE_DIR}/tins/sll.h
${LIBTINS_INCLUDE_DIR}/tins/small_uint.h
${LIBTINS_INCLUDE_DIR}/tins/snap.h
@@ -151,6 +154,7 @@ set(HEADERS
${LIBTINS_INCLUDE_DIR}/tins/utils/routing_utils.h
${LIBTINS_INCLUDE_DIR}/tins/utils/resolve_utils.h
${LIBTINS_INCLUDE_DIR}/tins/utils/pdu_utils.h
${LIBTINS_INCLUDE_DIR}/tins/vxlan.h
)
SET(DOT11_DEPENDENT_SOURCES

View File

@@ -705,8 +705,11 @@ WPA2Decrypter::bssids_map::const_iterator WPA2Decrypter::find_ap(const Dot11Data
bool WPA2Decrypter::decrypt(PDU& pdu) {
if (capturer_.process_packet(pdu)) {
try_add_keys(pdu.rfind_pdu<Dot11Data>(), capturer_.handshakes().front());
capturer_.clear_handshakes();
Dot11Data* data = pdu.find_pdu<Dot11Data>();
if (data) {
try_add_keys(*data, capturer_.handshakes().front());
capturer_.clear_handshakes();
}
}
else if (const Dot11Beacon* beacon = pdu.find_pdu<Dot11Beacon>()) {
if (aps_.count(beacon->addr3()) == 0) {

View File

@@ -169,6 +169,8 @@ Tins::PDU* pdu_from_flag(PDU::PDUType type, const uint8_t* buffer, uint32_t size
return new Tins::IEEE802_3(buffer, size);
case Tins::PDU::PPPOE:
return new Tins::PPPoE(buffer, size);
case Tins::PDU::RAW:
return new Tins::RawPDU(buffer, size);
#ifdef TINS_HAVE_DOT11
case Tins::PDU::RADIOTAP:
return new Tins::RadioTap(buffer, size);

View File

@@ -86,14 +86,18 @@ void DNS::skip_to_dname_end(InputMemoryStream& stream) const {
break;
}
else {
if ((value & 0xc0)) {
// This is an offset label, skip the second byte and we're done
const uint8_t offset_discriminator = value & 0xc0;
if (offset_discriminator == 0xc0) {
// This is an offset pointer, skip the second byte and we're done
stream.skip(1);
break;
}
else {
else if (offset_discriminator == 0) {
// This is an actual label, skip its contents
stream.skip(value);
} else {
// high order two bits of the first octet of a label must be either 11 or 00
throw malformed_packet();
}
}
}
@@ -336,9 +340,13 @@ uint32_t DNS::compose_name(const uint8_t* ptr, char* out_ptr) const {
const uint8_t* end = &records_data_[0] + records_data_.size();
const uint8_t* end_ptr = 0;
char* current_out_ptr = out_ptr;
uint8_t pointer_counter = 0;
while (*ptr) {
if (pointer_counter++ > 30){
throw dns_decompression_pointer_loops();
}
// It's an offset
if ((*ptr & 0xc0)) {
if (((*ptr & 0xc0) == 0xc0)) {
if (TINS_UNLIKELY(ptr + sizeof(uint16_t) > end)) {
throw malformed_packet();
}
@@ -347,7 +355,7 @@ uint32_t DNS::compose_name(const uint8_t* ptr, char* out_ptr) const {
index = Endian::be_to_host(index) & 0x3fff;
// Check that the offset is neither too low or too high
if (index < 0x0c || (&records_data_[0] + (index - 0x0c)) >= end) {
throw malformed_packet();
throw dns_decompression_pointer_out_of_bounds();
}
// We've probably found the end of the original domain name. Save it.
if (end_ptr == 0) {
@@ -410,10 +418,11 @@ void DNS::inline_convert_v4(uint32_t value, char* output) {
// Parses records in some section.
void DNS::convert_records(const uint8_t* ptr,
const uint8_t* end,
resources_type& res) const {
resources_type& res,
const uint16_t rr_count) const {
InputMemoryStream stream(ptr, end - ptr);
char dname[256], small_addr_buf[256];
while (stream) {
while (stream && (res.size() < rr_count)) {
string data;
bool used_small_buffer = false;
// Retrieve the record's domain name.
@@ -573,7 +582,8 @@ DNS::resources_type DNS::answers() const {
convert_records(
&records_data_[0] + answers_idx_,
&records_data_[0] + authority_idx_,
res
res,
answers_count()
);
}
return res;
@@ -585,7 +595,8 @@ DNS::resources_type DNS::authority() const {
convert_records(
&records_data_[0] + authority_idx_,
&records_data_[0] + additional_idx_,
res
res,
authority_count()
);
}
return res;
@@ -597,7 +608,8 @@ DNS::resources_type DNS::additional() const {
convert_records(
&records_data_[0] + additional_idx_,
&records_data_[0] + records_data_.size(),
res
res,
additional_count()
);
}
return res;

View File

@@ -98,7 +98,7 @@ void ICMP::sequence(uint16_t new_seq) {
}
void ICMP::gateway(address_type new_gw) {
header_.un.gateway = Endian::host_to_be(static_cast<uint32_t>(new_gw));
header_.un.gateway = static_cast<uint32_t>(new_gw);
}
void ICMP::mtu(uint16_t new_mtu) {
@@ -122,7 +122,7 @@ void ICMP::transmit_timestamp(uint32_t new_timestamp) {
}
void ICMP::address_mask(address_type new_mask) {
orig_timestamp_or_address_mask_ = Endian::host_to_be(static_cast<uint32_t>(new_mask));
orig_timestamp_or_address_mask_ = static_cast<uint32_t>(new_mask);
}
uint32_t ICMP::header_size() const {

View File

@@ -62,7 +62,7 @@ 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)));
return IPv4Address(prefix_length ? Endian::host_to_be(0xffffffff << (32 - prefix_length)) : 0u);
}
IPv4Address::IPv4Address(uint32_t ip)

View File

@@ -32,6 +32,9 @@
#include <netinet/in.h>
#include <sys/socket.h>
#else
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <ws2tcpip.h>
#endif
#include <tins/ipv6.h>
@@ -127,7 +130,7 @@ IPv6::IPv6(const uint8_t* buffer, uint32_t total_sz) {
uint32_t actual_payload_length = payload_length();
bool is_payload_fragmented = false;
while (stream) {
if (is_extension_header(current_header)) {
if (is_extension_header(current_header) && current_header != NO_NEXT_HEADER) {
if (current_header == FRAGMENT) {
is_payload_fragmented = true;
}
@@ -366,11 +369,16 @@ void IPv6::write_serialization(uint8_t* buffer, uint32_t total_sz) {
}
#ifndef BSD
void IPv6::send(PacketSender& sender, const NetworkInterface &) {
void IPv6::send(PacketSender& sender, const NetworkInterface& interface) {
sockaddr_in6 link_addr;
const PacketSender::SocketType type = PacketSender::IPV6_SOCKET;
link_addr.sin6_family = AF_INET6;
link_addr.sin6_port = 0;
// Required to set sin6_scope_id to interface index as stated in RFC2553.
// https://datatracker.ietf.org/doc/html/rfc2553#section-3.3
if (IPv6Address(header_.dst_addr).is_local_unicast()) {
link_addr.sin6_scope_id = interface.id();
}
memcpy((uint8_t*)&link_addr.sin6_addr, header_.dst_addr, address_type::address_size);
sender.send_l3(*this, (struct sockaddr*)&link_addr, sizeof(link_addr), type);
}

View File

@@ -331,7 +331,7 @@ NetworkInterface::Info NetworkInterface::info() const {
}
#else // _WIN32
#if !defined(ANDROID) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 24)
struct ifaddrs* ifaddrs = 0;
struct ifaddrs* if_it = 0;
getifaddrs(&ifaddrs);
@@ -341,7 +341,9 @@ NetworkInterface::Info NetworkInterface::info() const {
if (ifaddrs) {
freeifaddrs(ifaddrs);
}
#else
throw new std::runtime_error("android ifaddr not supported");
#endif
#endif // _WIN32
// If we didn't even get the hw address or ip address, this went wrong

View File

@@ -267,6 +267,11 @@ void PacketSender::open_l3_socket(SocketType type) {
#endif
const int level = (is_v6) ? IPPROTO_IPV6 : IPPROTO_IP;
if (setsockopt(sockfd, level, IP_HDRINCL, (option_ptr)&on, sizeof(on)) != 0) {
#ifndef _WIN32
::close(sockfd);
#else
::closesocket(sockfd);
#endif
throw socket_open_error(make_error_string());
}

195
src/rtp.cpp Normal file
View File

@@ -0,0 +1,195 @@
#include <algorithm>
#include <tins/exceptions.h>
#include <tins/internals.h>
#include <tins/memory_helpers.h>
#include <tins/rtp.h>
using std::logic_error;
using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins {
RTP::RTP()
: header_(), ext_header_(), padding_size_(0) {
version(2);
}
RTP::RTP(const uint8_t* buffer, uint32_t total_sz) {
InputMemoryStream stream(buffer, total_sz);
stream.read(header_);
small_uint<4> csrc_count_ = csrc_count();
for (uint32_t i = 0; i < csrc_count_; ++i) {
uint32_t csrc_id;
stream.read(csrc_id);
csrc_ids_.push_back(csrc_id);
}
if (extension_bit() == 1) {
stream.read(ext_header_);
for (uint32_t i = 0; i < extension_length(); ++i) {
uint32_t data;
stream.read(data);
ext_data_.push_back(data);
}
}
padding_size_ = 0;
const uint8_t* data_ptr = stream.pointer();
const size_t data_size = stream.size();
if (padding_bit() == 1) {
if (data_size > 0) {
stream.skip(data_size - sizeof(uint8_t));
stream.read(padding_size_);
} else {
throw malformed_packet();
}
if (padding_size() == 0) {
throw malformed_packet();
}
}
if (padding_size() > data_size) {
throw malformed_packet();
}
if (data_size > padding_size()) {
inner_pdu(
Internals::pdu_from_flag(
PDU::RAW,
data_ptr,
data_size - padding_size()
)
);
}
}
uint32_t RTP::header_size() const {
uint32_t extension_size = 0;
if (extension_bit() == 1) {
extension_size = sizeof(ext_header_) + (extension_length() * sizeof(uint32_t));
}
return static_cast<uint32_t>(sizeof(header_) + (csrc_ids_.size() * sizeof(uint32_t)) + extension_size);
}
void RTP::add_csrc_id(const uint32_t csrc_id) {
small_uint<4> csrc_count_ = csrc_count();
if (TINS_UNLIKELY(csrc_count_ >= 15)) {
throw logic_error("Maximum number of CSRC IDs reached");
}
csrc_ids_.push_back(Endian::host_to_be(csrc_id));
csrc_count(csrc_count_ + 1);
}
bool RTP::remove_csrc_id(const uint32_t csrc_id) {
small_uint<4> csrc_count_ = csrc_count();
if (csrc_count_ == 0) {
return false;
}
csrc_ids_type::iterator iter = search_csrc_id_iterator(Endian::host_to_be(csrc_id));
if (iter == csrc_ids_.end()) {
return false;
}
csrc_ids_.erase(iter);
csrc_count(csrc_count_ - 1);
return true;
}
bool RTP::search_csrc_id(const uint32_t csrc_id) {
csrc_ids_type::const_iterator iter = search_csrc_id_iterator(Endian::host_to_be(csrc_id));
return (iter != csrc_ids_.cend());
}
RTP::csrc_ids_type::const_iterator RTP::search_csrc_id_iterator(const uint32_t csrc_id) const {
return std::find(csrc_ids_.cbegin(), csrc_ids_.cend(), csrc_id);
}
RTP::csrc_ids_type::iterator RTP::search_csrc_id_iterator(const uint32_t csrc_id) {
return std::find(csrc_ids_.begin(), csrc_ids_.end(), csrc_id);
}
void RTP::add_extension_data(const uint32_t value) {
if (TINS_UNLIKELY(extension_length() >= 65535)) {
throw logic_error("Maximum number of extension data reached");
}
extension_bit(1);
ext_data_.push_back(Endian::host_to_be(value));
extension_length(extension_length() + 1);
}
bool RTP::remove_extension_data(const uint32_t value) {
if (extension_bit() == 0 || extension_length() == 0) {
return false;
}
extension_header_data_type::iterator iter = search_extension_data_iterator(Endian::host_to_be(value));
if (iter == ext_data_.end()) {
return false;
}
ext_data_.erase(iter);
extension_length(extension_length() - 1);
if (extension_length() == 0) {
extension_bit(0);
}
return true;
}
bool RTP::search_extension_data(const uint32_t value) {
if (extension_bit() == 0 || extension_length() == 0) {
return false;
}
extension_header_data_type::const_iterator iter = search_extension_data_iterator(Endian::host_to_be(value));
return (iter != ext_data_.cend());
}
RTP::extension_header_data_type::const_iterator RTP::search_extension_data_iterator(const uint32_t data) const {
return std::find(ext_data_.cbegin(), ext_data_.cend(), data);
}
RTP::extension_header_data_type::iterator RTP::search_extension_data_iterator(const uint32_t data) {
return std::find(ext_data_.begin(), ext_data_.end(), data);
}
void RTP::write_serialization(uint8_t* buffer, uint32_t total_sz) {
OutputMemoryStream stream(buffer, total_sz);
stream.write(header_);
for (auto csrc_id : csrc_ids_) {
stream.write(csrc_id);
}
if (extension_bit() == 1) {
stream.write(ext_header_);
for (auto data : ext_data_) {
stream.write(data);
}
}
if (padding_bit() == 1) {
if (padding_size() > 0) {
if (inner_pdu()) {
stream.skip(inner_pdu()->size());
}
stream.fill(padding_size() - 1, 0);
stream.write(padding_size());
} else {
throw pdu_not_serializable();
}
}
}
} // Tins

View File

@@ -391,6 +391,20 @@ void Sniffer::set_rfmon(bool rfmon_enabled) {
// **************************** FileSniffer ****************************
FileSniffer::FileSniffer(FILE *fp,
const SnifferConfiguration& configuration) {
char error[PCAP_ERRBUF_SIZE];
pcap_t* phandle = pcap_fopen_offline(fp, error);
if (!phandle) {
throw pcap_error(error);
}
set_pcap_handle(phandle);
// Configure the sniffer
configuration.configure_sniffer_pre_activation(*this);
}
FileSniffer::FileSniffer(const string& file_name,
const SnifferConfiguration& configuration) {
char error[PCAP_ERRBUF_SIZE];
@@ -420,6 +434,22 @@ FileSniffer::FileSniffer(const string& file_name, const string& filter) {
config.configure_sniffer_pre_activation(*this);
}
FileSniffer::FileSniffer(FILE *fp, const string& filter) {
SnifferConfiguration config;
config.set_filter(filter);
char error[PCAP_ERRBUF_SIZE];
pcap_t* phandle = pcap_fopen_offline(fp, error);
if (!phandle) {
throw pcap_error(error);
}
set_pcap_handle(phandle);
// Configure the sniffer
config.configure_sniffer_pre_activation(*this);
}
// ************************ SnifferConfiguration ************************
const unsigned SnifferConfiguration::DEFAULT_SNAP_LEN = 65535;

View File

@@ -33,8 +33,6 @@
#include <tins/detail/sequence_number_helpers.h>
using std::move;
using Tins::Internals::seq_compare;
namespace Tins {
@@ -67,7 +65,7 @@ bool DataTracker::process_payload(uint32_t seq, payload_type payload) {
}
bool added_some = false;
// Store this payload
store_payload(seq, move(payload));
store_payload(seq, std::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) {
@@ -85,7 +83,7 @@ bool DataTracker::process_payload(uint32_t seq, payload_type payload) {
payload.begin(),
payload.begin() + (seq_number_ - iter->first)
);
store_payload(seq_number_, move(iter->second));
store_payload(seq_number_, std::move(iter->second));
iter = erase_iterator(iter);
}
else {
@@ -158,14 +156,14 @@ void DataTracker::store_payload(uint32_t seq, payload_type payload) {
// New segment, store it
if (iter == buffered_payload_.end()) {
total_buffered_bytes_ += payload.size();
buffered_payload_.insert(make_pair(seq, move(payload)));
buffered_payload_.insert(make_pair(seq, std::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);
iter->second = std::move(payload);
}
}

View File

@@ -115,7 +115,7 @@ void Flow::process_packet(PDU& pdu) {
}
// can process either way, since it will abort immediately if not needed
if (data_tracker_.process_payload(tcp->seq(), move(raw->payload()))) {
if (data_tracker_.process_payload(tcp->seq(), std::move(raw->payload()))) {
if (on_data_callback_) {
on_data_callback_(*this);
}

View File

@@ -59,9 +59,11 @@ Stream::Stream(PDU& packet, const timestamp_type& ts)
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.has_flags(TCP::SYN);
const TCP* tcp = packet.find_pdu<TCP>();
if (tcp) {
// If this is not the first packet of a stream (SYN), then it's a partial stream
is_partial_stream_ = !tcp->has_flags(TCP::SYN);
}
}
void Stream::process_packet(PDU& packet, const timestamp_type& ts) {

View File

@@ -154,6 +154,7 @@ vector<char> query_route_table(int family) {
throw exception_base("sysctl failed");
}
buf.resize(len);
return buf;
}
@@ -412,17 +413,21 @@ set<string> network_interfaces() {
}
#else
set<string> network_interfaces() {
set<string> output;
struct ifaddrs* ifaddrs = 0;
struct ifaddrs* if_it = 0;
getifaddrs(&ifaddrs);
for (if_it = ifaddrs; if_it; if_it = if_it->ifa_next) {
output.insert(if_it->ifa_name);
}
if (ifaddrs) {
freeifaddrs(ifaddrs);
}
#if !defined(ANDROID) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 24)
set<string> output;
struct ifaddrs* ifaddrs = 0;
struct ifaddrs* if_it = 0;
getifaddrs(&ifaddrs);
for (if_it = ifaddrs; if_it; if_it = if_it->ifa_next) {
output.insert(if_it->ifa_name);
}
if (ifaddrs) {
freeifaddrs(ifaddrs);
}
return output;
#else
throw std::runtime_error("android ifaddr not supported");
#endif
}
#endif // _WIN32

36
src/vxlan.cpp Normal file
View File

@@ -0,0 +1,36 @@
#include <tins/internals.h>
#include <tins/memory_helpers.h>
#include <tins/small_uint.h>
#include <tins/vxlan.h>
using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins {
VXLAN::VXLAN(const small_uint<24> vni) {
set_flags(8);
set_vni(vni);
}
VXLAN::VXLAN(const uint8_t* buffer, uint32_t total_sz) {
InputMemoryStream stream(buffer, total_sz);
stream.read(header_);
// If there is any size left
if (stream) {
inner_pdu(
Internals::pdu_from_flag(
PDU::ETHERNET_II,
stream.pointer(),
stream.size()
)
);
}
}
void VXLAN::write_serialization(uint8_t* buffer, uint32_t total_sz) {
OutputMemoryStream stream(buffer, total_sz);
stream.write(header_);
}
} // Tins

View File

@@ -63,6 +63,7 @@ CREATE_TEST(pppoe)
CREATE_TEST(raw_pdu)
CREATE_TEST(rc4_eapol)
CREATE_TEST(rsn_eapol)
CREATE_TEST(rtp)
CREATE_TEST(sll)
CREATE_TEST(snap)
CREATE_TEST(stp)
@@ -70,6 +71,7 @@ CREATE_TEST(tcp)
CREATE_TEST(tcp_ip)
CREATE_TEST(udp)
CREATE_TEST(utils)
CREATE_TEST(vxlan)
IF(LIBTINS_ENABLE_PCAP)
CREATE_TEST(offline_packet_filter)

View File

@@ -12,11 +12,19 @@ using namespace Tins;
class AddressRangeTest : public testing::Test {
public:
void contain_tests0(const IPv4Range& range);
void contain_tests0(const IPv6Range& range);
void contain_tests24(const IPv4Range& range);
void contain_tests24(const IPv6Range& range);
void contain_tests26(const IPv4Range& range);
};
void AddressRangeTest::contain_tests0(const IPv4Range& range) {
EXPECT_TRUE(range.contains("0.0.0.0"));
EXPECT_TRUE(range.contains("192.168.1.1"));
EXPECT_TRUE(range.contains("255.255.255.255"));
}
void AddressRangeTest::contain_tests24(const IPv4Range& range) {
EXPECT_TRUE(range.contains("192.168.0.0"));
EXPECT_TRUE(range.contains("192.168.0.1"));
@@ -33,6 +41,12 @@ void AddressRangeTest::contain_tests26(const IPv4Range& range) {
EXPECT_FALSE(range.contains("192.168.254.191"));
}
void AddressRangeTest::contain_tests0(const IPv6Range& range) {
EXPECT_TRUE(range.contains("::"));
EXPECT_TRUE(range.contains("dead::1:1"));
EXPECT_TRUE(range.contains("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"));
}
void AddressRangeTest::contain_tests24(const IPv6Range& range) {
EXPECT_TRUE(range.contains("dead::1"));
EXPECT_TRUE(range.contains("dead::1fee"));
@@ -42,13 +56,22 @@ void AddressRangeTest::contain_tests24(const IPv6Range& range) {
}
TEST_F(AddressRangeTest, Contains) {
contain_tests0(IPv4Range("0.0.0.0", "255.255.255.255"));
contain_tests0(IPv4Range::from_mask("0.0.0.0", "0.0.0.0"));
contain_tests0(IPv4Range::from_mask("0.0.0.0", IPv4Address::from_prefix_length(0)));
contain_tests24(IPv4Range("192.168.0.0", "192.168.0.255"));
contain_tests24(IPv4Range::from_mask("192.168.0.0", "255.255.255.0"));
contain_tests24(IPv4Range::from_mask("192.168.0.0", IPv4Address::from_prefix_length(24)));
contain_tests26(IPv4Range("192.168.254.192", "192.168.254.255"));
contain_tests26(IPv4Range::from_mask("192.168.254.192", "255.255.255.192"));
contain_tests26(IPv4Range::from_mask("192.168.254.192", IPv4Address::from_prefix_length(26)));
contain_tests0(IPv6Range("::0", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"));
contain_tests0(IPv6Range::from_mask("::", "::"));
contain_tests0(IPv6Range::from_mask("::", IPv6Address::from_prefix_length(0)));
contain_tests24(IPv6Range("dead::0", "dead::ffff"));
contain_tests24(IPv6Range::from_mask("dead::0", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0"));
contain_tests24(IPv6Range::from_mask("dead::0", IPv6Address::from_prefix_length(112)));
{
AddressRange<HWAddress<6> > range("00:00:00:00:00:00", "00:00:00:00:00:ff");

View File

@@ -551,3 +551,113 @@ TEST_F(DNSTest, SOARecordSerialize) {
EXPECT_EQ(0x8ad71928U, r2.expire());
EXPECT_EQ(0x1ad92871U, r2.minimum_ttl());
}
TEST_F(DNSTest, BadLabelSize) {
const uint8_t header[] = {
0x45, 0xbc, // ID
0x81, 0x80, // response, recursion desired, recursion available, no error
0x00, 0x01, // QDCOUNT
0x00, 0x00, // ANCOUNT
0x00, 0x00, // NSCOUNT
0x00, 0x00 // ARCOUNT
};
size_t payload_sz{sizeof(header)};
uint8_t payload[512];
// copy header
std::copy(header,
header + payload_sz,
payload);
// add bad length
const size_t bad_label_len{0x80};
const size_t label_offset = payload_sz;
payload[payload_sz++] = bad_label_len;
// fill label for incorrect length and terminate
std::fill(payload + payload_sz,
payload + payload_sz + bad_label_len,
'a');
payload_sz += bad_label_len;
payload[payload_sz++] = 0x0;
// add type and class
const uint8_t type_class[] = {
0x00, 0x01,
0x00, 0x01
};
std::copy(type_class,
type_class + sizeof(type_class),
payload + payload_sz);
payload_sz += sizeof(type_class);
// invalid high two bits of label first octest is detected early now
try {
const DNS packet(payload, payload_sz);
FAIL();
} catch (malformed_packet& mp) {
SUCCEED();
}
// check the other invalid value of high two bits in label size
payload[label_offset] = 0x10;
try {
const DNS packet(payload, payload_sz);
FAIL();
} catch (malformed_packet& mp) {
SUCCEED();
}
}
TEST_F(DNSTest, BadPacketLength) {
// valid response packet with RR's in all sections
const uint8_t payload[] = {
0x74,0xa9,0x85,0x80,0x00,0x01,0x00,0x02,0x00,0x01,0x00,0x04,0x08,0x5f,0x73,0x65,0x72,
0x76,0x69,0x63,0x65,0x04,0x5f,0x74,0x63,0x70,0x05,0x77,0x69,0x66,0x69,0x36,0x03,
0x6c,0x61,0x6e,0x00,0x00,0x21,0x00,0x01,0xc0,0x0c,0x00,0x21,0x00,0x01,0x00,0x01,
0x51,0x80,0x00,0x16,0x00,0x00,0x00,0x03,0x00,0x09,0x04,0x66,0x61,0x73,0x74,0x05,
0x77,0x69,0x66,0x69,0x36,0x03,0x6c,0x61,0x6e,0x00,0xc0,0x0c,0x00,0x21,0x00,0x01,
0x00,0x01,0x51,0x80,0x00,0x16,0x00,0x00,0x00,0x01,0x00,0x09,0x04,0x73,0x6c,0x6f,
0x77,0x05,0x77,0x69,0x66,0x69,0x36,0x03,0x6c,0x61,0x6e,0x00,0xc0,0x62,0x00,0x02,
0x00,0x01,0x00,0x01,0x51,0x80,0x00,0x05,0x02,0x70,0x69,0xc0,0x62,0xc0,0x5d,0x00,
0x01,0x00,0x01,0x00,0x01,0x51,0x80,0x00,0x04,0x0a,0x18,0x00,0x02,0xc0,0x3b,0x00,
0x01,0x00,0x01,0x00,0x01,0x51,0x80,0x00,0x04,0x0a,0x18,0x00,0x02,0xc0,0x79,0x00,
0x01,0x00,0x01,0x00,0x01,0x51,0x80,0x00,0x04,0x0a,0x18,0x00,0x02,0x00,0x00,0x29,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x00,0x0a,0x00,0x18,0x86,0x1f,0x14,0x0f,
0x41,0xfa,0xf3,0x95,0x48,0x6e,0x79,0x61,0x61,0x78,0x32,0x0f,0x44,0x5d,0x21,0x47,
0x85,0x83,0x9a,0x95
};
// valid DNS message but misreport packet size;
// before fix, parser headed into uncharted waters on requesting additional section
// buffer with space for valid packet plus garbage bytes
const size_t bigsz{512};
uint8_t big_packet[bigsz];
// copy valid packet
std::copy(payload,
payload + sizeof(payload),
big_packet);
// fill additional bytes with junk
std::fill(big_packet + sizeof(payload),
big_packet + bigsz,
0x5A);
// initial packet parse ok
const DNS packet(big_packet, bigsz);
// RR's parse ok now
EXPECT_EQ(packet.questions_count(), 1);
EXPECT_EQ(packet.answers_count(), 2);
EXPECT_EQ(packet.authority_count(), 1);
EXPECT_EQ(packet.additional_count(), 4);
EXPECT_EQ(packet.queries().size(), 1U);
EXPECT_EQ(packet.answers().size(), 2U);
EXPECT_EQ(packet.authority().size(), 1U);
EXPECT_EQ(packet.additional().size(), 4U);
}

292
tests/src/rtp_test.cpp Normal file
View File

@@ -0,0 +1,292 @@
#include <gtest/gtest.h>
#include <string>
#include <tins/endianness.h>
#include <tins/ethernetII.h>
#include <tins/ip.h>
#include <tins/udp.h>
#include <tins/pdu.h>
#include <tins/rawpdu.h>
#include <tins/small_uint.h>
#include <tins/rtp.h>
#define PACKET_SIZE 60ul
#define CSRC_COUNT 5
#define EXTENSION_LENGTH 2
#define PAYLOAD_SIZE 12
using namespace std;
using namespace Tins;
class RTPTest : public testing::Test {
public:
static const uint8_t expected_packet[PACKET_SIZE];
static const uint8_t invalid_packet_one[];
static const uint8_t invalid_packet_two[];
static const uint8_t packet_with_zero_padding_value[];
static const uint8_t packet_without_data_one[];
static const uint8_t packet_without_data_two[];
static const uint8_t packet_with_zero_extension_length[];
static const small_uint<2> version;
static const small_uint<1> padding;
static const small_uint<1> extension;
static const small_uint<4> csrc_count;
static const small_uint<1> marker;
static const small_uint<7> payload_type;
static const uint16_t sequence_number;
static const uint32_t timestamp;
static const uint32_t ssrc_id;
static const uint32_t csrc_ids[CSRC_COUNT];
static const uint16_t profile;
static const uint16_t extension_length;
static const uint32_t extension_data[EXTENSION_LENGTH];
static const uint8_t padding_size;
static const uint8_t payload[PAYLOAD_SIZE];
static const uint16_t dport, sport;
static const IP::address_type dst_ip, src_ip;
static const EthernetII::address_type dst_addr, src_addr;
};
const uint8_t RTPTest::expected_packet[PACKET_SIZE] = {
0xb5, 0xaa, 0xa4, 0x10,
0xde, 0xad, 0xbe, 0xef,
0xab, 0xcd, 0xad, 0xbc,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x05,
0x01, 0x01, 0x00, 0x02,
0x77, 0x00, 0x00, 0x00,
0x88, 0x00, 0x00, 0x00,
0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42,
0x00, 0x00, 0x00, 0x04,
};
const uint8_t RTPTest::invalid_packet_one[] = {
160, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0xff,
};
const uint8_t RTPTest::invalid_packet_two[] = {
160, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
};
const uint8_t RTPTest::packet_with_zero_padding_value[] = {
160, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
};
const uint8_t RTPTest::packet_without_data_one[] = {
128, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
};
const uint8_t RTPTest::packet_without_data_two[] = {
160, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 7,
};
const uint8_t RTPTest::packet_with_zero_extension_length[] = {
144, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0x56, 0x97, 0, 0,
};
const small_uint<2> RTPTest::version = 2;
const small_uint<1> RTPTest::padding = 1;
const small_uint<1> RTPTest::extension = 1;
const small_uint<4> RTPTest::csrc_count = CSRC_COUNT;
const small_uint<1> RTPTest::marker = 1;
const small_uint<7> RTPTest::payload_type = 42;
const uint16_t RTPTest::sequence_number = 42000;
const uint32_t RTPTest::timestamp = 0xdeadbeef;
const uint32_t RTPTest::ssrc_id = 0xabcdadbc;
const uint32_t RTPTest::csrc_ids[CSRC_COUNT] = { 1, 2, 3, 4, 5 };
const uint16_t RTPTest::profile = 0x0101;
const uint16_t RTPTest::extension_length = EXTENSION_LENGTH;
const uint32_t RTPTest::extension_data[EXTENSION_LENGTH] = { 0x77000000, 0x88000000 };
const uint8_t RTPTest::padding_size = 4;
const uint8_t RTPTest::payload[PAYLOAD_SIZE] = {
0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42,
};
const uint16_t RTPTest::dport = 5004;
const uint16_t RTPTest::sport = 30000;
const IP::address_type RTPTest::dst_ip = IP::address_type{"2.2.2.2"};
const IP::address_type RTPTest::src_ip = IP::address_type{"1.1.1.1"};
const EthernetII::address_type RTPTest::dst_addr = EthernetII::address_type{"aa:bb:cc:dd:ee:ff"};
const EthernetII::address_type RTPTest::src_addr = EthernetII::address_type{"8a:8b:8c:8d:8e:8f"};
TEST_F(RTPTest, DefaultConstructor) {
auto const rtp = RTP{};
EXPECT_EQ(rtp.version(), version);
EXPECT_EQ(rtp.padding_bit(), 0);
EXPECT_EQ(rtp.extension_bit(), 0);
EXPECT_EQ(rtp.csrc_count(), 0);
EXPECT_EQ(rtp.marker_bit(), 0);
EXPECT_EQ(rtp.payload_type(), 0);
EXPECT_EQ(rtp.sequence_number(), 0);
EXPECT_EQ(rtp.timestamp(), 0);
EXPECT_EQ(rtp.ssrc_id(), 0);
EXPECT_EQ(rtp.csrc_ids().size(), 0);
EXPECT_EQ(rtp.extension_profile(), 0);
EXPECT_EQ(rtp.extension_length(), 0);
EXPECT_EQ(rtp.extension_data().size(), 0);
EXPECT_EQ(rtp.padding_size(), 0);
EXPECT_EQ(rtp.header_size(), 12);
EXPECT_EQ(rtp.trailer_size(), 0);
}
TEST_F(RTPTest, Serialize) {
auto rtp = RTP{};
rtp.version(version);
rtp.padding_size(padding_size);
rtp.extension_bit(extension);
rtp.marker_bit(marker);
rtp.payload_type(payload_type);
rtp.sequence_number(sequence_number);
rtp.timestamp(timestamp);
rtp.ssrc_id(ssrc_id);
for (auto csrc_id : csrc_ids) {
rtp.add_csrc_id(csrc_id);
}
rtp.extension_profile(profile);
for (auto data : extension_data) {
rtp.add_extension_data(data);
}
auto raw_pdu = RawPDU(payload, PAYLOAD_SIZE);
rtp.inner_pdu(raw_pdu);
EXPECT_EQ(rtp.header_size(), PACKET_SIZE - PAYLOAD_SIZE - padding_size);
EXPECT_EQ(rtp.trailer_size(), padding_size);
auto serialized = rtp.serialize();
ASSERT_EQ(serialized.size(), PACKET_SIZE);
EXPECT_TRUE(std::equal(serialized.begin(), serialized.end(), expected_packet));
}
TEST_F(RTPTest, ConstructorFromBuffer) {
auto rtp = RTP{expected_packet, PACKET_SIZE};
EXPECT_EQ(rtp.version(), version);
EXPECT_EQ(rtp.padding_bit(), padding);
EXPECT_EQ(rtp.extension_bit(), extension);
EXPECT_EQ(rtp.csrc_count(), csrc_count);
EXPECT_EQ(rtp.marker_bit(), marker);
EXPECT_EQ(rtp.payload_type(), payload_type);
EXPECT_EQ(rtp.sequence_number(), sequence_number);
EXPECT_EQ(rtp.timestamp(), timestamp);
EXPECT_EQ(rtp.ssrc_id(), ssrc_id);
auto csrc_id_values = rtp.csrc_ids();
for (size_t i = 0; i < csrc_count; ++i) {
EXPECT_EQ(csrc_id_values[i], Endian::host_to_be(csrc_ids[i]));
}
EXPECT_EQ(rtp.extension_profile(), profile);
EXPECT_EQ(rtp.extension_length(), extension_length);
auto extension_data_values = rtp.extension_data();
for (size_t i = 0; i < extension_length; ++i) {
EXPECT_EQ(extension_data_values[i], Endian::host_to_be(extension_data[i]));
}
EXPECT_EQ(rtp.padding_size(), padding_size);
EXPECT_EQ(rtp.header_size(), PACKET_SIZE - PAYLOAD_SIZE - padding_size);
auto inner_pdu_payload = rtp.inner_pdu()->serialize();
EXPECT_TRUE(std::equal(inner_pdu_payload.begin(), inner_pdu_payload.end(), payload));
auto raw_pdu = RawPDU(payload, PAYLOAD_SIZE);
auto raw_pdu_payload = raw_pdu.serialize();
EXPECT_EQ(rtp.inner_pdu()->size(), raw_pdu.size());
EXPECT_EQ(inner_pdu_payload, raw_pdu_payload);
}
TEST_F(RTPTest, SearchAndRemoveCSRCID) {
auto rtp = RTP{};
for (auto csrc_id : csrc_ids) {
rtp.add_csrc_id(csrc_id);
}
for (size_t i = 0; i < csrc_count; ++i) {
EXPECT_TRUE(rtp.search_csrc_id(csrc_ids[i]));
}
EXPECT_FALSE(rtp.search_csrc_id(0));
EXPECT_FALSE(rtp.remove_csrc_id(0));
EXPECT_TRUE(rtp.remove_csrc_id(csrc_ids[0]));
EXPECT_FALSE(rtp.search_csrc_id(csrc_ids[0]));
}
TEST_F(RTPTest, SearchAndRemoveExtensionData) {
auto rtp = RTP{};
for (auto data : extension_data) {
rtp.add_extension_data(data);
}
for (size_t i = 0; i < extension_length; ++i) {
EXPECT_TRUE(rtp.search_extension_data(extension_data[i]));
}
EXPECT_FALSE(rtp.search_extension_data(0));
EXPECT_FALSE(rtp.remove_extension_data(0));
EXPECT_TRUE(rtp.remove_extension_data(extension_data[0]));
EXPECT_FALSE(rtp.search_extension_data(extension_data[0]));
}
TEST_F(RTPTest, OuterUDP) {
auto pkt = EthernetII{dst_addr, src_addr} / IP{dst_ip, src_ip} / UDP{dport, sport} / RTP{expected_packet, PACKET_SIZE};
auto udp = pkt.find_pdu<UDP>();
ASSERT_TRUE(udp != nullptr);
EXPECT_EQ(udp->dport(), dport);
EXPECT_EQ(udp->sport(), sport);
auto rtp = udp->find_pdu<RTP>();
ASSERT_TRUE(rtp != nullptr);
EXPECT_EQ(rtp->header_size(), PACKET_SIZE - PAYLOAD_SIZE - padding_size);
EXPECT_EQ(rtp->trailer_size(), padding_size);
EXPECT_EQ(rtp->size(), PACKET_SIZE);
EXPECT_EQ(rtp->inner_pdu()->size(), PAYLOAD_SIZE);
auto inner_pdu_payload = rtp->inner_pdu()->serialize();
EXPECT_TRUE(std::equal(inner_pdu_payload.begin(), inner_pdu_payload.end(), payload));
}
TEST_F(RTPTest, PaddingSizeTooLarge) {
EXPECT_THROW((RTP{invalid_packet_one, sizeof(invalid_packet_one)}), malformed_packet);
}
TEST_F(RTPTest, PaddingBitSetWithoutPadding) {
EXPECT_THROW((RTP{invalid_packet_two, sizeof(invalid_packet_two)}), malformed_packet);
}
TEST_F(RTPTest, PacketWithInvalidZeroPaddingValue) {
EXPECT_THROW((RTP{packet_with_zero_padding_value, sizeof(packet_with_zero_padding_value)}), malformed_packet);
}
TEST_F(RTPTest, PacketWithoutData) {
auto rtp = RTP{packet_without_data_one, sizeof(packet_without_data_one)};
EXPECT_EQ(rtp.size(), sizeof(packet_without_data_one));
EXPECT_EQ(rtp.header_size(), sizeof(packet_without_data_one));
EXPECT_EQ(rtp.inner_pdu(), nullptr);
EXPECT_EQ(rtp.padding_size(), 0);
const uint8_t padding_size_ = 7;
rtp = RTP{packet_without_data_two, sizeof(packet_without_data_two)};
EXPECT_EQ(rtp.size(), sizeof(packet_without_data_two));
EXPECT_EQ(rtp.header_size(), sizeof(packet_without_data_two) - padding_size_);
EXPECT_EQ(rtp.inner_pdu(), nullptr);
EXPECT_EQ(rtp.padding_size(), padding_size_);
}
TEST_F(RTPTest, PacketWithZeroExtensionLength) {
auto rtp = RTP{packet_with_zero_extension_length, sizeof(packet_with_zero_extension_length)};
EXPECT_EQ(rtp.size(), sizeof(packet_with_zero_extension_length));
EXPECT_EQ(rtp.header_size(), sizeof(packet_with_zero_extension_length));
EXPECT_EQ(rtp.extension_profile(), 0x5697);
EXPECT_EQ(rtp.extension_length(), 0);
EXPECT_EQ(rtp.extension_data().size(), 0);
}

94
tests/src/vxlan_test.cpp Normal file
View File

@@ -0,0 +1,94 @@
#include <gtest/gtest.h>
#include <string>
#include <tins/ethernetII.h>
#include <tins/ip.h>
#include <tins/tcp.h>
#include <tins/udp.h>
#include <tins/pdu.h>
#include <tins/small_uint.h>
#include <tins/vxlan.h>
#define PACKET_SIZE 68ul
using namespace std;
using namespace Tins;
class VXLANTest : public testing::Test {
public:
static const uint8_t expected_packet[PACKET_SIZE];
static const uint8_t flags;
static const uint16_t dport, sport, p_type;
static const small_uint<24> vni;
static const IP::address_type dst_ip, src_ip;
static const EthernetII::address_type dst_addr, src_addr;
};
const uint8_t VXLANTest::expected_packet[PACKET_SIZE] = {
0x08, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0x00,
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const uint8_t VXLANTest::flags = 8;
const uint16_t VXLANTest::dport = 4789;
const uint16_t VXLANTest::sport = 19627;
const uint16_t VXLANTest::p_type = 0xd0ab;
const small_uint<24> VXLANTest::vni = 0xffffff;
const IP::address_type VXLANTest::dst_ip = IP::address_type{"2.2.2.2"};
const IP::address_type VXLANTest::src_ip = IP::address_type{"1.1.1.1"};
const EthernetII::address_type VXLANTest::dst_addr = EthernetII::address_type{"aa:bb:cc:dd:ee:ff"};
const EthernetII::address_type VXLANTest::src_addr = EthernetII::address_type{"8a:8b:8c:8d:8e:8f"};
TEST_F(VXLANTest, Flags) {
auto const vxlan = VXLAN{};
EXPECT_EQ(vxlan.get_flags(), flags);
}
TEST_F(VXLANTest, VNI) {
auto const vxlan = VXLAN{vni};
EXPECT_EQ(vxlan.get_vni(), vni);
}
TEST_F(VXLANTest, Find) {
auto const pdu = VXLAN{} / EthernetII{dst_addr, src_addr};
auto const eth = pdu.find_pdu<EthernetII>();
ASSERT_TRUE(eth != nullptr);
EXPECT_EQ(eth->dst_addr(), dst_addr);
EXPECT_EQ(eth->src_addr(), src_addr);
}
TEST_F(VXLANTest, Serialize) {
auto eth = EthernetII{dst_addr, src_addr};
eth.payload_type(p_type);
auto vxlan = VXLAN{vni};
vxlan.inner_pdu(eth);
auto serialized = vxlan.serialize();
ASSERT_EQ(serialized.size(), PACKET_SIZE);
EXPECT_TRUE(std::equal(serialized.begin(), serialized.end(), expected_packet));
}
TEST_F(VXLANTest, ConstructorFromBuffer) {
auto vxlan = VXLAN{expected_packet, PACKET_SIZE};
EXPECT_EQ(vxlan.get_vni(), vni);
EXPECT_EQ(vxlan.get_flags(), flags);
auto const eth = vxlan.find_pdu<EthernetII>();
ASSERT_TRUE(eth != nullptr);
EXPECT_EQ(eth->dst_addr(), dst_addr);
EXPECT_EQ(eth->src_addr(), src_addr);
}
TEST_F(VXLANTest, OuterUDP) {
auto pkt = IP{dst_ip, src_ip} / UDP{dport, sport} / VXLAN{expected_packet, PACKET_SIZE};
auto const udp = pkt.find_pdu<UDP>();
ASSERT_TRUE(udp != nullptr);
EXPECT_EQ(udp->dport(), dport);
EXPECT_EQ(udp->sport(), sport);
auto const vxlan = udp->find_pdu<VXLAN>();
ASSERT_TRUE(vxlan != nullptr);
EXPECT_EQ(vxlan->get_flags(), flags);
EXPECT_EQ(vxlan->get_vni(), vni);
}