From e2656739f14809c50d8e0912200543f44ddca0c5 Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Mon, 23 Dec 2013 23:02:58 -0300 Subject: [PATCH] Ported DHCP and Dot11. Almost ported DHCPv6 completely. --- include/dhcp.h | 29 ++-- include/dhcpv6.h | 69 +++++++++- include/dot11/dot11_mgmt.h | 18 +++ include/pdu_option.h | 28 +++- src/dhcp.cpp | 61 +++----- src/dhcpv6.cpp | 276 ++++++++++++++++++------------------- src/dot11/dot11_mgmt.cpp | 262 +++++++++++++++++++---------------- tests/src/dhcp.cpp | 31 ++--- 8 files changed, 425 insertions(+), 349 deletions(-) diff --git a/include/dhcp.h b/include/dhcp.h index 9b9097f..7414c22 100644 --- a/include/dhcp.h +++ b/include/dhcp.h @@ -32,6 +32,7 @@ #include +#include #include #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 &routers); + void routers(const std::vector &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 &dns); + void domain_name_servers(const std::vector &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 Containing the routers + * \return std::vector Containing the routers * option data. */ - std::list routers() const; + std::vector routers() const; /** * \brief Searchs for a dns option. @@ -391,7 +392,7 @@ namespace Tins { * \return std::list Contanining the DNS servers * provided. */ - std::list domain_name_servers() const; + std::vector 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 - struct type2type {}; void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); - + template - T generic_search(OptionTypes opt, type2type) 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(); } void internal_add_option(const option &opt); - std::list generic_search(OptionTypes opt, type2type >) const; - std::string generic_search(OptionTypes opt, type2type) const; - ipaddress_type generic_search(OptionTypes opt, type2type) const; - - serialization_type serialize_list(const std::list &ip_list); + serialization_type serialize_list(const std::vector &ip_list); options_type _options; uint32_t _size; diff --git a/include/dhcpv6.h b/include/dhcpv6.h index 94e9194..e45ddd2 100644 --- a/include/dhcpv6.h +++ b/include/dhcpv6.h @@ -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 option_request_type; + typedef std::vector option_request_type; /** * The type used to store the Relay Message option. @@ -837,6 +853,14 @@ private: throw option_not_found(); return option; } + + template + T search_and_convert(OptionTypes opt) const { + const option *option = search_option(opt); + if(!option) + throw option_not_found(); + return option->to(); + } template 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 +void class_option_data2option(InputIterator start, InputIterator end, + std::vector& 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(start->size()); + index += sizeof(uint16_t); + std::copy(start->begin(), start->end(), buffer.begin() + index); + index += start->size(); + + start++; + } +} + +template +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 diff --git a/include/dot11/dot11_mgmt.h b/include/dot11/dot11_mgmt.h index fe13d40..736b406 100644 --- a/include/dot11/dot11_mgmt.h +++ b/include/dot11/dot11_mgmt.h @@ -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); }; /** diff --git a/include/pdu_option.h b/include/pdu_option.h index bb94b48..3fdd26b 100644 --- a/include/pdu_option.h +++ b/include/pdu_option.h @@ -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(opt.data_ptr()); } }; + + template<> + struct converter { + template + static IPv4Address convert(const PDUOption& 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 { + template + static IPv6Address convert(const PDUOption& opt) { + if(opt.data_size() != IPv6Address::address_size) + throw malformed_option(); + return IPv6Address(opt.data_ptr()); + } + }; template<> struct converter { @@ -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; } diff --git a/src/dhcp.cpp b/src/dhcp.cpp index 30256e4..a57a18f 100644 --- a/src/dhcp.cpp +++ b/src/dhcp.cpp @@ -104,7 +104,7 @@ void DHCP::end() { } uint8_t DHCP::type() const { - return generic_search(DHCP_MESSAGE_TYPE, type2type()); + return search_and_convert(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()); + return search_and_convert(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())); + return search_and_convert(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())); + return search_and_convert(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()); + return search_and_convert(SUBNET_MASK); } -void DHCP::routers(const list &routers) { +void DHCP::routers(const std::vector &routers) { serialization_type buffer = serialize_list(routers); add_option(option(ROUTERS, buffer.begin(), buffer.end())); } -std::list DHCP::routers() const { - return generic_search(ROUTERS, type2type >()); +std::vector DHCP::routers() const { + return search_and_convert >(ROUTERS); } -void DHCP::domain_name_servers(const list &dns) { +void DHCP::domain_name_servers(const std::vector &dns) { serialization_type buffer = serialize_list(dns); add_option(option(DOMAIN_NAME_SERVERS, buffer.begin(), buffer.end())); } -std::list DHCP::domain_name_servers() const { - return generic_search(DOMAIN_NAME_SERVERS, type2type >()); +std::vector DHCP::domain_name_servers() const { + return search_and_convert >(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()); + return search_and_convert(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()); + return search_and_convert(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()); + return search_and_convert(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())); + return search_and_convert(DHCP_REBINDING_TIME); } -PDU::serialization_type DHCP::serialize_list(const list &ip_list) { +PDU::serialization_type DHCP::serialize_list(const std::vector &ip_list) { serialization_type buffer(ip_list.size() * sizeof(uint32_t)); uint32_t *ptr = (uint32_t*)&buffer[0]; - for(list::const_iterator it = ip_list.begin(); it != ip_list.end(); ++it) + for(std::vector::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::generic_search(OptionTypes opt_type, type2type >) 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 container; - while(len) { - container.push_back(ipaddress_type(*(ptr++))); - len -= sizeof(uint32_t); - } - return container; -} - -std::string DHCP::generic_search(OptionTypes opt_type, type2type) 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) const { - return ipaddress_type(generic_search(opt, type2type())); -} } diff --git a/src/dhcpv6.cpp b/src/dhcpv6.cpp index 8f61c30..6c2f4f9 100644 --- a/src/dhcpv6.cpp +++ b/src/dhcpv6.cpp @@ -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( - 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); } DHCPv6::ia_ta_type DHCPv6::ia_ta() const { - const option *opt = safe_search_option( - 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); } DHCPv6::ia_address_type DHCPv6::ia_address() const { - const option *opt = safe_search_option( - 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_ADDR); } DHCPv6::option_request_type DHCPv6::option_request() const { - const option *opt = safe_search_option( - 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(Endian::be_to_host(*ptr++)) - ); - } - return output; + return search_and_convert(OPTION_REQUEST); } uint8_t DHCPv6::preference() const { - const option *opt = safe_search_option( - PREFERENCE, 1 - ); - return *opt->data_ptr(); + return search_and_convert(PREFERENCE); } uint16_t DHCPv6::elapsed_time() const { - const option *opt = safe_search_option( - ELAPSED_TIME, 2 - ); - return Endian::be_to_host( - *(const uint16_t*)opt->data_ptr() - ); + return search_and_convert(ELAPSED_TIME); } DHCPv6::relay_msg_type DHCPv6::relay_message() const { - const option *opt = safe_search_option( - RELAY_MSG, 1 - ); - return relay_msg_type( - opt->data_ptr(), - opt->data_ptr() + opt->data_size() - ); + return search_and_convert(RELAY_MSG); } DHCPv6::authentication_type DHCPv6::authentication() const { - const option *opt = safe_search_option( - 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(AUTH); } DHCPv6::ipaddress_type DHCPv6::server_unicast() const { - const option *opt = safe_search_option( - UNICAST, ipaddress_type::address_size - ); - return ipaddress_type(opt->data_ptr()); + return search_and_convert(UNICAST); } DHCPv6::status_code_type DHCPv6::status_code() const { - const option *opt = safe_search_option( - 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); } 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( - 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( - opt->data_ptr() + sizeof(uint32_t), - opt->data_size() - sizeof(uint32_t) - ); - - return output; + return search_and_convert(VENDOR_CLASS); } DHCPv6::vendor_info_type DHCPv6::vendor_info() const { - const option *opt = safe_search_option( - 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_OPTS); } DHCPv6::interface_id_type DHCPv6::interface_id() const { - const option *opt = safe_search_option( - INTERFACE_ID, 0 - ); - return interface_id_type( - opt->data_ptr(), - opt->data_ptr() + opt->data_size() - ); + return search_and_convert(INTERFACE_ID); } uint8_t DHCPv6::reconfigure_msg() const { - return *safe_search_option( - RECONF_MSG, 1 - )->data_ptr(); + return search_and_convert(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( - 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(CLIENTID); } DHCPv6::duid_type DHCPv6::server_id() const { - const option *opt = safe_search_option( - 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(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( + 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 diff --git a/src/dot11/dot11_mgmt.cpp b/src/dot11/dot11_mgmt.cpp index 1d9d81f..09e6c2b 100644 --- a/src/dot11/dot11_mgmt.cpp +++ b/src/dot11/dot11_mgmt.cpp @@ -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_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_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); } 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); } std::pair Dot11ManagementFrame::fh_parameters() const { @@ -480,19 +436,7 @@ std::pair 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(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); } 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); } std::pair 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 >(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(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); } 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); } 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(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 diff --git a/tests/src/dhcp.cpp b/tests/src/dhcp.cpp index 8645edc..07fc894 100644 --- a/tests/src/dhcp.cpp +++ b/tests/src/dhcp.cpp @@ -203,34 +203,24 @@ TEST_F(DHCPTest, SubnetMaskOption) { TEST_F(DHCPTest, RoutersOption) { DHCP dhcp; - list routers; + std::vector routers; routers.push_back("192.168.0.253"); routers.push_back("10.123.45.67"); dhcp.routers(routers); - list 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 routers2 = dhcp.routers(); + EXPECT_EQ(routers, routers2); } TEST_F(DHCPTest, DNSOption) { DHCP dhcp; - list dns; + std::vector dns; dns.push_back("192.168.0.253"); dns.push_back("10.123.45.67"); dhcp.domain_name_servers(dns); - list 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 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 routers; - IPv4Address expected_routers[] = { "192.168.0.1", "127.0.0.1" }; + std::vector 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) {