mirror of
https://github.com/mfontanini/libtins
synced 2026-01-27 20:24:26 +01:00
Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3aedc56ed | ||
|
|
3b006c15db | ||
|
|
177d0b4621 | ||
|
|
24ac038c30 | ||
|
|
a619e4ff98 | ||
|
|
14bb185d7a | ||
|
|
137b56d5a7 | ||
|
|
ed2b3c12d5 | ||
|
|
1650b60234 | ||
|
|
c20c82bcb5 | ||
|
|
5858132261 | ||
|
|
16f5795243 | ||
|
|
e90e377b73 | ||
|
|
222611b377 | ||
|
|
b447c664e1 | ||
|
|
468159e6d2 | ||
|
|
cd40b232e7 | ||
|
|
1166094a2f | ||
|
|
b3d874d6a8 | ||
|
|
553b1fb255 | ||
|
|
94939dd0fa | ||
|
|
0774a8dcad | ||
|
|
f46dee9f19 | ||
|
|
5b082a82b2 | ||
|
|
07012648fb | ||
|
|
ce409dbc7e | ||
|
|
16e77146ab | ||
|
|
a87c4a64f5 | ||
|
|
9e61286a59 | ||
|
|
8da102fb48 | ||
|
|
750c3556d9 | ||
|
|
28663b0e93 | ||
|
|
731e36e373 | ||
|
|
608b48f25c | ||
|
|
de247fcbc8 | ||
|
|
7bc4d38470 | ||
|
|
a926b75224 | ||
|
|
064439236c | ||
|
|
0c40a0714b | ||
|
|
d74520768b | ||
|
|
3385df9cc9 | ||
|
|
18c31b20f5 | ||
|
|
7387912ca1 | ||
|
|
0d52763a61 | ||
|
|
86b505f998 | ||
|
|
62a803c55c | ||
|
|
0573808aeb | ||
|
|
22b4435c81 | ||
|
|
b803959e11 | ||
|
|
2f16497bf8 | ||
|
|
78aa7d1787 | ||
|
|
ba2216e6e9 | ||
|
|
74e3d909e6 |
38
CHANGES.md
38
CHANGES.md
@@ -1,3 +1,41 @@
|
|||||||
|
##### 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)
|
||||||
|
|
||||||
|
- Don't consider IPv6 ESP header a normal extension header (#374)
|
||||||
|
|
||||||
|
- Don't include non-existing headers when installed without libpcap (#382)
|
||||||
|
|
||||||
|
- Add `IPv6Address::is_local_unicast` (#369)
|
||||||
|
|
||||||
|
- Fix memory leak in `PacketWriter` (#343)
|
||||||
|
|
||||||
|
- Fix memory leaks in `OfflinePacketFilter` (#343)
|
||||||
|
|
||||||
|
- Fix detection of new TCP stream (#335)
|
||||||
|
|
||||||
|
- Introduce `TCP::has_flags` (#334)
|
||||||
|
|
||||||
|
- Fix padding calculations in RadioTapWriter (#333)
|
||||||
|
|
||||||
##### v4.2 - Fri Mar 8 04:15:13 UTC 2019
|
##### v4.2 - Fri Mar 8 04:15:13 UTC 2019
|
||||||
|
|
||||||
- Updated location of installed CMake files in unix systems (#331)
|
- Updated location of installed CMake files in unix systems (#331)
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ ENDIF(LIBTINS_BUILD_SHARED)
|
|||||||
|
|
||||||
# The version number.
|
# The version number.
|
||||||
SET(TINS_VERSION_MAJOR 4)
|
SET(TINS_VERSION_MAJOR 4)
|
||||||
SET(TINS_VERSION_MINOR 2)
|
SET(TINS_VERSION_MINOR 4)
|
||||||
SET(TINS_VERSION_PATCH 0)
|
SET(TINS_VERSION_PATCH 0)
|
||||||
SET(LIBTINS_VERSION "${TINS_VERSION_MAJOR}.${TINS_VERSION_MINOR}")
|
SET(LIBTINS_VERSION "${TINS_VERSION_MAJOR}.${TINS_VERSION_MINOR}")
|
||||||
|
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ bool Scanner::callback(PDU& pdu) {
|
|||||||
cout << "Port: " << setw(5) << tcp.sport() << " closed\n";
|
cout << "Port: " << setw(5) << tcp.sport() << " closed\n";
|
||||||
}
|
}
|
||||||
// Is SYN flag on? Then port is open!
|
// Is SYN flag on? Then port is open!
|
||||||
else if(tcp.flags() == (TCP::SYN | TCP::ACK)) {
|
else if(tcp.has_flags(TCP::SYN | TCP::ACK)) {
|
||||||
cout << "Port: " << setw(5) << tcp.sport() << " open\n";
|
cout << "Port: " << setw(5) << tcp.sport() << " open\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ private:
|
|||||||
const IP& ip = pdu.rfind_pdu<IP>();
|
const IP& ip = pdu.rfind_pdu<IP>();
|
||||||
const TCP& tcp = pdu.rfind_pdu<TCP>();
|
const TCP& tcp = pdu.rfind_pdu<TCP>();
|
||||||
// We'll only close a connection when seeing a SYN|ACK
|
// We'll only close a connection when seeing a SYN|ACK
|
||||||
if (tcp.flags() == (TCP::SYN | TCP::ACK)) {
|
if (tcp.has_flags(TCP::SYN | TCP::ACK)) {
|
||||||
// Create an ethernet header flipping the addresses
|
// Create an ethernet header flipping the addresses
|
||||||
EthernetII packet(eth.src_addr(), eth.dst_addr());
|
EthernetII packet(eth.src_addr(), eth.dst_addr());
|
||||||
// Do the same for IP
|
// Do the same for IP
|
||||||
|
|||||||
@@ -652,7 +652,7 @@ public:
|
|||||||
// Getters
|
// Getters
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Setter for the id field.
|
* \brief Getter for the id field.
|
||||||
*
|
*
|
||||||
* \return uint16_t containing the value of 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
|
* \return QRType containing the value of the query response
|
||||||
* field.
|
* 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.
|
* \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
|
* \return uint8_t containing the value of the authoritative
|
||||||
* answer field.
|
* 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.
|
* \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
|
* \return uint8_t containing the value of the recursion
|
||||||
* desired field.
|
* 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
|
* \return uint8_t containing the value of the recursion
|
||||||
* available field.
|
* 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.
|
* \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
|
* \return uint8_t containing the value of the authenticated
|
||||||
* data field.
|
* 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
|
* \return uint8_t containing the value of the checking
|
||||||
* disabled field.
|
* 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.
|
* \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.
|
* \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.
|
* \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.
|
* \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.
|
* \return uint16_t containing the value of the additional field.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -97,6 +97,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
class TINS_API Dot11ControlTA : public Dot11Control {
|
class TINS_API Dot11ControlTA : public Dot11Control {
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* \brief This PDU's flag.
|
||||||
|
*/
|
||||||
|
static const PDU::PDUType pdu_flag = PDU::DOT11_CONTROL_TA;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Getter for the target address field.
|
* \brief Getter for the target address field.
|
||||||
*/
|
*/
|
||||||
@@ -109,6 +114,15 @@ public:
|
|||||||
* \param addr The new target address.
|
* \param addr The new target address.
|
||||||
*/
|
*/
|
||||||
void target_addr(const address_type& addr);
|
void target_addr(const address_type& addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Check whether this PDU matches the specified flag.
|
||||||
|
* \param flag The flag to match
|
||||||
|
* \sa PDU::matches_flag
|
||||||
|
*/
|
||||||
|
bool matches_flag(PDUType flag) const {
|
||||||
|
return flag == pdu_flag || Dot11::matches_flag(flag);
|
||||||
|
}
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* \brief Constructor for creating a 802.11 control frame TA PDU
|
* \brief Constructor for creating a 802.11 control frame TA PDU
|
||||||
|
|||||||
@@ -64,8 +64,26 @@ public:
|
|||||||
class malformed_packet : public exception_base {
|
class malformed_packet : public exception_base {
|
||||||
public:
|
public:
|
||||||
malformed_packet() : exception_base("Malformed packet") { }
|
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.
|
* \brief Exception thrown when serializing a packet fails.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -89,7 +89,9 @@ public:
|
|||||||
INFO_REQUEST = 15,
|
INFO_REQUEST = 15,
|
||||||
INFO_REPLY = 16,
|
INFO_REPLY = 16,
|
||||||
ADDRESS_MASK_REQUEST = 17,
|
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.
|
* \return Returns the gateway field value.
|
||||||
*/
|
*/
|
||||||
address_type gateway() const {
|
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.
|
* \return Returns the address mask value.
|
||||||
*/
|
*/
|
||||||
address_type address_mask() const {
|
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_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -92,7 +92,9 @@ public:
|
|||||||
MULTICAST_ROUTER_ADVERT = 151,
|
MULTICAST_ROUTER_ADVERT = 151,
|
||||||
MULTICAST_ROUTER_SOLICIT = 152,
|
MULTICAST_ROUTER_SOLICIT = 152,
|
||||||
MULTICAST_ROUTER_TERMINATE = 153,
|
MULTICAST_ROUTER_TERMINATE = 153,
|
||||||
RPL_CONTROL_MSG = 155
|
RPL_CONTROL_MSG = 155,
|
||||||
|
EXTENDED_ECHO_REQUEST = 160,
|
||||||
|
EXTENDED_ECHO_REPLY = 161
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -173,7 +175,7 @@ public:
|
|||||||
|
|
||||||
addr_list_type(const addresses_type& addresses = addresses_type())
|
addr_list_type(const addresses_type& addresses = addresses_type())
|
||||||
: addresses(addresses) {
|
: addresses(addresses) {
|
||||||
std::fill(reserved, reserved + sizeof(reserved), 0);
|
std::fill(reserved, reserved + sizeof(reserved), static_cast<uint8_t>(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static addr_list_type from_option(const option& opt);
|
static addr_list_type from_option(const option& opt);
|
||||||
@@ -199,7 +201,7 @@ public:
|
|||||||
|
|
||||||
naack_type(uint8_t code = 0, uint8_t status = 0)
|
naack_type(uint8_t code = 0, uint8_t status = 0)
|
||||||
: code(code), status(status) {
|
: code(code), status(status) {
|
||||||
std::fill(reserved, reserved + 4, 0);
|
std::fill(reserved, reserved + 4, static_cast<uint8_t>(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static naack_type from_option(const option& opt);
|
static naack_type from_option(const option& opt);
|
||||||
@@ -323,7 +325,7 @@ public:
|
|||||||
* The key_hash member will be 0-initialized.
|
* The key_hash member will be 0-initialized.
|
||||||
*/
|
*/
|
||||||
rsa_sign_type() {
|
rsa_sign_type() {
|
||||||
std::fill(key_hash, key_hash + sizeof(key_hash), 0);
|
std::fill(key_hash, key_hash + sizeof(key_hash), static_cast<uint8_t>(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static rsa_sign_type from_option(const option& opt);
|
static rsa_sign_type from_option(const option& opt);
|
||||||
@@ -489,7 +491,7 @@ public:
|
|||||||
|
|
||||||
timestamp_type(uint64_t timestamp = 0)
|
timestamp_type(uint64_t timestamp = 0)
|
||||||
: timestamp(timestamp) {
|
: timestamp(timestamp) {
|
||||||
std::fill(reserved, reserved + sizeof(reserved), 0);
|
std::fill(reserved, reserved + sizeof(reserved), static_cast<uint8_t>(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static timestamp_type from_option(const option& opt);
|
static timestamp_type from_option(const option& opt);
|
||||||
|
|||||||
@@ -174,9 +174,9 @@ public:
|
|||||||
option_identifier(OptionNumber number, OptionClass op_class,
|
option_identifier(OptionNumber number, OptionClass op_class,
|
||||||
small_uint<1> copied)
|
small_uint<1> copied)
|
||||||
#if TINS_IS_LITTLE_ENDIAN
|
#if TINS_IS_LITTLE_ENDIAN
|
||||||
: number(number), op_class(op_class), copied(copied) {}
|
: number(static_cast<uint8_t>(number)), op_class(static_cast<uint8_t>(op_class)), copied(copied) {}
|
||||||
#else
|
#else
|
||||||
: copied(copied), op_class(op_class), number(number) {}
|
: copied(copied), op_class(static_cast<uint8_t>(op_class)), number(static_cast<uint8_t>(number)) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -230,6 +230,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool is_multicast() const;
|
bool is_multicast() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Return true if this is a Link-Local unicast IPv6 address.
|
||||||
|
*
|
||||||
|
* This method returns true if this address is in the address range
|
||||||
|
* fe80::/10, false otherwise
|
||||||
|
*/
|
||||||
|
bool is_local_unicast() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Returns the size of an IPv6 Address.
|
* \brief Returns the size of an IPv6 Address.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ public:
|
|||||||
* \return The LLC frame format.
|
* \return The LLC frame format.
|
||||||
*/
|
*/
|
||||||
uint8_t type() {
|
uint8_t type() {
|
||||||
return type_;
|
return static_cast<uint8_t>(type_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -245,7 +245,7 @@ public:
|
|||||||
* \return The sender send sequence number if format is INFORMATION else 0.
|
* \return The sender send sequence number if format is INFORMATION else 0.
|
||||||
*/
|
*/
|
||||||
uint8_t send_seq_number() {
|
uint8_t send_seq_number() {
|
||||||
return (type() == INFORMATION) ? (control_field.info.send_seq_num) : 0;
|
return static_cast<uint8_t>((type() == INFORMATION) ? (control_field.info.send_seq_num) : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -65,7 +65,9 @@ class PDU;
|
|||||||
* - Those that don't contain a link layer PDU. In this case, the
|
* - Those that don't contain a link layer PDU. In this case, the
|
||||||
* kernel will be responsible for picking the appropriate network interface
|
* kernel will be responsible for picking the appropriate network interface
|
||||||
* based on the destination address.
|
* 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:
|
* \par Note for Windows users:
|
||||||
* Sending layer 3 PDUs (without a link layer protocol) is very restricted
|
* 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>).
|
* on Windows (<a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms740548(v=vs.85).aspx">link</a>).
|
||||||
|
|||||||
@@ -179,6 +179,7 @@ public:
|
|||||||
IPSEC_ESP,
|
IPSEC_ESP,
|
||||||
PKTAP,
|
PKTAP,
|
||||||
MPLS,
|
MPLS,
|
||||||
|
DOT11_CONTROL_TA,
|
||||||
UNKNOWN = 999,
|
UNKNOWN = 999,
|
||||||
USER_DEFINED_PDU = 1000
|
USER_DEFINED_PDU = 1000
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -288,7 +288,7 @@ public:
|
|||||||
* \code
|
* \code
|
||||||
* TCP tcp = ...;
|
* TCP tcp = ...;
|
||||||
* if(tcp.flags() == (TCP::SYN | TCP::ACK)) {
|
* if(tcp.flags() == (TCP::SYN | TCP::ACK)) {
|
||||||
* // It's a SYN+ACK!
|
* // It's a SYN+ACK, but not SYN+ACK+ECN!
|
||||||
* }
|
* }
|
||||||
* \endcode
|
* \endcode
|
||||||
*
|
*
|
||||||
@@ -296,6 +296,22 @@ public:
|
|||||||
*/
|
*/
|
||||||
small_uint<12> flags() const;
|
small_uint<12> flags() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Check if the given flags are set.
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* 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)
|
||||||
|
* }
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* \param check_flags
|
||||||
|
* \return true if all check_flags are set
|
||||||
|
*/
|
||||||
|
bool has_flags(small_uint<12> check_flags) const;
|
||||||
|
|
||||||
/* Setters */
|
/* Setters */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -49,16 +49,19 @@
|
|||||||
#include <tins/ipv6.h>
|
#include <tins/ipv6.h>
|
||||||
#include <tins/mpls.h>
|
#include <tins/mpls.h>
|
||||||
#include <tins/packet_sender.h>
|
#include <tins/packet_sender.h>
|
||||||
#include <tins/packet_writer.h>
|
|
||||||
#include <tins/pdu.h>
|
#include <tins/pdu.h>
|
||||||
#include <tins/radiotap.h>
|
#include <tins/radiotap.h>
|
||||||
#include <tins/rawpdu.h>
|
#include <tins/rawpdu.h>
|
||||||
#include <tins/snap.h>
|
#include <tins/snap.h>
|
||||||
#include <tins/sniffer.h>
|
|
||||||
#include <tins/tcp.h>
|
#include <tins/tcp.h>
|
||||||
#include <tins/udp.h>
|
#include <tins/udp.h>
|
||||||
#include <tins/utils.h>
|
#include <tins/utils.h>
|
||||||
|
#if defined(TINS_HAVE_PCAP)
|
||||||
|
#include <tins/packet_writer.h>
|
||||||
|
#include <tins/sniffer.h>
|
||||||
|
#include <tins/ppi.h>
|
||||||
#include <tins/tcp_stream.h>
|
#include <tins/tcp_stream.h>
|
||||||
|
#endif
|
||||||
#include <tins/crypto.h>
|
#include <tins/crypto.h>
|
||||||
#include <tins/pdu_cacher.h>
|
#include <tins/pdu_cacher.h>
|
||||||
#include <tins/rsn_information.h>
|
#include <tins/rsn_information.h>
|
||||||
@@ -75,7 +78,7 @@
|
|||||||
#include <tins/pdu_allocator.h>
|
#include <tins/pdu_allocator.h>
|
||||||
#include <tins/ipsec.h>
|
#include <tins/ipsec.h>
|
||||||
#include <tins/ip_reassembler.h>
|
#include <tins/ip_reassembler.h>
|
||||||
#include <tins/ppi.h>
|
|
||||||
#include <tins/pdu_iterator.h>
|
#include <tins/pdu_iterator.h>
|
||||||
|
|
||||||
#endif // TINS_TINS_H
|
#endif // TINS_TINS_H
|
||||||
|
|||||||
@@ -336,7 +336,11 @@ 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 = &records_data_[0] + records_data_.size();
|
||||||
const uint8_t* end_ptr = 0;
|
const uint8_t* end_ptr = 0;
|
||||||
char* current_out_ptr = out_ptr;
|
char* current_out_ptr = out_ptr;
|
||||||
|
uint8_t pointer_counter = 0;
|
||||||
while (*ptr) {
|
while (*ptr) {
|
||||||
|
if (pointer_counter++ > 30){
|
||||||
|
throw dns_decompression_pointer_loops();
|
||||||
|
}
|
||||||
// It's an offset
|
// It's an offset
|
||||||
if ((*ptr & 0xc0)) {
|
if ((*ptr & 0xc0)) {
|
||||||
if (TINS_UNLIKELY(ptr + sizeof(uint16_t) > end)) {
|
if (TINS_UNLIKELY(ptr + sizeof(uint16_t) > end)) {
|
||||||
@@ -347,7 +351,7 @@ uint32_t DNS::compose_name(const uint8_t* ptr, char* out_ptr) const {
|
|||||||
index = Endian::be_to_host(index) & 0x3fff;
|
index = Endian::be_to_host(index) & 0x3fff;
|
||||||
// Check that the offset is neither too low or too high
|
// Check that the offset is neither too low or too high
|
||||||
if (index < 0x0c || (&records_data_[0] + (index - 0x0c)) >= end) {
|
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.
|
// We've probably found the end of the original domain name. Save it.
|
||||||
if (end_ptr == 0) {
|
if (end_ptr == 0) {
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ void ICMP::sequence(uint16_t new_seq) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ICMP::gateway(address_type new_gw) {
|
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) {
|
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) {
|
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 {
|
uint32_t ICMP::header_size() const {
|
||||||
|
|||||||
14
src/ipv6.cpp
14
src/ipv6.cpp
@@ -32,6 +32,9 @@
|
|||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#else
|
#else
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
#endif
|
#endif
|
||||||
#include <tins/ipv6.h>
|
#include <tins/ipv6.h>
|
||||||
@@ -204,8 +207,8 @@ IPv6::IPv6(const uint8_t* buffer, uint32_t total_sz) {
|
|||||||
bool IPv6::is_extension_header(uint8_t header_id) {
|
bool IPv6::is_extension_header(uint8_t header_id) {
|
||||||
return header_id == HOP_BY_HOP || header_id == DESTINATION_ROUTING_OPTIONS
|
return header_id == HOP_BY_HOP || header_id == DESTINATION_ROUTING_OPTIONS
|
||||||
|| header_id == ROUTING || header_id == FRAGMENT || header_id == AUTHENTICATION
|
|| header_id == ROUTING || header_id == FRAGMENT || header_id == AUTHENTICATION
|
||||||
|| header_id == SECURITY_ENCAPSULATION || header_id == DESTINATION_OPTIONS
|
|| header_id == DESTINATION_OPTIONS || header_id == MOBILITY
|
||||||
|| header_id == MOBILITY || header_id == NO_NEXT_HEADER;
|
|| header_id == NO_NEXT_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t IPv6::get_padding_size(const ext_header& header) {
|
uint32_t IPv6::get_padding_size(const ext_header& header) {
|
||||||
@@ -366,11 +369,16 @@ void IPv6::write_serialization(uint8_t* buffer, uint32_t total_sz) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef BSD
|
#ifndef BSD
|
||||||
void IPv6::send(PacketSender& sender, const NetworkInterface &) {
|
void IPv6::send(PacketSender& sender, const NetworkInterface& interface) {
|
||||||
sockaddr_in6 link_addr;
|
sockaddr_in6 link_addr;
|
||||||
const PacketSender::SocketType type = PacketSender::IPV6_SOCKET;
|
const PacketSender::SocketType type = PacketSender::IPV6_SOCKET;
|
||||||
link_addr.sin6_family = AF_INET6;
|
link_addr.sin6_family = AF_INET6;
|
||||||
link_addr.sin6_port = 0;
|
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);
|
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);
|
sender.send_l3(*this, (struct sockaddr*)&link_addr, sizeof(link_addr), type);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ namespace Tins {
|
|||||||
|
|
||||||
const IPv6Address loopback_address = "::1";
|
const IPv6Address loopback_address = "::1";
|
||||||
const AddressRange<IPv6Address> multicast_range = IPv6Address("ff00::") / 8;
|
const AddressRange<IPv6Address> multicast_range = IPv6Address("ff00::") / 8;
|
||||||
|
const AddressRange<IPv6Address> local_unicast_range = IPv6Address("fe80::") / 10;
|
||||||
|
|
||||||
IPv6Address IPv6Address::from_prefix_length(uint32_t prefix_length) {
|
IPv6Address IPv6Address::from_prefix_length(uint32_t prefix_length) {
|
||||||
IPv6Address address;
|
IPv6Address address;
|
||||||
@@ -138,6 +139,10 @@ bool IPv6Address::is_multicast() const {
|
|||||||
return multicast_range.contains(*this);
|
return multicast_range.contains(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IPv6Address::is_local_unicast() const {
|
||||||
|
return local_unicast_range.contains(*this);
|
||||||
|
}
|
||||||
|
|
||||||
ostream& operator<<(ostream& os, const IPv6Address& addr) {
|
ostream& operator<<(ostream& os, const IPv6Address& addr) {
|
||||||
return os << addr.to_string();
|
return os << addr.to_string();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,11 +37,14 @@ using std::string;
|
|||||||
namespace Tins {
|
namespace Tins {
|
||||||
|
|
||||||
OfflinePacketFilter::OfflinePacketFilter(const OfflinePacketFilter& other) {
|
OfflinePacketFilter::OfflinePacketFilter(const OfflinePacketFilter& other) {
|
||||||
*this = other;
|
string_filter_ = other.string_filter_;
|
||||||
|
init(string_filter_, pcap_datalink(other.handle_), pcap_snapshot(other.handle_));
|
||||||
}
|
}
|
||||||
|
|
||||||
OfflinePacketFilter& OfflinePacketFilter::operator=(const OfflinePacketFilter& other) {
|
OfflinePacketFilter& OfflinePacketFilter::operator=(const OfflinePacketFilter& other) {
|
||||||
string_filter_ = other.string_filter_;
|
string_filter_ = other.string_filter_;
|
||||||
|
pcap_freecode(&filter_);
|
||||||
|
pcap_close(handle_);
|
||||||
init(string_filter_, pcap_datalink(other.handle_), pcap_snapshot(other.handle_));
|
init(string_filter_, pcap_datalink(other.handle_), pcap_snapshot(other.handle_));
|
||||||
return* this;
|
return* this;
|
||||||
}
|
}
|
||||||
@@ -58,8 +61,14 @@ void OfflinePacketFilter::init(const string& pcap_filter,
|
|||||||
link_type,
|
link_type,
|
||||||
snap_len
|
snap_len
|
||||||
);
|
);
|
||||||
|
if (!handle_) {
|
||||||
|
throw pcap_open_failed();
|
||||||
|
}
|
||||||
if (pcap_compile(handle_, &filter_, pcap_filter.c_str(), 1, 0xffffffff) == -1) {
|
if (pcap_compile(handle_, &filter_, pcap_filter.c_str(), 1, 0xffffffff) == -1) {
|
||||||
throw invalid_pcap_filter(pcap_geterr(handle_));
|
string error(pcap_geterr(handle_));
|
||||||
|
pcap_freecode(&filter_);
|
||||||
|
pcap_close(handle_);
|
||||||
|
throw invalid_pcap_filter(error.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -267,6 +267,11 @@ void PacketSender::open_l3_socket(SocketType type) {
|
|||||||
#endif
|
#endif
|
||||||
const int level = (is_v6) ? IPPROTO_IPV6 : IPPROTO_IP;
|
const int level = (is_v6) ? IPPROTO_IPV6 : IPPROTO_IP;
|
||||||
if (setsockopt(sockfd, level, IP_HDRINCL, (option_ptr)&on, sizeof(on)) != 0) {
|
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());
|
throw socket_open_error(make_error_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,8 +86,9 @@ void PacketWriter::init(const string& file_name, int link_type) {
|
|||||||
}
|
}
|
||||||
dumper_ = pcap_dump_open(handle_, file_name.c_str());
|
dumper_ = pcap_dump_open(handle_, file_name.c_str());
|
||||||
if (!dumper_) {
|
if (!dumper_) {
|
||||||
|
string error(pcap_geterr(handle_));
|
||||||
pcap_close(handle_);
|
pcap_close(handle_);
|
||||||
throw pcap_error(pcap_geterr(handle_));
|
throw pcap_error(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -257,6 +257,10 @@ small_uint<12> TCP::flags() const {
|
|||||||
return (header_.res1 << 8) | header_.flags_8;
|
return (header_.res1 << 8) | header_.flags_8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TCP::has_flags(small_uint<12> check_flags) const {
|
||||||
|
return (flags() & check_flags) == check_flags;
|
||||||
|
}
|
||||||
|
|
||||||
void TCP::set_flag(Flags tcp_flag, small_uint<1> value) {
|
void TCP::set_flag(Flags tcp_flag, small_uint<1> value) {
|
||||||
switch (tcp_flag) {
|
switch (tcp_flag) {
|
||||||
case FIN:
|
case FIN:
|
||||||
|
|||||||
@@ -127,19 +127,19 @@ void Flow::advance_sequence(uint32_t seq) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Flow::update_state(const TCP& tcp) {
|
void Flow::update_state(const TCP& tcp) {
|
||||||
if ((tcp.flags() & TCP::FIN) != 0) {
|
if (tcp.has_flags(TCP::FIN)) {
|
||||||
state_ = FIN_SENT;
|
state_ = FIN_SENT;
|
||||||
}
|
}
|
||||||
else if ((tcp.flags() & TCP::RST) != 0) {
|
else if (tcp.has_flags(TCP::RST)) {
|
||||||
state_ = RST_SENT;
|
state_ = RST_SENT;
|
||||||
}
|
}
|
||||||
else if (state_ == SYN_SENT && (tcp.flags() & TCP::ACK) != 0) {
|
else if (state_ == SYN_SENT && tcp.has_flags(TCP::ACK)) {
|
||||||
#ifdef TINS_HAVE_ACK_TRACKER
|
#ifdef TINS_HAVE_ACK_TRACKER
|
||||||
ack_tracker_ = AckTracker(tcp.ack_seq());
|
ack_tracker_ = AckTracker(tcp.ack_seq());
|
||||||
#endif // TINS_HAVE_ACK_TRACKER
|
#endif // TINS_HAVE_ACK_TRACKER
|
||||||
state_ = ESTABLISHED;
|
state_ = ESTABLISHED;
|
||||||
}
|
}
|
||||||
else if (state_ == UNKNOWN && (tcp.flags() & TCP::SYN) != 0) {
|
else if (state_ == UNKNOWN && tcp.has_flags(TCP::SYN)) {
|
||||||
// This is the server's state, sending it's first SYN|ACK
|
// This is the server's state, sending it's first SYN|ACK
|
||||||
#ifdef TINS_HAVE_ACK_TRACKER
|
#ifdef TINS_HAVE_ACK_TRACKER
|
||||||
ack_tracker_ = AckTracker(tcp.ack_seq());
|
ack_tracker_ = AckTracker(tcp.ack_seq());
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ Stream::Stream(PDU& packet, const timestamp_type& ts)
|
|||||||
}
|
}
|
||||||
const TCP& tcp = packet.rfind_pdu<TCP>();
|
const TCP& tcp = packet.rfind_pdu<TCP>();
|
||||||
// If this is not the first packet of a stream (SYN), then it's a partial stream
|
// If this is not the first packet of a stream (SYN), then it's a partial stream
|
||||||
is_partial_stream_ = tcp.flags() != TCP::SYN;
|
is_partial_stream_ = !tcp.has_flags(TCP::SYN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::process_packet(PDU& packet, const timestamp_type& ts) {
|
void Stream::process_packet(PDU& packet, const timestamp_type& ts) {
|
||||||
|
|||||||
@@ -84,7 +84,9 @@ void StreamFollower::process_packet(PDU& packet, const timestamp_type& ts) {
|
|||||||
if (iter == streams_.end()) {
|
if (iter == streams_.end()) {
|
||||||
// Start tracking if they're either SYNs or they contain data (attach
|
// Start tracking if they're either SYNs or they contain data (attach
|
||||||
// to an already running flow).
|
// to an already running flow).
|
||||||
if (tcp->flags() == TCP::SYN || (attach_to_flows_ && tcp->find_pdu<RawPDU>() != 0)) {
|
// Start on client's SYN, not on server's SYN+ACK
|
||||||
|
const bool is_syn = tcp->has_flags(TCP::SYN) && !tcp->has_flags(TCP::ACK);
|
||||||
|
if (is_syn || (attach_to_flows_ && tcp->find_pdu<RawPDU>() != 0)) {
|
||||||
iter = streams_.insert(make_pair(identifier, Stream(packet, ts))).first;
|
iter = streams_.insert(make_pair(identifier, Stream(packet, ts))).first;
|
||||||
iter->second.setup_flows_callbacks();
|
iter->second.setup_flows_callbacks();
|
||||||
if (on_new_connection_) {
|
if (on_new_connection_) {
|
||||||
@@ -93,7 +95,7 @@ void StreamFollower::process_packet(PDU& packet, const timestamp_type& ts) {
|
|||||||
else {
|
else {
|
||||||
throw callback_not_set();
|
throw callback_not_set();
|
||||||
}
|
}
|
||||||
if (tcp->flags() != TCP::SYN) {
|
if (!is_syn) {
|
||||||
// assume the connection is established
|
// assume the connection is established
|
||||||
iter->second.client_flow().state(Flow::ESTABLISHED);
|
iter->second.client_flow().state(Flow::ESTABLISHED);
|
||||||
iter->second.server_flow().state(Flow::ESTABLISHED);
|
iter->second.server_flow().state(Flow::ESTABLISHED);
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ bool TCPStream::generic_process(uint32_t& my_seq,
|
|||||||
|
|
||||||
bool TCPStream::update(IP* ip, TCP* tcp) {
|
bool TCPStream::update(IP* ip, TCP* tcp) {
|
||||||
if (!syn_ack_sent_) {
|
if (!syn_ack_sent_) {
|
||||||
if (tcp->flags() == (TCP::SYN | TCP::ACK)) {
|
if (tcp->has_flags(TCP::SYN | TCP::ACK)) {
|
||||||
server_seq_ = tcp->seq() + 1;
|
server_seq_ = tcp->seq() + 1;
|
||||||
client_seq_ = tcp->ack_seq();
|
client_seq_ = tcp->ack_seq();
|
||||||
syn_ack_sent_ = true;
|
syn_ack_sent_ = true;
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ struct RadioTapFlags {
|
|||||||
} TINS_END_PACK;
|
} TINS_END_PACK;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void align_buffer(const uint8_t* buffer_start, const uint8_t*& buffer, uint32_t size, size_t n) {
|
void align_buffer(const uint8_t* buffer_start, const uint8_t*& buffer, size_t n) {
|
||||||
uint32_t offset = (buffer - buffer_start) & (n - 1);
|
uint32_t offset = (buffer - buffer_start) & (n - 1);
|
||||||
if (offset) {
|
if (offset) {
|
||||||
offset = n - offset;
|
offset = n - offset;
|
||||||
@@ -278,7 +278,7 @@ bool RadioTapParser::advance_to_next_field() {
|
|||||||
if (current_bit_ < MAX_RADIOTAP_FIELD) {
|
if (current_bit_ < MAX_RADIOTAP_FIELD) {
|
||||||
const uint8_t* radiotap_start = start_ - sizeof(uint32_t);
|
const uint8_t* radiotap_start = start_ - sizeof(uint32_t);
|
||||||
// Skip and align the buffer
|
// Skip and align the buffer
|
||||||
align_buffer(radiotap_start, current_ptr_, end_ - radiotap_start,
|
align_buffer(radiotap_start, current_ptr_,
|
||||||
RADIOTAP_METADATA[current_bit_].alignment);
|
RADIOTAP_METADATA[current_bit_].alignment);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,11 +41,12 @@ namespace Tins {
|
|||||||
namespace Utils {
|
namespace Utils {
|
||||||
|
|
||||||
uint32_t calculate_padding(uint32_t alignment, uint32_t offset) {
|
uint32_t calculate_padding(uint32_t alignment, uint32_t offset) {
|
||||||
return offset % alignment;
|
uint32_t extra = offset % alignment;
|
||||||
|
return extra == 0 ? 0 : alignment - extra;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t get_bit(uint32_t value) {
|
uint32_t get_bit(uint32_t value) {
|
||||||
return log(value) / log(2);
|
return round(log2(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
RadioTapWriter::RadioTapWriter(vector<uint8_t>& buffer)
|
RadioTapWriter::RadioTapWriter(vector<uint8_t>& buffer)
|
||||||
@@ -54,7 +55,7 @@ RadioTapWriter::RadioTapWriter(vector<uint8_t>& buffer)
|
|||||||
|
|
||||||
void RadioTapWriter::write_option(const RadioTap::option& option) {
|
void RadioTapWriter::write_option(const RadioTap::option& option) {
|
||||||
const uint32_t bit = get_bit(option.option());
|
const uint32_t bit = get_bit(option.option());
|
||||||
if (bit > RadioTapParser::MAX_RADIOTAP_FIELD) {
|
if (bit >= RadioTapParser::MAX_RADIOTAP_FIELD) {
|
||||||
throw malformed_option();
|
throw malformed_option();
|
||||||
}
|
}
|
||||||
const bool is_empty = buffer_.empty();
|
const bool is_empty = buffer_.empty();
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ vector<char> query_route_table(int family) {
|
|||||||
throw exception_base("sysctl failed");
|
throw exception_base("sysctl failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf.resize(len);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ private:
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void ActiveTestRunner::add_test() {
|
void ActiveTestRunner::add_test() {
|
||||||
tests_.emplace_back(new T(packet_sender_, configuration_));
|
tests_.emplace_back(std::unique_ptr<T>(new T(packet_sender_, configuration_)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TINS_ACTIVE_TEST_RUNNER_H
|
#endif // TINS_ACTIVE_TEST_RUNNER_H
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ const uint8_t DHCPTest::expected_packet[] = {
|
|||||||
TEST_F(DHCPTest, DefaultConstructor) {
|
TEST_F(DHCPTest, DefaultConstructor) {
|
||||||
DHCP dhcp;
|
DHCP dhcp;
|
||||||
EXPECT_EQ(dhcp.htype(), 1);
|
EXPECT_EQ(dhcp.htype(), 1);
|
||||||
EXPECT_EQ(dhcp.hlen(), (const size_t)EthernetII::address_type::address_size);
|
EXPECT_EQ(dhcp.hlen(), (size_t)EthernetII::address_type::address_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DHCPTest, CopyConstructor) {
|
TEST_F(DHCPTest, CopyConstructor) {
|
||||||
@@ -280,7 +280,7 @@ TEST_F(DHCPTest, ConstructorFromBuffer) {
|
|||||||
|
|
||||||
EXPECT_EQ(dhcp1.opcode(), DHCP::DISCOVER);
|
EXPECT_EQ(dhcp1.opcode(), DHCP::DISCOVER);
|
||||||
EXPECT_EQ(dhcp1.htype(), 1);
|
EXPECT_EQ(dhcp1.htype(), 1);
|
||||||
ASSERT_EQ(dhcp1.hlen(), (const size_t)EthernetII::address_type::address_size);
|
ASSERT_EQ(dhcp1.hlen(), (size_t)EthernetII::address_type::address_size);
|
||||||
EXPECT_EQ(dhcp1.hops(), 0x1f);
|
EXPECT_EQ(dhcp1.hops(), 0x1f);
|
||||||
EXPECT_EQ(dhcp1.xid(), 0x3fab23deU);
|
EXPECT_EQ(dhcp1.xid(), 0x3fab23deU);
|
||||||
EXPECT_EQ(dhcp1.secs(), 0x9f1a);
|
EXPECT_EQ(dhcp1.secs(), 0x9f1a);
|
||||||
|
|||||||
@@ -759,4 +759,27 @@ TEST_F(RadioTapTest, RadioTapWritingEmptyBuffer) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(RadioTapTest, RadioTapWritingInvalidOption) {
|
||||||
|
vector<uint8_t> buffer(4, 0);
|
||||||
|
RadioTapWriter writer(buffer);
|
||||||
|
uint8_t foo = 0;
|
||||||
|
RadioTap::option option((RadioTap::PresentFlags)(1 << RadioTapParser::MAX_RADIOTAP_FIELD), sizeof(foo), &foo);
|
||||||
|
EXPECT_THROW(writer.write_option(option), malformed_option);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RadioTapTest, RadioTapWriterAlignment) {
|
||||||
|
vector<uint8_t> buffer(4, 0);
|
||||||
|
RadioTapWriter writer(buffer);
|
||||||
|
uint8_t flags = 10;
|
||||||
|
uint8_t xchannel[sizeof(RadioTap::xchannel_type)] = {
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8
|
||||||
|
};
|
||||||
|
writer.write_option(RadioTap::option(RadioTap::FLAGS, sizeof(flags), &flags));
|
||||||
|
writer.write_option(RadioTap::option(RadioTap::XCHANNEL, sizeof(xchannel), xchannel));
|
||||||
|
vector<uint8_t> expected = {
|
||||||
|
2, 0, 4, 0, 10, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8
|
||||||
|
};
|
||||||
|
EXPECT_EQ(buffer, expected);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // TINS_HAVE_DOT11
|
#endif // TINS_HAVE_DOT11
|
||||||
|
|||||||
Reference in New Issue
Block a user