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 "pdu_option.h"
namespace Tins {
namespace Tins {
namespace Memory {
class OutputMemoryStream;
} // Memory
/**
* \class DHCPv6
* \brief Represents a DHCPv6 PDU.
@@ -869,7 +873,7 @@ public:
}
private:
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::iterator search_option_iterator(OptionTypes type);

View File

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

View File

@@ -49,7 +49,7 @@ public:
/**
* \brief Exception thrown when an option is not found.
*/
class option_not_found : exception_base {
class option_not_found : public exception_base {
public:
// try to avoid allocations by doing this.
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.
*/

View File

@@ -46,6 +46,7 @@
namespace Tins {
namespace Memory {
class InputMemoryStream;
class OutputMemoryStream;
} // memory
/**
@@ -1379,7 +1380,7 @@ private:
void internal_add_option(const option &option);
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 write_option(const option &opt, Memory::OutputMemoryStream& stream);
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;

View File

@@ -40,6 +40,9 @@
#include "cxxstd.h"
namespace Tins {
namespace Memory {
class OutputMemoryStream;
} // Memory
/**
* \class IP
@@ -725,7 +728,7 @@ namespace Tins {
void internal_add_option(const option &option);
void init_ip_fields();
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);
generic_route_option_type search_route_option(option_identifier id) const;
void checksum(uint16_t new_check);

View File

@@ -40,6 +40,10 @@
#include "ipv6_address.h"
namespace Tins {
namespace Memory {
class OutputMemoryStream;
} // Memory
class PacketSender;
/**
@@ -299,7 +303,7 @@ public:
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
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);
TINS_BEGIN_PACK

View File

@@ -383,6 +383,7 @@ namespace Tins {
#endif
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);
@@ -395,7 +396,7 @@ namespace Tins {
} control_field;
Format _type;
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 <cstring>
#include <algorithm>
#include "exceptions.h"
#include "ip_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));
}
inline void write_data(uint8_t* buffer, const uint8_t* ptr, uint32_t size) {
std::memcpy(buffer, ptr, size);
}
template <typename T>
void write_value(uint8_t* buffer, const T& value) {
std::memcpy(buffer, &value, sizeof(value));
@@ -105,6 +110,73 @@ private:
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
} // Tins

View File

@@ -44,6 +44,10 @@
#include "cxxstd.h"
namespace Tins {
namespace Memory {
class OutputMemoryStream;
} // Memory
/**
* \class TCP
* \brief Represents a TCP PDU.
@@ -583,7 +587,7 @@ namespace Tins {
options_type::const_iterator search_option_iterator(OptionTypes type) const;
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;
uint16_t _options_size, _total_options_size;

View File

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

View File

@@ -29,12 +29,12 @@
#include <stdexcept>
#include <cstring>
#include <cassert>
#include "bootp.h"
#include "exceptions.h"
#include "memory_helpers.h"
using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
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) {
#ifdef TINS_DEBUG
assert(total_sz >= sizeof(bootphdr) + _vend.size());
#endif
std::memcpy(buffer, &_bootp, sizeof(bootphdr));
std::copy(_vend.begin(), _vend.end(), buffer + sizeof(bootphdr));
OutputMemoryStream stream(buffer, total_sz);
stream.write(_bootp);
stream.write(_vend.begin(), _vend.end());
}
bool BootP::matches_response(const uint8_t *ptr, uint32_t total_sz) const {

View File

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

View File

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

View File

@@ -29,7 +29,6 @@
#include <utility>
#include <stdexcept>
#include <cassert>
#include <sstream>
#include <memory>
#include <cstdio>
@@ -45,6 +44,7 @@ using std::string;
using std::list;
using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
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) {
#ifdef TINS_DEBUG
assert(total_sz >= sizeof(dns) + records_data.size());//extra_size);
#endif
std::memcpy(buffer, &dns, sizeof(dns));
buffer += sizeof(dns);
std::copy(records_data.begin(), records_data.end(), buffer);
OutputMemoryStream stream(buffer, total_sz);
stream.write(dns);
stream.write(records_data.begin(), records_data.end());
}
// Optimization. Creating an IPv4Address and then using IPv4Address::to_string

View File

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

View File

@@ -50,6 +50,7 @@
#include "memory_helpers.h"
using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
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) {
#ifdef TINS_DEBUG
assert(total_sz >= header_size());
#endif
_eth.length = Endian::host_to_be(static_cast<uint16_t>(size() - sizeof(_eth)));
memcpy(buffer, &_eth, sizeof(ethhdr));
OutputMemoryStream stream(buffer, total_sz);
_eth.length = Endian::host_to_be<uint16_t>(size() - sizeof(_eth));
stream.write(_eth);
}
#ifndef _WIN32

View File

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

View File

@@ -56,6 +56,7 @@
#include "memory_helpers.h"
using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
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) {
#ifdef TINS_DEBUG
assert(total_sz >= header_size() + trailer_size());
#endif
/* Inner type defaults to IP */
OutputMemoryStream stream(buffer, total_sz);
if (inner_pdu()) {
Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_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));
}
}
memcpy(buffer, &_eth, sizeof(ethhdr));
uint32_t trailer = trailer_size();
stream.write(_eth);
const uint32_t trailer = trailer_size();
if (trailer) {
uint32_t trailer_offset = header_size();
if (inner_pdu())
trailer_offset += inner_pdu()->size();
memset(buffer + trailer_offset, 0, trailer);
if (inner_pdu()) {
stream.skip(inner_pdu()->size());
}
stream.fill(trailer, 0);
}
}

View File

@@ -42,6 +42,7 @@
#include "memory_helpers.h"
using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
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 *) {
#ifdef TINS_DEBUG
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));
}
OutputMemoryStream stream(buffer, total_sz);
// If extensions are allowed and we have to set the length field
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()) {
uint8_t* extensions_ptr = buffer + sizeof(icmphdr);
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));
}
// checksum calc
_icmp.check = 0;
memcpy(buffer, &_icmp, sizeof(icmphdr));
// Calculate checksum
uint32_t checksum = Utils::do_checksum(buffer, buffer + total_sz);
while (checksum >> 16)
while (checksum >> 16) {
checksum = (checksum & 0xffff) + (checksum >> 16);
}
// Write back only the 2 checksum bytes
_icmp.check = Endian::host_to_be<uint16_t>(~checksum);
memcpy(buffer + 2, &_icmp.check, sizeof(uint16_t));
}

View File

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

View File

@@ -40,6 +40,7 @@
#include "memory_helpers.h"
using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
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) {
#ifdef TINS_DEBUG
assert(total_sz >= header_size());
#endif
uint32_t full_sz = total_sz;
uint8_t *buffer_start = buffer;
_header.cksum = 0;
OutputMemoryStream stream(buffer, total_sz);
// If extensions are allowed and we have to set the length field
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);
}
}
// Initially set checksum to 0, we'll calculate it at the end
_header.cksum = 0;
stream.write(_header);
std::memcpy(buffer, &_header, sizeof(_header));
buffer += sizeof(_header);
total_sz -= sizeof(_header);
if(has_target_addr()) {
buffer = _target_address.copy(buffer);
total_sz -= sizeof(ipaddress_type::address_size);
if (has_target_addr()) {
stream.write(_target_address);
}
if(has_dest_addr()) {
buffer = _dest_address.copy(buffer);
total_sz -= sizeof(ipaddress_type::address_size);
if (has_dest_addr()) {
stream.write(_dest_address);
}
if(type() == ROUTER_ADVERT) {
std::memcpy(buffer, &reach_time, sizeof(uint32_t));
buffer += sizeof(uint32_t);
std::memcpy(buffer, &retrans_timer, sizeof(uint32_t));
buffer += sizeof(uint32_t);
total_sz -= sizeof(uint32_t) * 2;
if (type() == ROUTER_ADVERT) {
stream.write(reach_time);
stream.write(retrans_timer);
}
for(options_type::const_iterator it = _options.begin(); it != _options.end(); ++it) {
#ifdef TINS_DEBUG
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);
write_option(*it, stream);
}
if (has_extensions()) {
uint8_t* extensions_ptr = buffer;
uint8_t* extensions_ptr = stream.pointer();
if (inner_pdu()) {
// Get the size of the next pdu, padded to the next 32 bit boundary
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;
}
// 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);
if(ipv6) {
if (ipv6) {
uint32_t checksum = Utils::pseudoheader_checksum(
ipv6->src_addr(),
ipv6->dst_addr(),
size(),
Constants::IP::PROTO_ICMPV6
) + Utils::do_checksum(buffer_start, buffer_start + full_sz);
while (checksum >> 16)
ipv6->src_addr(),
ipv6->dst_addr(),
size(),
Constants::IP::PROTO_ICMPV6
) + Utils::do_checksum(buffer, buffer + total_sz);
while (checksum >> 16) {
checksum = (checksum & 0xffff) + (checksum >> 16);
}
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;
}
uint8_t *ICMPv6::write_option(const option &opt, uint8_t *buffer) {
*buffer++ = opt.option();
*buffer++ = static_cast<uint8_t>((opt.length_field() + sizeof(uint8_t) * 2) / 8);
return std::copy(opt.data_ptr(), opt.data_ptr() + opt.data_size(), buffer);
void ICMPv6::write_option(const option &opt, OutputMemoryStream& stream) {
stream.write(opt.option());
stream.write<uint8_t>((opt.length_field() + sizeof(uint8_t) * 2) / 8);
stream.write(opt.data_ptr(), opt.data_size());
}
const ICMPv6::option *ICMPv6::search_option(OptionTypes type) const {

View File

@@ -53,6 +53,7 @@
using std::list;
using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
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);
}
uint8_t* IP::write_option(const option &opt, uint8_t* buffer) {
option_identifier opt_type = opt.option();
memcpy(buffer, &opt_type, 1);
if(*buffer <= 1)
return ++buffer;
buffer++;
*buffer = static_cast<uint8_t>(opt.length_field());
if(opt.data_size() == opt.length_field())
*buffer += 2;
buffer++;
return std::copy(opt.data_ptr(), opt.data_ptr() + opt.data_size(), buffer);
void IP::write_option(const option &opt, OutputMemoryStream& stream) {
stream.write(opt.option());
// Check what we wrote. We'll do this for any option != [END, NOOP]
if (*(stream.pointer() - 1) > NOOP) {
uint8_t length = opt.length_field();
if (opt.data_size() == opt.length_field()) {
length += 2;
}
stream.write(length);
stream.write(opt.data_ptr(), opt.data_size());
}
}
/* 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) {
uint32_t my_sz = header_size();
#ifdef TINS_DEBUG
assert(total_sz >= my_sz);
#endif
OutputMemoryStream stream(buffer, total_sz);
checksum(0);
if(inner_pdu()) {
if (inner_pdu()) {
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>(
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);
}
}
#if __FreeBSD__ || defined(__FreeBSD_kernel__) || __APPLE__
if(!parent)
if(!parent) {
total_sz = Endian::host_to_be<uint16_t>(total_sz);
}
#endif
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) {
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);
while (check >> 16)
while (check >> 16) {
check = (check & 0xffff) + (check >> 16);
}
checksum(~check);
((iphdr*)buffer)->check = _ip.check;
}

View File

@@ -48,6 +48,7 @@
#include "memory_helpers.h"
using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
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) {
#ifdef TINS_DEBUG
assert(total_sz >= header_size());
#endif
if(inner_pdu()) {
OutputMemoryStream stream(buffer, total_sz);
if (inner_pdu()) {
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>(
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);
}
payload_length(static_cast<uint16_t>(total_sz - sizeof(_header)));
std::memcpy(buffer, &_header, sizeof(_header));
buffer += sizeof(_header);
stream.write(_header);
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);
}
uint8_t *IPv6::write_header(const ext_header &header, uint8_t *buffer) {
*buffer++ = header.option();
*buffer++ = static_cast<uint8_t>((header.length_field() > 8) ? (header.length_field() - 8) : 0);
return std::copy(header.data_ptr(), header.data_ptr() + header.data_size(), buffer);
void IPv6::write_header(const ext_header &header, OutputMemoryStream& stream) {
const uint8_t length = (header.length_field() > 8) ? (header.length_field() - 8) : 0;
stream.write(header.option());
stream.write(length);
stream.write(header.data_ptr(), header.data_size());
}
}
} // Tins

View File

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

View File

@@ -56,6 +56,7 @@
#endif
using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
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 *) {
#ifdef TINS_DEBUG
assert(total_sz >= sizeof(_family));
#endif
OutputMemoryStream stream(buffer, total_sz);
#ifndef _WIN32
if(tins_cast<const Tins::IP*>(inner_pdu()))
if (tins_cast<const Tins::IP*>(inner_pdu())) {
_family = PF_INET;
else if(tins_cast<const Tins::LLC*>(inner_pdu()))
}
else if (tins_cast<const Tins::LLC*>(inner_pdu())) {
_family = PF_LLC;
*reinterpret_cast<uint32_t*>(buffer) = _family;
}
stream.write(_family);
#endif // _WIN32
}

View File

@@ -37,6 +37,7 @@
#include "memory_helpers.h"
using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
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 *)
{
#ifdef TINS_DEBUG
assert(total_sz == sizeof(_header) + _tags_size);
#endif
std::memcpy(buffer, &_header, sizeof(_header));
if(_tags_size > 0)
((pppoe_hdr*)buffer)->payload_length = Endian::host_to_be(_tags_size);
buffer += sizeof(_header);
uint16_t uint16_t_buffer;
OutputMemoryStream stream(buffer, total_sz);
if (_tags_size > 0) {
payload_length(_tags_size);
}
stream.write(_header);
for(tags_type::const_iterator it = _tags.begin(); it != _tags.end(); ++it) {
uint16_t_buffer = it->option();
std::memcpy(buffer, &uint16_t_buffer, sizeof(uint16_t));
uint16_t_buffer = Endian::host_to_be(static_cast<uint16_t>(it->length_field()));
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();
stream.write<uint16_t>(it->option());
stream.write(Endian::host_to_be<uint16_t>(it->length_field()));
stream.write(it->data_ptr(), it->data_size());
}
}

View File

@@ -50,8 +50,12 @@
#include "utils.h"
#include "packet_sender.h"
#include "exceptions.h"
#include "memory_helpers.h"
using Tins::Memory::OutputMemoryStream;
namespace Tins {
void check_size(uint32_t total_sz, size_t field_size) {
if(total_sz < field_size)
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) {
uint32_t sz = header_size();
OutputMemoryStream stream(buffer, total_sz);
uint8_t *buffer_start = buffer;
#ifdef TINS_DEBUG
assert(total_sz >= sz);
#endif
_radio.it_len = Endian::host_to_le<uint16_t>(sz);
memcpy(buffer, &_radio, sizeof(_radio));
buffer += sizeof(_radio);
_radio.it_len = Endian::host_to_le<uint16_t>(header_size());
stream.write(_radio);
if(_radio.flags.tsft) {
memcpy(buffer, &_tsft, sizeof(_tsft));
buffer += sizeof(_tsft);
stream.write(_tsft);
}
if(_radio.flags.flags) {
memcpy(buffer, &_flags, sizeof(_flags));
buffer += sizeof(_flags);
stream.write(_flags);
}
if(_radio.flags.rate) {
memcpy(buffer, &_rate, sizeof(_rate));
buffer += sizeof(_rate);
stream.write(_rate);
}
if(_radio.flags.channel) {
if(((buffer - buffer_start) & 1) == 1)
*(buffer++) = 0;
memcpy(buffer, &_channel_freq, sizeof(_channel_freq));
buffer += sizeof(_channel_freq);
memcpy(buffer, &_channel_type, sizeof(_channel_type));
buffer += sizeof(_channel_type);
if(((buffer - buffer_start) & 1) == 1) {
stream.write<uint8_t>(0);
}
stream.write(_channel_freq);
stream.write(_channel_type);
}
if(_radio.flags.dbm_signal) {
memcpy(buffer, &_dbm_signal, sizeof(_dbm_signal));
buffer += sizeof(_dbm_signal);
stream.write(_dbm_signal);
}
if(_radio.flags.dbm_noise) {
memcpy(buffer, &_dbm_noise, sizeof(_dbm_noise));
buffer += sizeof(_dbm_noise);
stream.write(_dbm_noise);
}
if(_radio.flags.lock_quality) {
if(((buffer - buffer_start) & 1) == 1)
*(buffer++) = 0;
memcpy(buffer, &_signal_quality, sizeof(_signal_quality));
buffer += sizeof(_signal_quality);
if(((buffer - buffer_start) & 1) == 1) {
stream.write<uint8_t>(0);
}
stream.write(_signal_quality);
}
if(_radio.flags.antenna) {
memcpy(buffer, &_antenna, sizeof(_antenna));
buffer += sizeof(_antenna);
stream.write(_antenna);
}
if(_radio.flags.db_signal) {
memcpy(buffer, &_db_signal, sizeof(_db_signal));
buffer += sizeof(_db_signal);
stream.write(_db_signal);
}
if(_radio.flags.rx_flags) {
if(((buffer - buffer_start) & 1) == 1)
*(buffer++) = 0;
memcpy(buffer, &_rx_flags, sizeof(_rx_flags));
buffer += sizeof(_rx_flags);
if(((buffer - buffer_start) & 1) == 1) {
stream.write<uint8_t>(0);
}
stream.write(_rx_flags);
}
if(_radio.flags.channel_plus) {
uint32_t offset = ((buffer - buffer_start) % 4);
if(offset) {
offset = 4 - offset;
while(offset--) {
*buffer++ = 0;
}
const uint32_t padding = ((stream.pointer() - buffer_start) % 4);
if (padding != 0) {
stream.fill(4 - padding, 0);
}
uint32_t dummy = _channel_type;
// nasty Big Endian fix
dummy = Endian::le_to_host<uint32_t>(Endian::host_to_le<uint16_t>(dummy));
memcpy(buffer, &dummy, sizeof(dummy));
buffer += sizeof(dummy);
memcpy(buffer, &_channel_freq, sizeof(_channel_freq));
buffer += sizeof(_channel_freq);
memcpy(buffer, &_channel, sizeof(_channel));
buffer += sizeof(_channel);
memcpy(buffer, &_max_power, sizeof(_max_power));
buffer += sizeof(_max_power);
stream.write(dummy);
stream.write(_channel_freq);
stream.write(_channel);
stream.write(_max_power);
}
if((_flags & 0x10) != 0 && inner_pdu()) {
if ((_flags & 0x10) != 0 && inner_pdu()) {
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
#include <algorithm>
#include "rawpdu.h"
#include "memory_helpers.h"
using Tins::Memory::OutputMemoryStream;
namespace Tins {
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 *) {
#ifdef TINS_DEBUG
assert(total_sz >= _payload.size());
#endif
std::copy(_payload.begin(), _payload.end(), buffer);
OutputMemoryStream stream(buffer, total_sz);
stream.write(_payload.begin(), _payload.end());
}
void RawPDU::payload(const payload_type &pload) {

View File

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

View File

@@ -35,6 +35,7 @@
#include "memory_helpers.h"
using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
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 *) {
if(inner_pdu()) {
OutputMemoryStream stream(buffer, total_sz);
if (inner_pdu()) {
Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_type(
inner_pdu()->pdu_type()
);
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"
using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
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) {
#ifdef TINS_DEBUG
assert(total_sz >= sizeof(_snap));
#endif
OutputMemoryStream stream(buffer, total_sz);
if (inner_pdu()) {
Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_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)
);
}
std::memcpy(buffer, &_snap, sizeof(_snap));
stream.write(_snap);
}
} // Tins

View File

@@ -37,6 +37,7 @@
#include "memory_helpers.h"
using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
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 *) {
#ifdef TINS_DEBUG
assert(total_sz >= sizeof(_header));
#endif
std::memcpy(buffer, &_header, sizeof(_header));
OutputMemoryStream stream(buffer, total_sz);
stream.write(_header);
}
uint32_t STP::header_size() const {

View File

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

View File

@@ -42,6 +42,7 @@
#include "memory_helpers.h"
using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
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) {
#ifdef TINS_DEBUG
assert(total_sz >= sizeof(udphdr));
#endif
OutputMemoryStream stream(buffer, total_sz);
// Set checksum to 0, we'll calculate it at the end
_udp.check = 0;
if(inner_pdu()) {
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 {
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);
if(ip_packet) {
uint32_t checksum = Utils::pseudoheader_checksum(
ip_packet->src_addr(),
ip_packet->dst_addr(),
size(),
Constants::IP::PROTO_UDP
) + Utils::do_checksum(buffer, buffer + total_sz);
while (checksum >> 16)
ip_packet->src_addr(),
ip_packet->dst_addr(),
size(),
Constants::IP::PROTO_UDP
) + Utils::do_checksum(buffer, buffer + total_sz);
while (checksum >> 16) {
checksum = (checksum & 0xffff)+(checksum >> 16);
}
_udp.check = Endian::host_to_be<uint16_t>(~checksum);
((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);
if(ip6_packet) {
uint32_t checksum = Utils::pseudoheader_checksum(
ip6_packet->src_addr(),
ip6_packet->dst_addr(),
size(),
Constants::IP::PROTO_UDP
) + Utils::do_checksum(buffer, buffer + total_sz);
while (checksum >> 16)
ip6_packet->src_addr(),
ip6_packet->dst_addr(),
size(),
Constants::IP::PROTO_UDP
) + Utils::do_checksum(buffer, buffer + total_sz);
while (checksum >> 16) {
checksum = (checksum & 0xffff)+(checksum >> 16);
}
_udp.check = Endian::host_to_be<uint16_t>(~checksum);
((udphdr*)buffer)->check = _udp.check;
}