mirror of
https://github.com/mfontanini/libtins
synced 2026-01-23 10:45:57 +01:00
Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67c81199fb | ||
|
|
fe22186623 | ||
|
|
bbac2ece52 | ||
|
|
ba9a2155ca | ||
|
|
00619e0500 | ||
|
|
64da67ca56 | ||
|
|
3943700830 | ||
|
|
142b6f62cb | ||
|
|
dfd2701ee4 | ||
|
|
850bb9b642 | ||
|
|
b7e61f4c76 | ||
|
|
e2a14d8898 | ||
|
|
ba0c820852 | ||
|
|
df509e7e36 | ||
|
|
fa87e1b6f6 | ||
|
|
812be7966d | ||
|
|
f89cc9f076 | ||
|
|
638bf9b34b | ||
|
|
eb997f5438 | ||
|
|
18cbab4fc7 | ||
|
|
7cd2b2c396 | ||
|
|
2601493752 | ||
|
|
7204fbd688 | ||
|
|
c302e659d7 | ||
|
|
54e4e4b0f4 | ||
|
|
6a17e59032 | ||
|
|
e3aedc56ed | ||
|
|
3b006c15db | ||
|
|
177d0b4621 | ||
|
|
24ac038c30 | ||
|
|
a619e4ff98 | ||
|
|
14bb185d7a | ||
|
|
137b56d5a7 | ||
|
|
ed2b3c12d5 | ||
|
|
1650b60234 | ||
|
|
c20c82bcb5 | ||
|
|
5858132261 | ||
|
|
16f5795243 | ||
|
|
e90e377b73 | ||
|
|
222611b377 | ||
|
|
b447c664e1 | ||
|
|
468159e6d2 | ||
|
|
cd40b232e7 | ||
|
|
1166094a2f | ||
|
|
b3d874d6a8 | ||
|
|
553b1fb255 | ||
|
|
94939dd0fa | ||
|
|
0774a8dcad |
28
.github/workflows/tests.yaml
vendored
Normal file
28
.github/workflows/tests.yaml
vendored
Normal 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
|
||||
46
CHANGES.md
46
CHANGES.md
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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_);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
#include <functional>
|
||||
#include <stdint.h>
|
||||
#include <cstdint>
|
||||
#include <tins/cxxstd.h>
|
||||
#include <tins/macros.h>
|
||||
|
||||
|
||||
@@ -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>).
|
||||
|
||||
@@ -180,6 +180,8 @@ public:
|
||||
PKTAP,
|
||||
MPLS,
|
||||
DOT11_CONTROL_TA,
|
||||
VXLAN,
|
||||
RTP,
|
||||
UNKNOWN = 999,
|
||||
USER_DEFINED_PDU = 1000
|
||||
};
|
||||
|
||||
@@ -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
328
include/tins/rtp.h
Normal 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
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
98
include/tins/vxlan.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
32
src/dns.cpp
32
src/dns.cpp
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
12
src/ipv6.cpp
12
src/ipv6.cpp
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
195
src/rtp.cpp
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
36
src/vxlan.cpp
Normal 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
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
292
tests/src/rtp_test.cpp
Normal 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
94
tests/src/vxlan_test.cpp
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user