mirror of
https://github.com/mfontanini/libtins
synced 2026-01-23 02:35:57 +01:00
Add input memory stream class and port some PDUs to use it
This commit is contained in:
@@ -49,6 +49,9 @@
|
||||
#include "icmp_extension.h"
|
||||
|
||||
namespace Tins {
|
||||
namespace Memory {
|
||||
class InputMemoryStream;
|
||||
} // memory
|
||||
|
||||
/**
|
||||
* \class ICMP
|
||||
@@ -460,7 +463,7 @@ private:
|
||||
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
|
||||
|
||||
uint32_t get_adjusted_inner_pdu_size() const;
|
||||
void try_parse_extensions(const uint8_t* buffer, uint32_t& total_sz);
|
||||
void try_parse_extensions(Memory::InputMemoryStream& stream);
|
||||
bool are_extensions_allowed() const;
|
||||
|
||||
icmphdr _icmp;
|
||||
|
||||
@@ -44,6 +44,10 @@
|
||||
#include "cxxstd.h"
|
||||
|
||||
namespace Tins {
|
||||
namespace Memory {
|
||||
class InputMemoryStream;
|
||||
} // memory
|
||||
|
||||
/**
|
||||
* \class ICMPv6
|
||||
* \brief Represents an ICMPv6 PDU.
|
||||
@@ -1376,12 +1380,12 @@ private:
|
||||
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
|
||||
bool has_options() const;
|
||||
uint8_t *write_option(const option &opt, uint8_t *buffer);
|
||||
void parse_options(const uint8_t *&buffer, uint32_t &total_sz);
|
||||
void parse_options(Memory::InputMemoryStream& stream);
|
||||
void add_addr_list(uint8_t type, const addr_list_type &value);
|
||||
addr_list_type search_addr_list(OptionTypes type) const;
|
||||
options_type::const_iterator search_option_iterator(OptionTypes type) const;
|
||||
options_type::iterator search_option_iterator(OptionTypes type);
|
||||
void try_parse_extensions(const uint8_t* buffer, uint32_t& total_sz);
|
||||
void try_parse_extensions(Memory::InputMemoryStream& stream);
|
||||
bool are_extensions_allowed() const;
|
||||
uint32_t get_adjusted_inner_pdu_size() const;
|
||||
|
||||
|
||||
@@ -45,6 +45,9 @@
|
||||
* \cond
|
||||
*/
|
||||
namespace Tins {
|
||||
namespace Memory {
|
||||
class InputMemoryStream;
|
||||
} // Memory
|
||||
class IPv4Address;
|
||||
class IPv6Address;
|
||||
class ICMPExtensionsStructure;
|
||||
@@ -126,7 +129,7 @@ Constants::Ethernet::e pdu_flag_to_ether_type(PDU::PDUType flag);
|
||||
Constants::IP::e pdu_flag_to_ip_type(PDU::PDUType flag);
|
||||
|
||||
uint32_t get_padded_icmp_inner_pdu_size(const PDU* inner_pdu, uint32_t pad_alignment);
|
||||
void try_parse_icmp_extensions(const uint8_t* buffer, uint32_t& total_sz,
|
||||
void try_parse_icmp_extensions(Memory::InputMemoryStream& stream,
|
||||
uint32_t payload_length, ICMPExtensionsStructure& extensions);
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -34,19 +34,25 @@
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
// Packing directives....
|
||||
// Check if this is Visual Studio
|
||||
#ifdef _MSC_VER
|
||||
// This is Visual Studio
|
||||
#define TINS_BEGIN_PACK __pragma( pack(push, 1) )
|
||||
#define TINS_END_PACK __pragma( pack(pop) )
|
||||
#define TINS_PACKED(DECLARATION) __pragma( pack(push, 1) ) DECLARATION __pragma( pack(pop) )
|
||||
#define TINS_DEPRECATED(func) __declspec(deprecated) func
|
||||
#define TINS_NOEXCEPT
|
||||
#define TINS_LIKELY(x) (x)
|
||||
#define TINS_UNLIKELY(x) (x)
|
||||
#else
|
||||
// Not Vistual Studio. Assume this is gcc compatible
|
||||
#define TINS_BEGIN_PACK
|
||||
#define TINS_END_PACK __attribute__((packed))
|
||||
#define TINS_PACKED(DECLARATION) DECLARATION __attribute__((packed))
|
||||
#define TINS_DEPRECATED(func) func __attribute__ ((deprecated))
|
||||
#define TINS_NOEXCEPT noexcept
|
||||
#endif
|
||||
#define TINS_LIKELY(x) __builtin_expect((x),1)
|
||||
#define TINS_UNLIKELY(x) __builtin_expect((x),0)
|
||||
#endif //
|
||||
|
||||
#endif
|
||||
#endif // TINS_MACROS_H
|
||||
|
||||
101
include/tins/memory_helpers.h
Normal file
101
include/tins/memory_helpers.h
Normal file
@@ -0,0 +1,101 @@
|
||||
#ifndef TINS_MEMORY_HELPERS_H
|
||||
#define TINS_MEMORY_HELPERS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstring>
|
||||
#include "exceptions.h"
|
||||
#include "ip_address.h"
|
||||
#include "ipv6_address.h"
|
||||
|
||||
namespace Tins {
|
||||
namespace Memory {
|
||||
|
||||
inline void read_data(const uint8_t* buffer, uint8_t* output_buffer, uint32_t size) {
|
||||
std::memcpy(output_buffer, buffer, size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void read_value(const uint8_t* buffer, T& value) {
|
||||
std::memcpy(&value, buffer, sizeof(value));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void write_value(uint8_t* buffer, const T& value) {
|
||||
std::memcpy(buffer, &value, sizeof(value));
|
||||
}
|
||||
|
||||
class InputMemoryStream {
|
||||
public:
|
||||
InputMemoryStream(const uint8_t* buffer, uint32_t total_sz)
|
||||
: buffer_(buffer), size_(total_sz) {
|
||||
}
|
||||
|
||||
void skip(uint32_t size) {
|
||||
buffer_ += size;
|
||||
size_ -= size;
|
||||
}
|
||||
|
||||
bool can_read(uint32_t byte_count) const {
|
||||
return TINS_LIKELY(size_ >= byte_count);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T read() {
|
||||
T output;
|
||||
read(output);
|
||||
return output;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void read(T& value) {
|
||||
if (!can_read(sizeof(value))) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
read_value(buffer_, value);
|
||||
skip(sizeof(value));
|
||||
}
|
||||
|
||||
void read(IPv4Address& address) {
|
||||
address = IPv4Address(read<uint32_t>());
|
||||
}
|
||||
|
||||
void read(IPv6Address& address) {
|
||||
if (!can_read(IPv6Address::address_size)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
address = pointer();
|
||||
skip(IPv6Address::address_size);
|
||||
}
|
||||
|
||||
void read(void* output_buffer, uint32_t output_buffer_size) {
|
||||
if (!can_read(output_buffer_size)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
read_data(buffer_, (uint8_t*)output_buffer, output_buffer_size);
|
||||
skip(output_buffer_size);
|
||||
}
|
||||
|
||||
const uint8_t* pointer() const {
|
||||
return buffer_;
|
||||
}
|
||||
|
||||
uint32_t size() const {
|
||||
return size_;
|
||||
}
|
||||
|
||||
void size(uint32_t new_size) {
|
||||
size_ = new_size;
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return size_ > 0;
|
||||
}
|
||||
private:
|
||||
const uint8_t* buffer_;
|
||||
uint32_t size_;
|
||||
};
|
||||
|
||||
} // Memory
|
||||
} // Tins
|
||||
|
||||
#endif // TINS_MEMORY_HELPERS_H
|
||||
20
src/arp.cpp
20
src/arp.cpp
@@ -37,16 +37,18 @@
|
||||
#include "constants.h"
|
||||
#include "network_interface.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::runtime_error;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
ARP::ARP(ipaddress_type target_ip, ipaddress_type sender_ip,
|
||||
const hwaddress_type &target_hw, const hwaddress_type &sender_hw)
|
||||
const hwaddress_type &target_hw, const hwaddress_type &sender_hw)
|
||||
: _arp()
|
||||
{
|
||||
memset(&_arp, 0, sizeof(arphdr));
|
||||
hw_addr_format((uint16_t)Constants::ARP::ETHER);
|
||||
prot_addr_format((uint16_t)Constants::Ethernet::IP);
|
||||
hw_addr_length(Tins::EthernetII::address_type::address_size);
|
||||
@@ -59,13 +61,11 @@ ARP::ARP(ipaddress_type target_ip, ipaddress_type sender_ip,
|
||||
|
||||
ARP::ARP(const uint8_t *buffer, uint32_t total_sz)
|
||||
{
|
||||
if(total_sz < sizeof(arphdr))
|
||||
throw malformed_packet();
|
||||
memcpy(&_arp, buffer, sizeof(arphdr));
|
||||
total_sz -= sizeof(arphdr);
|
||||
//TODO: Check whether this should be removed or not.
|
||||
if(total_sz)
|
||||
inner_pdu(new RawPDU(buffer + sizeof(arphdr), total_sz));
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_arp);
|
||||
if (stream) {
|
||||
inner_pdu(new RawPDU(stream.pointer(), stream.size()));
|
||||
}
|
||||
}
|
||||
|
||||
void ARP::sender_hw_addr(const hwaddress_type &new_snd_hw_addr) {
|
||||
|
||||
@@ -32,23 +32,25 @@
|
||||
#include <cassert>
|
||||
#include "bootp.h"
|
||||
#include "exceptions.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
|
||||
namespace Tins{
|
||||
|
||||
BootP::BootP()
|
||||
: _vend(64) {
|
||||
std::memset(&_bootp, 0, sizeof(bootphdr));
|
||||
: _bootp(), _vend(64) {
|
||||
|
||||
}
|
||||
|
||||
BootP::BootP(const uint8_t *buffer, uint32_t total_sz, uint32_t vend_field_size)
|
||||
: _vend(vend_field_size)
|
||||
{
|
||||
if(total_sz < sizeof(bootphdr) + vend_field_size)
|
||||
throw malformed_packet();
|
||||
std::memcpy(&_bootp, buffer, sizeof(bootphdr));
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_bootp);
|
||||
buffer += sizeof(bootphdr);
|
||||
total_sz -= sizeof(bootphdr);
|
||||
_vend.assign(buffer, buffer + vend_field_size);
|
||||
// Maybe RawPDU on what is left on the buffer?...
|
||||
_vend.assign(stream.pointer(), stream.pointer() + vend_field_size);
|
||||
}
|
||||
|
||||
uint32_t BootP::header_size() const {
|
||||
|
||||
48
src/dhcp.cpp
48
src/dhcp.cpp
@@ -35,15 +35,20 @@
|
||||
#include "ethernetII.h"
|
||||
#include "internals.h"
|
||||
#include "exceptions.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::string;
|
||||
using std::list;
|
||||
using std::runtime_error;
|
||||
using std::find_if;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
// Magic cookie: uint32_t.
|
||||
DHCP::DHCP() : _size(sizeof(uint32_t)) {
|
||||
DHCP::DHCP()
|
||||
: _size(sizeof(uint32_t)) {
|
||||
opcode(BOOTREQUEST);
|
||||
htype(1); //ethernet
|
||||
hlen(EthernetII::address_type::address_size);
|
||||
@@ -52,33 +57,26 @@ DHCP::DHCP() : _size(sizeof(uint32_t)) {
|
||||
DHCP::DHCP(const uint8_t *buffer, uint32_t total_sz)
|
||||
: BootP(buffer, total_sz, 0), _size(sizeof(uint32_t))
|
||||
{
|
||||
buffer += BootP::header_size() - vend().size();
|
||||
total_sz -= static_cast<uint32_t>(BootP::header_size() - vend().size());
|
||||
uint8_t args[2] = {0};
|
||||
uint32_t uint32_t_buffer;
|
||||
std::memcpy(&uint32_t_buffer, buffer, sizeof(uint32_t));
|
||||
if(total_sz < sizeof(uint32_t) || uint32_t_buffer != Endian::host_to_be<uint32_t>(0x63825363))
|
||||
const uint32_t bootp_size = BootP::header_size() - vend().size();
|
||||
InputMemoryStream stream(buffer + bootp_size, total_sz - bootp_size);
|
||||
const uint32_t magic_number = stream.read<uint32_t>();
|
||||
if (magic_number != Endian::host_to_be<uint32_t>(0x63825363))
|
||||
throw malformed_packet();
|
||||
buffer += sizeof(uint32_t);
|
||||
total_sz -= sizeof(uint32_t);
|
||||
while(total_sz) {
|
||||
for(unsigned i(0); i < 2; ++i) {
|
||||
args[i] = *(buffer++);
|
||||
total_sz--;
|
||||
if(args[0] == END || args[0] == PAD) {
|
||||
args[1] = 0;
|
||||
i = 2;
|
||||
}
|
||||
else if(!total_sz)
|
||||
throw malformed_packet();
|
||||
// While there's data left
|
||||
while (stream) {
|
||||
OptionTypes option_type;
|
||||
uint8_t option_length = 0;
|
||||
option_type = (OptionTypes)stream.read<uint8_t>();
|
||||
// We should only read the length if it's not END nor PAD
|
||||
if (option_type != END && option_type != PAD) {
|
||||
option_length = stream.read<uint8_t>();
|
||||
}
|
||||
if(total_sz < args[1])
|
||||
// Make sure we can read the payload size
|
||||
if (!stream.can_read(option_length)) {
|
||||
throw malformed_packet();
|
||||
add_option(
|
||||
option((OptionTypes)args[0], args[1], buffer)
|
||||
);
|
||||
buffer += args[1];
|
||||
total_sz -= args[1];
|
||||
}
|
||||
add_option(option(option_type, option_length, stream.pointer()));
|
||||
stream.skip(option_length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,53 +31,50 @@
|
||||
#include <algorithm>
|
||||
#include "dhcpv6.h"
|
||||
#include "exceptions.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::find_if;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
DHCPv6::DHCPv6() : options_size() {
|
||||
std::fill(header_data, header_data + sizeof(header_data), 0);
|
||||
|
||||
DHCPv6::DHCPv6()
|
||||
: header_data(), options_size() {
|
||||
|
||||
}
|
||||
|
||||
DHCPv6::DHCPv6(const uint8_t *buffer, uint32_t total_sz)
|
||||
: options_size()
|
||||
{
|
||||
if(total_sz == 0)
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
if (!stream) {
|
||||
throw malformed_packet();
|
||||
// Relay Agent/Server Messages
|
||||
bool is_relay_msg = (buffer[0] == 12 || buffer[0] == 13);
|
||||
uint32_t required_size = is_relay_msg ? 2 : 4;
|
||||
if(total_sz < required_size)
|
||||
throw malformed_packet();
|
||||
std::copy(buffer, buffer + required_size, header_data);
|
||||
buffer += required_size;
|
||||
total_sz -= required_size;
|
||||
if(is_relay_message()) {
|
||||
if(total_sz < ipaddress_type::address_size * 2)
|
||||
throw malformed_packet();
|
||||
link_addr = buffer;
|
||||
peer_addr = buffer + ipaddress_type::address_size;
|
||||
buffer += ipaddress_type::address_size * 2;
|
||||
total_sz -= ipaddress_type::address_size * 2;
|
||||
}
|
||||
while(total_sz) {
|
||||
if(total_sz < sizeof(uint16_t) * 2)
|
||||
// Relay Agent/Server Messages
|
||||
const MessageType message_type = (MessageType)*stream.pointer();
|
||||
bool is_relay_msg = (message_type == RELAY_FORWARD || message_type == RELAY_REPLY);
|
||||
uint32_t required_size = is_relay_msg ? 2 : 4;
|
||||
stream.read(&header_data, required_size);
|
||||
if (is_relay_message()) {
|
||||
if (!stream.can_read(ipaddress_type::address_size * 2)) {
|
||||
throw malformed_packet();
|
||||
|
||||
uint16_t opt;
|
||||
std::memcpy(&opt, buffer, sizeof(uint16_t));
|
||||
opt = Endian::be_to_host(opt);
|
||||
uint16_t data_size;
|
||||
std::memcpy(&data_size, buffer + sizeof(uint16_t), sizeof(uint16_t));
|
||||
data_size = Endian::be_to_host(data_size);
|
||||
if(total_sz - sizeof(uint16_t) * 2 < data_size)
|
||||
}
|
||||
// Read both addresses
|
||||
link_addr = stream.pointer();
|
||||
peer_addr = stream.pointer() + ipaddress_type::address_size;
|
||||
stream.skip(ipaddress_type::address_size * 2);
|
||||
}
|
||||
while (stream) {
|
||||
uint16_t opt = Endian::be_to_host(stream.read<uint16_t>());
|
||||
uint16_t data_size = Endian::be_to_host(stream.read<uint16_t>());
|
||||
if(!stream.can_read(data_size)) {
|
||||
throw malformed_packet();
|
||||
buffer += sizeof(uint16_t) * 2;
|
||||
}
|
||||
add_option(
|
||||
option(opt, buffer, buffer + data_size)
|
||||
option(opt, stream.pointer(), stream.pointer() + data_size)
|
||||
);
|
||||
buffer += data_size;
|
||||
total_sz -= sizeof(uint16_t) * 2 + data_size;
|
||||
stream.skip(data_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
18
src/dns.cpp
18
src/dns.cpp
@@ -39,30 +39,28 @@
|
||||
#include "exceptions.h"
|
||||
#include "rawpdu.h"
|
||||
#include "endianness.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::string;
|
||||
using std::list;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
DNS::DNS()
|
||||
: answers_idx(), authority_idx(), additional_idx()
|
||||
: dns(), answers_idx(), authority_idx(), additional_idx()
|
||||
{
|
||||
std::memset(&dns, 0, sizeof(dns));
|
||||
}
|
||||
|
||||
DNS::DNS(const uint8_t *buffer, uint32_t total_sz)
|
||||
: answers_idx(), authority_idx(), additional_idx()
|
||||
{
|
||||
if(total_sz < sizeof(dnshdr))
|
||||
throw malformed_packet();
|
||||
std::memcpy(&dns, buffer, sizeof(dnshdr));
|
||||
records_data.assign(
|
||||
buffer + sizeof(dnshdr),
|
||||
buffer + total_sz
|
||||
);
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(dns);
|
||||
records_data.assign(stream.pointer(), stream.pointer() + stream.size());
|
||||
// Avoid doing this if there's no data. Otherwise VS's asserts fail.
|
||||
if(!records_data.empty()) {
|
||||
if (!records_data.empty()) {
|
||||
buffer = &records_data[0];
|
||||
const uint8_t *end = &records_data[0] + records_data.size(), *prev_start = buffer;
|
||||
uint16_t nquestions = questions_count();
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
#include "dot1q.h"
|
||||
#include "internals.h"
|
||||
#include "exceptions.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
@@ -45,18 +48,15 @@ Dot1Q::Dot1Q(small_uint<12> tag_id, bool append_pad)
|
||||
Dot1Q::Dot1Q(const uint8_t *buffer, uint32_t total_sz)
|
||||
: _append_padding()
|
||||
{
|
||||
if(total_sz < sizeof(_header))
|
||||
throw malformed_packet();
|
||||
std::memcpy(&_header, buffer, sizeof(_header));
|
||||
buffer += sizeof(_header);
|
||||
total_sz -= sizeof(_header);
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_header);
|
||||
|
||||
if(total_sz) {
|
||||
if (stream) {
|
||||
inner_pdu(
|
||||
Internals::pdu_from_flag(
|
||||
(Constants::Ethernet::e)payload_type(),
|
||||
buffer,
|
||||
total_sz
|
||||
stream.pointer(),
|
||||
stream.size()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
16
src/dot3.cpp
16
src/dot3.cpp
@@ -47,8 +47,12 @@
|
||||
#include "packet_sender.h"
|
||||
#include "llc.h"
|
||||
#include "exceptions.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
const Dot3::address_type Dot3::BROADCAST("ff:ff:ff:ff:ff:ff");
|
||||
|
||||
Dot3::Dot3(const address_type &dst_hw_addr, const address_type &src_hw_addr)
|
||||
@@ -62,13 +66,11 @@ Dot3::Dot3(const address_type &dst_hw_addr, const address_type &src_hw_addr)
|
||||
|
||||
Dot3::Dot3(const uint8_t *buffer, uint32_t total_sz)
|
||||
{
|
||||
if(total_sz < sizeof(ethhdr))
|
||||
throw malformed_packet();
|
||||
memcpy(&_eth, buffer, sizeof(ethhdr));
|
||||
buffer += sizeof(ethhdr);
|
||||
total_sz -= sizeof(ethhdr);
|
||||
if(total_sz)
|
||||
inner_pdu(new Tins::LLC(buffer, total_sz));
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_eth);
|
||||
if (stream) {
|
||||
inner_pdu(new Tins::LLC(stream.pointer(), stream.size()));
|
||||
}
|
||||
}
|
||||
|
||||
void Dot3::dst_addr(const address_type &new_dst_mac) {
|
||||
|
||||
@@ -36,11 +36,15 @@
|
||||
#include "eapol.h"
|
||||
#include "rsn_information.h"
|
||||
#include "exceptions.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
EAPOL::EAPOL(uint8_t packet_type, EAPOLTYPE type)
|
||||
: _header()
|
||||
{
|
||||
std::memset(&_header, 0, sizeof(_header));
|
||||
_header.version = 1;
|
||||
_header.packet_type = packet_type;
|
||||
_header.type = (uint8_t)type;
|
||||
@@ -48,14 +52,14 @@ EAPOL::EAPOL(uint8_t packet_type, EAPOLTYPE type)
|
||||
|
||||
EAPOL::EAPOL(const uint8_t *buffer, uint32_t total_sz)
|
||||
{
|
||||
if(total_sz < sizeof(_header))
|
||||
throw malformed_packet();
|
||||
std::memcpy(&_header, buffer, sizeof(_header));
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_header);
|
||||
}
|
||||
|
||||
EAPOL *EAPOL::from_bytes(const uint8_t *buffer, uint32_t total_sz) {
|
||||
if(total_sz < sizeof(eapolhdr))
|
||||
if (total_sz < sizeof(eapolhdr)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
const eapolhdr *ptr = (const eapolhdr*)buffer;
|
||||
uint32_t data_len = Endian::be_to_host<uint16_t>(ptr->length);
|
||||
// at least 4 for fields always present
|
||||
|
||||
@@ -53,33 +53,33 @@
|
||||
#include "constants.h"
|
||||
#include "internals.h"
|
||||
#include "exceptions.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
const EthernetII::address_type EthernetII::BROADCAST("ff:ff:ff:ff:ff:ff");
|
||||
|
||||
EthernetII::EthernetII(const address_type &dst_hw_addr,
|
||||
const address_type &src_hw_addr)
|
||||
: _eth()
|
||||
{
|
||||
memset(&_eth, 0, sizeof(ethhdr));
|
||||
dst_addr(dst_hw_addr);
|
||||
src_addr(src_hw_addr);
|
||||
_eth.payload_type = 0;
|
||||
|
||||
}
|
||||
|
||||
EthernetII::EthernetII(const uint8_t *buffer, uint32_t total_sz)
|
||||
{
|
||||
if(total_sz < sizeof(ethhdr))
|
||||
throw malformed_packet();
|
||||
memcpy(&_eth, buffer, sizeof(ethhdr));
|
||||
buffer += sizeof(ethhdr);
|
||||
total_sz -= sizeof(ethhdr);
|
||||
if(total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_eth);
|
||||
// If there's any size left
|
||||
if (stream) {
|
||||
inner_pdu(
|
||||
Internals::pdu_from_flag(
|
||||
(Constants::Ethernet::e)payload_type(),
|
||||
buffer,
|
||||
total_sz
|
||||
stream.pointer(),
|
||||
stream.size()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
41
src/icmp.cpp
41
src/icmp.cpp
@@ -39,6 +39,9 @@
|
||||
#include "utils.h"
|
||||
#include "exceptions.h"
|
||||
#include "icmp.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
@@ -51,36 +54,20 @@ ICMP::ICMP(Flags flag)
|
||||
|
||||
ICMP::ICMP(const uint8_t *buffer, uint32_t total_sz)
|
||||
{
|
||||
if(total_sz < sizeof(icmphdr))
|
||||
throw malformed_packet();
|
||||
std::memcpy(&_icmp, buffer, sizeof(icmphdr));
|
||||
buffer += sizeof(icmphdr);
|
||||
total_sz -= sizeof(icmphdr);
|
||||
uint32_t uint32_t_buffer = 0;
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_icmp);
|
||||
if(type() == TIMESTAMP_REQUEST || type() == TIMESTAMP_REPLY) {
|
||||
if(total_sz < sizeof(uint32_t) * 3)
|
||||
throw malformed_packet();
|
||||
memcpy(&uint32_t_buffer, buffer, sizeof(uint32_t));
|
||||
original_timestamp(uint32_t_buffer);
|
||||
memcpy(&uint32_t_buffer, buffer + sizeof(uint32_t), sizeof(uint32_t));
|
||||
receive_timestamp(uint32_t_buffer);
|
||||
memcpy(&uint32_t_buffer, buffer + 2 * sizeof(uint32_t), sizeof(uint32_t));
|
||||
transmit_timestamp(uint32_t_buffer);
|
||||
total_sz -= sizeof(uint32_t) * 3;
|
||||
buffer += sizeof(uint32_t) * 3;
|
||||
original_timestamp(stream.read<uint32_t>());
|
||||
receive_timestamp(stream.read<uint32_t>());
|
||||
transmit_timestamp(stream.read<uint32_t>());
|
||||
}
|
||||
else if(type() == ADDRESS_MASK_REQUEST || type() == ADDRESS_MASK_REPLY) {
|
||||
if(total_sz < sizeof(uint32_t))
|
||||
throw malformed_packet();
|
||||
memcpy(&uint32_t_buffer, buffer, sizeof(uint32_t));
|
||||
address_mask(address_type(uint32_t_buffer));
|
||||
total_sz -= sizeof(uint32_t);
|
||||
buffer += sizeof(uint32_t);
|
||||
address_mask(address_type(stream.read<uint32_t>()));
|
||||
}
|
||||
// Attempt to parse ICMP extensions
|
||||
try_parse_extensions(buffer, total_sz);
|
||||
if (total_sz) {
|
||||
inner_pdu(new RawPDU(buffer, total_sz));
|
||||
try_parse_extensions(stream);
|
||||
if (stream) {
|
||||
inner_pdu(new RawPDU(stream.pointer(), stream.size()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,10 +275,10 @@ uint32_t ICMP::get_adjusted_inner_pdu_size() const {
|
||||
return Internals::get_padded_icmp_inner_pdu_size(inner_pdu(), sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void ICMP::try_parse_extensions(const uint8_t* buffer, uint32_t& total_sz) {
|
||||
void ICMP::try_parse_extensions(InputMemoryStream& stream) {
|
||||
// Check if this is one of the types defined in RFC 4884
|
||||
if (are_extensions_allowed()) {
|
||||
Internals::try_parse_icmp_extensions(buffer, total_sz, length() * sizeof(uint32_t),
|
||||
Internals::try_parse_icmp_extensions(stream, length() * sizeof(uint32_t),
|
||||
extensions_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
#include "icmp_extension.h"
|
||||
#include "exceptions.h"
|
||||
#include "utils.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::runtime_error;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
const uint32_t ICMPExtension::BASE_HEADER_SIZE = sizeof(uint16_t) + sizeof(uint8_t) * 2;
|
||||
@@ -24,22 +27,17 @@ ICMPExtension::ICMPExtension(uint8_t ext_class, uint8_t ext_type)
|
||||
|
||||
|
||||
ICMPExtension::ICMPExtension(const uint8_t* buffer, uint32_t total_sz) {
|
||||
// Check for the base header (u16 length + u8 clss + u8 type)
|
||||
if (total_sz < BASE_HEADER_SIZE) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
|
||||
uint16_t length = Endian::be_to_host(*(const uint16_t*)buffer);
|
||||
buffer += sizeof(uint16_t);
|
||||
extension_class_ = *buffer++;
|
||||
extension_type_ = *buffer++;
|
||||
total_sz -= BASE_HEADER_SIZE;
|
||||
uint16_t length = Endian::be_to_host(stream.read<uint16_t>());
|
||||
extension_class_ = stream.read<uint8_t>();
|
||||
extension_type_ = stream.read<uint8_t>();
|
||||
// Length is BASE_HEADER_SIZE + payload size, make sure it's valid
|
||||
if (length < BASE_HEADER_SIZE || length - BASE_HEADER_SIZE > total_sz) {
|
||||
if (length < BASE_HEADER_SIZE || length - BASE_HEADER_SIZE > stream.size()) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
length -= BASE_HEADER_SIZE;
|
||||
payload_.assign(buffer, buffer + length);
|
||||
payload_.assign(stream.pointer(), stream.pointer() + length);
|
||||
}
|
||||
|
||||
void ICMPExtension::extension_class(uint8_t value) {
|
||||
@@ -88,19 +86,14 @@ ICMPExtensionsStructure::ICMPExtensionsStructure()
|
||||
}
|
||||
|
||||
ICMPExtensionsStructure::ICMPExtensionsStructure(const uint8_t* buffer, uint32_t total_sz) {
|
||||
if (total_sz < BASE_HEADER_SIZE) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
|
||||
version_and_reserved_ = *(const uint16_t*)buffer;
|
||||
buffer += sizeof(uint16_t);
|
||||
checksum_ = *(const uint16_t*)buffer;
|
||||
buffer += sizeof(uint16_t);
|
||||
total_sz -= BASE_HEADER_SIZE;
|
||||
while (total_sz > 0) {
|
||||
extensions_.push_back(ICMPExtension(buffer, total_sz));
|
||||
uint16_t size = Endian::be_to_host(*(const uint16_t*)buffer);
|
||||
total_sz -= size;
|
||||
version_and_reserved_ = stream.read<uint16_t>();
|
||||
checksum_ = stream.read<uint16_t>();
|
||||
while (stream) {
|
||||
extensions_.push_back(ICMPExtension(stream.pointer(), stream.size()));
|
||||
uint16_t size = Endian::be_to_host(stream.read<uint16_t>());
|
||||
stream.skip(size - sizeof(uint16_t));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,9 @@
|
||||
#include "utils.h"
|
||||
#include "constants.h"
|
||||
#include "exceptions.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
@@ -50,63 +53,49 @@ ICMPv6::ICMPv6(Types tp)
|
||||
ICMPv6::ICMPv6(const uint8_t *buffer, uint32_t total_sz)
|
||||
: _options_size(), reach_time(0), retrans_timer(0)
|
||||
{
|
||||
if (total_sz < sizeof(_header)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
std::memcpy(&_header, buffer, sizeof(_header));
|
||||
buffer += sizeof(_header);
|
||||
total_sz -= sizeof(_header);
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_header);
|
||||
if (has_target_addr()) {
|
||||
if(total_sz < ipaddress_type::address_size) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
target_addr(buffer);
|
||||
buffer += ipaddress_type::address_size;
|
||||
total_sz -= ipaddress_type::address_size;
|
||||
_target_address = stream.read<ipaddress_type>();
|
||||
}
|
||||
if (has_dest_addr()) {
|
||||
if(total_sz < ipaddress_type::address_size) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
dest_addr(buffer);
|
||||
buffer += ipaddress_type::address_size;
|
||||
total_sz -= ipaddress_type::address_size;
|
||||
_dest_address = stream.read<ipaddress_type>();
|
||||
}
|
||||
if (type() == ROUTER_ADVERT) {
|
||||
if(total_sz < sizeof(uint32_t) * 2) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
memcpy(&reach_time, buffer, sizeof(uint32_t));
|
||||
memcpy(&retrans_timer, buffer + sizeof(uint32_t), sizeof(uint32_t));
|
||||
|
||||
buffer += sizeof(uint32_t) * 2;
|
||||
total_sz -= sizeof(uint32_t) * 2;
|
||||
reach_time = stream.read<uint32_t>();
|
||||
retrans_timer = stream.read<uint32_t>();
|
||||
}
|
||||
// Retrieve options
|
||||
if (has_options()) {
|
||||
parse_options(buffer, total_sz);
|
||||
parse_options(stream);
|
||||
}
|
||||
// Attempt to parse ICMP extensions
|
||||
try_parse_extensions(buffer, total_sz);
|
||||
if (total_sz) {
|
||||
inner_pdu(new RawPDU(buffer, total_sz));
|
||||
try_parse_extensions(stream);
|
||||
if (stream) {
|
||||
inner_pdu(new RawPDU(stream.pointer(), stream.size()));
|
||||
}
|
||||
}
|
||||
|
||||
void ICMPv6::parse_options(const uint8_t *&buffer, uint32_t &total_sz) {
|
||||
while(total_sz > 0) {
|
||||
if(total_sz < 8 || (static_cast<uint32_t>(buffer[1]) * 8) > total_sz || buffer[1] < 1)
|
||||
void ICMPv6::parse_options(InputMemoryStream& stream) {
|
||||
while (stream) {
|
||||
const uint8_t opt_type = stream.read<uint8_t>();
|
||||
const uint32_t opt_size = static_cast<uint32_t>(stream.read<uint8_t>()) * 8;
|
||||
if (opt_size < sizeof(uint8_t) << 1) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
// size(option) = option_size - identifier_size - length_identifier_size
|
||||
const uint32_t payload_size = opt_size - (sizeof(uint8_t) << 1);
|
||||
if (!stream.can_read(payload_size)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
add_option(
|
||||
option(
|
||||
buffer[0],
|
||||
static_cast<uint32_t>(buffer[1]) * 8 - sizeof(uint8_t) * 2,
|
||||
buffer + 2
|
||||
opt_type,
|
||||
payload_size,
|
||||
stream.pointer()
|
||||
)
|
||||
);
|
||||
total_sz -= buffer[1] * 8;
|
||||
buffer += buffer[1] * 8;
|
||||
stream.skip(payload_size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -660,10 +649,10 @@ uint32_t ICMPv6::get_adjusted_inner_pdu_size() const {
|
||||
return Internals::get_padded_icmp_inner_pdu_size(inner_pdu(), sizeof(uint64_t));
|
||||
}
|
||||
|
||||
void ICMPv6::try_parse_extensions(const uint8_t* buffer, uint32_t& total_sz) {
|
||||
void ICMPv6::try_parse_extensions(InputMemoryStream& stream) {
|
||||
// Check if this is one of the types defined in RFC 4884
|
||||
if (are_extensions_allowed()) {
|
||||
Internals::try_parse_icmp_extensions(buffer, total_sz, length() * sizeof(uint64_t),
|
||||
Internals::try_parse_icmp_extensions(stream, length() * sizeof(uint64_t),
|
||||
extensions_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,11 +52,15 @@
|
||||
#include "ip_address.h"
|
||||
#include "ipv6_address.h"
|
||||
#include "pdu_allocator.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
namespace Internals {
|
||||
|
||||
bool from_hex(const string &str, uint32_t &result) {
|
||||
unsigned i(0);
|
||||
result = 0;
|
||||
@@ -275,9 +279,9 @@ uint32_t get_padded_icmp_inner_pdu_size(const PDU* inner_pdu, uint32_t pad_align
|
||||
}
|
||||
}
|
||||
|
||||
void try_parse_icmp_extensions(const uint8_t* buffer, uint32_t& total_sz,
|
||||
uint32_t payload_length, ICMPExtensionsStructure& extensions) {
|
||||
if (total_sz == 0) {
|
||||
void try_parse_icmp_extensions(InputMemoryStream& stream, uint32_t payload_length,
|
||||
ICMPExtensionsStructure& extensions) {
|
||||
if (!stream) {
|
||||
return;
|
||||
}
|
||||
// Check if this is one of the types defined in RFC 4884
|
||||
@@ -286,15 +290,15 @@ void try_parse_icmp_extensions(const uint8_t* buffer, uint32_t& total_sz,
|
||||
// the minimum encapsulated packet size
|
||||
const uint8_t* extensions_ptr;
|
||||
uint32_t extensions_size;
|
||||
if (payload_length < total_sz && payload_length >= minimum_payload) {
|
||||
extensions_ptr = buffer + payload_length;
|
||||
extensions_size = total_sz - payload_length;
|
||||
if (stream.can_read(payload_length) && payload_length >= minimum_payload) {
|
||||
extensions_ptr = stream.pointer() + payload_length;
|
||||
extensions_size = stream.size() - payload_length;
|
||||
}
|
||||
else if (total_sz > minimum_payload) {
|
||||
else if (stream.can_read(minimum_payload)) {
|
||||
// This packet might be non-rfc compliant. In that case the length
|
||||
// field can contain garbage.
|
||||
extensions_ptr = buffer + minimum_payload;
|
||||
extensions_size = total_sz - minimum_payload;
|
||||
extensions_ptr = stream.pointer() + minimum_payload;
|
||||
extensions_size = stream.size() - minimum_payload;
|
||||
}
|
||||
else {
|
||||
// No more special cases, this doesn't have extensions
|
||||
@@ -302,7 +306,7 @@ void try_parse_icmp_extensions(const uint8_t* buffer, uint32_t& total_sz,
|
||||
}
|
||||
if (ICMPExtensionsStructure::validate_extensions(extensions_ptr, extensions_size)) {
|
||||
extensions = ICMPExtensionsStructure(extensions_ptr, extensions_size);
|
||||
total_sz -= extensions_size;
|
||||
stream.size(stream.size() - extensions_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
108
src/ip.cpp
108
src/ip.cpp
@@ -48,9 +48,12 @@
|
||||
#include "network_interface.h"
|
||||
#include "exceptions.h"
|
||||
#include "pdu_allocator.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::list;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
const uint8_t IP::DEFAULT_TTL = 128;
|
||||
@@ -62,46 +65,51 @@ IP::IP(address_type ip_dst, address_type ip_src)
|
||||
this->src_addr(ip_src);
|
||||
}
|
||||
|
||||
IP::IP(const uint8_t *buffer, uint32_t total_sz)
|
||||
IP::IP(const uint8_t *buffer, uint32_t total_sz)
|
||||
: _options_size(0)
|
||||
{
|
||||
if(total_sz < sizeof(iphdr))
|
||||
throw malformed_packet();
|
||||
std::memcpy(&_ip, buffer, sizeof(iphdr));
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_ip);
|
||||
|
||||
/* Options... */
|
||||
/* Establish beginning and ending of the options */
|
||||
const uint8_t* ptr_buffer = buffer + sizeof(iphdr);
|
||||
if(total_sz < head_len() * sizeof(uint32_t))
|
||||
// Make sure we have enough size for options and not less than we should
|
||||
if (head_len() * sizeof(uint32_t) > total_sz ||
|
||||
head_len() * sizeof(uint32_t) < sizeof(iphdr)) {
|
||||
throw malformed_packet();
|
||||
if(head_len() * sizeof(uint32_t) < sizeof(iphdr))
|
||||
throw malformed_packet();
|
||||
buffer += head_len() * sizeof(uint32_t);
|
||||
}
|
||||
const uint8_t* options_end = buffer + head_len() * sizeof(uint32_t);
|
||||
|
||||
_options_size = 0;
|
||||
//_padded_options_size = head_len() * sizeof(uint32_t) - sizeof(iphdr);
|
||||
/* While the end of the options is not reached read an option */
|
||||
while (ptr_buffer < buffer && (*ptr_buffer != 0)) {
|
||||
//ip_option opt_to_add;
|
||||
option_identifier opt_type;
|
||||
memcpy(&opt_type, ptr_buffer, sizeof(uint8_t));
|
||||
ptr_buffer++;
|
||||
if(opt_type.number > NOOP) {
|
||||
/* Multibyte options with length as second byte */
|
||||
if(ptr_buffer == buffer || *ptr_buffer == 0)
|
||||
// While the end of the options is not reached read an option
|
||||
while (stream.pointer() < options_end) {
|
||||
option_identifier opt_type = (option_identifier)stream.read<uint8_t>();
|
||||
if (opt_type.number > NOOP) {
|
||||
// Multibyte options with length as second byte
|
||||
const uint32_t option_size = stream.read<uint8_t>();
|
||||
if (TINS_UNLIKELY(option_size < (sizeof(uint8_t) << 1))) {
|
||||
throw malformed_packet();
|
||||
|
||||
const uint8_t data_size = *ptr_buffer - 2;
|
||||
if(data_size > 0) {
|
||||
ptr_buffer++;
|
||||
if(buffer - ptr_buffer < data_size)
|
||||
throw malformed_packet();
|
||||
_ip_options.push_back(option(opt_type, ptr_buffer, ptr_buffer + data_size));
|
||||
}
|
||||
else
|
||||
// The data size is the option size - the identifier and size fields
|
||||
const uint32_t data_size = option_size - (sizeof(uint8_t) << 1);
|
||||
if (data_size > 0) {
|
||||
if (stream.pointer() + data_size > options_end) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
_ip_options.push_back(
|
||||
option(opt_type, stream.pointer(), stream.pointer() + data_size)
|
||||
);
|
||||
stream.skip(data_size);
|
||||
}
|
||||
else {
|
||||
_ip_options.push_back(option(opt_type));
|
||||
|
||||
ptr_buffer += _ip_options.back().data_size() + 1;
|
||||
_options_size += static_cast<uint16_t>(_ip_options.back().data_size() + 2);
|
||||
}
|
||||
_options_size += option_size;
|
||||
}
|
||||
else if (opt_type == END) {
|
||||
// If the end option found, we're done
|
||||
if (TINS_UNLIKELY(stream.pointer() != options_end)) {
|
||||
// Make sure we found the END option at the end of the options list
|
||||
throw malformed_packet();
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
_ip_options.push_back(option(opt_type));
|
||||
@@ -110,39 +118,43 @@ IP::IP(const uint8_t *buffer, uint32_t total_sz)
|
||||
}
|
||||
uint8_t padding = _options_size % 4;
|
||||
_padded_options_size = padding ? (_options_size - padding + 4) : _options_size;
|
||||
// Don't avoid consuming more than we should if tot_len is 0,
|
||||
// since this is the case when using TCP segmentation offload
|
||||
if (tot_len() != 0)
|
||||
total_sz = std::min(total_sz, (uint32_t)tot_len());
|
||||
if (total_sz < head_len() * sizeof(uint32_t))
|
||||
throw malformed_packet();
|
||||
total_sz -= head_len() * sizeof(uint32_t);
|
||||
if (total_sz) {
|
||||
if (stream) {
|
||||
// Don't avoid consuming more than we should if tot_len is 0,
|
||||
// since this is the case when using TCP segmentation offload
|
||||
if (tot_len() != 0) {
|
||||
const uint32_t advertised_length = (uint32_t)tot_len() - head_len() * sizeof(uint32_t);
|
||||
total_sz = std::min(stream.size(), advertised_length);
|
||||
}
|
||||
else {
|
||||
total_sz = stream.size();
|
||||
}
|
||||
|
||||
// Don't try to decode it if it's fragmented
|
||||
if(!is_fragmented()) {
|
||||
if (!is_fragmented()) {
|
||||
inner_pdu(
|
||||
Internals::pdu_from_flag(
|
||||
static_cast<Constants::IP::e>(_ip.protocol),
|
||||
buffer,
|
||||
stream.pointer(),
|
||||
total_sz,
|
||||
false
|
||||
)
|
||||
);
|
||||
if(!inner_pdu()) {
|
||||
if (!inner_pdu()) {
|
||||
inner_pdu(
|
||||
Internals::allocate<IP>(
|
||||
_ip.protocol,
|
||||
buffer,
|
||||
stream.pointer(),
|
||||
total_sz
|
||||
)
|
||||
);
|
||||
if(!inner_pdu())
|
||||
inner_pdu(new RawPDU(buffer, total_sz));
|
||||
if (!inner_pdu()) {
|
||||
inner_pdu(new RawPDU(stream.pointer(), total_sz));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// It's fragmented, just use RawPDU
|
||||
inner_pdu(new RawPDU(buffer, total_sz));
|
||||
inner_pdu(new RawPDU(stream.pointer(), total_sz));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
60
src/tcp.cpp
60
src/tcp.cpp
@@ -38,17 +38,18 @@
|
||||
#include "utils.h"
|
||||
#include "exceptions.h"
|
||||
#include "internals.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::find_if;
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
const uint16_t TCP::DEFAULT_WINDOW = 32678;
|
||||
|
||||
TCP::TCP(uint16_t dport, uint16_t sport)
|
||||
: _options_size(0), _total_options_size(0)
|
||||
: _tcp(), _options_size(0), _total_options_size(0)
|
||||
{
|
||||
std::memset(&_tcp, 0, sizeof(tcphdr));
|
||||
this->dport(dport);
|
||||
this->sport(sport);
|
||||
data_offset(sizeof(tcphdr) / sizeof(uint32_t));
|
||||
@@ -56,45 +57,54 @@ TCP::TCP(uint16_t dport, uint16_t sport)
|
||||
}
|
||||
|
||||
TCP::TCP(const uint8_t *buffer, uint32_t total_sz)
|
||||
: _options_size(0), _total_options_size(0)
|
||||
{
|
||||
if(total_sz < sizeof(tcphdr))
|
||||
throw malformed_packet();
|
||||
std::memcpy(&_tcp, buffer, sizeof(tcphdr));
|
||||
if(data_offset() * sizeof(uint32_t) > total_sz || data_offset() * sizeof(uint32_t) < sizeof(tcphdr))
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_tcp);
|
||||
// Check that we have at least the amount of bytes we need and not less
|
||||
if (TINS_UNLIKELY(data_offset() * sizeof(uint32_t) > total_sz ||
|
||||
data_offset() * sizeof(uint32_t) < sizeof(tcphdr))) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
const uint8_t *header_end = buffer + (data_offset() * sizeof(uint32_t));
|
||||
total_sz = static_cast<uint32_t>(total_sz - (header_end - buffer));
|
||||
buffer += sizeof(tcphdr);
|
||||
|
||||
_total_options_size = 0;
|
||||
_options_size = 0;
|
||||
|
||||
while(buffer < header_end) {
|
||||
if(*buffer <= NOP) {
|
||||
while (stream.pointer() < header_end) {
|
||||
const OptionTypes option_type = (OptionTypes)stream.read<uint8_t>();
|
||||
if (option_type <= NOP) {
|
||||
#if TINS_IS_CXX11
|
||||
add_option((OptionTypes)*buffer, 0);
|
||||
add_option(option_type, 0);
|
||||
#else
|
||||
add_option(option((OptionTypes)*buffer, 0));
|
||||
add_option(option(option_type, 0));
|
||||
#endif // TINS_IS_CXX11
|
||||
++buffer;
|
||||
}
|
||||
else {
|
||||
if(buffer + 1 == header_end)
|
||||
// Extract the length
|
||||
uint32_t len = stream.read<uint8_t>();
|
||||
const uint8_t *data_start = stream.pointer();
|
||||
|
||||
// We need to subtract the option type and length from the size
|
||||
if (TINS_UNLIKELY(len < sizeof(uint8_t) << 1)) {
|
||||
throw malformed_packet();
|
||||
const uint8_t len = buffer[1] - (sizeof(uint8_t) << 1);
|
||||
const uint8_t *data_start = buffer + 2;
|
||||
if(data_start + len > header_end)
|
||||
}
|
||||
len -= (sizeof(uint8_t) << 1);
|
||||
// Make sure we have enough bytes for the advertised option payload length
|
||||
if (TINS_UNLIKELY(data_start + len > header_end)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
// If we're using C++11, use the variadic template overload
|
||||
#if TINS_IS_CXX11
|
||||
add_option((OptionTypes)*buffer, data_start, data_start + len);
|
||||
add_option(option_type, data_start, data_start + len);
|
||||
#else
|
||||
add_option(option((OptionTypes)*buffer, data_start, data_start + len));
|
||||
add_option(option(option_type, data_start, data_start + len));
|
||||
#endif // TINS_IS_CXX11
|
||||
buffer = data_start + len;
|
||||
// Skip the option's payload
|
||||
stream.skip(len);
|
||||
}
|
||||
}
|
||||
if(total_sz)
|
||||
inner_pdu(new RawPDU(buffer, total_sz));
|
||||
// If we still have any bytes left
|
||||
if (stream) {
|
||||
inner_pdu(new RawPDU(stream.pointer(), stream.size()));
|
||||
}
|
||||
}
|
||||
|
||||
void TCP::dport(uint16_t new_dport) {
|
||||
|
||||
Reference in New Issue
Block a user