mirror of
https://github.com/mfontanini/libtins
synced 2026-01-27 12:14:26 +01:00
Added PDUOption::to<>. TCP options now use this method when being converted to their appropriate types.
This commit is contained in:
@@ -145,7 +145,7 @@ namespace Tins {
|
||||
/**
|
||||
* The DHCP option type.
|
||||
*/
|
||||
typedef PDUOption<uint8_t> option;
|
||||
typedef PDUOption<uint8_t, DHCP> option;
|
||||
|
||||
/**
|
||||
* The type used to store the DHCP options.
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
/**
|
||||
* Represents a DHCPv6 option.
|
||||
*/
|
||||
typedef PDUOption<uint16_t> option;
|
||||
typedef PDUOption<uint16_t, DHCPv6> option;
|
||||
|
||||
/**
|
||||
* The message types.
|
||||
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
/**
|
||||
* \brief IEEE 802.11 options struct.
|
||||
*/
|
||||
typedef PDUOption<uint8_t> option;
|
||||
typedef PDUOption<uint8_t, Dot11> option;
|
||||
|
||||
/**
|
||||
* The type used to store tagged options.
|
||||
|
||||
@@ -55,6 +55,16 @@
|
||||
|
||||
namespace Tins {
|
||||
namespace Endian {
|
||||
/**
|
||||
* \brief "Changes" a 8-bit integral value's endianess. This is an
|
||||
* identity function.
|
||||
*
|
||||
* \param data The data to convert.
|
||||
*/
|
||||
inline uint8_t do_change_endian(uint8_t data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Changes a 16-bit integral value's endianess.
|
||||
*
|
||||
|
||||
@@ -135,7 +135,7 @@ public:
|
||||
/**
|
||||
* The type used to represent ICMPv6 options.
|
||||
*/
|
||||
typedef PDUOption<uint8_t> option;
|
||||
typedef PDUOption<uint8_t, ICMPv6> option;
|
||||
|
||||
/**
|
||||
* The type used to store options.
|
||||
|
||||
@@ -99,14 +99,14 @@ private:
|
||||
void skip_line(std::istream &input);
|
||||
bool from_hex(const std::string &str, uint32_t &result);
|
||||
|
||||
template<bool, typename>
|
||||
template<bool, typename T = void>
|
||||
struct enable_if {
|
||||
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct enable_if<true, T> {
|
||||
typedef T type;
|
||||
struct enable_if<false, T> {
|
||||
|
||||
};
|
||||
|
||||
PDU *pdu_from_flag(Constants::Ethernet::e flag, const uint8_t *buffer,
|
||||
@@ -173,6 +173,31 @@ HWAddress<n> last_address_from_mask(HWAddress<n> addr, const HWAddress<n> &mask)
|
||||
inline bool is_dot3(const uint8_t *ptr, size_t sz) {
|
||||
return (sz >= 13 && ptr[12] < 8);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct is_unsigned_integral {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct is_unsigned_integral<uint8_t> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct is_unsigned_integral<uint16_t> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct is_unsigned_integral<uint32_t> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct is_unsigned_integral<uint64_t> {
|
||||
static const bool value = true;
|
||||
};
|
||||
} // namespace Internals
|
||||
} // namespace Tins
|
||||
/**
|
||||
|
||||
@@ -169,7 +169,7 @@ namespace Tins {
|
||||
/**
|
||||
* The IP options type.
|
||||
*/
|
||||
typedef PDUOption<option_identifier> option;
|
||||
typedef PDUOption<option_identifier, IP> option;
|
||||
|
||||
/**
|
||||
* The type of the security option.
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
/**
|
||||
* The type used to represent IPv6 extension headers.
|
||||
*/
|
||||
typedef PDUOption<uint8_t> ext_header;
|
||||
typedef PDUOption<uint8_t, IPv6> ext_header;
|
||||
|
||||
/**
|
||||
* The type used to store the extension headers.
|
||||
|
||||
@@ -65,6 +65,14 @@ namespace Tins {
|
||||
*/
|
||||
typedef byte_array serialization_type;
|
||||
|
||||
/**
|
||||
* The typep used to identify the endianness of every PDU.
|
||||
*/
|
||||
enum endian_type {
|
||||
BE,
|
||||
LE
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Enum which identifies each type of PDU.
|
||||
*
|
||||
@@ -123,6 +131,12 @@ namespace Tins {
|
||||
IPSEC_ESP,
|
||||
USER_DEFINED_PDU = 1000
|
||||
};
|
||||
|
||||
/**
|
||||
* The endianness used by this PDU. This can be overriden
|
||||
* by subclasses.
|
||||
*/
|
||||
static const endian_type endianness = BE;
|
||||
|
||||
/**
|
||||
* \brief Default constructor.
|
||||
|
||||
@@ -32,10 +32,120 @@
|
||||
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <stdint.h>
|
||||
#include "exceptions.h"
|
||||
#include "endianness.h"
|
||||
#include "internals.h"
|
||||
|
||||
namespace Tins {
|
||||
/**
|
||||
* \cond
|
||||
*/
|
||||
template<typename OptionType, class PDUType>
|
||||
class PDUOption;
|
||||
|
||||
namespace Internals {
|
||||
template<typename T, typename X, typename PDUType>
|
||||
T convert_to_integral(const PDUOption<X, PDUType> & opt) {
|
||||
if(opt.data_size() != sizeof(T))
|
||||
throw malformed_option();
|
||||
T data = *(T*)opt.data_ptr();
|
||||
if(PDUType::endianness == PDUType::BE)
|
||||
data = Endian::be_to_host(data);
|
||||
else
|
||||
data = Endian::le_to_host(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
template<typename T, typename = void>
|
||||
struct converter {
|
||||
template<typename X, typename PDUType>
|
||||
static T convert(const PDUOption<X, PDUType>& opt) {
|
||||
return T::from_option(opt);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct converter<uint8_t> {
|
||||
template<typename X, typename PDUType>
|
||||
static uint8_t convert(const PDUOption<X, PDUType>& opt) {
|
||||
if(opt.data_size() != 1)
|
||||
throw malformed_option();
|
||||
return *opt.data_ptr();
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct converter<uint16_t> {
|
||||
template<typename X, typename PDUType>
|
||||
static uint16_t convert(const PDUOption<X, PDUType>& opt) {
|
||||
return convert_to_integral<uint16_t>(opt);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct converter<uint32_t> {
|
||||
template<typename X, typename PDUType>
|
||||
static uint32_t convert(const PDUOption<X, PDUType>& opt) {
|
||||
return convert_to_integral<uint32_t>(opt);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct converter<uint64_t> {
|
||||
template<typename X, typename PDUType>
|
||||
static uint64_t convert(const PDUOption<X, PDUType>& opt) {
|
||||
return convert_to_integral<uint64_t>(opt);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct converter<std::vector<T>, typename enable_if<is_unsigned_integral<T>::value>::type> {
|
||||
template<typename X, typename PDUType>
|
||||
static std::vector<T> convert(const PDUOption<X, PDUType>& opt) {
|
||||
if(opt.data_size() % sizeof(T) != 0)
|
||||
throw malformed_option();
|
||||
const T *ptr = (const T*)opt.data_ptr();
|
||||
const T *end = ptr + (opt.data_size() / sizeof(T));
|
||||
|
||||
std::vector<T> output(std::distance(ptr, end));
|
||||
typename std::vector<T>::iterator it = output.begin();
|
||||
while(ptr < end) {
|
||||
if(PDUType::endianness == PDUType::BE)
|
||||
*it++ = Endian::be_to_host(*(ptr++));
|
||||
else
|
||||
*it++ = Endian::le_to_host(*(ptr++));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct converter<std::pair<T, T>, typename enable_if<is_unsigned_integral<T>::value>::type> {
|
||||
template<typename X, typename PDUType>
|
||||
static std::pair<T, T> convert(const PDUOption<X, PDUType>& opt) {
|
||||
if(opt.data_size() != sizeof(T) * 2)
|
||||
throw malformed_option();
|
||||
const T *ptr = (const T*)opt.data_ptr();
|
||||
std::pair<T, T> output;
|
||||
if(PDUType::endianness == PDUType::BE) {
|
||||
output.first = Endian::be_to_host(*ptr++);
|
||||
output.second = Endian::be_to_host(*ptr);
|
||||
}
|
||||
else {
|
||||
output.first = Endian::le_to_host(*ptr++);
|
||||
output.second = Endian::le_to_host(*ptr);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* \endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* \class PDUOption
|
||||
* \brief Represents a PDU option field.
|
||||
@@ -46,16 +156,11 @@ namespace Tins {
|
||||
*
|
||||
* The OptionType template parameter indicates the type that will be
|
||||
* used to store this option's identifier.
|
||||
*
|
||||
* The Container template parameter indicates the container which will
|
||||
* be used to store this option's data. The container <b>must</b>
|
||||
* store data sequentially. std::vector<uint8_t> is the default
|
||||
* container.
|
||||
*/
|
||||
template<typename OptionType, class Container = std::vector<uint8_t> >
|
||||
template<typename OptionType, class PDUType>
|
||||
class PDUOption {
|
||||
public:
|
||||
typedef Container container_type;
|
||||
typedef std::vector<uint8_t> container_type;
|
||||
typedef typename container_type::value_type data_type;
|
||||
typedef OptionType option_type;
|
||||
|
||||
@@ -158,6 +263,18 @@ public:
|
||||
size_t length_field() const {
|
||||
return size_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Constructs a T from this PDUOption.
|
||||
*
|
||||
* Use this method to convert a PDUOption to the specific type that
|
||||
* represents it. For example, if you know an option is of type
|
||||
* PDU::SACK, you could use option.to<TCP::sack_type>().
|
||||
*/
|
||||
template<typename T>
|
||||
T to() const {
|
||||
return Internals::converter<T>::convert(*this);
|
||||
}
|
||||
private:
|
||||
option_type option_;
|
||||
uint16_t size_;
|
||||
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
/**
|
||||
* The type used to store a TLV option.
|
||||
*/
|
||||
typedef PDUOption<TagTypes> tag;
|
||||
typedef PDUOption<TagTypes, PPPoE> tag;
|
||||
|
||||
/**
|
||||
* The type used to store the options.
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace Tins {
|
||||
/**
|
||||
* The type used to store TCP options.
|
||||
*/
|
||||
typedef PDUOption<uint8_t> option;
|
||||
typedef PDUOption<uint8_t, TCP> option;
|
||||
|
||||
/**
|
||||
* The type used to store the options.
|
||||
@@ -490,11 +490,14 @@ namespace Tins {
|
||||
static const uint16_t DEFAULT_WINDOW;
|
||||
|
||||
template<class T>
|
||||
T generic_search(OptionTypes opt) const {
|
||||
const option *option = search_option(opt);
|
||||
if(option && option->data_size() == sizeof(T))
|
||||
T generic_search(OptionTypes opt_type) const {
|
||||
const option *opt = search_option(opt_type);
|
||||
if(!opt)
|
||||
throw option_not_found();
|
||||
return opt->to<T>();
|
||||
/*if(option && option->data_size() == sizeof(T))
|
||||
return *(const T*)(&option->data_ptr()[0]);
|
||||
throw option_not_found();
|
||||
throw option_not_found();*/
|
||||
}
|
||||
|
||||
void internal_add_option(const option &option);
|
||||
|
||||
22
src/tcp.cpp
22
src/tcp.cpp
@@ -123,7 +123,7 @@ void TCP::mss(uint16_t value) {
|
||||
}
|
||||
|
||||
uint16_t TCP::mss() const {
|
||||
return Endian::host_to_be(generic_search<uint16_t>(MSS));
|
||||
return generic_search<uint16_t>(MSS);
|
||||
}
|
||||
|
||||
void TCP::winscale(uint8_t value) {
|
||||
@@ -161,16 +161,10 @@ void TCP::sack(const sack_type &edges) {
|
||||
}
|
||||
|
||||
TCP::sack_type TCP::sack() const {
|
||||
const option *option = search_option(SACK);
|
||||
if(!option || (option->data_size() % sizeof(uint32_t)) != 0)
|
||||
const option *opt = search_option(SACK);
|
||||
if(!opt)
|
||||
throw option_not_found();
|
||||
const uint32_t *ptr = (const uint32_t*)option->data_ptr();
|
||||
const uint32_t *end = ptr + (option->data_size() / sizeof(uint32_t));
|
||||
sack_type edges(end - ptr);
|
||||
sack_type::iterator it = edges.begin();
|
||||
while(ptr < end)
|
||||
*it++ = Endian::host_to_be(*(ptr++));
|
||||
return edges;
|
||||
return opt->to<sack_type>();
|
||||
}
|
||||
|
||||
void TCP::timestamp(uint32_t value, uint32_t reply) {
|
||||
@@ -180,12 +174,10 @@ void TCP::timestamp(uint32_t value, uint32_t reply) {
|
||||
}
|
||||
|
||||
std::pair<uint32_t, uint32_t> TCP::timestamp() const {
|
||||
const option *option = search_option(TSOPT);
|
||||
if(!option || option->data_size() != (sizeof(uint32_t) << 1))
|
||||
const option *opt = search_option(TSOPT);
|
||||
if(!opt)
|
||||
throw option_not_found();
|
||||
uint64_t buffer = *(const uint64_t*)option->data_ptr();
|
||||
buffer = Endian::be_to_host(buffer);
|
||||
return std::make_pair(static_cast<uint32_t>(buffer >> 32), buffer & 0xffffffff);
|
||||
return opt->to<std::pair<uint32_t, uint32_t> >();
|
||||
}
|
||||
|
||||
void TCP::altchecksum(AltChecksums value) {
|
||||
|
||||
Reference in New Issue
Block a user