mirror of
https://github.com/mfontanini/libtins
synced 2026-01-23 02:35:57 +01:00
Implemented several ICMPv6 option getters/setters.
This commit is contained in:
189
include/icmpv6.h
189
include/icmpv6.h
@@ -337,6 +337,87 @@ public:
|
||||
prefix(prefix) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to store the recursive DNS servers option.
|
||||
*/
|
||||
struct recursive_dns_type {
|
||||
typedef std::vector<ipaddress_type> servers_type;
|
||||
|
||||
uint32_t lifetime;
|
||||
servers_type servers;
|
||||
|
||||
recursive_dns_type(uint32_t lifetime = 0,
|
||||
const servers_type &servers = servers_type())
|
||||
: lifetime(lifetime), servers(servers) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to store the handover key request option.
|
||||
*/
|
||||
struct handover_key_req_type {
|
||||
typedef std::vector<uint8_t> key_type;
|
||||
|
||||
small_uint<4> AT;
|
||||
key_type key;
|
||||
|
||||
handover_key_req_type(small_uint<4> AT = 0,
|
||||
const key_type &key = key_type())
|
||||
: AT(AT), key(key) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to store the handover key reply option.
|
||||
*/
|
||||
struct handover_key_reply_type : handover_key_req_type {
|
||||
uint16_t lifetime;
|
||||
|
||||
handover_key_reply_type(uint16_t lifetime = 0, small_uint<4> AT = 0,
|
||||
const key_type &key = key_type())
|
||||
: handover_key_req_type(AT, key), lifetime(lifetime) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to store the handover assist information option.
|
||||
*/
|
||||
struct handover_assist_info_type {
|
||||
typedef std::vector<uint8_t> hai_type;
|
||||
|
||||
uint8_t option_code;
|
||||
hai_type hai;
|
||||
|
||||
handover_assist_info_type(uint8_t option_code=0,
|
||||
const hai_type &hai = hai_type())
|
||||
: option_code(option_code), hai(hai) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to store the mobile node identifier option.
|
||||
*/
|
||||
struct mobile_node_id_type {
|
||||
typedef std::vector<uint8_t> mn_type;
|
||||
|
||||
uint8_t option_code;
|
||||
mn_type mn;
|
||||
|
||||
mobile_node_id_type(uint8_t option_code=0,
|
||||
const mn_type &mn = mn_type())
|
||||
: option_code(option_code), mn(mn) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used to store the DNS search list option.
|
||||
*/
|
||||
struct dns_search_list_type {
|
||||
typedef std::vector<std::string> domains_type;
|
||||
|
||||
uint32_t lifetime;
|
||||
domains_type domains;
|
||||
|
||||
dns_search_list_type(uint32_t lifetime = 0,
|
||||
const domains_type &domains = domains_type())
|
||||
: lifetime(lifetime), domains(domains) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Constructs an ICMPv6 object.
|
||||
*
|
||||
@@ -675,7 +756,9 @@ public:
|
||||
return new ICMPv6(*this);
|
||||
}
|
||||
|
||||
// Option setters
|
||||
// ****************************************************************
|
||||
// Option setters
|
||||
// ****************************************************************
|
||||
|
||||
/**
|
||||
* \brief Setter for the source link layer address option.
|
||||
@@ -806,7 +889,51 @@ public:
|
||||
*/
|
||||
void route_info(const route_info_type &value);
|
||||
|
||||
// Option getters
|
||||
/**
|
||||
* \brief Setter for the recursive DNS servers option.
|
||||
*
|
||||
* \param value The new recursive DNS servers option data.
|
||||
*/
|
||||
void recursive_dns_servers(const recursive_dns_type &value);
|
||||
|
||||
/**
|
||||
* \brief Setter for the handover key request option.
|
||||
*
|
||||
* \param value The new handover key request option data.
|
||||
*/
|
||||
void handover_key_request(const handover_key_req_type &value);
|
||||
|
||||
/**
|
||||
* \brief Setter for the handover key reply option.
|
||||
*
|
||||
* \param value The new handover key reply option data.
|
||||
*/
|
||||
void handover_key_reply(const handover_key_reply_type &value);
|
||||
|
||||
/**
|
||||
* \brief Setter for the handover assist info option.
|
||||
*
|
||||
* \param value The new handover assist info option data.
|
||||
*/
|
||||
void handover_assist_info(const handover_assist_info_type &value);
|
||||
|
||||
/**
|
||||
* \brief Setter for the mobile node identifier option.
|
||||
*
|
||||
* \param value The new mobile node identifier option data.
|
||||
*/
|
||||
void mobile_node_identifier(const mobile_node_id_type &value);
|
||||
|
||||
/**
|
||||
* \brief Setter for the DNS search list option.
|
||||
*
|
||||
* \param value The new DNS search list option data.
|
||||
*/
|
||||
void dns_search_list(const dns_search_list_type &value);
|
||||
|
||||
// ****************************************************************
|
||||
// Option getters
|
||||
// ****************************************************************
|
||||
|
||||
/**
|
||||
* \brief Getter for the source link layer address option.
|
||||
@@ -946,12 +1073,60 @@ public:
|
||||
map_type map() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the map option.
|
||||
* \brief Getter for the route information option.
|
||||
*
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
*/
|
||||
route_info_type route_info() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the recursive dns servers option.
|
||||
*
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
*/
|
||||
recursive_dns_type recursive_dns_servers() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the handover key request option.
|
||||
*
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
*/
|
||||
handover_key_req_type handover_key_request() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the handover key reply option.
|
||||
*
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
*/
|
||||
handover_key_reply_type handover_key_reply() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the handover key reply option.
|
||||
*
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
*/
|
||||
handover_assist_info_type handover_assist_info() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the mobile node identifier option.
|
||||
*
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
*/
|
||||
mobile_node_id_type mobile_node_identifier() const;
|
||||
|
||||
/**
|
||||
* \brief Getter for the mobile node identifier option.
|
||||
*
|
||||
* This method will throw an option_not_found exception if the
|
||||
* option is not found.
|
||||
*/
|
||||
dns_search_list_type dns_search_list() const;
|
||||
private:
|
||||
TINS_BEGIN_PACK
|
||||
struct icmp6hdr {
|
||||
@@ -1004,7 +1179,13 @@ private:
|
||||
void parse_options(const uint8_t *&buffer, uint32_t &total_sz);
|
||||
void add_addr_list(uint8_t type, const addr_list_type &value);
|
||||
addr_list_type search_addr_list(Options type) const;
|
||||
|
||||
template<template <typename> class Functor>
|
||||
const icmpv6_option *safe_search_option(Options opt, uint32_t size) const {
|
||||
const icmpv6_option *option = search_option(opt);
|
||||
if(!option || Functor<uint32_t>()(option->data_size(), size))
|
||||
throw option_not_found();
|
||||
return option;
|
||||
}
|
||||
|
||||
icmp6hdr _header;
|
||||
ipaddress_type _target_address, _dest_address;
|
||||
|
||||
276
src/icmpv6.cpp
276
src/icmpv6.cpp
@@ -38,14 +38,14 @@
|
||||
namespace Tins {
|
||||
|
||||
ICMPv6::ICMPv6(Types tp)
|
||||
: _options_size()
|
||||
: _options_size(), reach_time(0), retrans_timer(0)
|
||||
{
|
||||
std::memset(&_header, 0, sizeof(_header));
|
||||
type(tp);
|
||||
}
|
||||
|
||||
ICMPv6::ICMPv6(const uint8_t *buffer, uint32_t total_sz)
|
||||
: _options_size()
|
||||
: _options_size(), reach_time(0), retrans_timer(0)
|
||||
{
|
||||
if(total_sz < sizeof(_header))
|
||||
throw std::runtime_error("Not enough size for an ICMPv6 header");
|
||||
@@ -166,7 +166,10 @@ void ICMPv6::dest_addr(const ipaddress_type &new_dest_addr) {
|
||||
}
|
||||
|
||||
uint32_t ICMPv6::header_size() const {
|
||||
return sizeof(_header) + _options_size +
|
||||
uint32_t extra = 0;
|
||||
if(type() == ROUTER_ADVERT)
|
||||
extra = sizeof(uint32_t) * 2;
|
||||
return sizeof(_header) + _options_size + extra +
|
||||
(has_target_addr() ? ipaddress_type::address_size : 0) +
|
||||
(has_dest_addr() ? ipaddress_type::address_size : 0);
|
||||
}
|
||||
@@ -187,6 +190,13 @@ void ICMPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *
|
||||
buffer = _dest_address.copy(buffer);
|
||||
total_sz -= sizeof(ipaddress_type::address_size);
|
||||
}
|
||||
if(type() == ROUTER_ADVERT) {
|
||||
*(uint32_t*)buffer = reach_time;
|
||||
buffer += sizeof(uint32_t);
|
||||
*(uint32_t*)buffer = retrans_timer;
|
||||
buffer += sizeof(uint32_t);
|
||||
total_sz -= sizeof(uint32_t) * 2;
|
||||
}
|
||||
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);
|
||||
@@ -235,7 +245,9 @@ const ICMPv6::icmpv6_option *ICMPv6::search_option(Options id) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Option setters
|
||||
// ********************************************************************
|
||||
// Option setters
|
||||
// ********************************************************************
|
||||
|
||||
void ICMPv6::source_link_layer_addr(const hwaddress_type &addr) {
|
||||
add_option(icmpv6_option(SOURCE_ADDRESS, addr.begin(), addr.end()));
|
||||
@@ -312,7 +324,7 @@ void ICMPv6::add_addr_list(uint8_t type, const addr_list_type &value) {
|
||||
}
|
||||
|
||||
void ICMPv6::rsa_signature(const rsa_sign_type &value) {
|
||||
uint32_t total_sz = 2 + sizeof(value.key_hash) + value.signature.size();
|
||||
uint32_t total_sz = 4 + sizeof(value.key_hash) + value.signature.size();
|
||||
uint8_t padding = 8 - total_sz % 8;
|
||||
if(padding == 8)
|
||||
padding = 0;
|
||||
@@ -349,7 +361,7 @@ void ICMPv6::ip_prefix(const ip_prefix_type &value) {
|
||||
|
||||
void ICMPv6::link_layer_addr(lladdr_type value) {
|
||||
value.address.insert(value.address.begin(), value.option_code);
|
||||
uint8_t padding = 8 - value.address.size() % 8;
|
||||
uint8_t padding = 8 - (2 + value.address.size()) % 8;
|
||||
if(padding == 8)
|
||||
padding = 0;
|
||||
value.address.insert(value.address.end(), padding, 0);
|
||||
@@ -389,7 +401,115 @@ void ICMPv6::route_info(const route_info_type &value) {
|
||||
add_option(icmpv6_option(ROUTE_INFO, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
// Option getters
|
||||
void ICMPv6::recursive_dns_servers(const recursive_dns_type &value) {
|
||||
std::vector<uint8_t> buffer(
|
||||
2 + sizeof(uint32_t) + value.servers.size() * ipaddress_type::address_size
|
||||
);
|
||||
|
||||
buffer[0] = buffer[1] = 0;
|
||||
*(uint32_t*)&buffer[2] = Endian::host_to_be(value.lifetime);
|
||||
std::vector<uint8_t>::iterator out = buffer.begin() + 2 + sizeof(uint32_t);
|
||||
typedef recursive_dns_type::servers_type::const_iterator iterator;
|
||||
for(iterator it = value.servers.begin(); it != value.servers.end(); ++it)
|
||||
out = it->copy(out);
|
||||
add_option(icmpv6_option(RECURSIVE_DNS_SERV, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
void ICMPv6::handover_key_request(const handover_key_req_type &value) {
|
||||
uint8_t padding = 8 - (value.key.size() + 4) % 8;
|
||||
if(padding == 8)
|
||||
padding = 0;
|
||||
std::vector<uint8_t> buffer(2 + value.key.size() + padding);
|
||||
buffer[0] = padding;
|
||||
buffer[1] = value.AT << 4;
|
||||
// copy the key, and fill with padding
|
||||
std::fill(
|
||||
std::copy(value.key.begin(), value.key.end(), buffer.begin() + 2),
|
||||
buffer.end(),
|
||||
0
|
||||
);
|
||||
add_option(icmpv6_option(HANDOVER_KEY_REQ, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
void ICMPv6::handover_key_reply(const handover_key_reply_type &value) {
|
||||
const uint32_t data_size = value.key.size() + 2 + sizeof(uint16_t);
|
||||
uint8_t padding = 8 - (data_size+2) % 8;
|
||||
if(padding == 8)
|
||||
padding = 0;
|
||||
std::vector<uint8_t> buffer(data_size + padding);
|
||||
buffer[0] = padding;
|
||||
buffer[1] = value.AT << 4;
|
||||
*(uint16_t*)&buffer[2] = Endian::host_to_be(value.lifetime);
|
||||
// copy the key, and fill with padding
|
||||
std::fill(
|
||||
std::copy(value.key.begin(), value.key.end(), buffer.begin() + 2 + sizeof(uint16_t)),
|
||||
buffer.end(),
|
||||
0
|
||||
);
|
||||
add_option(icmpv6_option(HANDOVER_KEY_REPLY, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
void ICMPv6::handover_assist_info(const handover_assist_info_type &value) {
|
||||
const uint32_t data_size = value.hai.size() + 2;
|
||||
uint8_t padding = 8 - (data_size+2) % 8;
|
||||
if(padding == 8)
|
||||
padding = 0;
|
||||
std::vector<uint8_t> buffer(data_size + padding);
|
||||
buffer[0] = value.option_code;
|
||||
buffer[1] = static_cast<uint8_t>(value.hai.size());
|
||||
// copy hai + padding
|
||||
buffer.insert(
|
||||
std::copy(value.hai.begin(), value.hai.end(), buffer.begin() + 2),
|
||||
padding,
|
||||
0
|
||||
);
|
||||
add_option(icmpv6_option(HANDOVER_ASSIST_INFO, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
void ICMPv6::mobile_node_identifier(const mobile_node_id_type &value) {
|
||||
const uint32_t data_size = value.mn.size() + 2;
|
||||
uint8_t padding = 8 - (data_size+2) % 8;
|
||||
if(padding == 8)
|
||||
padding = 0;
|
||||
std::vector<uint8_t> buffer(data_size + padding);
|
||||
buffer[0] = value.option_code;
|
||||
buffer[1] = static_cast<uint8_t>(value.mn.size());
|
||||
// copy mn + padding
|
||||
buffer.insert(
|
||||
std::copy(value.mn.begin(), value.mn.end(), buffer.begin() + 2),
|
||||
padding,
|
||||
0
|
||||
);
|
||||
add_option(icmpv6_option(MOBILE_NODE_ID, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
void ICMPv6::dns_search_list(const dns_search_list_type &value) {
|
||||
// at least it's got this size
|
||||
std::vector<uint8_t> buffer(2 + sizeof(uint32_t));
|
||||
*(uint32_t*)&buffer[2] = Endian::host_to_be(value.lifetime);
|
||||
typedef dns_search_list_type::domains_type::const_iterator iterator;
|
||||
for(iterator it = value.domains.begin(); it != value.domains.end(); ++it) {
|
||||
size_t prev = 0, index;
|
||||
do {
|
||||
index = it->find('.', prev);
|
||||
std::string::const_iterator end = (index == std::string::npos) ? it->end() : (it->begin() + index);
|
||||
buffer.push_back(end - (it->begin() + prev));
|
||||
buffer.insert(buffer.end(), it->begin() + prev, end);
|
||||
prev = index + 1;
|
||||
} while(index != std::string::npos);
|
||||
// delimiter
|
||||
buffer.push_back(0);
|
||||
}
|
||||
uint8_t padding = 8 - (buffer.size() + 2) % 8;
|
||||
if(padding == 8)
|
||||
padding = 0;
|
||||
buffer.insert(buffer.end(), padding, 0);
|
||||
add_option(icmpv6_option(DNS_SEARCH_LIST, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
// ********************************************************************
|
||||
// Option getters
|
||||
// ********************************************************************
|
||||
|
||||
ICMPv6::hwaddress_type ICMPv6::source_link_layer_addr() const {
|
||||
const icmpv6_option *opt = search_option(SOURCE_ADDRESS);
|
||||
@@ -497,25 +617,23 @@ ICMPv6::rsa_sign_type ICMPv6::rsa_signature() const {
|
||||
}
|
||||
|
||||
uint64_t ICMPv6::timestamp() const {
|
||||
const icmpv6_option *opt = search_option(TIMESTAMP);
|
||||
// 6 bytes reserved
|
||||
if(!opt || opt->data_size() < 6 + sizeof(uint64_t))
|
||||
throw option_not_found();
|
||||
const icmpv6_option *opt = safe_search_option<std::less>(
|
||||
TIMESTAMP, 6 + sizeof(uint64_t)
|
||||
);
|
||||
return Endian::be_to_host(*(uint64_t*)(opt->data_ptr() + 6));
|
||||
}
|
||||
|
||||
ICMPv6::nonce_type ICMPv6::nonce() const {
|
||||
const icmpv6_option *opt = search_option(NONCE);
|
||||
// at least a one byte nonce(though it should be 8byte-padded as per the RFC).
|
||||
if(!opt || opt->data_size() == 0)
|
||||
throw option_not_found();
|
||||
const icmpv6_option *opt = safe_search_option<std::equal_to>(
|
||||
NONCE, 0
|
||||
);
|
||||
return nonce_type(opt->data_ptr(), opt->data_ptr() + opt->data_size());
|
||||
}
|
||||
|
||||
ICMPv6::ip_prefix_type ICMPv6::ip_prefix() const {
|
||||
const icmpv6_option *opt = search_option(IP_PREFIX);
|
||||
if(!opt || opt->data_size() != 6 + ipaddress_type::address_size)
|
||||
throw option_not_found();
|
||||
const icmpv6_option *opt = safe_search_option<std::less>(
|
||||
IP_PREFIX, 2
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr();
|
||||
ip_prefix_type output;
|
||||
output.option_code = *ptr++;
|
||||
@@ -527,10 +645,10 @@ ICMPv6::ip_prefix_type ICMPv6::ip_prefix() const {
|
||||
}
|
||||
|
||||
ICMPv6::lladdr_type ICMPv6::link_layer_addr() const {
|
||||
const icmpv6_option *opt = search_option(LINK_ADDRESS);
|
||||
// at least the option_code and 1 byte from the link layer address
|
||||
if(!opt || opt->data_size() < 2)
|
||||
throw option_not_found();
|
||||
const icmpv6_option *opt = safe_search_option<std::less>(
|
||||
LINK_ADDRESS, 2
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr();
|
||||
lladdr_type output(*ptr++);
|
||||
output.address.assign(ptr, opt->data_ptr() + opt->data_size());
|
||||
@@ -538,17 +656,17 @@ ICMPv6::lladdr_type ICMPv6::link_layer_addr() const {
|
||||
}
|
||||
|
||||
ICMPv6::naack_type ICMPv6::naack() const {
|
||||
const icmpv6_option *opt = search_option(NAACK);
|
||||
if(!opt || opt->data_size() != 6)
|
||||
throw option_not_found();
|
||||
const icmpv6_option *opt = safe_search_option<std::not_equal_to>(
|
||||
NAACK, 6
|
||||
);
|
||||
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 icmpv6_option *opt = safe_search_option<std::not_equal_to>(
|
||||
MAP, 2 + sizeof(uint32_t) + ipaddress_type::address_size
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr();
|
||||
map_type output;
|
||||
output.dist = (*ptr >> 4) & 0x0f;
|
||||
@@ -561,9 +679,9 @@ ICMPv6::map_type ICMPv6::map() const {
|
||||
}
|
||||
|
||||
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 icmpv6_option *opt = safe_search_option<std::less>(
|
||||
ROUTE_INFO, 2 + sizeof(uint32_t)
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr();
|
||||
route_info_type output;
|
||||
output.prefix_len = *ptr++;
|
||||
@@ -573,5 +691,103 @@ ICMPv6::route_info_type ICMPv6::route_info() const {
|
||||
output.prefix.assign(ptr, opt->data_ptr() + opt->data_size());
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::recursive_dns_type ICMPv6::recursive_dns_servers() const {
|
||||
const icmpv6_option *opt = safe_search_option<std::less>(
|
||||
RECURSIVE_DNS_SERV, 2 + sizeof(uint32_t) + ipaddress_type::address_size
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr() + 2, *end = opt->data_ptr() + opt->data_size();
|
||||
recursive_dns_type output;
|
||||
output.lifetime = Endian::be_to_host(*(uint32_t*)ptr);
|
||||
ptr += sizeof(uint32_t);
|
||||
while(ptr < end) {
|
||||
if(ptr + ipaddress_type::address_size > end)
|
||||
throw option_not_found();
|
||||
output.servers.push_back(ptr);
|
||||
ptr += ipaddress_type::address_size;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::handover_key_req_type ICMPv6::handover_key_request() const {
|
||||
const icmpv6_option *opt = safe_search_option<std::less>(
|
||||
HANDOVER_KEY_REQ, 2 + sizeof(uint32_t)
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr() + 1, *end = opt->data_ptr() + opt->data_size();
|
||||
handover_key_req_type output;
|
||||
output.AT = (*ptr++ >> 4) & 0x3;
|
||||
// is there enough size for the indicated padding?
|
||||
if(end - ptr < *opt->data_ptr())
|
||||
throw option_not_found();
|
||||
output.key.assign(ptr, ptr + ((end - ptr) - *opt->data_ptr()));
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::handover_key_reply_type ICMPv6::handover_key_reply() const {
|
||||
const icmpv6_option *opt = safe_search_option<std::less>(
|
||||
HANDOVER_KEY_REPLY, 2 + sizeof(uint32_t)
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr() + 1, *end = opt->data_ptr() + opt->data_size();
|
||||
handover_key_reply_type output;
|
||||
output.AT = (*ptr++ >> 4) & 0x3;
|
||||
output.lifetime = Endian::be_to_host(*(uint16_t*)ptr);
|
||||
ptr += sizeof(uint16_t);
|
||||
// is there enough size for the indicated padding?
|
||||
if(end - ptr < *opt->data_ptr())
|
||||
throw option_not_found();
|
||||
output.key.assign(ptr, ptr + ((end - ptr) - *opt->data_ptr()));
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::handover_assist_info_type ICMPv6::handover_assist_info() const {
|
||||
const icmpv6_option *opt = safe_search_option<std::less>(
|
||||
HANDOVER_ASSIST_INFO, 2
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr(), *end = ptr + opt->data_size();
|
||||
handover_assist_info_type output;
|
||||
output.option_code = *ptr++;
|
||||
if((end - ptr - 1) < *ptr)
|
||||
throw option_not_found();
|
||||
output.hai.assign(ptr + 1, ptr + 1 + *ptr);
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::mobile_node_id_type ICMPv6::mobile_node_identifier() const {
|
||||
const icmpv6_option *opt = safe_search_option<std::less>(
|
||||
MOBILE_NODE_ID, 2
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr(), *end = ptr + opt->data_size();
|
||||
mobile_node_id_type output;
|
||||
output.option_code = *ptr++;
|
||||
if((end - ptr - 1) < *ptr)
|
||||
throw option_not_found();
|
||||
output.mn.assign(ptr + 1, ptr + 1 + *ptr);
|
||||
return output;
|
||||
}
|
||||
|
||||
ICMPv6::dns_search_list_type ICMPv6::dns_search_list() const {
|
||||
const icmpv6_option *opt = safe_search_option<std::less>(
|
||||
DNS_SEARCH_LIST, 2 + sizeof(uint32_t)
|
||||
);
|
||||
const uint8_t *ptr = opt->data_ptr(), *end = ptr + opt->data_size();
|
||||
dns_search_list_type output;
|
||||
output.lifetime = Endian::be_to_host(*(uint32_t*)(ptr + 2));
|
||||
ptr += 2 + sizeof(uint32_t);
|
||||
while(ptr < end && *ptr) {
|
||||
std::string domain;
|
||||
while(ptr < end && *ptr && *ptr < (end - ptr)) {
|
||||
if(!domain.empty())
|
||||
domain.push_back('.');
|
||||
domain.insert(domain.end(), ptr + 1, ptr + *ptr + 1);
|
||||
ptr += *ptr + 1;
|
||||
}
|
||||
// not enough size
|
||||
if(ptr < end && *ptr != 0)
|
||||
throw option_not_found();
|
||||
output.domains.push_back(domain);
|
||||
ptr++;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -349,3 +349,74 @@ TEST_F(ICMPv6Test, RouteInfo) {
|
||||
ASSERT_LE(data.prefix.size(), output.prefix.size());
|
||||
EXPECT_TRUE(std::equal(data.prefix.begin(), data.prefix.end(), output.prefix.begin()));
|
||||
}
|
||||
|
||||
TEST_F(ICMPv6Test, RecursiveDNSServer) {
|
||||
ICMPv6 icmp;
|
||||
ICMPv6::recursive_dns_type data(0x9283712), output;
|
||||
data.servers.push_back("827d:adae::1");
|
||||
data.servers.push_back("2929:1234:fefe::2");
|
||||
icmp.recursive_dns_servers(data);
|
||||
output = icmp.recursive_dns_servers();
|
||||
EXPECT_EQ(output.lifetime, data.lifetime);
|
||||
EXPECT_EQ(output.servers, data.servers);
|
||||
}
|
||||
|
||||
TEST_F(ICMPv6Test, HandoverKeyRequest) {
|
||||
ICMPv6 icmp;
|
||||
ICMPv6::handover_key_req_type data(2), output;
|
||||
data.key.push_back(98);
|
||||
data.key.push_back(52);
|
||||
data.key.push_back(44);
|
||||
icmp.handover_key_request(data);
|
||||
output = icmp.handover_key_request();
|
||||
EXPECT_EQ(output.AT, data.AT);
|
||||
EXPECT_EQ(data.key, output.key);
|
||||
}
|
||||
|
||||
TEST_F(ICMPv6Test, HandoverKeyReply) {
|
||||
ICMPv6 icmp;
|
||||
ICMPv6::handover_key_reply_type data(0x9283, 2), output;
|
||||
data.key.push_back(98);
|
||||
data.key.push_back(52);
|
||||
data.key.push_back(44);
|
||||
icmp.handover_key_reply(data);
|
||||
output = icmp.handover_key_reply();
|
||||
EXPECT_EQ(output.AT, data.AT);
|
||||
EXPECT_EQ(output.lifetime, data.lifetime);
|
||||
EXPECT_EQ(data.key, output.key);
|
||||
}
|
||||
|
||||
TEST_F(ICMPv6Test, HandoverAssistInfo) {
|
||||
ICMPv6 icmp;
|
||||
ICMPv6::handover_assist_info_type data(0x92), output;
|
||||
data.hai.push_back(98);
|
||||
data.hai.push_back(52);
|
||||
data.hai.push_back(44);
|
||||
icmp.handover_assist_info(data);
|
||||
output = icmp.handover_assist_info();
|
||||
EXPECT_EQ(output.option_code, data.option_code);
|
||||
EXPECT_EQ(data.hai, output.hai);
|
||||
}
|
||||
|
||||
TEST_F(ICMPv6Test, MobileNodeIdentifier) {
|
||||
ICMPv6 icmp;
|
||||
ICMPv6::mobile_node_id_type data(0x92), output;
|
||||
data.mn.push_back(98);
|
||||
data.mn.push_back(52);
|
||||
data.mn.push_back(44);
|
||||
icmp.mobile_node_identifier(data);
|
||||
output = icmp.mobile_node_identifier();
|
||||
EXPECT_EQ(output.option_code, data.option_code);
|
||||
EXPECT_EQ(data.mn, output.mn);
|
||||
}
|
||||
|
||||
TEST_F(ICMPv6Test, DNSSearchList) {
|
||||
ICMPv6 icmp;
|
||||
ICMPv6::dns_search_list_type data(0x9283fd1), output;
|
||||
data.domains.push_back("libtins.sourceforge.net");
|
||||
data.domains.push_back("www.example.com");
|
||||
icmp.dns_search_list(data);
|
||||
output = icmp.dns_search_list();
|
||||
EXPECT_EQ(output.lifetime, data.lifetime);
|
||||
EXPECT_EQ(data.domains, output.domains);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user