mirror of
https://github.com/mfontanini/libtins
synced 2026-01-28 12:44:25 +01:00
Several classes now use PDUOption::length_field instead of data_size.
This commit is contained in:
@@ -46,79 +46,7 @@ public:
|
||||
/**
|
||||
* Represents a DHCPv6 option.
|
||||
*/
|
||||
class dhcpv6_option {
|
||||
public:
|
||||
typedef std::vector<uint8_t> container_type;
|
||||
typedef container_type::value_type data_type;
|
||||
typedef uint16_t option_type;
|
||||
|
||||
/**
|
||||
* \brief Constructs a PDUOption.
|
||||
* \param opt The option type.
|
||||
* \param length The option's data length.
|
||||
* \param data The option's data(if any).
|
||||
*/
|
||||
dhcpv6_option(option_type opt = 0, size_t length = 0, const data_type *data = 0)
|
||||
: option_(opt), option_size_(length) {
|
||||
if(data)
|
||||
value_.insert(value_.end(), data, data + length);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Constructs a PDUOption from iterators, which
|
||||
* indicate the data to be stored in it.
|
||||
*
|
||||
* \param opt The option type.
|
||||
* \param start The beginning of the option data.
|
||||
* \param end The end of the option data.
|
||||
*/
|
||||
template<typename ForwardIterator>
|
||||
dhcpv6_option(option_type opt, ForwardIterator start, ForwardIterator end)
|
||||
: option_(opt), option_size_(std::distance(start, end))
|
||||
{
|
||||
value_.insert(value_.end(), start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves this option's type.
|
||||
* \return uint8_t containing this option's size.
|
||||
*/
|
||||
uint16_t option() const {
|
||||
return option_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this option's type
|
||||
* \param opt The option type to be set.
|
||||
*/
|
||||
void option(uint16_t opt) {
|
||||
option_ = opt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves this option's data.
|
||||
*
|
||||
* If this method is called when data_size() == 0,
|
||||
* dereferencing the returned pointer will result in undefined
|
||||
* behaviour.
|
||||
*
|
||||
* \return const data_type& containing this option's value.
|
||||
*/
|
||||
const data_type *data_ptr() const {
|
||||
return &*value_.begin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the length of this option's data.
|
||||
*/
|
||||
uint16_t data_size() const {
|
||||
return option_size_;
|
||||
}
|
||||
private:
|
||||
option_type option_;
|
||||
uint16_t option_size_;
|
||||
container_type value_;
|
||||
};
|
||||
typedef PDUOption<uint16_t> dhcpv6_option;
|
||||
|
||||
/**
|
||||
* The message types.
|
||||
|
||||
@@ -153,7 +153,12 @@ public:
|
||||
/**
|
||||
* \brief Retrieves the data length field.
|
||||
*
|
||||
* This may be different to the actual size of the data.
|
||||
* This may be different to the actual size of the data. Note that
|
||||
* in some protocols, such as TCP, the size of the length and the
|
||||
* identifier fields is added to this field before serializing.
|
||||
* Therefore, if on one of such protocols, an option's length_field
|
||||
* returns X, then the actual length included in the serialized
|
||||
* option will be X + C, where C is the size of those fields.
|
||||
*
|
||||
* \sa data_size.
|
||||
*/
|
||||
|
||||
@@ -222,7 +222,7 @@ void DHCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *pa
|
||||
*((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++) = it->data_size();
|
||||
*(ptr++) = it->length_field();
|
||||
std::copy(it->data_ptr(), it->data_ptr() + it->data_size(), ptr);
|
||||
ptr += it->data_size();
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ const DHCPv6::dhcpv6_option *DHCPv6::search_option(Option id) const {
|
||||
|
||||
uint8_t* DHCPv6::write_option(const dhcpv6_option &option, uint8_t* buffer) const {
|
||||
*(uint16_t*)buffer = Endian::host_to_be(option.option());
|
||||
*(uint16_t*)&buffer[sizeof(uint16_t)] = Endian::host_to_be(option.data_size());
|
||||
*(uint16_t*)&buffer[sizeof(uint16_t)] = Endian::host_to_be<uint16_t>(option.length_field());
|
||||
return std::copy(
|
||||
option.data_ptr(),
|
||||
option.data_ptr() + option.data_size(),
|
||||
|
||||
@@ -221,7 +221,7 @@ void Dot11::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *p
|
||||
assert(total_sz >= child_len + _options_size);
|
||||
for(std::list<dot11_option>::const_iterator it = _options.begin(); it != _options.end(); ++it) {
|
||||
*(buffer++) = it->option();
|
||||
*(buffer++) = it->data_size();
|
||||
*(buffer++) = it->length_field();
|
||||
std::copy(it->data_ptr(), it->data_ptr() + it->data_size(), buffer);
|
||||
buffer += it->data_size();
|
||||
}
|
||||
|
||||
@@ -41,7 +41,9 @@ Dot1Q::Dot1Q(small_uint<12> tag_id, bool append_pad)
|
||||
id(tag_id);
|
||||
}
|
||||
|
||||
Dot1Q::Dot1Q(const uint8_t *buffer, uint32_t total_sz) {
|
||||
Dot1Q::Dot1Q(const uint8_t *buffer, uint32_t total_sz)
|
||||
: _append_padding()
|
||||
{
|
||||
if(total_sz < sizeof(_header))
|
||||
throw std::runtime_error("Not enough size for a Dot1Q header");
|
||||
std::memcpy(&_header, buffer, sizeof(_header));
|
||||
|
||||
@@ -254,7 +254,7 @@ void ICMPv6::internal_add_option(const icmpv6_option &option) {
|
||||
|
||||
uint8_t *ICMPv6::write_option(const icmpv6_option &opt, uint8_t *buffer) {
|
||||
*buffer++ = opt.option();
|
||||
*buffer++ = (opt.data_size() + sizeof(uint8_t) * 2) / 8;
|
||||
*buffer++ = (opt.length_field() + sizeof(uint8_t) * 2) / 8;
|
||||
return std::copy(opt.data_ptr(), opt.data_ptr() + opt.data_size(), buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -321,7 +321,7 @@ uint8_t* IP::write_option(const ip_option &opt, uint8_t* buffer) {
|
||||
option_identifier opt_type = opt.option();
|
||||
memcpy(buffer, &opt_type, 1);
|
||||
buffer++;
|
||||
*(buffer++) = opt.data_size() + 2;
|
||||
*(buffer++) = opt.length_field() + 2;
|
||||
std::copy(opt.data_ptr(), opt.data_ptr() + opt.data_size(), buffer);
|
||||
buffer += opt.data_size();
|
||||
return buffer;
|
||||
|
||||
@@ -264,7 +264,7 @@ void IPv6::set_last_next_header(uint8_t value) {
|
||||
|
||||
uint8_t *IPv6::write_header(const ipv6_ext_header &header, uint8_t *buffer) {
|
||||
*buffer++ = header.option();
|
||||
*buffer++ = (header.data_size() > 8) ? (header.data_size() - 8) : 0;
|
||||
*buffer++ = (header.length_field() > 8) ? (header.length_field() - 8) : 0;
|
||||
return std::copy(header.data_ptr(), header.data_ptr() + header.data_size(), buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -346,10 +346,10 @@ uint8_t *TCP::write_option(const tcp_option &opt, uint8_t *buffer) {
|
||||
}
|
||||
else {
|
||||
buffer[0] = opt.option();
|
||||
buffer[1] = opt.data_size() + (sizeof(uint8_t) << 1);
|
||||
buffer[1] = opt.length_field() + (sizeof(uint8_t) << 1);
|
||||
if(opt.data_size() != 0)
|
||||
std::copy(opt.data_ptr(), opt.data_ptr() + opt.data_size(), buffer + 2);
|
||||
return buffer + buffer[1];
|
||||
return buffer + opt.data_size() + (sizeof(uint8_t) << 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -417,3 +417,20 @@ TEST_F(ICMPv6Test, DNSSearchList) {
|
||||
EXPECT_EQ(output.lifetime, data.lifetime);
|
||||
EXPECT_EQ(data.domains, output.domains);
|
||||
}
|
||||
|
||||
TEST_F(ICMPv6Test, SpoofedOptions) {
|
||||
ICMPv6 pdu;
|
||||
uint8_t a[] = { 1,2,3,4,5,6 };
|
||||
pdu.add_option(
|
||||
ICMPv6::icmpv6_option(ICMPv6::NAACK, 250, a, a + sizeof(a))
|
||||
);
|
||||
pdu.add_option(
|
||||
ICMPv6::icmpv6_option(ICMPv6::NAACK, 250, a, a + sizeof(a))
|
||||
);
|
||||
pdu.add_option(
|
||||
ICMPv6::icmpv6_option(ICMPv6::NAACK, 250, a, a + sizeof(a))
|
||||
);
|
||||
// probably we'd expect it to crash if it's not working, valgrind plx
|
||||
EXPECT_EQ(3, pdu.options().size());
|
||||
EXPECT_EQ(pdu.serialize().size(), pdu.size());
|
||||
}
|
||||
|
||||
@@ -253,3 +253,20 @@ TEST_F(IPTest, StackedProtocols) {
|
||||
buffer = ip.serialize();
|
||||
EXPECT_TRUE(IP(&buffer[0], buffer.size()).find_pdu<ICMP>());
|
||||
}
|
||||
|
||||
TEST_F(IPTest, SpoofedOptions) {
|
||||
IP pdu;
|
||||
uint8_t a[] = { 1,2,3,4,5,6 };
|
||||
pdu.add_option(
|
||||
IP::ip_option(IP::NOOP, 250, a, a + sizeof(a))
|
||||
);
|
||||
pdu.add_option(
|
||||
IP::ip_option(IP::NOOP, 250, a, a + sizeof(a))
|
||||
);
|
||||
pdu.add_option(
|
||||
IP::ip_option(IP::NOOP, 250, a, a + sizeof(a))
|
||||
);
|
||||
// probably we'd expect it to crash if it's not working, valgrind plx
|
||||
EXPECT_EQ(3, pdu.options().size());
|
||||
EXPECT_EQ(pdu.serialize().size(), pdu.size());
|
||||
}
|
||||
|
||||
@@ -173,4 +173,5 @@ TEST_F(PPPoETest, SpoofedOptions) {
|
||||
);
|
||||
// probably we'd expect it to crash if it's not working, valgrind plx
|
||||
EXPECT_EQ(3, pdu.tags().size());
|
||||
EXPECT_EQ(pdu.serialize().size(), pdu.size());
|
||||
}
|
||||
|
||||
@@ -210,3 +210,20 @@ TEST_F(TCPTest, Serialize) {
|
||||
ASSERT_EQ(buffer.size(), sizeof(expected_packet));
|
||||
EXPECT_TRUE(std::equal(buffer.begin(), buffer.end(), expected_packet));
|
||||
}
|
||||
|
||||
TEST_F(TCPTest, SpoofedOptions) {
|
||||
TCP pdu;
|
||||
uint8_t a[] = { 1,2,3,4,5,6 };
|
||||
pdu.add_option(
|
||||
TCP::tcp_option(TCP::SACK, 250, a, a + sizeof(a))
|
||||
);
|
||||
pdu.add_option(
|
||||
TCP::tcp_option(TCP::SACK, 250, a, a + sizeof(a))
|
||||
);
|
||||
pdu.add_option(
|
||||
TCP::tcp_option(TCP::SACK, 250, a, a + sizeof(a))
|
||||
);
|
||||
// probably we'd expect it to crash if it's not working, valgrind plx
|
||||
EXPECT_EQ(3, pdu.options().size());
|
||||
EXPECT_EQ(pdu.serialize().size(), pdu.size());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user