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

Add OutputMemoryStream and port most classes to use it

This commit is contained in:
Matias Fontanini
2015-12-26 06:30:00 -08:00
parent 9750f46c6d
commit 02e2b278de
34 changed files with 438 additions and 418 deletions

View File

@@ -38,7 +38,11 @@
#include "ipv6_address.h" #include "ipv6_address.h"
#include "pdu_option.h" #include "pdu_option.h"
namespace Tins { namespace Tins {
namespace Memory {
class OutputMemoryStream;
} // Memory
/** /**
* \class DHCPv6 * \class DHCPv6
* \brief Represents a DHCPv6 PDU. * \brief Represents a DHCPv6 PDU.
@@ -869,7 +873,7 @@ public:
} }
private: private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *); void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *);
uint8_t* write_option(const option &option, uint8_t* buffer) const; void write_option(const option &option, Memory::OutputMemoryStream& stream) const;
options_type::const_iterator search_option_iterator(OptionTypes type) const; options_type::const_iterator search_option_iterator(OptionTypes type) const;
options_type::iterator search_option_iterator(OptionTypes type); options_type::iterator search_option_iterator(OptionTypes type);

View File

@@ -38,7 +38,10 @@
namespace Tins { namespace Tins {
namespace Memory {
class OutputMemoryStream;
} // Memory
/** \cond /** \cond
* Forward declaration. Avoid header inclusion. * Forward declaration. Avoid header inclusion.
*/ */
@@ -163,7 +166,7 @@ namespace Tins {
* \param buffer The pointer in which to save the serialization. * \param buffer The pointer in which to save the serialization.
* \param total_sz The total size of the buffer. * \param total_sz The total size of the buffer.
*/ */
virtual void write_body(uint8_t *buffer, uint32_t total_sz) = 0; virtual void write_body(Memory::OutputMemoryStream& stream) = 0;
private: private:
/** /**
* \brief Serialices this EAPOL PDU. * \brief Serialices this EAPOL PDU.
@@ -353,7 +356,7 @@ namespace Tins {
uint8_t key_sign[16]; uint8_t key_sign[16];
} TINS_END_PACK; } TINS_END_PACK;
void write_body(uint8_t *buffer, uint32_t total_sz); void write_body(Memory::OutputMemoryStream& stream);
key_type _key; key_type _key;
@@ -731,7 +734,7 @@ namespace Tins {
#endif #endif
} TINS_END_PACK; } TINS_END_PACK;
void write_body(uint8_t *buffer, uint32_t total_sz); void write_body(Memory::OutputMemoryStream& stream);
rsnhdr _header; rsnhdr _header;

View File

@@ -49,7 +49,7 @@ public:
/** /**
* \brief Exception thrown when an option is not found. * \brief Exception thrown when an option is not found.
*/ */
class option_not_found : exception_base { class option_not_found : public exception_base {
public: public:
// try to avoid allocations by doing this. // try to avoid allocations by doing this.
const char* what() const throw() { const char* what() const throw() {
@@ -67,6 +67,16 @@ public:
} }
}; };
/**
* \brief Exception thrown when serializing a packet fails.
*/
class serialization_error : public exception_base {
public:
const char* what() const throw() {
return "Serialization error";
}
};
/** /**
* \brief Exception thrown when a PDU is not found when using PDU::rfind_pdu. * \brief Exception thrown when a PDU is not found when using PDU::rfind_pdu.
*/ */

View File

@@ -46,6 +46,7 @@
namespace Tins { namespace Tins {
namespace Memory { namespace Memory {
class InputMemoryStream; class InputMemoryStream;
class OutputMemoryStream;
} // memory } // memory
/** /**
@@ -1379,7 +1380,7 @@ private:
void internal_add_option(const option &option); void internal_add_option(const option &option);
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
bool has_options() const; bool has_options() const;
uint8_t *write_option(const option &opt, uint8_t *buffer); void write_option(const option &opt, Memory::OutputMemoryStream& stream);
void parse_options(Memory::InputMemoryStream& stream); void parse_options(Memory::InputMemoryStream& stream);
void add_addr_list(uint8_t type, const addr_list_type &value); void add_addr_list(uint8_t type, const addr_list_type &value);
addr_list_type search_addr_list(OptionTypes type) const; addr_list_type search_addr_list(OptionTypes type) const;

View File

@@ -40,6 +40,9 @@
#include "cxxstd.h" #include "cxxstd.h"
namespace Tins { namespace Tins {
namespace Memory {
class OutputMemoryStream;
} // Memory
/** /**
* \class IP * \class IP
@@ -725,7 +728,7 @@ namespace Tins {
void internal_add_option(const option &option); void internal_add_option(const option &option);
void init_ip_fields(); void init_ip_fields();
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
uint8_t* write_option(const option &opt, uint8_t* buffer); void write_option(const option &opt, Memory::OutputMemoryStream& stream);
void add_route_option(option_identifier id, const generic_route_option_type &data); void add_route_option(option_identifier id, const generic_route_option_type &data);
generic_route_option_type search_route_option(option_identifier id) const; generic_route_option_type search_route_option(option_identifier id) const;
void checksum(uint16_t new_check); void checksum(uint16_t new_check);

View File

@@ -40,6 +40,10 @@
#include "ipv6_address.h" #include "ipv6_address.h"
namespace Tins { namespace Tins {
namespace Memory {
class OutputMemoryStream;
} // Memory
class PacketSender; class PacketSender;
/** /**
@@ -299,7 +303,7 @@ public:
private: private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
void set_last_next_header(uint8_t value); void set_last_next_header(uint8_t value);
static uint8_t *write_header(const ext_header &header, uint8_t *buffer); static void write_header(const ext_header &header, Memory::OutputMemoryStream& stream);
static bool is_extension_header(uint8_t header_id); static bool is_extension_header(uint8_t header_id);
TINS_BEGIN_PACK TINS_BEGIN_PACK

View File

@@ -383,6 +383,7 @@ namespace Tins {
#endif #endif
typedef std::vector<uint8_t> field_type; typedef std::vector<uint8_t> field_type;
typedef std::list<field_type> field_list;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
@@ -395,7 +396,7 @@ namespace Tins {
} control_field; } control_field;
Format _type; Format _type;
uint8_t information_field_length; uint8_t information_field_length;
std::list<field_type> information_fields; field_list information_fields;
}; };
} }

View File

@@ -3,6 +3,7 @@
#include <stdint.h> #include <stdint.h>
#include <cstring> #include <cstring>
#include <algorithm>
#include "exceptions.h" #include "exceptions.h"
#include "ip_address.h" #include "ip_address.h"
#include "ipv6_address.h" #include "ipv6_address.h"
@@ -20,6 +21,10 @@ void read_value(const uint8_t* buffer, T& value) {
std::memcpy(&value, buffer, sizeof(value)); std::memcpy(&value, buffer, sizeof(value));
} }
inline void write_data(uint8_t* buffer, const uint8_t* ptr, uint32_t size) {
std::memcpy(buffer, ptr, size);
}
template <typename T> template <typename T>
void write_value(uint8_t* buffer, const T& value) { void write_value(uint8_t* buffer, const T& value) {
std::memcpy(buffer, &value, sizeof(value)); std::memcpy(buffer, &value, sizeof(value));
@@ -105,6 +110,73 @@ private:
uint32_t size_; uint32_t size_;
}; };
class OutputMemoryStream {
public:
OutputMemoryStream(uint8_t* buffer, uint32_t total_sz)
: buffer_(buffer), size_(total_sz) {
}
void skip(uint32_t size) {
buffer_ += size;
size_ -= size;
}
template <typename T>
void write(const T& value) {
if (TINS_UNLIKELY(size_ < sizeof(value))) {
throw serialization_error();
}
write_value(buffer_, value);
skip(sizeof(value));
}
template <typename ForwardIterator>
void write(ForwardIterator start, ForwardIterator end) {
const uint32_t length = std::distance(start, end);
if (TINS_UNLIKELY(size_ < length)) {
throw serialization_error();
}
std::copy(start, end, buffer_);
skip(length);
}
void write(const uint8_t* ptr, uint32_t length) {
write(ptr, ptr + length);
}
void write(const IPv4Address& address) {
write(static_cast<uint32_t>(address));
}
void write(const IPv6Address& address) {
write(address.begin(), address.end());
}
template <size_t n>
void write(const HWAddress<n>& address) {
write(address.begin(), address.end());
}
void fill(uint32_t size, uint8_t value) {
if (TINS_UNLIKELY(size_ < size)) {
throw serialization_error();
}
std::fill(buffer_, buffer_ + size, value);
skip(size);
}
uint8_t* pointer() {
return buffer_;
}
uint32_t size() const {
return size_;
}
private:
uint8_t* buffer_;
uint32_t size_;
};
} // Memory } // Memory
} // Tins } // Tins

View File

@@ -44,6 +44,10 @@
#include "cxxstd.h" #include "cxxstd.h"
namespace Tins { namespace Tins {
namespace Memory {
class OutputMemoryStream;
} // Memory
/** /**
* \class TCP * \class TCP
* \brief Represents a TCP PDU. * \brief Represents a TCP PDU.
@@ -583,7 +587,7 @@ namespace Tins {
options_type::const_iterator search_option_iterator(OptionTypes type) const; options_type::const_iterator search_option_iterator(OptionTypes type) const;
options_type::iterator search_option_iterator(OptionTypes type); options_type::iterator search_option_iterator(OptionTypes type);
uint8_t *write_option(const option &opt, uint8_t *buffer); void write_option(const option &opt, Memory::OutputMemoryStream& stream);
tcphdr _tcp; tcphdr _tcp;
uint16_t _options_size, _total_options_size; uint16_t _options_size, _total_options_size;

View File

@@ -28,7 +28,6 @@
*/ */
#include <cstring> #include <cstring>
#include <cassert>
#include <algorithm> #include <algorithm>
#include "arp.h" #include "arp.h"
#include "ip.h" #include "ip.h"
@@ -42,6 +41,7 @@
using std::runtime_error; using std::runtime_error;
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -109,10 +109,8 @@ uint32_t ARP::header_size() const {
} }
void ARP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) { void ARP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
#ifdef TINS_DEBUG OutputMemoryStream stream(buffer, total_sz);
assert(total_sz >= sizeof(arphdr)); stream.write(_arp);
#endif
memcpy(buffer, &_arp, sizeof(arphdr));
} }
bool ARP::matches_response(const uint8_t *ptr, uint32_t total_sz) const { bool ARP::matches_response(const uint8_t *ptr, uint32_t total_sz) const {

View File

@@ -29,12 +29,12 @@
#include <stdexcept> #include <stdexcept>
#include <cstring> #include <cstring>
#include <cassert>
#include "bootp.h" #include "bootp.h"
#include "exceptions.h" #include "exceptions.h"
#include "memory_helpers.h" #include "memory_helpers.h"
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins{ namespace Tins{
@@ -116,11 +116,9 @@ void BootP::vend(const vend_type &new_vend) {
} }
void BootP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { void BootP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
#ifdef TINS_DEBUG OutputMemoryStream stream(buffer, total_sz);
assert(total_sz >= sizeof(bootphdr) + _vend.size()); stream.write(_bootp);
#endif stream.write(_vend.begin(), _vend.end());
std::memcpy(buffer, &_bootp, sizeof(bootphdr));
std::copy(_vend.begin(), _vend.end(), buffer + sizeof(bootphdr));
} }
bool BootP::matches_response(const uint8_t *ptr, uint32_t total_sz) const { bool BootP::matches_response(const uint8_t *ptr, uint32_t total_sz) const {

View File

@@ -28,7 +28,6 @@
*/ */
#include <stdexcept> #include <stdexcept>
#include <cassert>
#include <cstring> #include <cstring>
#include "endianness.h" #include "endianness.h"
#include "dhcp.h" #include "dhcp.h"
@@ -43,6 +42,7 @@ using std::runtime_error;
using std::find_if; using std::find_if;
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -57,8 +57,8 @@ DHCP::DHCP()
DHCP::DHCP(const uint8_t *buffer, uint32_t total_sz) DHCP::DHCP(const uint8_t *buffer, uint32_t total_sz)
: BootP(buffer, total_sz, 0), _size(sizeof(uint32_t)) : BootP(buffer, total_sz, 0), _size(sizeof(uint32_t))
{ {
const uint32_t bootp_size = BootP::header_size() - vend().size(); InputMemoryStream stream(buffer, total_sz);
InputMemoryStream stream(buffer + bootp_size, total_sz - bootp_size); stream.skip(BootP::header_size() - vend().size());
const uint32_t magic_number = stream.read<uint32_t>(); const uint32_t magic_number = stream.read<uint32_t>();
if (magic_number != Endian::host_to_be<uint32_t>(0x63825363)) if (magic_number != Endian::host_to_be<uint32_t>(0x63825363))
throw malformed_packet(); throw malformed_packet();
@@ -238,22 +238,19 @@ uint32_t DHCP::header_size() const {
} }
void DHCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { void DHCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
#ifdef TINS_DEBUG if (_size) {
assert(total_sz >= header_size()); vend_type &result = BootP::vend();
#endif
if(_size) {
vend_type &result(BootP::vend());
result.resize(_size); result.resize(_size);
uint8_t *ptr = &result[0] + sizeof(uint32_t); // Build a stream over the vend vector
OutputMemoryStream stream(&result[0], result.size());
// Magic cookie // Magic cookie
*((uint32_t*)&result[0]) = Endian::host_to_be<uint32_t>(0x63825363); stream.write(Endian::host_to_be<uint32_t>(0x63825363));
for(options_type::const_iterator it = _options.begin(); it != _options.end(); ++it) { for (options_type::const_iterator it = _options.begin(); it != _options.end(); ++it) {
*(ptr++) = it->option(); stream.write(it->option());
*(ptr++) = static_cast<uint8_t>(it->length_field()); stream.write<uint8_t>(it->length_field());
std::copy(it->data_ptr(), it->data_ptr() + it->data_size(), ptr); stream.write(it->data_ptr(), it->data_size());
ptr += it->data_size();
} }
} }
BootP::write_serialization(buffer, total_sz, parent); BootP::write_serialization(buffer, total_sz, parent);
} }
} } // Tins

View File

@@ -36,6 +36,7 @@
using std::find_if; using std::find_if;
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -109,16 +110,10 @@ DHCPv6::options_type::iterator DHCPv6::search_option_iterator(OptionTypes type)
return find_if(options_.begin(), options_.end(), comparator); return find_if(options_.begin(), options_.end(), comparator);
} }
uint8_t* DHCPv6::write_option(const option &opt, uint8_t* buffer) const { void DHCPv6::write_option(const option &opt, OutputMemoryStream& stream) const {
uint16_t uint16_t_buffer = Endian::host_to_be(opt.option()); stream.write(Endian::host_to_be<uint16_t>(opt.option()));
std::memcpy(buffer, &uint16_t_buffer, sizeof(uint16_t)); stream.write(Endian::host_to_be<uint16_t>(opt.length_field()));
uint16_t_buffer = Endian::host_to_be(static_cast<uint16_t>(opt.length_field())); stream.write(opt.data_ptr(), opt.data_size());
std::memcpy(&buffer[sizeof(uint16_t)], &uint16_t_buffer, sizeof(uint16_t));
return std::copy(
opt.data_ptr(),
opt.data_ptr() + opt.data_size(),
buffer + sizeof(uint16_t) * 2
);
} }
void DHCPv6::msg_type(MessageType type) { void DHCPv6::msg_type(MessageType type) {
@@ -163,13 +158,14 @@ bool DHCPv6::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
void DHCPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) { void DHCPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
const uint32_t required_size = is_relay_message() ? 2 : 4; const uint32_t required_size = is_relay_message() ? 2 : 4;
buffer = std::copy(header_data, header_data + required_size, buffer); OutputMemoryStream stream(buffer, total_sz);
if(is_relay_message()) { stream.write(header_data, required_size);
buffer = link_addr.copy(buffer); if (is_relay_message()) {
buffer = peer_addr.copy(buffer); stream.write(link_addr);
stream.write(peer_addr);
} }
for(options_type::const_iterator it = options_.begin(); it != options_.end(); ++it) { for (options_type::const_iterator it = options_.begin(); it != options_.end(); ++it) {
buffer = write_option(*it, buffer); write_option(*it, stream);
} }
} }

View File

@@ -29,7 +29,6 @@
#include <utility> #include <utility>
#include <stdexcept> #include <stdexcept>
#include <cassert>
#include <sstream> #include <sstream>
#include <memory> #include <memory>
#include <cstdio> #include <cstdio>
@@ -45,6 +44,7 @@ using std::string;
using std::list; using std::list;
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -361,12 +361,9 @@ const uint8_t* DNS::compose_name(const uint8_t *ptr, char *out_ptr) const {
} }
void DNS::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { void DNS::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
#ifdef TINS_DEBUG OutputMemoryStream stream(buffer, total_sz);
assert(total_sz >= sizeof(dns) + records_data.size());//extra_size); stream.write(dns);
#endif stream.write(records_data.begin(), records_data.end());
std::memcpy(buffer, &dns, sizeof(dns));
buffer += sizeof(dns);
std::copy(records_data.begin(), records_data.end(), buffer);
} }
// Optimization. Creating an IPv4Address and then using IPv4Address::to_string // Optimization. Creating an IPv4Address and then using IPv4Address::to_string

View File

@@ -29,13 +29,13 @@
#include <stdexcept> #include <stdexcept>
#include <cstring> #include <cstring>
#include <cassert>
#include "dot1q.h" #include "dot1q.h"
#include "internals.h" #include "internals.h"
#include "exceptions.h" #include "exceptions.h"
#include "memory_helpers.h" #include "memory_helpers.h"
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -88,33 +88,35 @@ uint32_t Dot1Q::header_size() const {
} }
uint32_t Dot1Q::trailer_size() const { uint32_t Dot1Q::trailer_size() const {
if(_append_padding) { if (_append_padding) {
uint32_t total_size = sizeof(_header); uint32_t total_size = sizeof(_header);
if(inner_pdu()) if (inner_pdu()) {
total_size += inner_pdu()->size(); total_size += inner_pdu()->size();
}
return (total_size > 50) ? 0 : (50 - total_size); return (total_size > 50) ? 0 : (50 - total_size);
} }
else else {
return 0; return 0;
}
} }
void Dot1Q::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) { void Dot1Q::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
uint32_t trailer = trailer_size(); OutputMemoryStream stream(buffer, total_sz);
#ifdef TINS_DEBUG
assert(total_sz >= sizeof(_header) + trailer);
#endif
if (inner_pdu()) { if (inner_pdu()) {
// Set the appropriate payload type flag
Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_type( Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_type(
inner_pdu()->pdu_type() inner_pdu()->pdu_type()
); );
payload_type(static_cast<uint16_t>(flag)); payload_type(static_cast<uint16_t>(flag));
} }
std::memcpy(buffer, &_header, sizeof(_header)); stream.write(_header);
buffer += sizeof(_header); // Skip inner PDU size
if(inner_pdu()) if (inner_pdu()) {
buffer += inner_pdu()->size(); stream.skip(inner_pdu()->size());
std::fill(buffer, buffer + trailer, 0); }
// Write trailer
stream.fill(trailer_size(), 0);
} }
#if TINS_IS_LITTLE_ENDIAN #if TINS_IS_LITTLE_ENDIAN

View File

@@ -50,6 +50,7 @@
#include "memory_helpers.h" #include "memory_helpers.h"
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -129,12 +130,9 @@ bool Dot3::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
} }
void Dot3::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { void Dot3::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
#ifdef TINS_DEBUG OutputMemoryStream stream(buffer, total_sz);
assert(total_sz >= header_size()); _eth.length = Endian::host_to_be<uint16_t>(size() - sizeof(_eth));
#endif stream.write(_eth);
_eth.length = Endian::host_to_be(static_cast<uint16_t>(size() - sizeof(_eth)));
memcpy(buffer, &_eth, sizeof(ethhdr));
} }
#ifndef _WIN32 #ifndef _WIN32

View File

@@ -39,6 +39,7 @@
#include "memory_helpers.h" #include "memory_helpers.h"
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -96,11 +97,10 @@ void EAPOL::type(uint8_t new_type) {
} }
void EAPOL::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) { void EAPOL::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
#ifdef TINS_DEBUG OutputMemoryStream stream(buffer, total_sz);
assert(total_sz >= header_size()); stream.write(_header);
#endif
std::memcpy(buffer, &_header, sizeof(_header)); std::memcpy(buffer, &_header, sizeof(_header));
write_body(buffer + sizeof(_header), total_sz - sizeof(_header)); write_body(stream);
} }
/* RC4EAPOL */ /* RC4EAPOL */
@@ -157,16 +157,12 @@ uint32_t RC4EAPOL::header_size() const {
return static_cast<uint32_t>(sizeof(eapolhdr) + sizeof(_header) + _key.size()); return static_cast<uint32_t>(sizeof(eapolhdr) + sizeof(_header) + _key.size());
} }
void RC4EAPOL::write_body(uint8_t *buffer, uint32_t total_sz) { void RC4EAPOL::write_body(OutputMemoryStream& stream) {
#ifdef TINS_DEBUG if (_key.size()) {
assert(total_sz >= sizeof(_header) + _key.size());
#endif
if(_key.size()) {
_header.key_length = Endian::host_to_be(static_cast<uint16_t>(_key.size())); _header.key_length = Endian::host_to_be(static_cast<uint16_t>(_key.size()));
} }
std::memcpy(buffer, &_header, sizeof(_header)); stream.write(_header);
buffer += sizeof(_header); stream.write(_key.begin(), _key.end());
std::copy(_key.begin(), _key.end(), buffer);
} }
/* RSNEAPOL */ /* RSNEAPOL */
@@ -273,21 +269,17 @@ uint32_t RSNEAPOL::header_size() const {
return static_cast<uint32_t>(sizeof(eapolhdr) + sizeof(_header) + _key.size()); return static_cast<uint32_t>(sizeof(eapolhdr) + sizeof(_header) + _key.size());
} }
void RSNEAPOL::write_body(uint8_t *buffer, uint32_t total_sz) { void RSNEAPOL::write_body(OutputMemoryStream& stream) {
#ifdef TINS_DEBUG if (_key.size()) {
assert(total_sz >= header_size() - sizeof(eapolhdr)); if (!_header.key_t) {
#endif
if(_key.size()) {
if(!_header.key_t) {
_header.key_length = Endian::host_to_be<uint16_t>(32); _header.key_length = Endian::host_to_be<uint16_t>(32);
wpa_length(static_cast<uint16_t>(_key.size())); wpa_length(static_cast<uint16_t>(_key.size()));
} }
else if(_key.size()) { else if (_key.size()) {
wpa_length(static_cast<uint16_t>(_key.size())); wpa_length(static_cast<uint16_t>(_key.size()));
} }
} }
std::memcpy(buffer, &_header, sizeof(_header)); stream.write(_header);
buffer += sizeof(_header); stream.write(_key.begin(), _key.end());
std::copy(_key.begin(), _key.end(), buffer);
} }
} }

View File

@@ -56,6 +56,7 @@
#include "memory_helpers.h" #include "memory_helpers.h"
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -152,11 +153,7 @@ bool EthernetII::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
} }
void EthernetII::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { void EthernetII::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
#ifdef TINS_DEBUG OutputMemoryStream stream(buffer, total_sz);
assert(total_sz >= header_size() + trailer_size());
#endif
/* Inner type defaults to IP */
if (inner_pdu()) { if (inner_pdu()) {
Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_type( Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_type(
inner_pdu()->pdu_type() inner_pdu()->pdu_type()
@@ -165,13 +162,13 @@ void EthernetII::write_serialization(uint8_t *buffer, uint32_t total_sz, const P
payload_type(static_cast<uint16_t>(flag)); payload_type(static_cast<uint16_t>(flag));
} }
} }
memcpy(buffer, &_eth, sizeof(ethhdr)); stream.write(_eth);
uint32_t trailer = trailer_size(); const uint32_t trailer = trailer_size();
if (trailer) { if (trailer) {
uint32_t trailer_offset = header_size(); if (inner_pdu()) {
if (inner_pdu()) stream.skip(inner_pdu()->size());
trailer_offset += inner_pdu()->size(); }
memset(buffer + trailer_offset, 0, trailer); stream.fill(trailer, 0);
} }
} }

View File

@@ -42,6 +42,7 @@
#include "memory_helpers.h" #include "memory_helpers.h"
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -207,23 +208,7 @@ void ICMP::use_length_field(bool value) {
} }
void ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) { void ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
#ifdef TINS_DEBUG OutputMemoryStream stream(buffer, total_sz);
assert(total_sz >= sizeof(icmphdr));
#endif
uint32_t uint32_t_buffer;
if(type() == TIMESTAMP_REQUEST || type() == TIMESTAMP_REPLY) {
uint32_t_buffer = original_timestamp();
memcpy(buffer + sizeof(icmphdr), &uint32_t_buffer, sizeof(uint32_t));
uint32_t_buffer = receive_timestamp();
memcpy(buffer + sizeof(icmphdr) + sizeof(uint32_t), &uint32_t_buffer, sizeof(uint32_t));
uint32_t_buffer = transmit_timestamp();
memcpy(buffer + sizeof(icmphdr) + 2 * sizeof(uint32_t), &uint32_t_buffer, sizeof(uint32_t));
}
else if(type() == ADDRESS_MASK_REQUEST || type() == ADDRESS_MASK_REPLY) {
uint32_t_buffer = address_mask();
memcpy(buffer + sizeof(icmphdr), &uint32_t_buffer, sizeof(uint32_t));
}
// If extensions are allowed and we have to set the length field // If extensions are allowed and we have to set the length field
if (are_extensions_allowed()) { if (are_extensions_allowed()) {
@@ -236,6 +221,19 @@ void ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *)
} }
} }
// Write the header using checksum 0
_icmp.check = 0;
stream.write(_icmp);
if(type() == TIMESTAMP_REQUEST || type() == TIMESTAMP_REPLY) {
stream.write(original_timestamp());
stream.write(receive_timestamp());
stream.write(transmit_timestamp());
}
else if(type() == ADDRESS_MASK_REQUEST || type() == ADDRESS_MASK_REPLY) {
stream.write(address_mask());
}
if (has_extensions()) { if (has_extensions()) {
uint8_t* extensions_ptr = buffer + sizeof(icmphdr); uint8_t* extensions_ptr = buffer + sizeof(icmphdr);
if (inner_pdu()) { if (inner_pdu()) {
@@ -258,14 +256,12 @@ void ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *)
extensions_.serialize(extensions_ptr, total_sz - (extensions_ptr - buffer)); extensions_.serialize(extensions_ptr, total_sz - (extensions_ptr - buffer));
} }
// checksum calc // Calculate checksum
_icmp.check = 0;
memcpy(buffer, &_icmp, sizeof(icmphdr));
uint32_t checksum = Utils::do_checksum(buffer, buffer + total_sz); uint32_t checksum = Utils::do_checksum(buffer, buffer + total_sz);
while (checksum >> 16) {
while (checksum >> 16)
checksum = (checksum & 0xffff) + (checksum >> 16); checksum = (checksum & 0xffff) + (checksum >> 16);
}
// Write back only the 2 checksum bytes
_icmp.check = Endian::host_to_be<uint16_t>(~checksum); _icmp.check = Endian::host_to_be<uint16_t>(~checksum);
memcpy(buffer + 2, &_icmp.check, sizeof(uint16_t)); memcpy(buffer + 2, &_icmp.check, sizeof(uint16_t));
} }

View File

@@ -8,6 +8,7 @@
using std::runtime_error; using std::runtime_error;
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -57,16 +58,11 @@ uint32_t ICMPExtension::size() const {
} }
void ICMPExtension::serialize(uint8_t* buffer, uint32_t buffer_size) const { void ICMPExtension::serialize(uint8_t* buffer, uint32_t buffer_size) const {
if (buffer_size < size()) { OutputMemoryStream stream(buffer, buffer_size);
throw runtime_error("Serialization buffer is too small"); stream.write(Endian::host_to_be<uint16_t>(size()));
} stream.write(extension_class_);
*(uint16_t*)buffer = Endian::host_to_be<uint16_t>(size()); stream.write(extension_type_);
buffer += sizeof(uint16_t); stream.write(payload_.begin(), payload_.end());
*buffer = extension_class_;
buffer += sizeof(uint8_t);
*buffer = extension_type_;
buffer += sizeof(uint8_t);
copy(payload_.begin(), payload_.end(), buffer);
} }
ICMPExtension::serialization_type ICMPExtension::serialize() const { ICMPExtension::serialization_type ICMPExtension::serialize() const {
@@ -140,25 +136,18 @@ void ICMPExtensionsStructure::add_extension(const ICMPExtension& extension) {
} }
void ICMPExtensionsStructure::serialize(uint8_t* buffer, uint32_t buffer_size) { void ICMPExtensionsStructure::serialize(uint8_t* buffer, uint32_t buffer_size) {
const uint32_t structure_size = size(); OutputMemoryStream stream(buffer, buffer_size);
if (buffer_size < structure_size) {
throw malformed_packet();
}
uint8_t* original_ptr = buffer; uint8_t* original_ptr = buffer;
memcpy(buffer, &version_and_reserved_, sizeof(version_and_reserved_)); stream.write(version_and_reserved_);
buffer += sizeof(uint16_t);
// Make checksum 0, for now, we'll compute it at the end // Make checksum 0, for now, we'll compute it at the end
memset(buffer, 0, sizeof(uint16_t)); stream.write<uint16_t>(0);
buffer += sizeof(uint16_t);
buffer_size -= BASE_HEADER_SIZE;
typedef extensions_type::const_iterator iterator; typedef extensions_type::const_iterator iterator;
for (iterator iter = extensions_.begin(); iter != extensions_.end(); ++iter) { for (iterator iter = extensions_.begin(); iter != extensions_.end(); ++iter) {
iter->serialize(buffer, buffer_size); iter->serialize(stream.pointer(), stream.size());
buffer += iter->size(); stream.skip(iter->size());
buffer_size -= iter->size();
} }
uint16_t checksum = ~Utils::sum_range(original_ptr, original_ptr + structure_size); uint16_t checksum = ~Utils::sum_range(original_ptr, original_ptr + size());
memcpy(original_ptr + sizeof(uint16_t), &checksum, sizeof(checksum)); memcpy(original_ptr + sizeof(uint16_t), &checksum, sizeof(checksum));
checksum_ = checksum; checksum_ = checksum;
} }

View File

@@ -40,6 +40,7 @@
#include "memory_helpers.h" #include "memory_helpers.h"
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -213,12 +214,7 @@ bool ICMPv6::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
} }
void ICMPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { void ICMPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
#ifdef TINS_DEBUG OutputMemoryStream stream(buffer, total_sz);
assert(total_sz >= header_size());
#endif
uint32_t full_sz = total_sz;
uint8_t *buffer_start = buffer;
_header.cksum = 0;
// If extensions are allowed and we have to set the length field // If extensions are allowed and we have to set the length field
if (are_extensions_allowed()) { if (are_extensions_allowed()) {
@@ -230,36 +226,26 @@ void ICMPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *
_header.rfc4884.length = length_value / sizeof(uint64_t); _header.rfc4884.length = length_value / sizeof(uint64_t);
} }
} }
// Initially set checksum to 0, we'll calculate it at the end
_header.cksum = 0;
stream.write(_header);
std::memcpy(buffer, &_header, sizeof(_header)); if (has_target_addr()) {
buffer += sizeof(_header); stream.write(_target_address);
total_sz -= sizeof(_header);
if(has_target_addr()) {
buffer = _target_address.copy(buffer);
total_sz -= sizeof(ipaddress_type::address_size);
} }
if(has_dest_addr()) { if (has_dest_addr()) {
buffer = _dest_address.copy(buffer); stream.write(_dest_address);
total_sz -= sizeof(ipaddress_type::address_size);
} }
if(type() == ROUTER_ADVERT) { if (type() == ROUTER_ADVERT) {
std::memcpy(buffer, &reach_time, sizeof(uint32_t)); stream.write(reach_time);
buffer += sizeof(uint32_t); stream.write(retrans_timer);
std::memcpy(buffer, &retrans_timer, sizeof(uint32_t));
buffer += sizeof(uint32_t);
total_sz -= sizeof(uint32_t) * 2;
} }
for(options_type::const_iterator it = _options.begin(); it != _options.end(); ++it) { for(options_type::const_iterator it = _options.begin(); it != _options.end(); ++it) {
#ifdef TINS_DEBUG write_option(*it, stream);
assert(total_sz >= it->data_size() + sizeof(uint8_t) * 2);
// total_sz is only used if TINS_DEBUG is defined.
total_sz -= it->data_size() + sizeof(uint8_t) * 2;
#endif
buffer = write_option(*it, buffer);
} }
if (has_extensions()) { if (has_extensions()) {
uint8_t* extensions_ptr = buffer; uint8_t* extensions_ptr = stream.pointer();
if (inner_pdu()) { if (inner_pdu()) {
// Get the size of the next pdu, padded to the next 32 bit boundary // Get the size of the next pdu, padded to the next 32 bit boundary
uint32_t inner_pdu_size = get_adjusted_inner_pdu_size(); uint32_t inner_pdu_size = get_adjusted_inner_pdu_size();
@@ -278,21 +264,25 @@ void ICMPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *
extensions_ptr += inner_pdu_size; extensions_ptr += inner_pdu_size;
} }
// Now serialize the exensions where they should be // Now serialize the exensions where they should be
extensions_.serialize(extensions_ptr, total_sz - (extensions_ptr - buffer)); extensions_.serialize(
extensions_ptr,
total_sz - (extensions_ptr - stream.pointer())
);
} }
const Tins::IPv6 *ipv6 = tins_cast<const Tins::IPv6*>(parent); const Tins::IPv6 *ipv6 = tins_cast<const Tins::IPv6*>(parent);
if(ipv6) { if (ipv6) {
uint32_t checksum = Utils::pseudoheader_checksum( uint32_t checksum = Utils::pseudoheader_checksum(
ipv6->src_addr(), ipv6->src_addr(),
ipv6->dst_addr(), ipv6->dst_addr(),
size(), size(),
Constants::IP::PROTO_ICMPV6 Constants::IP::PROTO_ICMPV6
) + Utils::do_checksum(buffer_start, buffer_start + full_sz); ) + Utils::do_checksum(buffer, buffer + total_sz);
while (checksum >> 16) while (checksum >> 16) {
checksum = (checksum & 0xffff) + (checksum >> 16); checksum = (checksum & 0xffff) + (checksum >> 16);
}
this->checksum(~checksum); this->checksum(~checksum);
memcpy(buffer_start + 2, &_header.cksum, sizeof(uint16_t)); memcpy(buffer + 2, &_header.cksum, sizeof(uint16_t));
} }
} }
@@ -329,10 +319,10 @@ bool ICMPv6::remove_option(OptionTypes type) {
return true; return true;
} }
uint8_t *ICMPv6::write_option(const option &opt, uint8_t *buffer) { void ICMPv6::write_option(const option &opt, OutputMemoryStream& stream) {
*buffer++ = opt.option(); stream.write(opt.option());
*buffer++ = static_cast<uint8_t>((opt.length_field() + sizeof(uint8_t) * 2) / 8); stream.write<uint8_t>((opt.length_field() + sizeof(uint8_t) * 2) / 8);
return std::copy(opt.data_ptr(), opt.data_ptr() + opt.data_size(), buffer); stream.write(opt.data_ptr(), opt.data_size());
} }
const ICMPv6::option *ICMPv6::search_option(OptionTypes type) const { const ICMPv6::option *ICMPv6::search_option(OptionTypes type) const {

View File

@@ -53,6 +53,7 @@
using std::list; using std::list;
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -353,17 +354,17 @@ IP::options_type::iterator IP::search_option_iterator(option_identifier id) {
return find_if(_ip_options.begin(), _ip_options.end(), comparator); return find_if(_ip_options.begin(), _ip_options.end(), comparator);
} }
uint8_t* IP::write_option(const option &opt, uint8_t* buffer) { void IP::write_option(const option &opt, OutputMemoryStream& stream) {
option_identifier opt_type = opt.option(); stream.write(opt.option());
memcpy(buffer, &opt_type, 1); // Check what we wrote. We'll do this for any option != [END, NOOP]
if(*buffer <= 1) if (*(stream.pointer() - 1) > NOOP) {
return ++buffer; uint8_t length = opt.length_field();
buffer++; if (opt.data_size() == opt.length_field()) {
*buffer = static_cast<uint8_t>(opt.length_field()); length += 2;
if(opt.data_size() == opt.length_field()) }
*buffer += 2; stream.write(length);
buffer++; stream.write(opt.data_ptr(), opt.data_size());
return std::copy(opt.data_ptr(), opt.data_ptr() + opt.data_size(), buffer); }
} }
/* Virtual method overriding. */ /* Virtual method overriding. */
@@ -415,40 +416,40 @@ void IP::prepare_for_serialize(const PDU *parent) {
} }
void IP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU* parent) { void IP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU* parent) {
uint32_t my_sz = header_size(); OutputMemoryStream stream(buffer, total_sz);
#ifdef TINS_DEBUG
assert(total_sz >= my_sz);
#endif
checksum(0); checksum(0);
if(inner_pdu()) { if (inner_pdu()) {
uint32_t new_flag = Internals::pdu_flag_to_ip_type(inner_pdu()->pdu_type()); uint32_t new_flag = Internals::pdu_flag_to_ip_type(inner_pdu()->pdu_type());
if(new_flag == 0xff && Internals::pdu_type_registered<IP>(inner_pdu()->pdu_type())) { if (new_flag == 0xff && Internals::pdu_type_registered<IP>(inner_pdu()->pdu_type())) {
new_flag = static_cast<Constants::IP::e>( new_flag = static_cast<Constants::IP::e>(
Internals::pdu_type_to_id<IP>(inner_pdu()->pdu_type()) Internals::pdu_type_to_id<IP>(inner_pdu()->pdu_type())
); );
} }
if(!is_fragmented() && new_flag != 0xff) if (!is_fragmented() && new_flag != 0xff) {
protocol(new_flag); protocol(new_flag);
}
} }
#if __FreeBSD__ || defined(__FreeBSD_kernel__) || __APPLE__ #if __FreeBSD__ || defined(__FreeBSD_kernel__) || __APPLE__
if(!parent) if(!parent) {
total_sz = Endian::host_to_be<uint16_t>(total_sz); total_sz = Endian::host_to_be<uint16_t>(total_sz);
}
#endif #endif
tot_len(total_sz); tot_len(total_sz);
head_len(static_cast<uint8_t>(my_sz / sizeof(uint32_t))); head_len(static_cast<uint8_t>(header_size() / sizeof(uint32_t)));
memcpy(buffer, &_ip, sizeof(_ip)); stream.write(_ip);
uint8_t* ptr_buffer = buffer + sizeof(_ip);
for(options_type::const_iterator it = _ip_options.begin(); it != _ip_options.end(); ++it) { for(options_type::const_iterator it = _ip_options.begin(); it != _ip_options.end(); ++it) {
ptr_buffer = write_option(*it, ptr_buffer); write_option(*it, stream);
} }
memset(buffer + sizeof(_ip) + _options_size, 0, _padded_options_size - _options_size); // Add option padding
stream.fill(_padded_options_size - _options_size, 0);
uint32_t check = Utils::do_checksum(buffer, buffer + sizeof(_ip) + _padded_options_size); uint32_t check = Utils::do_checksum(buffer, buffer + sizeof(_ip) + _padded_options_size);
while (check >> 16) while (check >> 16) {
check = (check & 0xffff) + (check >> 16); check = (check & 0xffff) + (check >> 16);
}
checksum(~check); checksum(~check);
((iphdr*)buffer)->check = _ip.check; ((iphdr*)buffer)->check = _ip.check;
} }

View File

@@ -48,6 +48,7 @@
#include "memory_helpers.h" #include "memory_helpers.h"
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -191,12 +192,10 @@ bool IPv6::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
} }
void IPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { void IPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
#ifdef TINS_DEBUG OutputMemoryStream stream(buffer, total_sz);
assert(total_sz >= header_size()); if (inner_pdu()) {
#endif
if(inner_pdu()) {
uint8_t new_flag = Internals::pdu_flag_to_ip_type(inner_pdu()->pdu_type()); uint8_t new_flag = Internals::pdu_flag_to_ip_type(inner_pdu()->pdu_type());
if(new_flag == 0xff && Internals::pdu_type_registered<IPv6>(inner_pdu()->pdu_type())) { if (new_flag == 0xff && Internals::pdu_type_registered<IPv6>(inner_pdu()->pdu_type())) {
new_flag = static_cast<Constants::IP::e>( new_flag = static_cast<Constants::IP::e>(
Internals::pdu_type_to_id<IPv6>(inner_pdu()->pdu_type()) Internals::pdu_type_to_id<IPv6>(inner_pdu()->pdu_type())
); );
@@ -204,10 +203,9 @@ void IPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *pa
set_last_next_header(new_flag); set_last_next_header(new_flag);
} }
payload_length(static_cast<uint16_t>(total_sz - sizeof(_header))); payload_length(static_cast<uint16_t>(total_sz - sizeof(_header)));
std::memcpy(buffer, &_header, sizeof(_header)); stream.write(_header);
buffer += sizeof(_header);
for(headers_type::const_iterator it = ext_headers.begin(); it != ext_headers.end(); ++it) { for(headers_type::const_iterator it = ext_headers.begin(); it != ext_headers.end(); ++it) {
buffer = write_header(*it, buffer); write_header(*it, stream);
} }
} }
@@ -249,10 +247,11 @@ void IPv6::set_last_next_header(uint8_t value) {
ext_headers.back().option(value); ext_headers.back().option(value);
} }
uint8_t *IPv6::write_header(const ext_header &header, uint8_t *buffer) { void IPv6::write_header(const ext_header &header, OutputMemoryStream& stream) {
*buffer++ = header.option(); const uint8_t length = (header.length_field() > 8) ? (header.length_field() - 8) : 0;
*buffer++ = static_cast<uint8_t>((header.length_field() > 8) ? (header.length_field() - 8) : 0); stream.write(header.option());
return std::copy(header.data_ptr(), header.data_ptr() + header.data_size(), buffer); stream.write(length);
stream.write(header.data_ptr(), header.data_size());
} }
} } // Tins

View File

@@ -39,6 +39,7 @@
#include "memory_helpers.h" #include "memory_helpers.h"
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -198,33 +199,26 @@ void LLC::clear_information_fields() {
} }
void LLC::write_serialization(uint8_t *buffer, uint32_t total_sz, const Tins::PDU *parent) { void LLC::write_serialization(uint8_t *buffer, uint32_t total_sz, const Tins::PDU *parent) {
#ifdef TINS_DEBUG OutputMemoryStream stream(buffer, total_sz);
assert(total_sz >= header_size()); if (inner_pdu() && inner_pdu()->pdu_type() == PDU::STP) {
#endif
if(inner_pdu() && inner_pdu()->pdu_type() == PDU::STP) {
dsap(0x42); dsap(0x42);
ssap(0x42); ssap(0x42);
} }
std::memcpy(buffer, &_header, sizeof(_header)); stream.write(_header);
buffer += sizeof(_header);
switch (type()) { switch (type()) {
case LLC::UNNUMBERED: case LLC::UNNUMBERED:
std::memcpy(buffer, &(control_field.unnumbered), sizeof(un_control_field)); stream.write(control_field.unnumbered);
buffer += sizeof(un_control_field);
break; break;
case LLC::INFORMATION: case LLC::INFORMATION:
std::memcpy(buffer, &(control_field.info), sizeof(info_control_field)); stream.write(control_field.info);
buffer += sizeof(info_control_field);
break; break;
case LLC::SUPERVISORY: case LLC::SUPERVISORY:
std::memcpy(buffer, &(control_field.super), sizeof(super_control_field)); stream.write(control_field.super);
buffer += sizeof(super_control_field);
break; break;
} }
for (std::list<field_type>::const_iterator it = information_fields.begin(); it != information_fields.end(); it++) { for (field_list::const_iterator it = information_fields.begin(); it != information_fields.end(); it++) {
std::copy(it->begin(), it->end(), buffer); stream.write(it->begin(), it->end());
buffer += it->size();
} }
} }

View File

@@ -56,6 +56,7 @@
#endif #endif
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -95,15 +96,15 @@ uint32_t Loopback::header_size() const {
} }
void Loopback::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) { void Loopback::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
#ifdef TINS_DEBUG OutputMemoryStream stream(buffer, total_sz);
assert(total_sz >= sizeof(_family));
#endif
#ifndef _WIN32 #ifndef _WIN32
if(tins_cast<const Tins::IP*>(inner_pdu())) if (tins_cast<const Tins::IP*>(inner_pdu())) {
_family = PF_INET; _family = PF_INET;
else if(tins_cast<const Tins::LLC*>(inner_pdu())) }
else if (tins_cast<const Tins::LLC*>(inner_pdu())) {
_family = PF_LLC; _family = PF_LLC;
*reinterpret_cast<uint32_t*>(buffer) = _family; }
stream.write(_family);
#endif // _WIN32 #endif // _WIN32
} }

View File

@@ -37,6 +37,7 @@
#include "memory_helpers.h" #include "memory_helpers.h"
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -109,25 +110,15 @@ uint32_t PPPoE::header_size() const {
void PPPoE::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) void PPPoE::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *)
{ {
#ifdef TINS_DEBUG OutputMemoryStream stream(buffer, total_sz);
assert(total_sz == sizeof(_header) + _tags_size); if (_tags_size > 0) {
#endif payload_length(_tags_size);
std::memcpy(buffer, &_header, sizeof(_header)); }
if(_tags_size > 0) stream.write(_header);
((pppoe_hdr*)buffer)->payload_length = Endian::host_to_be(_tags_size);
buffer += sizeof(_header);
uint16_t uint16_t_buffer;
for(tags_type::const_iterator it = _tags.begin(); it != _tags.end(); ++it) { for(tags_type::const_iterator it = _tags.begin(); it != _tags.end(); ++it) {
uint16_t_buffer = it->option(); stream.write<uint16_t>(it->option());
std::memcpy(buffer, &uint16_t_buffer, sizeof(uint16_t)); stream.write(Endian::host_to_be<uint16_t>(it->length_field()));
uint16_t_buffer = Endian::host_to_be(static_cast<uint16_t>(it->length_field())); stream.write(it->data_ptr(), it->data_size());
std::memcpy(buffer + sizeof(uint16_t), &uint16_t_buffer, sizeof(uint16_t));
std::copy(
it->data_ptr(),
it->data_ptr() + it->data_size(),
buffer + sizeof(uint16_t) * 2
);
buffer += sizeof(uint16_t) * 2 + it->data_size();
} }
} }

View File

@@ -50,8 +50,12 @@
#include "utils.h" #include "utils.h"
#include "packet_sender.h" #include "packet_sender.h"
#include "exceptions.h" #include "exceptions.h"
#include "memory_helpers.h"
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
void check_size(uint32_t total_sz, size_t field_size) { void check_size(uint32_t total_sz, size_t field_size) {
if(total_sz < field_size) if(total_sz < field_size)
throw malformed_packet(); throw malformed_packet();
@@ -471,87 +475,69 @@ bool RadioTap::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
} }
void RadioTap::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { void RadioTap::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
uint32_t sz = header_size(); OutputMemoryStream stream(buffer, total_sz);
uint8_t *buffer_start = buffer; uint8_t *buffer_start = buffer;
#ifdef TINS_DEBUG _radio.it_len = Endian::host_to_le<uint16_t>(header_size());
assert(total_sz >= sz); stream.write(_radio);
#endif
_radio.it_len = Endian::host_to_le<uint16_t>(sz);
memcpy(buffer, &_radio, sizeof(_radio));
buffer += sizeof(_radio);
if(_radio.flags.tsft) { if(_radio.flags.tsft) {
memcpy(buffer, &_tsft, sizeof(_tsft)); stream.write(_tsft);
buffer += sizeof(_tsft);
} }
if(_radio.flags.flags) { if(_radio.flags.flags) {
memcpy(buffer, &_flags, sizeof(_flags)); stream.write(_flags);
buffer += sizeof(_flags);
} }
if(_radio.flags.rate) { if(_radio.flags.rate) {
memcpy(buffer, &_rate, sizeof(_rate)); stream.write(_rate);
buffer += sizeof(_rate);
} }
if(_radio.flags.channel) { if(_radio.flags.channel) {
if(((buffer - buffer_start) & 1) == 1) if(((buffer - buffer_start) & 1) == 1) {
*(buffer++) = 0; stream.write<uint8_t>(0);
memcpy(buffer, &_channel_freq, sizeof(_channel_freq)); }
buffer += sizeof(_channel_freq); stream.write(_channel_freq);
memcpy(buffer, &_channel_type, sizeof(_channel_type)); stream.write(_channel_type);
buffer += sizeof(_channel_type);
} }
if(_radio.flags.dbm_signal) { if(_radio.flags.dbm_signal) {
memcpy(buffer, &_dbm_signal, sizeof(_dbm_signal)); stream.write(_dbm_signal);
buffer += sizeof(_dbm_signal);
} }
if(_radio.flags.dbm_noise) { if(_radio.flags.dbm_noise) {
memcpy(buffer, &_dbm_noise, sizeof(_dbm_noise)); stream.write(_dbm_noise);
buffer += sizeof(_dbm_noise);
} }
if(_radio.flags.lock_quality) { if(_radio.flags.lock_quality) {
if(((buffer - buffer_start) & 1) == 1) if(((buffer - buffer_start) & 1) == 1) {
*(buffer++) = 0; stream.write<uint8_t>(0);
memcpy(buffer, &_signal_quality, sizeof(_signal_quality)); }
buffer += sizeof(_signal_quality); stream.write(_signal_quality);
} }
if(_radio.flags.antenna) { if(_radio.flags.antenna) {
memcpy(buffer, &_antenna, sizeof(_antenna)); stream.write(_antenna);
buffer += sizeof(_antenna);
} }
if(_radio.flags.db_signal) { if(_radio.flags.db_signal) {
memcpy(buffer, &_db_signal, sizeof(_db_signal)); stream.write(_db_signal);
buffer += sizeof(_db_signal);
} }
if(_radio.flags.rx_flags) { if(_radio.flags.rx_flags) {
if(((buffer - buffer_start) & 1) == 1) if(((buffer - buffer_start) & 1) == 1) {
*(buffer++) = 0; stream.write<uint8_t>(0);
memcpy(buffer, &_rx_flags, sizeof(_rx_flags)); }
buffer += sizeof(_rx_flags); stream.write(_rx_flags);
} }
if(_radio.flags.channel_plus) { if(_radio.flags.channel_plus) {
uint32_t offset = ((buffer - buffer_start) % 4); const uint32_t padding = ((stream.pointer() - buffer_start) % 4);
if(offset) { if (padding != 0) {
offset = 4 - offset; stream.fill(4 - padding, 0);
while(offset--) {
*buffer++ = 0;
}
} }
uint32_t dummy = _channel_type; uint32_t dummy = _channel_type;
// nasty Big Endian fix // nasty Big Endian fix
dummy = Endian::le_to_host<uint32_t>(Endian::host_to_le<uint16_t>(dummy)); dummy = Endian::le_to_host<uint32_t>(Endian::host_to_le<uint16_t>(dummy));
memcpy(buffer, &dummy, sizeof(dummy)); stream.write(dummy);
buffer += sizeof(dummy); stream.write(_channel_freq);
memcpy(buffer, &_channel_freq, sizeof(_channel_freq)); stream.write(_channel);
buffer += sizeof(_channel_freq); stream.write(_max_power);
memcpy(buffer, &_channel, sizeof(_channel));
buffer += sizeof(_channel);
memcpy(buffer, &_max_power, sizeof(_max_power));
buffer += sizeof(_max_power);
} }
if((_flags & 0x10) != 0 && inner_pdu()) { if ((_flags & 0x10) != 0 && inner_pdu()) {
uint32_t crc32 = Endian::host_to_le( uint32_t crc32 = Endian::host_to_le(
Utils::crc32(buffer, inner_pdu()->size()) Utils::crc32(stream.pointer(), inner_pdu()->size())
); );
memcpy(buffer + inner_pdu()->size(), &crc32, sizeof(uint32_t)); stream.skip(inner_pdu()->size());
stream.write(crc32);
} }
} }
} }

View File

@@ -32,7 +32,9 @@
#endif #endif
#include <algorithm> #include <algorithm>
#include "rawpdu.h" #include "rawpdu.h"
#include "memory_helpers.h"
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
RawPDU::RawPDU(const uint8_t *pload, uint32_t size) RawPDU::RawPDU(const uint8_t *pload, uint32_t size)
@@ -51,10 +53,8 @@ uint32_t RawPDU::header_size() const {
} }
void RawPDU::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) { void RawPDU::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
#ifdef TINS_DEBUG OutputMemoryStream stream(buffer, total_sz);
assert(total_sz >= _payload.size()); stream.write(_payload.begin(), _payload.end());
#endif
std::copy(_payload.begin(), _payload.end(), buffer);
} }
void RawPDU::payload(const payload_type &pload) { void RawPDU::payload(const payload_type &pload) {

View File

@@ -38,6 +38,7 @@
#include "dot11/dot11_base.h" #include "dot11/dot11_base.h"
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -107,27 +108,18 @@ RSNInformation::serialization_type RSNInformation::serialize() const {
const uint16_t akm_cyphers_size = Endian::host_to_le<uint16_t>(_akm_cyphers.size()); const uint16_t akm_cyphers_size = Endian::host_to_le<uint16_t>(_akm_cyphers.size());
serialization_type buffer(size); serialization_type buffer(size);
serialization_type::value_type *ptr = &buffer[0]; OutputMemoryStream stream(&buffer[0], buffer.size());
std::memcpy(ptr, &_version, sizeof(_version)); stream.write(_version);
ptr += sizeof(uint16_t); stream.write(_group_suite);
std::memcpy(ptr, &_group_suite, sizeof(uint32_t)); stream.write(pairwise_cyphers_size);
ptr += sizeof(uint32_t); for (cyphers_type::const_iterator it = _pairwise_cyphers.begin(); it != _pairwise_cyphers.end(); ++it) {
std::memcpy(ptr, &pairwise_cyphers_size, sizeof(pairwise_cyphers_size)); stream.write(Endian::host_to_le<uint32_t>(*it));
ptr += sizeof(uint16_t);
for(cyphers_type::const_iterator it = _pairwise_cyphers.begin(); it != _pairwise_cyphers.end(); ++it) {
const uint32_t value = Endian::host_to_le<uint32_t>(*it);
std::memcpy(ptr, &value, sizeof(uint32_t));
ptr += sizeof(uint32_t);
} }
std::memcpy(ptr, &akm_cyphers_size, sizeof(akm_cyphers_size)); stream.write(akm_cyphers_size);
ptr += sizeof(uint16_t); for (akm_type::const_iterator it = _akm_cyphers.begin(); it != _akm_cyphers.end(); ++it) {
for(akm_type::const_iterator it = _akm_cyphers.begin(); it != _akm_cyphers.end(); ++it) { stream.write(Endian::host_to_le<uint32_t>(*it));
const uint32_t value = Endian::host_to_le<uint32_t>(*it);
std::memcpy(ptr, &value, sizeof(uint32_t));
ptr += sizeof(uint32_t);
} }
std::memcpy(ptr, &_capabilities, sizeof(uint16_t)); stream.write(_capabilities);
return buffer; return buffer;
} }

View File

@@ -35,6 +35,7 @@
#include "memory_helpers.h" #include "memory_helpers.h"
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -81,12 +82,14 @@ uint32_t SLL::header_size() const {
} }
void SLL::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) { void SLL::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
if(inner_pdu()) { OutputMemoryStream stream(buffer, total_sz);
if (inner_pdu()) {
Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_type( Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_type(
inner_pdu()->pdu_type() inner_pdu()->pdu_type()
); );
protocol(static_cast<uint16_t>(flag)); protocol(static_cast<uint16_t>(flag));
} }
std::memcpy(buffer, &_header, sizeof(_header)); stream.write(_header);
}
} }
} // Tins

View File

@@ -46,6 +46,7 @@
#include "memory_helpers.h" #include "memory_helpers.h"
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -95,9 +96,7 @@ uint32_t SNAP::header_size() const {
} }
void SNAP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { void SNAP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
#ifdef TINS_DEBUG OutputMemoryStream stream(buffer, total_sz);
assert(total_sz >= sizeof(_snap));
#endif
if (inner_pdu()) { if (inner_pdu()) {
Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_type( Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_type(
inner_pdu()->pdu_type() inner_pdu()->pdu_type()
@@ -106,7 +105,7 @@ void SNAP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *pa
static_cast<uint16_t>(flag) static_cast<uint16_t>(flag)
); );
} }
std::memcpy(buffer, &_snap, sizeof(_snap)); stream.write(_snap);
} }
} // Tins } // Tins

View File

@@ -37,6 +37,7 @@
#include "memory_helpers.h" #include "memory_helpers.h"
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -109,10 +110,8 @@ void STP::bridge_id(const bpdu_id_type &id) {
} }
void STP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) { void STP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
#ifdef TINS_DEBUG OutputMemoryStream stream(buffer, total_sz);
assert(total_sz >= sizeof(_header)); stream.write(_header);
#endif
std::memcpy(buffer, &_header, sizeof(_header));
} }
uint32_t STP::header_size() const { uint32_t STP::header_size() const {

View File

@@ -41,7 +41,9 @@
#include "memory_helpers.h" #include "memory_helpers.h"
using std::find_if; using std::find_if;
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -291,46 +293,46 @@ uint32_t TCP::header_size() const {
} }
void TCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { void TCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
assert(total_sz >= header_size()); OutputMemoryStream stream(buffer, total_sz);
uint8_t *tcp_start = buffer; // Set checksum to 0, we'll calculate it at the end
checksum(0); checksum(0);
buffer += sizeof(tcphdr);
_tcp.doff = (sizeof(tcphdr) + _total_options_size) / sizeof(uint32_t); _tcp.doff = (sizeof(tcphdr) + _total_options_size) / sizeof(uint32_t);
for(options_type::iterator it = _options.begin(); it != _options.end(); ++it) stream.write(_tcp);
buffer = write_option(*it, buffer); for(options_type::const_iterator it = _options.begin(); it != _options.end(); ++it) {
write_option(*it, stream);
if(_options_size < _total_options_size) {
uint16_t padding = _options_size;
while(padding < _total_options_size) {
*(buffer++) = 1;
padding++;
}
} }
memcpy(tcp_start, &_tcp, sizeof(tcphdr)); if (_options_size < _total_options_size) {
const uint16_t padding = _total_options_size - _options_size;
stream.fill(padding, 1);
}
const Tins::IP *ip_packet = tins_cast<const Tins::IP*>(parent); const Tins::IP *ip_packet = tins_cast<const Tins::IP*>(parent);
if(ip_packet) { if(ip_packet) {
uint32_t check = Utils::pseudoheader_checksum(ip_packet->src_addr(), uint32_t check = Utils::pseudoheader_checksum(
ip_packet->dst_addr(), ip_packet->src_addr(),
size(), Constants::IP::PROTO_TCP) + ip_packet->dst_addr(),
Utils::do_checksum(tcp_start, tcp_start + total_sz); size(),
while (check >> 16) Constants::IP::PROTO_TCP) + Utils::do_checksum(buffer, buffer + total_sz);
while (check >> 16) {
check = (check & 0xffff) + (check >> 16); check = (check & 0xffff) + (check >> 16);
}
checksum(~check); checksum(~check);
((tcphdr*)tcp_start)->check = _tcp.check; ((tcphdr*)buffer)->check = _tcp.check;
} }
else { else {
const Tins::IPv6 *ipv6_packet = tins_cast<const Tins::IPv6*>(parent); const Tins::IPv6 *ipv6_packet = tins_cast<const Tins::IPv6*>(parent);
if(ipv6_packet) { if(ipv6_packet) {
uint32_t check = Utils::pseudoheader_checksum(ipv6_packet->src_addr(), uint32_t check = Utils::pseudoheader_checksum(
ipv6_packet->dst_addr(), ipv6_packet->src_addr(),
size(), Constants::IP::PROTO_TCP) + ipv6_packet->dst_addr(),
Utils::do_checksum(tcp_start, tcp_start + total_sz); size(),
while (check >> 16) Constants::IP::PROTO_TCP) + Utils::do_checksum(buffer, buffer + total_sz);
while (check >> 16) {
check = (check & 0xffff) + (check >> 16); check = (check & 0xffff) + (check >> 16);
}
checksum(~check); checksum(~check);
((tcphdr*)tcp_start)->check = _tcp.check; ((tcphdr*)buffer)->check = _tcp.check;
} }
} }
} }
@@ -353,19 +355,18 @@ TCP::options_type::iterator TCP::search_option_iterator(OptionTypes type) {
/* options */ /* options */
uint8_t *TCP::write_option(const option &opt, uint8_t *buffer) { void TCP::write_option(const option &opt, OutputMemoryStream& stream) {
if(opt.option() == 0 || opt.option() == 1) { stream.write<uint8_t>(opt.option());
*buffer = opt.option(); // Only do this for non EOL nor NOP options
return buffer + 1; if(opt.option() > 1) {
} uint8_t length = opt.length_field();
else { // Only add the identifier and size field sizes if the length
buffer[0] = opt.option();
buffer[1] = static_cast<uint8_t>(opt.length_field());
// only add the identifier and size field sizes if the length
// field hasn't been spoofed. // field hasn't been spoofed.
if(opt.length_field() == opt.data_size()) if(opt.length_field() == opt.data_size()) {
buffer[1] += (sizeof(uint8_t) << 1); length += (sizeof(uint8_t) << 1);
return std::copy(opt.data_ptr(), opt.data_ptr() + opt.data_size(), buffer + 2); }
stream.write(length);
stream.write(opt.data_ptr(), opt.data_size());
} }
} }

View File

@@ -42,6 +42,7 @@
#include "memory_helpers.h" #include "memory_helpers.h"
using Tins::Memory::InputMemoryStream; using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins { namespace Tins {
@@ -77,9 +78,8 @@ uint32_t UDP::header_size() const {
} }
void UDP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { void UDP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
#ifdef TINS_DEBUG OutputMemoryStream stream(buffer, total_sz);
assert(total_sz >= sizeof(udphdr)); // Set checksum to 0, we'll calculate it at the end
#endif
_udp.check = 0; _udp.check = 0;
if(inner_pdu()) { if(inner_pdu()) {
length(static_cast<uint16_t>(sizeof(udphdr) + inner_pdu()->size())); length(static_cast<uint16_t>(sizeof(udphdr) + inner_pdu()->size()));
@@ -87,17 +87,18 @@ void UDP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *par
else { else {
length(static_cast<uint16_t>(sizeof(udphdr))); length(static_cast<uint16_t>(sizeof(udphdr)));
} }
std::memcpy(buffer, &_udp, sizeof(udphdr)); stream.write(_udp);
const Tins::IP *ip_packet = tins_cast<const Tins::IP*>(parent); const Tins::IP *ip_packet = tins_cast<const Tins::IP*>(parent);
if(ip_packet) { if(ip_packet) {
uint32_t checksum = Utils::pseudoheader_checksum( uint32_t checksum = Utils::pseudoheader_checksum(
ip_packet->src_addr(), ip_packet->src_addr(),
ip_packet->dst_addr(), ip_packet->dst_addr(),
size(), size(),
Constants::IP::PROTO_UDP Constants::IP::PROTO_UDP
) + Utils::do_checksum(buffer, buffer + total_sz); ) + Utils::do_checksum(buffer, buffer + total_sz);
while (checksum >> 16) while (checksum >> 16) {
checksum = (checksum & 0xffff)+(checksum >> 16); checksum = (checksum & 0xffff)+(checksum >> 16);
}
_udp.check = Endian::host_to_be<uint16_t>(~checksum); _udp.check = Endian::host_to_be<uint16_t>(~checksum);
((udphdr*)buffer)->check = _udp.check; ((udphdr*)buffer)->check = _udp.check;
} }
@@ -105,13 +106,14 @@ void UDP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *par
const Tins::IPv6 *ip6_packet = tins_cast<const Tins::IPv6*>(parent); const Tins::IPv6 *ip6_packet = tins_cast<const Tins::IPv6*>(parent);
if(ip6_packet) { if(ip6_packet) {
uint32_t checksum = Utils::pseudoheader_checksum( uint32_t checksum = Utils::pseudoheader_checksum(
ip6_packet->src_addr(), ip6_packet->src_addr(),
ip6_packet->dst_addr(), ip6_packet->dst_addr(),
size(), size(),
Constants::IP::PROTO_UDP Constants::IP::PROTO_UDP
) + Utils::do_checksum(buffer, buffer + total_sz); ) + Utils::do_checksum(buffer, buffer + total_sz);
while (checksum >> 16) while (checksum >> 16) {
checksum = (checksum & 0xffff)+(checksum >> 16); checksum = (checksum & 0xffff)+(checksum >> 16);
}
_udp.check = Endian::host_to_be<uint16_t>(~checksum); _udp.check = Endian::host_to_be<uint16_t>(~checksum);
((udphdr*)buffer)->check = _udp.check; ((udphdr*)buffer)->check = _udp.check;
} }