mirror of
https://github.com/pavel-odintsov/fastnetmon
synced 2024-11-23 13:22:36 +01:00
Reworked packet parser to avoid data modification in buffer during parsing process
This commit is contained in:
parent
0019093823
commit
e019b46802
@ -4,6 +4,7 @@
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
|
||||
#include "fast_endianless.hpp"
|
||||
@ -11,13 +12,16 @@
|
||||
#include "iana_ethertypes.hpp"
|
||||
#include "iana_ip_protocols.hpp"
|
||||
|
||||
// Get rid of this include and replace ntohs, ntohl by fast_endianless logic calls
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
//
|
||||
// If you have an idea to add unions to "improve" this code please stop and think.
|
||||
//
|
||||
// More details about issue https://en.cppreference.com/w/cpp/language/union
|
||||
//
|
||||
// "It is undefined behavior to read from the member of the union that wasn't most recently written. Many compilers implement,
|
||||
// as a non-standard language extension, the ability to read inactive members of a union."
|
||||
//
|
||||
// Few more additional details: https://stackoverflow.com/questions/53074726/c-union-struct-bitfield-implementation-and-portability/53074781#53074781
|
||||
//
|
||||
|
||||
// This function could copy X bytes from src to dst.
|
||||
// Where X - size of dst object (referenced by pointer)
|
||||
@ -26,17 +30,31 @@ template <typename dst_type, typename src_type> inline void* smart_memcpy(dst_ty
|
||||
}
|
||||
|
||||
namespace network_data_stuctures {
|
||||
/* We are using this structure as pretty interface for IPv4 address bytes in
|
||||
* host byte order (little
|
||||
* endian) */
|
||||
struct __attribute__((__packed__)) ipv4_octets_form_little_endian_t {
|
||||
|
||||
// We are using this structure as pretty interface for IPv4 address bytes in host byte order (little endian)
|
||||
class __attribute__((__packed__)) ipv4_octets_form_little_endian_t {
|
||||
public:
|
||||
uint8_t fourth = 0;
|
||||
uint8_t third = 0;
|
||||
uint8_t second = 0;
|
||||
uint8_t first = 0;
|
||||
};
|
||||
|
||||
// Convert IP as integer to string representation
|
||||
static_assert(sizeof(ipv4_octets_form_little_endian_t) == 4, "Bad size for ipv4_octets_form_little_endian_t");
|
||||
|
||||
|
||||
class __attribute__((__packed__)) ipv4_octets_form_big_endian_t {
|
||||
public:
|
||||
uint8_t first = 0;
|
||||
uint8_t second = 0;
|
||||
uint8_t third = 0;
|
||||
uint8_t fourth = 0;
|
||||
};
|
||||
|
||||
static_assert(sizeof(ipv4_octets_form_big_endian_t) == 4, "Bad size for ipv4_octets_form_big_endian_t");
|
||||
|
||||
|
||||
// Convert IP as integer in little endian to string representation
|
||||
inline std::string convert_ip_as_little_endian_to_string(uint32_t ip) {
|
||||
/*
|
||||
Actually we could use inet_ntoa but it's implementation uses not very
|
||||
@ -64,8 +82,36 @@ inline std::string convert_ip_as_little_endian_to_string(uint32_t ip) {
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
// Convert IP as integer in big endian to string representation
|
||||
inline std::string convert_ip_as_big_endian_to_string(uint32_t ip) {
|
||||
/*
|
||||
Actually we could use inet_ntoa but it's implementation uses not very
|
||||
convenient data
|
||||
structures (struct in_addr)
|
||||
Also it has multi thread issues (because it's using common buffer) and it
|
||||
solved by thread
|
||||
local storage.
|
||||
Which could produce performance issues too (chec http://www.agner.org)
|
||||
|
||||
Here you could
|
||||
https://github.com/bminor/glibc/blob/0a1f1e78fbdfaf2c01e9c2368023b2533e7136cf/inet/inet_ntoa.c#L31
|
||||
And has known performance issues: https://github.com/h2o/qrintf
|
||||
I decided to implement it manually
|
||||
*/
|
||||
|
||||
const size_t max_ip_as_string_size = 16; // Maximum string length as integer
|
||||
char buffer[max_ip_as_string_size];
|
||||
|
||||
ipv4_octets_form_big_endian_t* ipv4_octets = (ipv4_octets_form_big_endian_t*)&ip;
|
||||
|
||||
snprintf(buffer, max_ip_as_string_size, "%d.%d.%d.%d", ipv4_octets->first, ipv4_octets->second, ipv4_octets->third,
|
||||
ipv4_octets->fourth);
|
||||
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
// Here we are using very cryptic form of pointer to fixed size array
|
||||
inline std::string convert_mac_to_string(uint8_t (&mac_as_array)[6]) {
|
||||
inline std::string convert_mac_to_string(const uint8_t (&mac_as_array)[6]) {
|
||||
std::stringstream buffer;
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
@ -98,31 +144,74 @@ class __attribute__((__packed__)) mpls_label_t {
|
||||
|
||||
static_assert(sizeof(mpls_label_t) == 4, "Bad size for mpls_label_t");
|
||||
|
||||
// We are storing VLAN meta data and next ethertype in same packet
|
||||
// It's not standard approach! Be careful!
|
||||
class __attribute__((__packed__)) ethernet_vlan_header_t {
|
||||
// In this class we keep vlan id, priority and cfi
|
||||
class __attribute__((__packed__)) ethernet_vlan_metadata_t {
|
||||
public:
|
||||
union __attribute__((__packed__)) {
|
||||
// it's not allowed to initialise each bit field here as we initialize vlan_metadata_as_integer
|
||||
__extension__ struct { uint16_t vlan_id : 12, cfi : 1, priority : 3; };
|
||||
uint16_t vlan_id : 12, cfi : 1, priority : 3;
|
||||
};
|
||||
|
||||
static_assert(sizeof(ethernet_vlan_metadata_t) == 2, "Bad size for ethernet_vlan_metadata_t");
|
||||
|
||||
// We are storing VLAN meta data and next ethertype in same packet
|
||||
// It's not standard approach so be careful
|
||||
class __attribute__((__packed__)) ethernet_vlan_header_t {
|
||||
// We must not access these fields directly as it requires explicit byte order conversion
|
||||
private:
|
||||
uint16_t vlan_metadata_as_integer = 0;
|
||||
};
|
||||
uint16_t ethertype = 0;
|
||||
|
||||
uint16_t ethertype = 0;
|
||||
// We can access data in packet only using special methods which can do all required format conversions
|
||||
public:
|
||||
|
||||
void convert() {
|
||||
ethertype = ntohs(ethertype);
|
||||
vlan_metadata_as_integer = ntohs(vlan_metadata_as_integer);
|
||||
// Returns ethertype in host byte order
|
||||
uint16_t get_ethertype_host_byte_order() const {
|
||||
return fast_ntoh(ethertype);
|
||||
}
|
||||
|
||||
std::string print() {
|
||||
// Returns VLAN id in host byte order. You must call convert before calling it
|
||||
uint16_t get_vlan_id_host_byte_order() const {
|
||||
// Copy whole structure and convert to host byte order
|
||||
uint16_t vlan_metadata_little_endian = fast_ntoh(vlan_metadata_as_integer);
|
||||
|
||||
// Apply mask to retrieve vlan id field
|
||||
// TODO: I'm not 100% sure that it will work correct if cfi or priority are non zero or vlan id is relatively large number
|
||||
const ethernet_vlan_metadata_t* vlan_metadata = (ethernet_vlan_metadata_t*)&vlan_metadata_little_endian;
|
||||
|
||||
return vlan_metadata->vlan_id;
|
||||
}
|
||||
|
||||
// Returns CFI flag. You must call convert before calling it
|
||||
// TODO: We never tested this logic
|
||||
bool get_cfi_flag() const {
|
||||
// Copy whole structure and convert to host byte order
|
||||
uint16_t vlan_metadata_little_endian = fast_ntoh(vlan_metadata_as_integer);
|
||||
|
||||
const ethernet_vlan_metadata_t* vlan_metadata = (ethernet_vlan_metadata_t*)&vlan_metadata_little_endian;
|
||||
|
||||
return vlan_metadata->cfi;
|
||||
}
|
||||
|
||||
// Return priority in host byte order. You must call convert before calling it
|
||||
// TODO: We never tested this logic
|
||||
uint8_t get_priority() const {
|
||||
// Copy whole structure and convert to host byte order
|
||||
uint16_t vlan_metadata_little_endian = fast_ntoh(vlan_metadata_as_integer);
|
||||
|
||||
const ethernet_vlan_metadata_t* vlan_metadata = (ethernet_vlan_metadata_t*)&vlan_metadata_little_endian;
|
||||
|
||||
return vlan_metadata->priority;
|
||||
}
|
||||
|
||||
std::string print() const {
|
||||
std::stringstream buffer;
|
||||
|
||||
buffer << "priority: " << uint32_t(priority) << " "
|
||||
<< "cfi: " << uint32_t(cfi) << " "
|
||||
<< "vlan_id: " << uint32_t(vlan_id) << " ";
|
||||
// We use cast to avoid printing it as char
|
||||
buffer << "priority: " << uint32_t(get_priority()) << " ";
|
||||
|
||||
buffer << "ethertype: 0x" << std::setfill('0') << std::setw(4) << std::hex << ethertype;
|
||||
buffer << "cfi: " << std::boolalpha << get_cfi_flag() << " "
|
||||
<< "vlan_id: " << get_vlan_id_host_byte_order() << " ";
|
||||
|
||||
buffer << "ethertype: 0x" << std::setfill('0') << std::setw(4) << std::hex << get_ethertype_host_byte_order();
|
||||
|
||||
return buffer.str();
|
||||
}
|
||||
@ -134,16 +223,21 @@ class __attribute__((__packed__)) ethernet_header_t {
|
||||
public:
|
||||
uint8_t destination_mac[6];
|
||||
uint8_t source_mac[6];
|
||||
|
||||
private:
|
||||
// We must not access this field directly as it requires explicit byte order conversion
|
||||
uint16_t ethertype = 0;
|
||||
|
||||
void convert() {
|
||||
ethertype = ntohs(ethertype);
|
||||
public:
|
||||
// Returns ethertype in host byte order
|
||||
uint16_t get_ethertype_host_byte_order() {
|
||||
return fast_ntoh(ethertype);
|
||||
}
|
||||
|
||||
std::string print() {
|
||||
std::stringstream buffer;
|
||||
|
||||
buffer << "ethertype: 0x" << std::setfill('0') << std::setw(4) << std::hex << ethertype;
|
||||
buffer << "ethertype: 0x" << std::setfill('0') << std::setw(4) << std::hex << get_ethertype_host_byte_order();
|
||||
|
||||
buffer << " "
|
||||
<< "source mac: " << convert_mac_to_string(source_mac) << " "
|
||||
@ -159,7 +253,8 @@ static_assert(sizeof(ethernet_header_t) == 14, "Bad size for ethernet_header_t")
|
||||
// This structure will work only for IPv4 (4 byte address) + ethernet (6 byte
|
||||
// address)
|
||||
class __attribute__((__packed__)) arp_header_t {
|
||||
public:
|
||||
// These fields must not be accessed directly as we need to convert them to host byte order
|
||||
private:
|
||||
uint16_t hardware_type = 0;
|
||||
uint16_t protocol_type = 0;
|
||||
|
||||
@ -174,77 +269,121 @@ class __attribute__((__packed__)) arp_header_t {
|
||||
uint8_t target_hardware_address[6];
|
||||
uint32_t target_protocol_address = 0;
|
||||
|
||||
void convert() {
|
||||
// 16 bit
|
||||
hardware_type = ntohs(hardware_type);
|
||||
protocol_type = ntohs(protocol_type);
|
||||
operation = ntohs(operation);
|
||||
public:
|
||||
|
||||
// 32 bit
|
||||
sender_protocol_address = ntohl(sender_protocol_address);
|
||||
target_protocol_address = ntohl(target_protocol_address);
|
||||
uint8_t get_hardware_address_length() const {
|
||||
return hardware_address_length;
|
||||
}
|
||||
|
||||
std::string print() {
|
||||
uint8_t get_protocol_address_length() const {
|
||||
return protocol_address_length;
|
||||
}
|
||||
|
||||
uint16_t get_hardware_type_host_byte_order() const {
|
||||
return fast_ntoh(hardware_type);
|
||||
}
|
||||
|
||||
uint16_t get_protocol_type_host_byte_order() const {
|
||||
return fast_ntoh(protocol_type);
|
||||
}
|
||||
|
||||
uint16_t get_operation_host_byte_order() const {
|
||||
return fast_ntoh(operation);
|
||||
}
|
||||
|
||||
// Return it as is
|
||||
uint32_t get_sender_protocol_address_network_byte_order() const {
|
||||
return sender_protocol_address;
|
||||
}
|
||||
|
||||
// Return it as is
|
||||
uint32_t get_target_protocol_address_network_byte_order() const {
|
||||
return target_protocol_address;
|
||||
}
|
||||
|
||||
std::string print() const {
|
||||
std::stringstream buffer;
|
||||
|
||||
buffer << "hardware_type: " << uint32_t(hardware_type) << " "
|
||||
<< "protocol_type: " << uint32_t(protocol_type) << " "
|
||||
<< "hardware_address_length: " << uint32_t(hardware_address_length) << " "
|
||||
<< "protocol_address_length: " << uint32_t(protocol_address_length) << " "
|
||||
<< "operation: " << uint32_t(operation) << " "
|
||||
buffer << "hardware_type: " << get_hardware_type_host_byte_order() << " "
|
||||
<< "protocol_type: " << get_protocol_type_host_byte_order() << " "
|
||||
<< "hardware_address_length: " << uint32_t(get_hardware_address_length()) << " "
|
||||
<< "protocol_address_length: " << uint32_t(get_protocol_address_length()) << " "
|
||||
<< "operation: " << get_operation_host_byte_order() << " "
|
||||
<< "sender_hardware_address: " << convert_mac_to_string(sender_hardware_address) << " "
|
||||
<< "sender_protocol_address: " << convert_ip_as_little_endian_to_string(sender_protocol_address) << " "
|
||||
<< "sender_protocol_address: " << convert_ip_as_big_endian_to_string(get_sender_protocol_address_network_byte_order()) << " "
|
||||
<< "target_hardware_address: " << convert_mac_to_string(target_hardware_address) << " "
|
||||
<< "target_protocol_address: " << convert_ip_as_little_endian_to_string(target_protocol_address);
|
||||
<< "target_protocol_address: " << convert_ip_as_big_endian_to_string(get_target_protocol_address_network_byte_order());
|
||||
|
||||
return buffer.str();
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(arp_header_t) == 28, "Bad size for arp_header_t");
|
||||
|
||||
class __attribute__((__packed__)) icmp_header_t {
|
||||
public:
|
||||
// We must not access these fields directly as they may need conversion
|
||||
private:
|
||||
uint8_t type = 0;
|
||||
uint8_t code = 0;
|
||||
uint16_t checksum = 0;
|
||||
uint32_t rest_of_header = 0;
|
||||
|
||||
void convert() {
|
||||
checksum = htons(checksum);
|
||||
public:
|
||||
uint8_t get_type() const {
|
||||
return type;
|
||||
}
|
||||
|
||||
std::string print() {
|
||||
uint8_t get_code() const {
|
||||
return code;
|
||||
}
|
||||
|
||||
uint16_t get_checksum() const {
|
||||
return fast_ntoh(checksum);
|
||||
}
|
||||
|
||||
std::string print() const {
|
||||
std::stringstream buffer;
|
||||
|
||||
buffer << "type: " << uint32_t(type) << " "
|
||||
<< "code: " << uint32_t(code) << " "
|
||||
<< "checksum: " << uint32_t(checksum);
|
||||
buffer << "type: " << uint32_t(get_type()) << " "
|
||||
<< "code: " << uint32_t(get_code()) << " "
|
||||
<< "checksum: " << uint32_t(get_checksum());
|
||||
|
||||
return buffer.str();
|
||||
}
|
||||
};
|
||||
|
||||
class __attribute__((__packed__)) udp_header_t {
|
||||
public:
|
||||
// We must not access these fields directly as they may need conversion
|
||||
private:
|
||||
uint16_t source_port = 0;
|
||||
uint16_t destination_port = 0;
|
||||
uint16_t length = 0;
|
||||
uint16_t checksum = 0;
|
||||
|
||||
void convert() {
|
||||
source_port = ntohs(source_port);
|
||||
destination_port = ntohs(destination_port);
|
||||
length = ntohs(length);
|
||||
checksum = ntohs(checksum);
|
||||
public:
|
||||
uint16_t get_source_port_host_byte_order() const {
|
||||
return fast_ntoh(source_port);
|
||||
}
|
||||
|
||||
uint16_t get_destination_port_host_byte_order() const {
|
||||
return fast_ntoh(destination_port);
|
||||
}
|
||||
|
||||
uint16_t get_length_host_byte_order() const {
|
||||
return fast_ntoh(length);
|
||||
}
|
||||
|
||||
uint16_t get_checksum_host_byte_order() const {
|
||||
return fast_ntoh(checksum);
|
||||
}
|
||||
|
||||
std::string print() {
|
||||
std::string print() const {
|
||||
std::stringstream buffer;
|
||||
|
||||
buffer << "source_port: " << source_port << " "
|
||||
<< "destination_port: " << destination_port << " "
|
||||
<< "length: " << length << " "
|
||||
<< "checksum: " << checksum;
|
||||
buffer << "source_port: " << get_source_port_host_byte_order() << " "
|
||||
<< "destination_port: " << get_destination_port_host_byte_order() << " "
|
||||
<< "length: " << get_length_host_byte_order() << " "
|
||||
<< "checksum: " << get_checksum_host_byte_order();
|
||||
|
||||
return buffer.str();
|
||||
}
|
||||
@ -253,31 +392,45 @@ class __attribute__((__packed__)) udp_header_t {
|
||||
static_assert(sizeof(udp_header_t) == 8, "Bad size for udp_header_t");
|
||||
|
||||
// https://datatracker.ietf.org/doc/html/rfc2784
|
||||
class __attribute__((__packed__)) gre_packet_t {
|
||||
public:
|
||||
// Not sure about order of them, worth checking in future
|
||||
class __attribute__((__packed__)) gre_header_t {
|
||||
// We must not access these fields directly as they may need conversion
|
||||
private:
|
||||
// TODO: we have no pcaps where these fields are no zeros and we did not test this case
|
||||
// For some reasons PVS thinks that we did not initialised all members. I think they're not that great with bitfields
|
||||
uint16_t checksum : 1 = 0, reserved : 12 = 0, version : 3 = 0; //-V730
|
||||
uint16_t protocol_type = 0;
|
||||
|
||||
void convert() {
|
||||
// 16 bit
|
||||
protocol_type = ntohs(protocol_type);
|
||||
public:
|
||||
|
||||
uint16_t get_protocol_type_host_byte_order() const {
|
||||
return fast_ntoh(protocol_type);
|
||||
}
|
||||
|
||||
std::string print() {
|
||||
uint16_t get_reserved() const {
|
||||
return reserved;
|
||||
}
|
||||
|
||||
uint16_t get_checksum() const {
|
||||
return checksum;
|
||||
}
|
||||
|
||||
uint16_t get_version() const {
|
||||
return version;
|
||||
}
|
||||
|
||||
std::string print() const {
|
||||
std::stringstream buffer;
|
||||
|
||||
buffer << "checksum: " << uint32_t(checksum) << " "
|
||||
<< "reserved: " << uint32_t(reserved) << " "
|
||||
<< "version: " << uint32_t(version) << " "
|
||||
<< "protocol_type: " << uint32_t(protocol_type);
|
||||
buffer << "checksum: " << get_checksum() << " "
|
||||
<< "reserved: " << get_reserved() << " "
|
||||
<< "version: " << get_version() << " "
|
||||
<< "protocol_type: " << get_protocol_type_host_byte_order();
|
||||
|
||||
return buffer.str();
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(gre_packet_t) == 4, "Bad size for gre_packet_t");
|
||||
static_assert(sizeof(gre_header_t) == 4, "Bad size for gre_header_t");
|
||||
|
||||
// It's tcp packet flags represented as bitfield for user friendly access to this flags
|
||||
class __attribute__((__packed__)) tcp_flags_as_uint16_t {
|
||||
@ -316,63 +469,184 @@ class __attribute__((__packed__)) tcp_flags_as_uint32_t {
|
||||
}
|
||||
};
|
||||
|
||||
class __attribute__((__packed__)) tcp_header_t {
|
||||
class __attribute__((__packed__)) tcp_flags_t {
|
||||
public:
|
||||
uint16_t fin : 1, syn : 1, rst : 1, psh : 1, ack : 1, urg : 1, ece : 1, cwr : 1, ns : 1, reserved : 3, data_offset : 4;
|
||||
};
|
||||
|
||||
static_assert(sizeof(tcp_flags_t) == 2, "Bad size for tcp_flags_t");
|
||||
|
||||
class __attribute__((__packed__)) tcp_header_t {
|
||||
// These fields must not be accessed directly as they need decoding
|
||||
private:
|
||||
uint16_t source_port = 0;
|
||||
uint16_t destination_port = 0;
|
||||
uint32_t sequence_number = 0;
|
||||
uint32_t ack_number = 0;
|
||||
union __attribute__((__packed__)) {
|
||||
__extension__ struct __attribute__((__packed__)) {
|
||||
// uint16_t data_offset : 4, reserved : 3, ns : 1, cwr : 1, ece : 1, urg :
|
||||
// 1, ack : 1,
|
||||
// psh : 1, rst : 1, syn : 1, fin : 1;
|
||||
// it's not allowed to initialize each bitfield here as we initialize data_offset_and_flags_as_integer
|
||||
uint16_t fin : 1, syn : 1, rst : 1, psh : 1, ack : 1, urg : 1, ece : 1, cwr : 1, ns : 1, reserved : 3, data_offset : 4;
|
||||
};
|
||||
|
||||
// Flags here encoded as tcp_flags_t
|
||||
uint16_t data_offset_and_flags_as_integer = 0;
|
||||
|
||||
private:
|
||||
|
||||
uint16_t data_offset_and_flags_as_integer = 0;
|
||||
};
|
||||
uint16_t window_size = 0;
|
||||
uint16_t checksum = 0;
|
||||
uint16_t urgent = 0;
|
||||
|
||||
void convert() {
|
||||
// 16 bit data
|
||||
source_port = ntohs(source_port);
|
||||
destination_port = ntohs(destination_port);
|
||||
window_size = ntohs(window_size);
|
||||
checksum = ntohs(checksum);
|
||||
urgent = ntohs(urgent);
|
||||
public:
|
||||
|
||||
data_offset_and_flags_as_integer = ntohs(data_offset_and_flags_as_integer);
|
||||
|
||||
// 32 bit data
|
||||
sequence_number = ntohl(sequence_number);
|
||||
ack_number = ntohl(ack_number);
|
||||
uint16_t get_source_port_host_byte_order() const {
|
||||
return fast_ntoh(source_port);
|
||||
}
|
||||
|
||||
std::string print() {
|
||||
uint16_t get_destination_port_host_byte_order() const {
|
||||
return fast_ntoh(destination_port);
|
||||
}
|
||||
|
||||
uint32_t get_sequence_number_host_byte_order() const {
|
||||
return fast_ntoh(sequence_number);
|
||||
}
|
||||
|
||||
uint32_t get_ack_number_host_byte_order() const {
|
||||
return fast_ntoh(ack_number);
|
||||
}
|
||||
|
||||
uint16_t get_window_size_host_byte_order() const {
|
||||
return fast_ntoh(window_size);
|
||||
}
|
||||
|
||||
uint16_t get_checksum_host_byte_order() const {
|
||||
return fast_ntoh(checksum);
|
||||
}
|
||||
|
||||
uint16_t get_urgent_host_byte_order() const {
|
||||
return fast_ntoh(urgent);
|
||||
}
|
||||
|
||||
uint16_t get_data_offset_and_flags_host_byte_order() const {
|
||||
return fast_ntoh(data_offset_and_flags_as_integer);
|
||||
}
|
||||
|
||||
void set_data_offset(uint8_t data_offset) {
|
||||
uint16_t data_offset_and_flags_as_integer_litle_endian = fast_ntoh(data_offset_and_flags_as_integer);
|
||||
|
||||
tcp_flags_t* tcp_flags = (tcp_flags_t*)&data_offset_and_flags_as_integer_litle_endian;
|
||||
|
||||
tcp_flags->data_offset = data_offset;
|
||||
|
||||
// Re-encode into network byte order again
|
||||
data_offset_and_flags_as_integer = fast_hton(data_offset_and_flags_as_integer_litle_endian);
|
||||
}
|
||||
|
||||
bool get_fin() const {
|
||||
uint16_t data_offset_and_flags_as_integer_litle_endian = fast_ntoh(data_offset_and_flags_as_integer);
|
||||
|
||||
tcp_flags_t* tcp_flags = (tcp_flags_t*)&data_offset_and_flags_as_integer_litle_endian;
|
||||
|
||||
return tcp_flags->fin == 1;
|
||||
}
|
||||
|
||||
bool get_syn() const {
|
||||
uint16_t data_offset_and_flags_as_integer_litle_endian = fast_ntoh(data_offset_and_flags_as_integer);
|
||||
|
||||
tcp_flags_t* tcp_flags = (tcp_flags_t*)&data_offset_and_flags_as_integer_litle_endian;
|
||||
|
||||
return tcp_flags->syn == 1;
|
||||
}
|
||||
|
||||
bool get_rst() const {
|
||||
uint16_t data_offset_and_flags_as_integer_litle_endian = fast_ntoh(data_offset_and_flags_as_integer);
|
||||
|
||||
tcp_flags_t* tcp_flags = (tcp_flags_t*)&data_offset_and_flags_as_integer_litle_endian;
|
||||
|
||||
return tcp_flags->rst == 1;
|
||||
}
|
||||
|
||||
bool get_psh() const {
|
||||
uint16_t data_offset_and_flags_as_integer_litle_endian = fast_ntoh(data_offset_and_flags_as_integer);
|
||||
|
||||
tcp_flags_t* tcp_flags = (tcp_flags_t*)&data_offset_and_flags_as_integer_litle_endian;
|
||||
|
||||
return tcp_flags->psh == 1;
|
||||
}
|
||||
|
||||
bool get_ack() const {
|
||||
uint16_t data_offset_and_flags_as_integer_litle_endian = fast_ntoh(data_offset_and_flags_as_integer);
|
||||
|
||||
tcp_flags_t* tcp_flags = (tcp_flags_t*)&data_offset_and_flags_as_integer_litle_endian;
|
||||
|
||||
return tcp_flags->ack == 1;
|
||||
}
|
||||
|
||||
bool get_urg ()const {
|
||||
uint16_t data_offset_and_flags_as_integer_litle_endian = fast_ntoh(data_offset_and_flags_as_integer);
|
||||
|
||||
tcp_flags_t* tcp_flags = (tcp_flags_t*)&data_offset_and_flags_as_integer_litle_endian;
|
||||
|
||||
return tcp_flags->urg == 1;
|
||||
}
|
||||
|
||||
bool get_ece () const {
|
||||
uint16_t data_offset_and_flags_as_integer_litle_endian = fast_ntoh(data_offset_and_flags_as_integer);
|
||||
|
||||
tcp_flags_t* tcp_flags = (tcp_flags_t*)&data_offset_and_flags_as_integer_litle_endian;
|
||||
|
||||
return tcp_flags->ece == 1;
|
||||
}
|
||||
|
||||
bool get_cwr () const {
|
||||
uint16_t data_offset_and_flags_as_integer_litle_endian = fast_ntoh(data_offset_and_flags_as_integer);
|
||||
|
||||
tcp_flags_t* tcp_flags = (tcp_flags_t*)&data_offset_and_flags_as_integer_litle_endian;
|
||||
|
||||
return tcp_flags->cwr == 1;
|
||||
}
|
||||
|
||||
bool get_ns() const {
|
||||
uint16_t data_offset_and_flags_as_integer_litle_endian = fast_ntoh(data_offset_and_flags_as_integer);
|
||||
|
||||
tcp_flags_t* tcp_flags = (tcp_flags_t*)&data_offset_and_flags_as_integer_litle_endian;
|
||||
|
||||
return tcp_flags->ns == 1;
|
||||
}
|
||||
|
||||
uint8_t get_reserved() const{
|
||||
uint16_t data_offset_and_flags_as_integer_litle_endian = fast_ntoh(data_offset_and_flags_as_integer);
|
||||
|
||||
tcp_flags_t* tcp_flags = (tcp_flags_t*)&data_offset_and_flags_as_integer_litle_endian;
|
||||
|
||||
return tcp_flags->reserved;
|
||||
}
|
||||
|
||||
uint8_t get_data_offset() const {
|
||||
uint16_t data_offset_and_flags_as_integer_litle_endian = fast_ntoh(data_offset_and_flags_as_integer);
|
||||
|
||||
tcp_flags_t* tcp_flags = (tcp_flags_t*)&data_offset_and_flags_as_integer_litle_endian;
|
||||
|
||||
return tcp_flags->data_offset;
|
||||
}
|
||||
|
||||
std::string print() const {
|
||||
std::stringstream buffer;
|
||||
|
||||
buffer << "source_port: " << source_port << " "
|
||||
<< "destination_port: " << destination_port << " "
|
||||
<< "sequence_number: " << sequence_number << " "
|
||||
<< "ack_number: " << ack_number << " "
|
||||
<< "data_offset: " << uint32_t(data_offset) << " "
|
||||
<< "reserved: " << uint32_t(reserved) << " "
|
||||
<< "ns: " << uint32_t(ns) << " "
|
||||
<< "cwr: " << uint32_t(cwr) << " "
|
||||
<< "ece: " << uint32_t(ece) << " "
|
||||
<< "urg: " << uint32_t(urg) << " "
|
||||
<< "ack: " << uint32_t(ack) << " "
|
||||
<< "psh: " << uint32_t(psh) << " "
|
||||
<< "rst: " << uint32_t(rst) << " "
|
||||
<< "syn: " << uint32_t(syn) << " "
|
||||
<< "fin: " << uint32_t(fin) << " "
|
||||
<< "window_size: " << window_size << " "
|
||||
<< "checksum: " << checksum << " "
|
||||
<< "urgent: " << urgent;
|
||||
buffer << "source_port: " << get_source_port_host_byte_order() << " "
|
||||
<< "destination_port: " << get_destination_port_host_byte_order() << " "
|
||||
<< "sequence_number: " << get_sequence_number_host_byte_order() << " "
|
||||
<< "ack_number: " << get_ack_number_host_byte_order() << " "
|
||||
<< "data_offset: " << uint32_t(get_data_offset()) << " "
|
||||
<< "reserved: " << uint32_t(get_reserved()) << " "
|
||||
<< "ns: " << get_ns() << " "
|
||||
<< "cwr: " << get_cwr() << " "
|
||||
<< "ece: " << get_ece() << " "
|
||||
<< "urg: " << get_urg() << " "
|
||||
<< "ack: " << get_ack() << " "
|
||||
<< "psh: " << get_psh() << " "
|
||||
<< "rst: " << get_rst() << " "
|
||||
<< "syn: " << get_syn() << " "
|
||||
<< "fin: " << get_fin() << " "
|
||||
<< "window_size: " << get_window_size_host_byte_order() << " "
|
||||
<< "checksum: " << get_checksum_host_byte_order() << " "
|
||||
<< "urgent: " << get_urgent_host_byte_order();
|
||||
|
||||
return buffer.str();
|
||||
}
|
||||
@ -385,7 +659,7 @@ typedef uint8_t ipv6_address[16];
|
||||
// Custom type for pretty printing
|
||||
typedef uint16_t ipv6_address_16bit_blocks[8];
|
||||
|
||||
inline std::string convert_ipv6_in_byte_array_to_string(uint8_t (&v6_address)[16]) {
|
||||
inline std::string convert_ipv6_in_byte_array_to_string(const uint8_t (&v6_address)[16]) {
|
||||
std::stringstream buffer;
|
||||
|
||||
uint16_t* pretty_print = (uint16_t*)v6_address;
|
||||
@ -413,37 +687,82 @@ inline std::string convert_ipv6_in_byte_array_to_string(uint8_t (&v6_address)[16
|
||||
Encapsulating Security Payload - IpProtocolNumberESP
|
||||
*/
|
||||
|
||||
/* IPv6 fragmentation header option */
|
||||
class __attribute__((__packed__)) ipv6_fragment_header_flags {
|
||||
public:
|
||||
// fragment_offset is a number of 8byte chunk
|
||||
uint16_t more_fragments : 1, reserved2 : 2, fragment_offset : 13;
|
||||
};
|
||||
|
||||
static_assert(sizeof(ipv6_fragment_header_flags) == 2, "Bad size for ipv6_header_flags_t");
|
||||
|
||||
// IPv6 fragmentation header option
|
||||
class __attribute__((__packed__)) ipv6_extension_header_fragment_t {
|
||||
public:
|
||||
private:
|
||||
uint8_t next_header = 0;
|
||||
uint8_t reserved1 = 0;
|
||||
|
||||
union __attribute__((__packed__)) {
|
||||
__extension__ struct {
|
||||
// uint16_t fragment_offset : 13, reserved2 : 2, more_fragments : 1;
|
||||
// it's not allowed to initialize each bitfield here as we initialize fragmentation_and_flags_as_integer
|
||||
uint16_t more_fragments : 1, reserved2 : 2, fragment_offset : 13;
|
||||
};
|
||||
uint16_t fragmentation_and_flags_as_integer = 0;
|
||||
};
|
||||
// Multiple flags in format ipv6_fragment_header_flags
|
||||
uint16_t fragmentation_and_flags_as_integer = 0;
|
||||
|
||||
// We must not access these fields directly as they need proper decoding
|
||||
private:
|
||||
uint32_t identification = 0;
|
||||
|
||||
void convert() {
|
||||
fragmentation_and_flags_as_integer = ntohs(fragmentation_and_flags_as_integer);
|
||||
identification = ntohl(identification);
|
||||
public:
|
||||
|
||||
uint16_t get_more_fragments() const {
|
||||
uint16_t flags_little_endian = fast_ntoh(fragmentation_and_flags_as_integer);
|
||||
|
||||
ipv6_fragment_header_flags* flags = (ipv6_fragment_header_flags*)&flags_little_endian;
|
||||
|
||||
return flags->more_fragments;
|
||||
}
|
||||
|
||||
std::string print() {
|
||||
uint16_t get_reserved2() const {
|
||||
uint16_t flags_little_endian = fast_ntoh(fragmentation_and_flags_as_integer);
|
||||
|
||||
ipv6_fragment_header_flags* flags = (ipv6_fragment_header_flags*)&flags_little_endian;
|
||||
|
||||
return flags->reserved2;
|
||||
}
|
||||
|
||||
uint16_t get_fragment_offset_8byte_chunks() const {
|
||||
uint16_t flags_little_endian = fast_ntoh(fragmentation_and_flags_as_integer);
|
||||
|
||||
ipv6_fragment_header_flags* flags = (ipv6_fragment_header_flags*)&flags_little_endian;
|
||||
|
||||
return flags->fragment_offset;
|
||||
}
|
||||
|
||||
uint16_t get_fragment_offset_bytes() const {
|
||||
uint16_t flags_little_endian = fast_ntoh(fragmentation_and_flags_as_integer);
|
||||
|
||||
ipv6_fragment_header_flags* flags = (ipv6_fragment_header_flags*)&flags_little_endian;
|
||||
|
||||
return flags->fragment_offset * 8;
|
||||
}
|
||||
|
||||
uint8_t get_next_header() const {
|
||||
return next_header;
|
||||
}
|
||||
|
||||
uint8_t get_reserved1() const {
|
||||
return reserved1;
|
||||
}
|
||||
|
||||
uint32_t get_identification_host_byte_order() const {
|
||||
return fast_ntoh(identification);
|
||||
}
|
||||
|
||||
std::string print() const {
|
||||
std::stringstream buffer;
|
||||
|
||||
buffer << "next_header: " << uint32_t(next_header) << " "
|
||||
<< "reserved1: " << uint32_t(reserved1) << " "
|
||||
<< "fragment_offset: " << uint32_t(fragment_offset) << " "
|
||||
<< "reserverd2: " << uint32_t(reserved2) << " "
|
||||
<< "more_fragments: " << uint32_t(more_fragments) << " "
|
||||
<< "identification: " << identification;
|
||||
buffer << "next_header: " << uint32_t(get_next_header()) << " "
|
||||
<< "reserved1: " << uint32_t(get_reserved1()) << " "
|
||||
<< "fragment_offset_bytes: " << uint32_t(get_fragment_offset_bytes()) << " "
|
||||
<< "reserverd2: " << uint32_t(get_reserved2()) << " "
|
||||
<< "more_fragments: " << uint32_t(get_more_fragments()) << " "
|
||||
<< "identification: " << get_identification_host_byte_order();
|
||||
|
||||
return buffer.str();
|
||||
}
|
||||
@ -451,36 +770,72 @@ class __attribute__((__packed__)) ipv6_extension_header_fragment_t {
|
||||
|
||||
static_assert(sizeof(ipv6_extension_header_fragment_t) == 8, "Bad size for ipv6_extension_header_fragment_t");
|
||||
|
||||
class __attribute__((__packed__)) ipv6_header_t {
|
||||
class __attribute__((__packed__)) ipv6_header_flags_t {
|
||||
public:
|
||||
union __attribute__((__packed__)) {
|
||||
// it's not allowed to initialize each bitfield here as we initialize version_and_traffic_class_as_integer
|
||||
__extension__ struct { uint32_t flow_label : 20, traffic_class : 8, version : 4; };
|
||||
uint32_t flow_label : 20, traffic_class : 8, version : 4;
|
||||
};
|
||||
|
||||
uint32_t version_and_traffic_class_as_integer = 0;
|
||||
};
|
||||
static_assert(sizeof(ipv6_header_flags_t) == 4, "Bad size for ipv6_header_flags_t");
|
||||
|
||||
class __attribute__((__packed__)) ipv6_header_t {
|
||||
// We must not access these fields directly as they need decoding
|
||||
private:
|
||||
// Multiple flags carried in ipv6_header_flags_t
|
||||
uint32_t version_and_traffic_class_as_integer = 0;
|
||||
|
||||
uint16_t payload_length = 0;
|
||||
uint8_t next_header = 0;
|
||||
uint8_t hop_limit = 0;
|
||||
|
||||
public:
|
||||
ipv6_address source_address{};
|
||||
ipv6_address destination_address{};
|
||||
|
||||
void convert() {
|
||||
payload_length = ntohs(payload_length);
|
||||
version_and_traffic_class_as_integer = ntohl(version_and_traffic_class_as_integer);
|
||||
uint32_t get_flow_label() const {
|
||||
uint32_t version_and_traffic_class_little_endian = fast_ntoh(version_and_traffic_class_as_integer);
|
||||
|
||||
ipv6_header_flags_t* header_flags = (ipv6_header_flags_t*)&version_and_traffic_class_little_endian;
|
||||
|
||||
return header_flags->flow_label;
|
||||
}
|
||||
|
||||
std::string print() {
|
||||
uint32_t get_traffic_class() const {
|
||||
uint32_t version_and_traffic_class_little_endian = fast_ntoh(version_and_traffic_class_as_integer);
|
||||
|
||||
ipv6_header_flags_t* header_flags = (ipv6_header_flags_t*)&version_and_traffic_class_little_endian;
|
||||
|
||||
return header_flags->traffic_class;
|
||||
}
|
||||
|
||||
uint32_t get_version() const {
|
||||
uint32_t version_and_traffic_class_little_endian = fast_ntoh(version_and_traffic_class_as_integer);
|
||||
|
||||
ipv6_header_flags_t* header_flags = (ipv6_header_flags_t*)&version_and_traffic_class_little_endian;
|
||||
|
||||
return header_flags->version;
|
||||
}
|
||||
|
||||
uint16_t get_payload_length() const {
|
||||
return fast_ntoh(payload_length);
|
||||
}
|
||||
|
||||
uint8_t get_next_header() const {
|
||||
return next_header;
|
||||
}
|
||||
|
||||
uint8_t get_hop_limit() const {
|
||||
return hop_limit;
|
||||
}
|
||||
|
||||
std::string print() const {
|
||||
std::stringstream buffer;
|
||||
|
||||
buffer << "version: " << uint32_t(version) << " "
|
||||
<< "traffic_class: " << uint32_t(traffic_class) << " "
|
||||
<< "flow_label: " << uint32_t(flow_label) << " "
|
||||
<< "payload_length: " << uint32_t(payload_length) << " "
|
||||
<< "next_header: " << uint32_t(next_header) << " "
|
||||
<< "hop_limit: " << uint32_t(hop_limit) << " "
|
||||
buffer << "version: " << get_version() << " "
|
||||
<< "traffic_class: " << get_traffic_class() << " "
|
||||
<< "flow_label: " << get_flow_label() << " "
|
||||
<< "payload_length: " << get_payload_length() << " "
|
||||
<< "next_header: " << uint32_t(get_next_header()) << " "
|
||||
<< "hop_limit: " << uint32_t(get_hop_limit()) << " "
|
||||
<< "source_address: " << convert_ipv6_in_byte_array_to_string(source_address) << " "
|
||||
<< "destination_address: " << convert_ipv6_in_byte_array_to_string(destination_address);
|
||||
|
||||
@ -493,20 +848,8 @@ static_assert(sizeof(ipv6_header_t) == 40, "Bad size for ipv6_header_t");
|
||||
// It's class for fragmentation flag representation. It's pretty useful in some cases
|
||||
class __attribute__((__packed__)) ipv4_header_fragmentation_flags_t {
|
||||
public:
|
||||
union __attribute__((__packed__)) {
|
||||
// We should store bitfields in nested struct. Otherwise each of bitfields
|
||||
// will use same
|
||||
// storage as each other!
|
||||
// We are using GCC extension here. It's working perfectly for clang and gcc
|
||||
// but could
|
||||
// produce warning in pedantic mode
|
||||
// it's not allowed to initialize each bitfield here as we initialize fragmentation_details_as_integer
|
||||
__extension__ struct {
|
||||
uint16_t fragment_offset : 13, more_fragments_flag : 1, dont_fragment_flag : 1, reserved_flag : 1;
|
||||
};
|
||||
|
||||
uint16_t fragmentation_details_as_integer = 0;
|
||||
};
|
||||
// The offset value is the number of 8 byte blocks of data
|
||||
uint16_t fragment_offset : 13, more_fragments_flag : 1, dont_fragment_flag : 1, reserved_flag : 1;
|
||||
|
||||
std::string print() {
|
||||
|
||||
@ -534,7 +877,9 @@ class __attribute__((__packed__)) ipv4_header_fragmentation_flags_as_32bit_t {
|
||||
};
|
||||
|
||||
class __attribute__((__packed__)) ipv4_header_t {
|
||||
public:
|
||||
// We must not access these fields directly as they need conversion
|
||||
private:
|
||||
|
||||
uint8_t ihl : 4 = 0, version : 4 = 0;
|
||||
uint8_t ecn : 2 = 0, dscp : 6 = 0;
|
||||
|
||||
@ -542,78 +887,189 @@ class __attribute__((__packed__)) ipv4_header_t {
|
||||
uint16_t total_length = 0;
|
||||
uint16_t identification = 0;
|
||||
|
||||
union __attribute__((__packed__)) {
|
||||
// We should store bitfields in nested struct. Otherwise each of bitfields
|
||||
// will use same
|
||||
// storage as each other!
|
||||
// We are using GCC extension here. It's working perfectly for clang and gcc
|
||||
// but could
|
||||
// produce warning in pedantic mode
|
||||
// it's not allowed to initialize each bitfield here as we initialize fragmentation_details_as_integer
|
||||
__extension__ struct {
|
||||
uint16_t fragment_offset : 13, more_fragments_flag : 1, dont_fragment_flag : 1, reserved_flag : 1;
|
||||
};
|
||||
|
||||
uint16_t fragmentation_details_as_integer = 0;
|
||||
};
|
||||
// There we have plenty of fragmentation specific fields encoded in ipv4_header_fragmentation_flags_t
|
||||
uint16_t fragmentation_details_as_integer = 0;
|
||||
|
||||
uint8_t ttl = 0;
|
||||
uint8_t protocol = 0;
|
||||
|
||||
uint16_t checksum = 0;
|
||||
|
||||
uint32_t source_ip = 0;
|
||||
uint32_t destination_ip = 0;
|
||||
|
||||
public:
|
||||
|
||||
ipv4_header_t()
|
||||
: ihl(0), version(0), ecn(0), dscp(0), total_length(0), identification(0), fragmentation_details_as_integer(0),
|
||||
ttl(0), protocol(0), checksum(0), source_ip(0), destination_ip(0) {
|
||||
}
|
||||
|
||||
// Should be called AFTER convert() call
|
||||
uint16_t get_checksum_host_byte_order() const {
|
||||
return fast_ntoh(checksum);
|
||||
}
|
||||
|
||||
uint16_t get_total_length_host_byte_order() const {
|
||||
return fast_ntoh(total_length);
|
||||
}
|
||||
|
||||
bool is_fragmented() {
|
||||
if (this->more_fragments_flag != 0) {
|
||||
if (this->get_more_fragments_flag()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this->fragment_offset != 0) {
|
||||
if (this->get_fragment_offset_bytes() != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void convert() {
|
||||
// Convert all 2 or 4 byte values to little endian from network format (big
|
||||
// endian)
|
||||
uint8_t get_ihl() const {
|
||||
return ihl;
|
||||
}
|
||||
|
||||
uint8_t get_version() const {
|
||||
return version;
|
||||
}
|
||||
|
||||
uint8_t get_ecn() const {
|
||||
return ecn;
|
||||
}
|
||||
|
||||
uint8_t get_dscp() const {
|
||||
return dscp;
|
||||
}
|
||||
|
||||
// 4 byte integers
|
||||
source_ip = ntohl(source_ip);
|
||||
destination_ip = ntohl(destination_ip);
|
||||
|
||||
fragmentation_details_as_integer = ntohs(fragmentation_details_as_integer);
|
||||
|
||||
// 2 byte integers
|
||||
identification = ntohs(identification);
|
||||
total_length = ntohs(total_length);
|
||||
uint16_t get_fragmentation_details_host_byte_order() {
|
||||
return fast_ntoh(fragmentation_details_as_integer);
|
||||
}
|
||||
|
||||
std::string print() {
|
||||
// Returns fragment offset in number of 8 byte chunks
|
||||
uint16_t get_fragment_offset_8byte_chunks() const {
|
||||
uint16_t fragmenation_details_little_endian = fast_ntoh(fragmentation_details_as_integer);
|
||||
|
||||
ipv4_header_fragmentation_flags_t* fragmentation_flags = (ipv4_header_fragmentation_flags_t*)&fragmenation_details_little_endian;
|
||||
|
||||
return fragmentation_flags->fragment_offset;
|
||||
}
|
||||
|
||||
// Returns offset in bytes
|
||||
uint16_t get_fragment_offset_bytes() const {
|
||||
uint16_t fragmenation_details_little_endian = fast_ntoh(fragmentation_details_as_integer);
|
||||
|
||||
ipv4_header_fragmentation_flags_t* fragmentation_flags = (ipv4_header_fragmentation_flags_t*)&fragmenation_details_little_endian;
|
||||
|
||||
// The offset value is the number of 8 byte blocks of data
|
||||
return fragmentation_flags->fragment_offset * 8;
|
||||
}
|
||||
|
||||
bool get_more_fragments_flag() const {
|
||||
uint16_t fragmenation_details_little_endian = fast_ntoh(fragmentation_details_as_integer);
|
||||
|
||||
ipv4_header_fragmentation_flags_t* fragmentation_flags = (ipv4_header_fragmentation_flags_t*)&fragmenation_details_little_endian;
|
||||
|
||||
return fragmentation_flags->more_fragments_flag == 1;
|
||||
}
|
||||
|
||||
bool get_dont_fragment_flag() const {
|
||||
uint16_t fragmenation_details_little_endian = fast_ntoh(fragmentation_details_as_integer);
|
||||
|
||||
ipv4_header_fragmentation_flags_t* fragmentation_flags = (ipv4_header_fragmentation_flags_t*)&fragmenation_details_little_endian;
|
||||
|
||||
return fragmentation_flags->dont_fragment_flag == 1;
|
||||
}
|
||||
|
||||
uint16_t get_reserved_flag() const {
|
||||
uint16_t fragmenation_details_little_endian = fast_ntoh(fragmentation_details_as_integer);
|
||||
|
||||
ipv4_header_fragmentation_flags_t* fragmentation_flags = (ipv4_header_fragmentation_flags_t*)&fragmenation_details_little_endian;
|
||||
|
||||
return fragmentation_flags->reserved_flag;
|
||||
}
|
||||
|
||||
// Clears reserved flag
|
||||
void clear_reserved_flag() {
|
||||
uint16_t fragmenation_details_little_endian = fast_ntoh(fragmentation_details_as_integer);
|
||||
|
||||
ipv4_header_fragmentation_flags_t* fragmentation_flags = (ipv4_header_fragmentation_flags_t*)&fragmenation_details_little_endian;
|
||||
|
||||
fragmentation_flags->reserved_flag = 0;
|
||||
|
||||
// Re-encode back to network byte order
|
||||
fragmentation_details_as_integer = fast_hton(fragmenation_details_little_endian);
|
||||
}
|
||||
|
||||
// Clears dont_fragment_flag flag
|
||||
void clear_dont_fragment_flag() {
|
||||
uint16_t fragmenation_details_little_endian = fast_ntoh(fragmentation_details_as_integer);
|
||||
|
||||
ipv4_header_fragmentation_flags_t* fragmentation_flags = (ipv4_header_fragmentation_flags_t*)&fragmenation_details_little_endian;
|
||||
|
||||
fragmentation_flags->dont_fragment_flag = 0;
|
||||
|
||||
// Re-encode back to network byte order
|
||||
fragmentation_details_as_integer = fast_hton(fragmenation_details_little_endian);
|
||||
}
|
||||
|
||||
// Value is a number of 8 byte blocks
|
||||
void set_fragment_offset_8byte_chunks(uint16_t value) {
|
||||
uint16_t fragmenation_details_little_endian = fast_ntoh(fragmentation_details_as_integer);
|
||||
|
||||
ipv4_header_fragmentation_flags_t* fragmentation_flags = (ipv4_header_fragmentation_flags_t*)&fragmenation_details_little_endian;
|
||||
|
||||
fragmentation_flags->fragment_offset = value;
|
||||
|
||||
// Re-encode back to network byte order
|
||||
fragmentation_details_as_integer = fast_hton(fragmenation_details_little_endian);
|
||||
}
|
||||
|
||||
uint32_t get_source_ip_network_byte_order() const {
|
||||
return source_ip;
|
||||
}
|
||||
|
||||
uint32_t get_destination_ip_network_byte_order() const {
|
||||
return destination_ip;
|
||||
}
|
||||
|
||||
uint32_t get_source_ip_host_byte_order() const {
|
||||
return fast_ntoh(source_ip);
|
||||
}
|
||||
|
||||
uint32_t get_destination_ip_host_byte_order() const {
|
||||
return fast_ntoh(destination_ip);
|
||||
}
|
||||
|
||||
uint16_t get_identification_host_byte_order() const {
|
||||
return fast_ntoh(identification);
|
||||
}
|
||||
|
||||
uint8_t get_ttl() const {
|
||||
return ttl;
|
||||
}
|
||||
|
||||
uint8_t get_protocol() const {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
std::string print() const {
|
||||
std::stringstream buffer;
|
||||
|
||||
buffer << "version: " << uint32_t(version) << " "
|
||||
<< "ihl: " << uint32_t(ihl) << " "
|
||||
<< "dscp: " << uint32_t(dscp) << " "
|
||||
<< "ecn: " << uint32_t(ecn) << " "
|
||||
<< "length: " << uint32_t(total_length) << " "
|
||||
<< "identification: " << uint32_t(identification) << " "
|
||||
<< "fragment_offset: " << uint32_t(fragment_offset) << " "
|
||||
<< "reserved_flag: " << uint32_t(reserved_flag) << " "
|
||||
<< "dont_fragment_flag: " << uint32_t(dont_fragment_flag) << " "
|
||||
<< "more_fragments_flag: " << uint32_t(more_fragments_flag) << " "
|
||||
<< "ttl: " << uint32_t(ttl) << " "
|
||||
<< "protocol: " << uint32_t(protocol) << " "
|
||||
<< "checksum: " << uint32_t(checksum) << " "
|
||||
<< "source_ip: " << convert_ip_as_little_endian_to_string(source_ip) << " "
|
||||
<< "destination_ip: " << convert_ip_as_little_endian_to_string(destination_ip);
|
||||
buffer << "version: " << uint32_t(get_version()) << " "
|
||||
<< "ihl: " << uint32_t(get_ihl()) << " "
|
||||
<< "dscp: " << uint32_t(get_dscp()) << " "
|
||||
<< "ecn: " << uint32_t(get_ecn()) << " "
|
||||
<< "length: " << get_total_length_host_byte_order() << " "
|
||||
<< "identification: " << get_identification_host_byte_order() << " "
|
||||
<< "fragment_offset_bytes: " << this->get_fragment_offset_bytes() << " "
|
||||
<< "reserved_flag: " << uint32_t(get_reserved_flag()) << " "
|
||||
<< "dont_fragment_flag: " << uint32_t(get_dont_fragment_flag()) << " "
|
||||
<< "more_fragments_flag: " << uint32_t(get_more_fragments_flag()) << " "
|
||||
<< "ttl: " << uint32_t(get_ttl()) << " "
|
||||
<< "protocol: " << uint32_t(get_protocol()) << " "
|
||||
<< "checksum: " << get_checksum_host_byte_order() << " "
|
||||
<< "source_ip: " << convert_ip_as_little_endian_to_string(get_source_ip_host_byte_order()) << " "
|
||||
<< "destination_ip: " << convert_ip_as_little_endian_to_string(get_destination_ip_host_byte_order());
|
||||
|
||||
return buffer.str();
|
||||
}
|
||||
@ -633,4 +1089,5 @@ enum class parser_code_t {
|
||||
};
|
||||
|
||||
std::string parser_code_to_string(parser_code_t code);
|
||||
parser_code_t parse_ipv4_to_map(std::map<std::string, uint32_t>& map, uint8_t* pointer, size_t length, bool ignore_do_not_fragment);
|
||||
} // namespace network_data_stuctures
|
||||
|
Loading…
Reference in New Issue
Block a user