mirror of
https://github.com/mfontanini/libtins
synced 2026-01-23 02:35:57 +01:00
Added some ICMPv6 option getters/setters.
This commit is contained in:
137
include/icmpv6.h
137
include/icmpv6.h
@@ -39,6 +39,7 @@
|
||||
#include "endianness.h"
|
||||
#include "small_uint.h"
|
||||
#include "hw_address.h"
|
||||
#include "small_uint.h"
|
||||
|
||||
namespace Tins {
|
||||
/**
|
||||
@@ -102,7 +103,7 @@ public:
|
||||
IP_PREFIX,
|
||||
NEW_ROUTER_PREFIX,
|
||||
LINK_ADDRESS,
|
||||
NEIGHBOUR_ADVERT_ACK,
|
||||
NAACK,
|
||||
MAP = 23,
|
||||
ROUTE_INFO,
|
||||
RECURSIVE_DNS_SERV,
|
||||
@@ -159,6 +160,15 @@ public:
|
||||
*/
|
||||
typedef std::vector<uint8_t> nonce_type;
|
||||
|
||||
/**
|
||||
* \brief The type used to store the neighbour advertisement
|
||||
* acknowledgement option data.
|
||||
*
|
||||
* The first member contains the option code field, while
|
||||
* the second one contains the status.
|
||||
*/
|
||||
typedef std::pair<uint8_t, uint8_t> naack_type;
|
||||
|
||||
/**
|
||||
* \brief The type used to store the link layer address option data.
|
||||
*/
|
||||
@@ -201,37 +211,21 @@ public:
|
||||
/**
|
||||
* Type type used to store the prefix information option data.
|
||||
*/
|
||||
TINS_BEGIN_PACK
|
||||
struct prefix_info_type {
|
||||
uint8_t prefix_len;
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
uint8_t reserved1:6,
|
||||
A:1,
|
||||
L:1;
|
||||
#else
|
||||
uint8_t L:1,
|
||||
A:1,
|
||||
reserved1:6;
|
||||
#endif
|
||||
small_uint<1> A, L;
|
||||
uint32_t valid_lifetime,
|
||||
preferred_lifetime,
|
||||
reserved2;
|
||||
uint8_t prefix[ipaddress_type::address_size];
|
||||
ipaddress_type prefix;
|
||||
|
||||
prefix_info_type(uint8_t prefix_len=0, small_uint<1> A=0, small_uint<1> L=0,
|
||||
uint32_t valid_lifetime=0, uint32_t preferred_lifetime=0,
|
||||
const ipaddress_type &addr = ipaddress_type())
|
||||
: prefix_len(prefix_len), reserved1(0),
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
A(A), L(L),
|
||||
#else
|
||||
L(L), A(A),
|
||||
#endif
|
||||
valid_lifetime(valid_lifetime), preferred_lifetime(preferred_lifetime)
|
||||
{
|
||||
addr.copy(prefix);
|
||||
}
|
||||
} TINS_END_PACK;
|
||||
uint32_t valid_lifetime=0, uint32_t preferred_lifetime=0,
|
||||
const ipaddress_type &prefix = ipaddress_type())
|
||||
: prefix_len(prefix_len), A(A), L(L),
|
||||
valid_lifetime(valid_lifetime), preferred_lifetime(preferred_lifetime),
|
||||
prefix(prefix) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to store the RSA signature option.
|
||||
@@ -310,6 +304,39 @@ public:
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to store the map option.
|
||||
*/
|
||||
struct map_type {
|
||||
small_uint<4> dist, pref;
|
||||
small_uint<1> r;
|
||||
uint32_t valid_lifetime;
|
||||
ipaddress_type address;
|
||||
|
||||
map_type(small_uint<4> dist = 0, small_uint<4> pref = 0,
|
||||
small_uint<1> r = 0, uint32_t valid_lifetime = 0,
|
||||
const ipaddress_type &address = ipaddress_type())
|
||||
: dist(dist), pref(pref), r(r), valid_lifetime(valid_lifetime),
|
||||
address(address) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to store the route information option.
|
||||
*/
|
||||
struct route_info_type {
|
||||
typedef std::vector<uint8_t> prefix_type;
|
||||
|
||||
uint8_t prefix_len;
|
||||
small_uint<2> pref;
|
||||
uint32_t route_lifetime;
|
||||
prefix_type prefix;
|
||||
|
||||
route_info_type(uint8_t prefix_len = 0, small_uint<2> pref = 0,
|
||||
uint32_t route_lifetime = 0, const prefix_type &prefix = prefix_type())
|
||||
: prefix_len(prefix_len), pref(pref), route_lifetime(route_lifetime),
|
||||
prefix(prefix) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Constructs an ICMPv6 object.
|
||||
*
|
||||
@@ -758,6 +785,27 @@ public:
|
||||
*/
|
||||
void link_layer_addr(lladdr_type value);
|
||||
|
||||
/**
|
||||
* \brief Setter for the neighbour advertisement acknowledgement option.
|
||||
*
|
||||
* \param value The new naack option data.
|
||||
*/
|
||||
void naack(const naack_type &value);
|
||||
|
||||
/**
|
||||
* \brief Setter for the map option.
|
||||
*
|
||||
* \param value The new map option data.
|
||||
*/
|
||||
void map(const map_type &value);
|
||||
|
||||
/**
|
||||
* \brief Setter for the route information option.
|
||||
*
|
||||
* \param value The new route information option data.
|
||||
*/
|
||||
void route_info(const route_info_type &value);
|
||||
|
||||
// Option getters
|
||||
|
||||
/**
|
||||
@@ -825,7 +873,7 @@ public:
|
||||
new_ha_info_type new_home_agent_info() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the new source address list option.
|
||||
* \brief Getter for the source address list option.
|
||||
*
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
@@ -833,7 +881,7 @@ public:
|
||||
addr_list_type source_addr_list() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the new target address list option.
|
||||
* \brief Getter for the target address list option.
|
||||
*
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
@@ -841,7 +889,7 @@ public:
|
||||
addr_list_type target_addr_list() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the new RSA signature option.
|
||||
* \brief Getter for the RSA signature option.
|
||||
*
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
@@ -849,7 +897,7 @@ public:
|
||||
rsa_sign_type rsa_signature() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the new timestamp option.
|
||||
* \brief Getter for the timestamp option.
|
||||
*
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
@@ -857,7 +905,7 @@ public:
|
||||
uint64_t timestamp() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the new nonce option.
|
||||
* \brief Getter for the nonce option.
|
||||
*
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
@@ -865,7 +913,7 @@ public:
|
||||
nonce_type nonce() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the new IP address/prefix option.
|
||||
* \brief Getter for the IP address/prefix option.
|
||||
*
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
@@ -873,12 +921,37 @@ public:
|
||||
ip_prefix_type ip_prefix() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the new link layer address option.
|
||||
* \brief Getter for the link layer address option.
|
||||
*
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
*/
|
||||
lladdr_type link_layer_addr() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the neighbour advertisement acknowledgement
|
||||
* option.
|
||||
*
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
*/
|
||||
naack_type naack() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the map option.
|
||||
*
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
*/
|
||||
map_type map() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the map option.
|
||||
*
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
*/
|
||||
route_info_type route_info() const;
|
||||
private:
|
||||
TINS_BEGIN_PACK
|
||||
struct icmp6hdr {
|
||||
|
||||
@@ -246,10 +246,15 @@ void ICMPv6::target_link_layer_addr(const hwaddress_type &addr) {
|
||||
}
|
||||
|
||||
void ICMPv6::prefix_info(prefix_info_type info) {
|
||||
info.valid_lifetime = Endian::host_to_be(info.valid_lifetime);
|
||||
info.preferred_lifetime = Endian::host_to_be(info.preferred_lifetime);
|
||||
uint8_t buffer[2 + sizeof(uint32_t) * 3 + ipaddress_type::address_size];
|
||||
buffer[0] = info.prefix_len;
|
||||
buffer[1] = (info.L << 7) | (info.A << 6);
|
||||
*(uint32_t*)(buffer + 2) = Endian::host_to_be(info.valid_lifetime);
|
||||
*(uint32_t*)(buffer + 2 + sizeof(uint32_t)) = Endian::host_to_be(info.preferred_lifetime);
|
||||
*(uint32_t*)(buffer + 2 + sizeof(uint32_t) * 2) = 0;
|
||||
info.prefix.copy(buffer + 2 + sizeof(uint32_t) * 3);
|
||||
add_option(
|
||||
icmpv6_option(PREFIX_INFO, sizeof(prefix_info_type), (const uint8_t*)&info)
|
||||
icmpv6_option(PREFIX_INFO, buffer, buffer + sizeof(buffer))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -351,6 +356,39 @@ void ICMPv6::link_layer_addr(lladdr_type value) {
|
||||
add_option(icmpv6_option(LINK_ADDRESS, value.address.begin(), value.address.end()));
|
||||
}
|
||||
|
||||
void ICMPv6::naack(const naack_type &value) {
|
||||
uint8_t buffer[6];
|
||||
buffer[0] = value.first;
|
||||
buffer[1] = value.second;
|
||||
add_option(icmpv6_option(NAACK, buffer, buffer + sizeof(buffer)));
|
||||
}
|
||||
|
||||
void ICMPv6::map(const map_type &value) {
|
||||
uint8_t buffer[sizeof(uint8_t) * 2 + sizeof(uint32_t) + ipaddress_type::address_size];
|
||||
buffer[0] = value.dist << 4 | value.pref;
|
||||
buffer[1] = value.r << 7;
|
||||
*(uint32_t*)(buffer + 2) = Endian::host_to_be(value.valid_lifetime);
|
||||
value.address.copy(buffer + 2 + sizeof(uint32_t));
|
||||
add_option(icmpv6_option(MAP, buffer, buffer + sizeof(buffer)));
|
||||
}
|
||||
|
||||
void ICMPv6::route_info(const route_info_type &value) {
|
||||
uint8_t padding = 8 - value.prefix.size() % 8;
|
||||
if(padding == 8)
|
||||
padding = 0;
|
||||
std::vector<uint8_t> buffer(2 + sizeof(uint32_t) + value.prefix.size() + padding);
|
||||
buffer[0] = value.prefix_len;
|
||||
buffer[1] = value.pref << 3;
|
||||
*(uint32_t*)&buffer[2] = Endian::host_to_be(value.route_lifetime);
|
||||
// copy the prefix and then fill with padding
|
||||
buffer.insert(
|
||||
std::copy(value.prefix.begin(), value.prefix.end(), buffer.begin() + 2 + sizeof(uint32_t)),
|
||||
padding,
|
||||
0
|
||||
);
|
||||
add_option(icmpv6_option(ROUTE_INFO, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
// Option getters
|
||||
|
||||
ICMPv6::hwaddress_type ICMPv6::source_link_layer_addr() const {
|
||||
@@ -369,12 +407,17 @@ ICMPv6::hwaddress_type ICMPv6::target_link_layer_addr() const {
|
||||
|
||||
ICMPv6::prefix_info_type ICMPv6::prefix_info() const {
|
||||
const icmpv6_option *opt = search_option(PREFIX_INFO);
|
||||
if(!opt || opt->data_size() != sizeof(prefix_info_type))
|
||||
if(!opt || opt->data_size() != 2 + sizeof(uint32_t) * 3 + ipaddress_type::address_size)
|
||||
throw option_not_found();
|
||||
const uint8_t *ptr = opt->data_ptr();
|
||||
prefix_info_type output;
|
||||
std::memcpy(&output, opt->data_ptr(), sizeof(prefix_info_type));
|
||||
output.valid_lifetime = Endian::be_to_host(output.valid_lifetime);
|
||||
output.preferred_lifetime = Endian::be_to_host(output.preferred_lifetime);
|
||||
output.prefix_len = *ptr++;
|
||||
output.L = (*ptr >> 7) & 0x1;
|
||||
output.A = (*ptr++ >> 6) & 0x1;
|
||||
output.valid_lifetime = Endian::be_to_host(*(uint32_t*)ptr);
|
||||
ptr += sizeof(uint32_t);
|
||||
output.preferred_lifetime = Endian::be_to_host(*(uint32_t*)ptr);
|
||||
output.prefix = ptr + sizeof(uint32_t) * 2;
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -493,5 +536,42 @@ ICMPv6::lladdr_type ICMPv6::link_layer_addr() const {
|
||||
output.address.assign(ptr, opt->data_ptr() + opt->data_size());
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::naack_type ICMPv6::naack() const {
|
||||
const icmpv6_option *opt = search_option(NAACK);
|
||||
if(!opt || opt->data_size() != 6)
|
||||
throw option_not_found();
|
||||
const uint8_t *ptr = opt->data_ptr();
|
||||
return naack_type(ptr[0], ptr[1]);
|
||||
}
|
||||
|
||||
ICMPv6::map_type ICMPv6::map() const {
|
||||
const icmpv6_option *opt = search_option(MAP);
|
||||
if(!opt || opt->data_size() != 2 + sizeof(uint32_t) + ipaddress_type::address_size)
|
||||
throw option_not_found();
|
||||
const uint8_t *ptr = opt->data_ptr();
|
||||
map_type output;
|
||||
output.dist = (*ptr >> 4) & 0x0f;
|
||||
output.pref = *ptr++ & 0x0f;
|
||||
output.r = (*ptr++ >> 7) & 0x01;
|
||||
output.valid_lifetime = *(uint32_t*)ptr;
|
||||
ptr += sizeof(uint32_t);
|
||||
output.address = ptr;
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::route_info_type ICMPv6::route_info() const {
|
||||
const icmpv6_option *opt = search_option(ROUTE_INFO);
|
||||
if(!opt || opt->data_size() < 2 + sizeof(uint32_t))
|
||||
throw option_not_found();
|
||||
const uint8_t *ptr = opt->data_ptr();
|
||||
route_info_type output;
|
||||
output.prefix_len = *ptr++;
|
||||
output.pref = (*ptr++ >> 3) & 0x3;
|
||||
output.route_lifetime = Endian::be_to_host(*(uint32_t*)ptr);
|
||||
ptr += sizeof(uint32_t);
|
||||
output.prefix.assign(ptr, opt->data_ptr() + opt->data_size());
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -316,3 +316,36 @@ TEST_F(ICMPv6Test, LinkLayerAddress) {
|
||||
ASSERT_LE(data.address.size(), output.address.size());
|
||||
EXPECT_TRUE(std::equal(data.address.begin(), data.address.end(), output.address.begin()));
|
||||
}
|
||||
|
||||
TEST_F(ICMPv6Test, NAACK) {
|
||||
ICMPv6 icmp;
|
||||
ICMPv6::naack_type data(0x92, 0xb3);
|
||||
icmp.naack(data);
|
||||
EXPECT_EQ(icmp.naack(), data);
|
||||
}
|
||||
|
||||
TEST_F(ICMPv6Test, MAP) {
|
||||
ICMPv6 icmp;
|
||||
ICMPv6::map_type data(0x9, 0xb, 1, 0x9283719, "f029:adde::1"), output;
|
||||
icmp.map(data);
|
||||
output = icmp.map();
|
||||
EXPECT_EQ(output.dist, data.dist);
|
||||
EXPECT_EQ(output.pref, data.pref);
|
||||
EXPECT_EQ(output.r, data.r);
|
||||
EXPECT_EQ(output.address, data.address);
|
||||
}
|
||||
|
||||
TEST_F(ICMPv6Test, RouteInfo) {
|
||||
ICMPv6 icmp;
|
||||
ICMPv6::route_info_type data(0x92, 2, 0xf23a8823), output;
|
||||
data.prefix.push_back(98);
|
||||
data.prefix.push_back(52);
|
||||
data.prefix.push_back(44);
|
||||
icmp.route_info(data);
|
||||
output = icmp.route_info();
|
||||
EXPECT_EQ(output.prefix_len, data.prefix_len);
|
||||
EXPECT_EQ(output.pref, data.pref);
|
||||
EXPECT_EQ(output.route_lifetime, data.route_lifetime);
|
||||
ASSERT_LE(data.prefix.size(), output.prefix.size());
|
||||
EXPECT_TRUE(std::equal(data.prefix.begin(), data.prefix.end(), output.prefix.begin()));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user