1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 02:35:57 +01:00

Ported DHCP and Dot11. Almost ported DHCPv6 completely.

This commit is contained in:
Matias Fontanini
2013-12-23 23:02:58 -03:00
parent 33091ccbae
commit e2656739f1
8 changed files with 425 additions and 349 deletions

View File

@@ -32,6 +32,7 @@
#include <list>
#include <vector>
#include <string>
#include "bootp.h"
#include "pdu_option.h"
@@ -271,7 +272,7 @@ namespace Tins {
*
* \param routers A list of ip addresses.
*/
void routers(const std::list<ipaddress_type> &routers);
void routers(const std::vector<ipaddress_type> &routers);
/**
* \brief Adds a domain name servers option.
@@ -280,7 +281,7 @@ namespace Tins {
*
* \param dns A list of ip addresses.
*/
void domain_name_servers(const std::list<ipaddress_type> &dns);
void domain_name_servers(const std::vector<ipaddress_type> &dns);
/**
* \brief Adds a broadcast address option.
@@ -377,10 +378,10 @@ namespace Tins {
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return std::list<ipaddress_type> Containing the routers
* \return std::vector<ipaddress_type> Containing the routers
* option data.
*/
std::list<ipaddress_type> routers() const;
std::vector<ipaddress_type> routers() const;
/**
* \brief Searchs for a dns option.
@@ -391,7 +392,7 @@ namespace Tins {
* \return std::list<ipaddress_type> Contanining the DNS servers
* provided.
*/
std::list<ipaddress_type> domain_name_servers() const;
std::vector<ipaddress_type> domain_name_servers() const;
/**
* \brief Searchs for a broadcast option.
@@ -450,27 +451,19 @@ namespace Tins {
}
private:
static const uint32_t MAX_DHCP_SIZE;
template<typename T>
struct type2type {};
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
template<class T>
T generic_search(OptionTypes opt, type2type<T>) const {
T search_and_convert(OptionTypes opt) const {
const option *option = search_option(opt);
if(option && option->data_size() == sizeof(T))
return *(const T*)option->data_ptr();
else
if(!option)
throw option_not_found();
return option->to<T>();
}
void internal_add_option(const option &opt);
std::list<ipaddress_type> generic_search(OptionTypes opt, type2type<std::list<ipaddress_type> >) const;
std::string generic_search(OptionTypes opt, type2type<std::string>) const;
ipaddress_type generic_search(OptionTypes opt, type2type<ipaddress_type>) const;
serialization_type serialize_list(const std::list<ipaddress_type> &ip_list);
serialization_type serialize_list(const std::vector<ipaddress_type> &ip_list);
options_type _options;
uint32_t _size;

View File

@@ -179,6 +179,8 @@ public:
ia_na_type(uint32_t id = 0, uint32_t t1 = 0, uint32_t t2 = 0,
const options_type& options = options_type())
: id(id), t1(t1), t2(t2), options(options) {}
static ia_na_type from_option(const option &opt);
};
/**
@@ -194,6 +196,8 @@ public:
ia_ta_type(uint32_t id = 0,
const options_type& options = options_type())
: id(id), options(options) {}
static ia_ta_type from_option(const option &opt);
};
/**
@@ -211,6 +215,8 @@ public:
const options_type& options = options_type())
: address(address), preferred_lifetime(preferred_lifetime),
valid_lifetime(valid_lifetime), options(options) {}
static ia_address_type from_option(const option &opt);
};
/**
@@ -228,6 +234,8 @@ public:
const auth_info_type &auth_info = auth_info_type())
: protocol(protocol), algorithm(algorithm), rdm(rdm),
replay_detection(replay_detection), auth_info(auth_info) {}
static authentication_type from_option(const option &opt);
};
/**
@@ -239,6 +247,8 @@ public:
status_code_type(uint16_t code = 0, const std::string &message = "")
: code(code), message(message) { }
static status_code_type from_option(const option &opt);
};
/**
@@ -253,6 +263,8 @@ public:
vendor_info_type(uint32_t enterprise_number = 0,
const data_type &data = data_type())
: enterprise_number(enterprise_number), data(data) { }
static vendor_info_type from_option(const option &opt);
};
@@ -279,6 +291,8 @@ public:
const class_data_type &vendor_class_data = class_data_type())
: enterprise_number(enterprise_number),
vendor_class_data(vendor_class_data) { }
static vendor_class_type from_option(const option &opt);
};
/**
@@ -361,12 +375,14 @@ public:
duid_type(const duid_ll &identifier)
: id(duid_en::duid_id), data(identifier.serialize()) {}
static duid_type from_option(const option &opt);
};
/**
* The type used to store the Option Request option.
*/
typedef std::vector<OptionTypes> option_request_type;
typedef std::vector<uint16_t> option_request_type;
/**
* The type used to store the Relay Message option.
@@ -837,6 +853,14 @@ private:
throw option_not_found();
return option;
}
template<typename T>
T search_and_convert(OptionTypes opt) const {
const option *option = search_option(opt);
if(!option)
throw option_not_found();
return option->to<T>();
}
template<typename InputIterator>
void class_option_data2option(InputIterator start, InputIterator end,
@@ -882,7 +906,48 @@ private:
uint32_t options_size;
ipaddress_type link_addr, peer_addr;
options_type options_;
};
};
namespace Internals {
template<typename InputIterator>
void class_option_data2option(InputIterator start, InputIterator end,
std::vector<uint8_t>& buffer, size_t start_index = 0)
{
size_t index = start_index;
while(start != end) {
buffer.resize(buffer.size() + sizeof(uint16_t) + start->size());
*(uint16_t*)&buffer[index] = Endian::host_to_be<uint16_t>(start->size());
index += sizeof(uint16_t);
std::copy(start->begin(), start->end(), buffer.begin() + index);
index += start->size();
start++;
}
}
template<typename OutputType>
OutputType option2class_option_data(const uint8_t *ptr, uint32_t total_sz)
{
typedef typename OutputType::value_type value_type;
OutputType output;
size_t index = 0;
while(index + 2 < total_sz) {
uint16_t size = Endian::be_to_host(
*(const uint16_t*)(ptr + index)
);
index += sizeof(uint16_t);
if(index + size > total_sz)
throw option_not_found();
output.push_back(
value_type(ptr + index, ptr + index + size)
);
index += size;
}
if(index != total_sz)
throw malformed_option();
return output;
}
}
}
#endif // TINS_DHCPV6_H

View File

@@ -379,6 +379,8 @@ public:
uint8_t hop_pattern, uint8_t hop_index)
: dwell_time(dwell_time), hop_set(hop_set),
hop_pattern(hop_pattern), hop_index(hop_index) {}
static fh_params_set from_option(const option &opt);
};
/**
@@ -395,6 +397,8 @@ public:
: cfp_count(cfp_count), cfp_period(cfp_period),
cfp_max_duration(cfp_max_duration),
cfp_dur_remaining(cfp_dur_remaining) {}
static cf_params_set from_option(const option &opt);
};
/**
@@ -413,6 +417,8 @@ public:
uint8_t recovery_interval, const channels_type &channels)
: dfs_owner(addr), recovery_interval(recovery_interval),
channel_map(channels) {}
static ibss_dfs_params from_option(const option &opt);
};
/**
@@ -431,6 +437,8 @@ public:
const byte_array &number, const byte_array &max)
: country(country), first_channel(first), number_channels(number),
max_transmit_power(max) {}
static country_params from_option(const option &opt);
};
/**
@@ -448,6 +456,8 @@ public:
uint8_t offset, const byte_array& table)
: flag(flag), number_of_sets(sets), modulus(modulus),
offset(offset), random_table(table) {}
static fh_pattern_type from_option(const option &opt);
};
/**
@@ -460,6 +470,8 @@ public:
channel_switch_type(uint8_t mode, uint8_t channel, uint8_t count)
: switch_mode(mode), new_channel(channel), switch_count(count) { }
static channel_switch_type from_option(const option &opt);
};
/**
@@ -475,6 +487,8 @@ public:
uint16_t offset)
: quiet_count(count), quiet_period(period),
quiet_duration(duration), quiet_offset(offset) {}
static quiet_type from_option(const option &opt);
};
/**
@@ -491,6 +505,8 @@ public:
uint16_t capacity)
: station_count(count), available_capacity(capacity),
channel_utilization(utilization) {}
static bss_load_type from_option(const option &opt);
};
/**
@@ -506,6 +522,8 @@ public:
const byte_array &bitmap)
: dtim_count(count), dtim_period(period), bitmap_control(control),
partial_virtual_bitmap(bitmap) {}
static tim_type from_option(const option &opt);
};
/**

View File

@@ -39,8 +39,8 @@
#include "endianness.h"
#include "internals.h"
#include "ip_address.h"
#include "hw_address.h"
#include "ipv6_address.h"
#include "hw_address.h"
namespace Tins {
/**
@@ -113,6 +113,30 @@ namespace Internals {
return HWAddress<n>(opt.data_ptr());
}
};
template<>
struct converter<IPv4Address> {
template<typename X, typename PDUType>
static IPv4Address convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() != sizeof(uint32_t))
throw malformed_option();
const uint32_t *ptr = (const uint32_t*)opt.data_ptr();
if(PDUType::endianness == PDUType::BE)
return IPv4Address(*ptr);
else
return IPv4Address(Endian::change_endian(*ptr));
}
};
template<>
struct converter<IPv6Address> {
template<typename X, typename PDUType>
static IPv6Address convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() != IPv6Address::address_size)
throw malformed_option();
return IPv6Address(opt.data_ptr());
}
};
template<>
struct converter<std::string> {
@@ -208,7 +232,7 @@ namespace Internals {
if(PDUType::endianness == PDUType::BE)
*it++ = IPv4Address(*ptr++);
else
*it++ = Endian::change_endian(*ptr++);
*it++ = IPv4Address(Endian::change_endian(*ptr++));
}
return output;
}

View File

@@ -104,7 +104,7 @@ void DHCP::end() {
}
uint8_t DHCP::type() const {
return generic_search(DHCP_MESSAGE_TYPE, type2type<uint8_t>());
return search_and_convert<uint8_t>(DHCP_MESSAGE_TYPE);
}
void DHCP::server_identifier(ipaddress_type ip) {
@@ -113,7 +113,7 @@ void DHCP::server_identifier(ipaddress_type ip) {
}
DHCP::ipaddress_type DHCP::server_identifier() const {
return generic_search(DHCP_SERVER_IDENTIFIER, type2type<ipaddress_type>());
return search_and_convert<ipaddress_type>(DHCP_SERVER_IDENTIFIER);
}
void DHCP::lease_time(uint32_t time) {
@@ -122,7 +122,7 @@ void DHCP::lease_time(uint32_t time) {
}
uint32_t DHCP::lease_time() const {
return Endian::host_to_be(generic_search(DHCP_LEASE_TIME, type2type<uint32_t>()));
return search_and_convert<uint32_t>(DHCP_LEASE_TIME);
}
void DHCP::renewal_time(uint32_t time) {
@@ -131,7 +131,7 @@ void DHCP::renewal_time(uint32_t time) {
}
uint32_t DHCP::renewal_time() const {
return Endian::host_to_be(generic_search(DHCP_RENEWAL_TIME, type2type<uint32_t>()));
return search_and_convert<uint32_t>(DHCP_RENEWAL_TIME);
}
void DHCP::subnet_mask(ipaddress_type mask) {
@@ -140,25 +140,25 @@ void DHCP::subnet_mask(ipaddress_type mask) {
}
DHCP::ipaddress_type DHCP::subnet_mask() const {
return generic_search(SUBNET_MASK, type2type<ipaddress_type>());
return search_and_convert<ipaddress_type>(SUBNET_MASK);
}
void DHCP::routers(const list<ipaddress_type> &routers) {
void DHCP::routers(const std::vector<ipaddress_type> &routers) {
serialization_type buffer = serialize_list(routers);
add_option(option(ROUTERS, buffer.begin(), buffer.end()));
}
std::list<DHCP::ipaddress_type> DHCP::routers() const {
return generic_search(ROUTERS, type2type<std::list<ipaddress_type> >());
std::vector<DHCP::ipaddress_type> DHCP::routers() const {
return search_and_convert<std::vector<DHCP::ipaddress_type> >(ROUTERS);
}
void DHCP::domain_name_servers(const list<ipaddress_type> &dns) {
void DHCP::domain_name_servers(const std::vector<ipaddress_type> &dns) {
serialization_type buffer = serialize_list(dns);
add_option(option(DOMAIN_NAME_SERVERS, buffer.begin(), buffer.end()));
}
std::list<DHCP::ipaddress_type> DHCP::domain_name_servers() const {
return generic_search(DOMAIN_NAME_SERVERS, type2type<std::list<ipaddress_type> >());
std::vector<DHCP::ipaddress_type> DHCP::domain_name_servers() const {
return search_and_convert<std::vector<DHCP::ipaddress_type> >(DOMAIN_NAME_SERVERS);
}
void DHCP::broadcast(ipaddress_type addr) {
@@ -167,7 +167,7 @@ void DHCP::broadcast(ipaddress_type addr) {
}
DHCP::ipaddress_type DHCP::broadcast() const {
return generic_search(BROADCAST_ADDRESS, type2type<ipaddress_type>());
return search_and_convert<ipaddress_type>(BROADCAST_ADDRESS);
}
void DHCP::requested_ip(ipaddress_type addr) {
@@ -176,7 +176,7 @@ void DHCP::requested_ip(ipaddress_type addr) {
}
DHCP::ipaddress_type DHCP::requested_ip() const {
return generic_search(DHCP_REQUESTED_ADDRESS, type2type<ipaddress_type>());
return search_and_convert<ipaddress_type>(DHCP_REQUESTED_ADDRESS);
}
void DHCP::domain_name(const string &name) {
@@ -184,7 +184,7 @@ void DHCP::domain_name(const string &name) {
}
std::string DHCP::domain_name() const {
return generic_search(DOMAIN_NAME, type2type<std::string>());
return search_and_convert<std::string>(DOMAIN_NAME);
}
void DHCP::rebind_time(uint32_t time) {
@@ -193,13 +193,13 @@ void DHCP::rebind_time(uint32_t time) {
}
uint32_t DHCP::rebind_time() const {
return Endian::host_to_be(generic_search(DHCP_REBINDING_TIME, type2type<uint32_t>()));
return search_and_convert<uint32_t>(DHCP_REBINDING_TIME);
}
PDU::serialization_type DHCP::serialize_list(const list<ipaddress_type> &ip_list) {
PDU::serialization_type DHCP::serialize_list(const std::vector<ipaddress_type> &ip_list) {
serialization_type buffer(ip_list.size() * sizeof(uint32_t));
uint32_t *ptr = (uint32_t*)&buffer[0];
for(list<ipaddress_type>::const_iterator it = ip_list.begin(); it != ip_list.end(); ++it)
for(std::vector<ipaddress_type>::const_iterator it = ip_list.begin(); it != ip_list.end(); ++it)
*(ptr++) = *it;
return buffer;
}
@@ -227,31 +227,4 @@ void DHCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *pa
}
BootP::write_serialization(buffer, total_sz, parent);
}
std::list<DHCP::ipaddress_type> DHCP::generic_search(OptionTypes opt_type, type2type<std::list<ipaddress_type> >) const {
const option *opt = search_option(opt_type);
if(!opt)
throw option_not_found();
const uint32_t *ptr = (const uint32_t*)opt->data_ptr();
uint32_t len = opt->data_size();
if((len % sizeof(uint32_t)) != 0)
throw option_not_found();
std::list<ipaddress_type> container;
while(len) {
container.push_back(ipaddress_type(*(ptr++)));
len -= sizeof(uint32_t);
}
return container;
}
std::string DHCP::generic_search(OptionTypes opt_type, type2type<std::string>) const {
const option *opt = search_option(opt_type);
if(!opt)
throw option_not_found();
return string(opt->data_ptr(), opt->data_ptr() + opt->data_size());
}
DHCP::ipaddress_type DHCP::generic_search(OptionTypes opt, type2type<ipaddress_type>) const {
return ipaddress_type(generic_search(opt, type2type<uint32_t>()));
}
}

View File

@@ -157,121 +157,43 @@ void DHCPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *
// ********************************************************************
DHCPv6::ia_na_type DHCPv6::ia_na() const {
const option *opt = safe_search_option<std::less>(
IA_NA, sizeof(uint32_t) * 3
);
const uint8_t *ptr = opt->data_ptr() + sizeof(uint32_t) * 3;
const uint32_t *ptr_32 = (const uint32_t*)opt->data_ptr();
DHCPv6::ia_na_type output;
output.id = Endian::be_to_host(*ptr_32++);
output.t1 = Endian::be_to_host(*ptr_32++);
output.t2 = Endian::be_to_host(*ptr_32++);
output.options.assign(ptr, opt->data_ptr() + opt->data_size());
return output;
return search_and_convert<ia_na_type>(IA_NA);
}
DHCPv6::ia_ta_type DHCPv6::ia_ta() const {
const option *opt = safe_search_option<std::less>(
IA_TA, sizeof(uint32_t)
);
const uint8_t *ptr = opt->data_ptr() + sizeof(uint32_t);
const uint32_t *ptr_32 = (const uint32_t*)opt->data_ptr();
DHCPv6::ia_ta_type output;
output.id = Endian::be_to_host(*ptr_32++);
output.options.assign(ptr, opt->data_ptr() + opt->data_size());
return output;
return search_and_convert<ia_ta_type>(IA_TA);
}
DHCPv6::ia_address_type DHCPv6::ia_address() const {
const option *opt = safe_search_option<std::less>(
IA_ADDR, sizeof(uint32_t) * 2 + ipaddress_type::address_size
);
const uint8_t *ptr = opt->data_ptr() + sizeof(uint32_t) * 2 + ipaddress_type::address_size;
const uint32_t *ptr_32 = (const uint32_t*)(opt->data_ptr() + ipaddress_type::address_size);
DHCPv6::ia_address_type output;
output.address = opt->data_ptr();
output.preferred_lifetime = Endian::be_to_host(*ptr_32++);
output.valid_lifetime = Endian::be_to_host(*ptr_32++);
output.options.assign(ptr, opt->data_ptr() + opt->data_size());
return output;
return search_and_convert<ia_address_type>(IA_ADDR);
}
DHCPv6::option_request_type DHCPv6::option_request() const {
const option *opt = safe_search_option<std::less>(
OPTION_REQUEST, 2
);
const uint16_t *ptr = (const uint16_t*)opt->data_ptr(),
*end = (const uint16_t*)(opt->data_ptr() + opt->data_size());
option_request_type output;
while(ptr < end) {
output.push_back(
static_cast<OptionTypes>(Endian::be_to_host(*ptr++))
);
}
return output;
return search_and_convert<option_request_type>(OPTION_REQUEST);
}
uint8_t DHCPv6::preference() const {
const option *opt = safe_search_option<std::not_equal_to>(
PREFERENCE, 1
);
return *opt->data_ptr();
return search_and_convert<uint8_t>(PREFERENCE);
}
uint16_t DHCPv6::elapsed_time() const {
const option *opt = safe_search_option<std::not_equal_to>(
ELAPSED_TIME, 2
);
return Endian::be_to_host(
*(const uint16_t*)opt->data_ptr()
);
return search_and_convert<uint16_t>(ELAPSED_TIME);
}
DHCPv6::relay_msg_type DHCPv6::relay_message() const {
const option *opt = safe_search_option<std::less>(
RELAY_MSG, 1
);
return relay_msg_type(
opt->data_ptr(),
opt->data_ptr() + opt->data_size()
);
return search_and_convert<relay_msg_type>(RELAY_MSG);
}
DHCPv6::authentication_type DHCPv6::authentication() const {
const option *opt = safe_search_option<std::less>(
AUTH, sizeof(uint8_t) * 3 + sizeof(uint64_t)
);
const uint8_t *ptr = opt->data_ptr();
authentication_type output;
output.protocol = *ptr++;
output.algorithm = *ptr++;
output.rdm = *ptr++;
output.replay_detection = Endian::be_to_host(
*(const uint64_t*)ptr
);
ptr += sizeof(uint64_t);
output.auth_info.assign(ptr, opt->data_ptr() + opt->data_size());
return output;
return search_and_convert<authentication_type>(AUTH);
}
DHCPv6::ipaddress_type DHCPv6::server_unicast() const {
const option *opt = safe_search_option<std::not_equal_to>(
UNICAST, ipaddress_type::address_size
);
return ipaddress_type(opt->data_ptr());
return search_and_convert<ipaddress_type>(UNICAST);
}
DHCPv6::status_code_type DHCPv6::status_code() const {
const option *opt = safe_search_option<std::less>(
STATUS_CODE, sizeof(uint16_t)
);
status_code_type output;
output.code = Endian::be_to_host(*(const uint16_t*)opt->data_ptr());
output.message.assign(
opt->data_ptr() + sizeof(uint16_t),
opt->data_ptr() + opt->data_size()
);
return output;
return search_and_convert<status_code_type>(STATUS_CODE);
}
bool DHCPv6::has_rapid_commit() const {
@@ -288,51 +210,19 @@ DHCPv6::user_class_type DHCPv6::user_class() const {
}
DHCPv6::vendor_class_type DHCPv6::vendor_class() const {
const option *opt = safe_search_option<std::less>(
VENDOR_CLASS, sizeof(uint32_t)
);
typedef vendor_class_type::class_data_type data_type;
vendor_class_type output;
output.enterprise_number = Endian::be_to_host(
*(const uint32_t*)opt->data_ptr()
);
output.vendor_class_data = option2class_option_data<data_type>(
opt->data_ptr() + sizeof(uint32_t),
opt->data_size() - sizeof(uint32_t)
);
return output;
return search_and_convert<vendor_class_type>(VENDOR_CLASS);
}
DHCPv6::vendor_info_type DHCPv6::vendor_info() const {
const option *opt = safe_search_option<std::less>(
VENDOR_OPTS, sizeof(uint32_t)
);
vendor_info_type output;
output.enterprise_number = Endian::be_to_host(
*(const uint32_t*)opt->data_ptr()
);
output.data.assign(
opt->data_ptr() + sizeof(uint32_t),
opt->data_ptr() + opt->data_size()
);
return output;
return search_and_convert<vendor_info_type>(VENDOR_OPTS);
}
DHCPv6::interface_id_type DHCPv6::interface_id() const {
const option *opt = safe_search_option<std::equal_to>(
INTERFACE_ID, 0
);
return interface_id_type(
opt->data_ptr(),
opt->data_ptr() + opt->data_size()
);
return search_and_convert<interface_id_type>(INTERFACE_ID);
}
uint8_t DHCPv6::reconfigure_msg() const {
return *safe_search_option<std::not_equal_to>(
RECONF_MSG, 1
)->data_ptr();
return search_and_convert<uint8_t>(RECONF_MSG);
}
bool DHCPv6::has_reconfigure_accept() const {
@@ -340,29 +230,11 @@ bool DHCPv6::has_reconfigure_accept() const {
}
DHCPv6::duid_type DHCPv6::client_id() const {
const option *opt = safe_search_option<std::less>(
CLIENTID, sizeof(uint16_t) + 1
);
return duid_type(
Endian::be_to_host(*(const uint16_t*)opt->data_ptr()),
serialization_type(
opt->data_ptr() + sizeof(uint16_t),
opt->data_ptr() + opt->data_size()
)
);
return search_and_convert<duid_type>(CLIENTID);
}
DHCPv6::duid_type DHCPv6::server_id() const {
const option *opt = safe_search_option<std::less>(
SERVERID, sizeof(uint16_t) + 1
);
return duid_type(
Endian::be_to_host(*(const uint16_t*)opt->data_ptr()),
serialization_type(
opt->data_ptr() + sizeof(uint16_t),
opt->data_ptr() + opt->data_size()
)
);
return search_and_convert<duid_type>(SERVERID);
}
// ********************************************************************
@@ -650,4 +522,120 @@ void DHCPv6::server_id(const duid_type &value) {
);
}
// Options
DHCPv6::ia_na_type DHCPv6::ia_na_type::from_option(const option &opt)
{
if(opt.data_size() < sizeof(uint32_t) * 3)
throw malformed_option();
const uint8_t *ptr = opt.data_ptr() + sizeof(uint32_t) * 3;
const uint32_t *ptr_32 = (const uint32_t*)opt.data_ptr();
DHCPv6::ia_na_type output;
output.id = Endian::be_to_host(*ptr_32++);
output.t1 = Endian::be_to_host(*ptr_32++);
output.t2 = Endian::be_to_host(*ptr_32++);
output.options.assign(ptr, opt.data_ptr() + opt.data_size());
return output;
}
DHCPv6::ia_ta_type DHCPv6::ia_ta_type::from_option(const option &opt)
{
if(opt.data_size() < sizeof(uint32_t))
throw malformed_option();
const uint8_t *ptr = opt.data_ptr() + sizeof(uint32_t);
const uint32_t *ptr_32 = (const uint32_t*)opt.data_ptr();
DHCPv6::ia_ta_type output;
output.id = Endian::be_to_host(*ptr_32++);
output.options.assign(ptr, opt.data_ptr() + opt.data_size());
return output;
}
DHCPv6::ia_address_type DHCPv6::ia_address_type::from_option(const option &opt)
{
if(opt.data_size() < sizeof(uint32_t) * 2 + DHCPv6::ipaddress_type::address_size)
throw malformed_option();
const uint8_t *ptr = opt.data_ptr() + sizeof(uint32_t) * 2 + ipaddress_type::address_size;
const uint32_t *ptr_32 = (const uint32_t*)(opt.data_ptr() + ipaddress_type::address_size);
DHCPv6::ia_address_type output;
output.address = opt.data_ptr();
output.preferred_lifetime = Endian::be_to_host(*ptr_32++);
output.valid_lifetime = Endian::be_to_host(*ptr_32++);
output.options.assign(ptr, opt.data_ptr() + opt.data_size());
return output;
}
DHCPv6::authentication_type DHCPv6::authentication_type::from_option(const option &opt)
{
if(opt.data_size() < sizeof(uint8_t) * 3 + sizeof(uint64_t))
throw malformed_option();
const uint8_t *ptr = opt.data_ptr();
authentication_type output;
output.protocol = *ptr++;
output.algorithm = *ptr++;
output.rdm = *ptr++;
output.replay_detection = Endian::be_to_host(
*(const uint64_t*)ptr
);
ptr += sizeof(uint64_t);
output.auth_info.assign(ptr, opt.data_ptr() + opt.data_size());
return output;
}
DHCPv6::status_code_type DHCPv6::status_code_type::from_option(const option &opt)
{
if(opt.data_size() < sizeof(uint16_t))
throw malformed_option();
status_code_type output;
output.code = Endian::be_to_host(*(const uint16_t*)opt.data_ptr());
output.message.assign(
opt.data_ptr() + sizeof(uint16_t),
opt.data_ptr() + opt.data_size()
);
return output;
}
DHCPv6::vendor_info_type DHCPv6::vendor_info_type::from_option(const option &opt)
{
if(opt.data_size() < sizeof(uint32_t))
throw malformed_option();
vendor_info_type output;
output.enterprise_number = Endian::be_to_host(
*(const uint32_t*)opt.data_ptr()
);
output.data.assign(
opt.data_ptr() + sizeof(uint32_t),
opt.data_ptr() + opt.data_size()
);
return output;
}
DHCPv6::vendor_class_type DHCPv6::vendor_class_type::from_option(const option &opt)
{
if(opt.data_size() < sizeof(uint32_t))
throw malformed_option();
typedef vendor_class_type::class_data_type data_type;
vendor_class_type output;
output.enterprise_number = Endian::be_to_host(
*(const uint32_t*)opt.data_ptr()
);
output.vendor_class_data = Internals::option2class_option_data<data_type>(
opt.data_ptr() + sizeof(uint32_t),
opt.data_size() - sizeof(uint32_t)
);
return output;
}
DHCPv6::duid_type DHCPv6::duid_type::from_option(const option &opt)
{
if(opt.data_size() < sizeof(uint16_t) + 1)
throw malformed_option();
return duid_type(
Endian::be_to_host(*(const uint16_t*)opt.data_ptr()),
serialization_type(
opt.data_ptr() + sizeof(uint16_t),
opt.data_ptr() + opt.data_size()
)
);
}
} // namespace Tins

View File

@@ -408,15 +408,7 @@ Dot11ManagementFrame::request_info_type Dot11ManagementFrame::request_informatio
}
Dot11ManagementFrame::fh_params_set Dot11ManagementFrame::fh_parameter_set() const {
const Dot11::option *option = search_option(FH_SET);
if(!option || option->data_size() != 5)
throw option_not_found();
fh_params_set output;
output.dwell_time = Endian::le_to_host(*(uint16_t*)option->data_ptr());
output.hop_set = option->data_ptr()[2];
output.hop_pattern = option->data_ptr()[3];
output.hop_index = option->data_ptr()[4];
return output;
return search_and_convert<fh_params_set>(FH_SET);
}
uint8_t Dot11ManagementFrame::ds_parameter_set() const {
@@ -424,15 +416,7 @@ uint8_t Dot11ManagementFrame::ds_parameter_set() const {
}
Dot11ManagementFrame::cf_params_set Dot11ManagementFrame::cf_parameter_set() const {
const Dot11::option *option = search_option(CF_SET);
if(!option || option->data_size() != 6)
throw option_not_found();
cf_params_set output;
output.cfp_count = *option->data_ptr();
output.cfp_period = option->data_ptr()[1];
output.cfp_max_duration = Endian::le_to_host(*(uint16_t*)&option->data_ptr()[2]);
output.cfp_dur_remaining = Endian::le_to_host(*(uint16_t*)&option->data_ptr()[4]);
return output;
return search_and_convert<cf_params_set>(CF_SET);
}
uint16_t Dot11ManagementFrame::ibss_parameter_set() const {
@@ -440,39 +424,11 @@ uint16_t Dot11ManagementFrame::ibss_parameter_set() const {
}
Dot11ManagementFrame::ibss_dfs_params Dot11ManagementFrame::ibss_dfs() const {
const Dot11::option *option = search_option(IBSS_DFS);
if(!option || option->data_size() < ibss_dfs_params::minimum_size)
throw option_not_found();
ibss_dfs_params output;
const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size();
output.dfs_owner = ptr;
ptr += output.dfs_owner.size();
output.recovery_interval = *(ptr++);
while(ptr != end) {
uint8_t first = *(ptr++);
if(ptr == end)
throw option_not_found();
output.channel_map.push_back(std::make_pair(first, *(ptr++)));
}
return output;
return search_and_convert<ibss_dfs_params>(IBSS_DFS);
}
Dot11ManagementFrame::country_params Dot11ManagementFrame::country() const {
const Dot11::option *option = search_option(COUNTRY);
if(!option || option->data_size() < country_params::minimum_size)
throw option_not_found();
country_params output;
const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size();
std::copy(ptr, ptr + 3, std::back_inserter(output.country));
ptr += output.country.size();
while(end - ptr >= 3) {
output.first_channel.push_back(*(ptr++));
output.number_channels.push_back(*(ptr++));
output.max_transmit_power.push_back(*(ptr++));
}
if(ptr != end)
throw option_not_found();
return output;
return search_and_convert<country_params>(COUNTRY);
}
std::pair<uint8_t, uint8_t> Dot11ManagementFrame::fh_parameters() const {
@@ -480,19 +436,7 @@ std::pair<uint8_t, uint8_t> Dot11ManagementFrame::fh_parameters() const {
}
Dot11ManagementFrame::fh_pattern_type Dot11ManagementFrame::fh_pattern_table() const {
const Dot11::option *option = search_option(HOPPING_PATTERN_TABLE);
if(!option || option->data_size() < fh_pattern_type::minimum_size)
throw option_not_found();
fh_pattern_type output;
const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size();
output.flag = *(ptr++);
output.number_of_sets = *(ptr++);
output.modulus = *(ptr++);
output.offset = *(ptr++);
output.random_table.assign(ptr, end);
return output;
return search_and_convert<fh_pattern_type>(HOPPING_PATTERN_TABLE);
}
uint8_t Dot11ManagementFrame::power_constraint() const {
@@ -500,81 +444,31 @@ uint8_t Dot11ManagementFrame::power_constraint() const {
}
Dot11ManagementFrame::channel_switch_type Dot11ManagementFrame::channel_switch() const {
const Dot11::option *option = search_option(CHANNEL_SWITCH);
if(!option || option->data_size() != sizeof(uint8_t) * 3)
throw option_not_found();
const uint8_t *ptr = option->data_ptr();
channel_switch_type output;
output.switch_mode = *(ptr++);
output.new_channel = *(ptr++);
output.switch_count = *(ptr++);
return output;
return search_and_convert<channel_switch_type>(CHANNEL_SWITCH);
}
Dot11ManagementFrame::quiet_type Dot11ManagementFrame::quiet() const {
const Dot11::option *option = search_option(QUIET);
if(!option || option->data_size() != (sizeof(uint8_t) * 2 + sizeof(uint16_t) * 2))
throw option_not_found();
const uint8_t *ptr = option->data_ptr();
quiet_type output;
output.quiet_count = *(ptr++);
output.quiet_period = *(ptr++);
const uint16_t *ptr_16 = (const uint16_t*)ptr;
output.quiet_duration = Endian::le_to_host(*(ptr_16++));
output.quiet_offset = Endian::le_to_host(*ptr_16);
return output;
return search_and_convert<quiet_type>(QUIET);
}
std::pair<uint8_t, uint8_t> Dot11ManagementFrame::tpc_report() const {
const Dot11::option *option = search_option(TPC_REPORT);
if(!option || option->data_size() != sizeof(uint8_t) * 2)
throw option_not_found();
const uint8_t *ptr = option->data_ptr();
uint8_t first = *(ptr++);
return std::make_pair(first, *ptr);
return search_and_convert<std::pair<uint8_t, uint8_t> >(TPC_REPORT);
}
uint8_t Dot11ManagementFrame::erp_information() const {
const Dot11::option *option = search_option(ERP_INFORMATION);
if(!option || option->data_size() != sizeof(uint8_t))
throw option_not_found();
return *option->data_ptr();
return search_and_convert<uint8_t>(ERP_INFORMATION);
}
Dot11ManagementFrame::bss_load_type Dot11ManagementFrame::bss_load() const {
const Dot11::option *option = search_option(BSS_LOAD);
if(!option || option->data_size() != sizeof(uint8_t) + 2 * sizeof(uint16_t))
throw option_not_found();
bss_load_type output;
const uint8_t *ptr = option->data_ptr();
output.station_count = Endian::le_to_host(*(uint16_t*)ptr);
output.channel_utilization = ptr[2];
output.available_capacity = Endian::le_to_host(*(uint16_t*)(ptr + 3));
return output;
return search_and_convert<bss_load_type>(BSS_LOAD);
}
Dot11ManagementFrame::tim_type Dot11ManagementFrame::tim() const {
const Dot11::option *option = search_option(TIM);
if(!option || option->data_size() < 4 * sizeof(uint8_t))
throw option_not_found();
const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size();
tim_type output;
output.dtim_count = *(ptr++);
output.dtim_period = *(ptr++);
output.bitmap_control = *(ptr++);
output.partial_virtual_bitmap.assign(ptr, end);
return output;
return search_and_convert<tim_type>(TIM);
}
std::string Dot11ManagementFrame::challenge_text() const {
const Dot11::option *option = search_option(CHALLENGE_TEXT);
if(!option || option->data_size() == 0)
throw option_not_found();
return std::string(option->data_ptr(), option->data_ptr() + option->data_size());
return search_and_convert<std::string>(CHALLENGE_TEXT);
}
Dot11ManagementFrame::vendor_specific_type Dot11ManagementFrame::vendor_specific() const {
@@ -595,6 +489,138 @@ Dot11ManagementFrame::vendor_specific_type
);
}
// Options
Dot11ManagementFrame::fh_params_set Dot11ManagementFrame::fh_params_set::from_option(const option &opt)
{
if(opt.data_size() != 5)
throw malformed_option();
fh_params_set output;
output.dwell_time = Endian::le_to_host(*(uint16_t*)opt.data_ptr());
output.hop_set = opt.data_ptr()[2];
output.hop_pattern = opt.data_ptr()[3];
output.hop_index = opt.data_ptr()[4];
return output;
}
Dot11ManagementFrame::cf_params_set Dot11ManagementFrame::cf_params_set::from_option(const option &opt)
{
if(opt.data_size() != 6)
throw malformed_option();
cf_params_set output;
output.cfp_count = *opt.data_ptr();
output.cfp_period = opt.data_ptr()[1];
output.cfp_max_duration = Endian::le_to_host(*(uint16_t*)&opt.data_ptr()[2]);
output.cfp_dur_remaining = Endian::le_to_host(*(uint16_t*)&opt.data_ptr()[4]);
return output;
}
Dot11ManagementFrame::ibss_dfs_params Dot11ManagementFrame::ibss_dfs_params::from_option(const option &opt)
{
if(opt.data_size() < ibss_dfs_params::minimum_size)
throw malformed_option();
ibss_dfs_params output;
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
output.dfs_owner = ptr;
ptr += output.dfs_owner.size();
output.recovery_interval = *(ptr++);
while(ptr != end) {
uint8_t first = *(ptr++);
if(ptr == end)
throw option_not_found();
output.channel_map.push_back(std::make_pair(first, *(ptr++)));
}
return output;
}
Dot11ManagementFrame::country_params Dot11ManagementFrame::country_params::from_option(const option &opt)
{
if(opt.data_size() < country_params::minimum_size)
throw malformed_option();
country_params output;
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
std::copy(ptr, ptr + 3, std::back_inserter(output.country));
ptr += output.country.size();
while(end - ptr >= 3) {
output.first_channel.push_back(*(ptr++));
output.number_channels.push_back(*(ptr++));
output.max_transmit_power.push_back(*(ptr++));
}
if(ptr != end)
throw malformed_option();
return output;
}
Dot11ManagementFrame::fh_pattern_type Dot11ManagementFrame::fh_pattern_type::from_option(const option &opt)
{
if(opt.data_size() < fh_pattern_type::minimum_size)
throw malformed_option();
fh_pattern_type output;
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
output.flag = *(ptr++);
output.number_of_sets = *(ptr++);
output.modulus = *(ptr++);
output.offset = *(ptr++);
output.random_table.assign(ptr, end);
return output;
}
Dot11ManagementFrame::channel_switch_type Dot11ManagementFrame::channel_switch_type::from_option(const option &opt)
{
if(opt.data_size() != sizeof(uint8_t) * 3)
throw malformed_option();
const uint8_t *ptr = opt.data_ptr();
channel_switch_type output;
output.switch_mode = *(ptr++);
output.new_channel = *(ptr++);
output.switch_count = *(ptr++);
return output;
}
Dot11ManagementFrame::quiet_type Dot11ManagementFrame::quiet_type::from_option(const option &opt)
{
if(opt.data_size() != (sizeof(uint8_t) * 2 + sizeof(uint16_t) * 2))
throw malformed_option();
const uint8_t *ptr = opt.data_ptr();
quiet_type output;
output.quiet_count = *(ptr++);
output.quiet_period = *(ptr++);
const uint16_t *ptr_16 = (const uint16_t*)ptr;
output.quiet_duration = Endian::le_to_host(*(ptr_16++));
output.quiet_offset = Endian::le_to_host(*ptr_16);
return output;
}
Dot11ManagementFrame::bss_load_type Dot11ManagementFrame::bss_load_type::from_option(const option &opt)
{
if(opt.data_size() != sizeof(uint8_t) + 2 * sizeof(uint16_t))
throw malformed_option();
bss_load_type output;
const uint8_t *ptr = opt.data_ptr();
output.station_count = Endian::le_to_host(*(uint16_t*)ptr);
output.channel_utilization = ptr[2];
output.available_capacity = Endian::le_to_host(*(uint16_t*)(ptr + 3));
return output;
}
Dot11ManagementFrame::tim_type Dot11ManagementFrame::tim_type::from_option(const option &opt)
{
if(opt.data_size() < 4 * sizeof(uint8_t))
throw malformed_option();
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
tim_type output;
output.dtim_count = *(ptr++);
output.dtim_period = *(ptr++);
output.bitmap_control = *(ptr++);
output.partial_virtual_bitmap.assign(ptr, end);
return output;
}
} // namespace Tins
#endif // HAVE_DOT11

View File

@@ -203,34 +203,24 @@ TEST_F(DHCPTest, SubnetMaskOption) {
TEST_F(DHCPTest, RoutersOption) {
DHCP dhcp;
list<IPv4Address> routers;
std::vector<IPv4Address> routers;
routers.push_back("192.168.0.253");
routers.push_back("10.123.45.67");
dhcp.routers(routers);
list<IPv4Address> routers2 = dhcp.routers();
ASSERT_EQ(routers.size(), routers2.size());
while(routers.size()) {
EXPECT_EQ(routers.front(), routers2.front());
routers.pop_front();
routers2.pop_front();
}
std::vector<IPv4Address> routers2 = dhcp.routers();
EXPECT_EQ(routers, routers2);
}
TEST_F(DHCPTest, DNSOption) {
DHCP dhcp;
list<IPv4Address> dns;
std::vector<IPv4Address> dns;
dns.push_back("192.168.0.253");
dns.push_back("10.123.45.67");
dhcp.domain_name_servers(dns);
list<IPv4Address> dns2 = dhcp.domain_name_servers();
ASSERT_EQ(dns.size(), dns2.size());
while(dns.size()) {
EXPECT_EQ(dns.front(), dns2.front());
dns.pop_front();
dns2.pop_front();
}
std::vector<IPv4Address> dns2 = dhcp.domain_name_servers();
EXPECT_EQ(dns, dns2);
}
TEST_F(DHCPTest, DomainNameOption) {
@@ -277,8 +267,9 @@ void DHCPTest::test_equals(const DHCP &dhcp1, const DHCP &dhcp2) {
TEST_F(DHCPTest, ConstructorFromBuffer) {
DHCP dhcp1(expected_packet, sizeof(expected_packet));
std::list<IPv4Address> routers;
IPv4Address expected_routers[] = { "192.168.0.1", "127.0.0.1" };
std::vector<IPv4Address> routers, expected_routers;
expected_routers.push_back("192.168.0.1");
expected_routers.push_back("127.0.0.1");
EXPECT_EQ(dhcp1.opcode(), DHCP::DISCOVER);
EXPECT_EQ(dhcp1.htype(), 1);
@@ -293,9 +284,7 @@ TEST_F(DHCPTest, ConstructorFromBuffer) {
EXPECT_EQ(dhcp1.siaddr(), IPv4Address("167.32.11.154"));
EXPECT_EQ(dhcp1.server_identifier(), IPv4Address("192.168.4.2"));
routers = dhcp1.routers();
ASSERT_EQ(routers.size(), sizeof(expected_routers) / sizeof(IPv4Address));
ASSERT_TRUE(std::equal(routers.begin(), routers.end(), expected_routers));
EXPECT_EQ(expected_routers, routers);
}
TEST_F(DHCPTest, Serialize) {