diff --git a/depends.d b/depends.d index 5bea4b7..6813251 100644 --- a/depends.d +++ b/depends.d @@ -1,7 +1,8 @@ src/arp.o: src/arp.cpp include/arp.h include/pdu.h include/endianness.h \ include/hwaddress.h include/ipaddress.h include/ip.h \ - include/small_uint.h include/ethernetII.h include/network_interface.h \ - include/rawpdu.h include/constants.h include/network_interface.h + include/small_uint.h include/pdu_option.h include/ethernetII.h \ + include/network_interface.h include/rawpdu.h include/constants.h \ + include/network_interface.h include/arp.h: @@ -17,6 +18,8 @@ include/ip.h: include/small_uint.h: +include/pdu_option.h: + include/ethernetII.h: include/network_interface.h: @@ -126,7 +129,7 @@ include/rsn_information.h: src/ethernetII.o: src/ethernetII.cpp include/ethernetII.h include/pdu.h \ include/endianness.h include/hwaddress.h include/network_interface.h \ include/ipaddress.h include/packet_sender.h include/rawpdu.h \ - include/ip.h include/small_uint.h include/arp.h + include/ip.h include/small_uint.h include/pdu_option.h include/arp.h include/ethernetII.h: @@ -148,6 +151,8 @@ include/ip.h: include/small_uint.h: +include/pdu_option.h: + include/arp.h: src/icmp.o: src/icmp.cpp include/icmp.h include/pdu.h \ include/endianness.h include/rawpdu.h include/utils.h \ @@ -192,9 +197,10 @@ include/ipaddress.h: include/endianness.h: src/ip.o: src/ip.cpp include/ip.h include/pdu.h include/small_uint.h \ - include/endianness.h include/ipaddress.h include/tcp.h include/udp.h \ - include/icmp.h include/rawpdu.h include/utils.h include/hwaddress.h \ - include/packet_sender.h include/constants.h + include/endianness.h include/ipaddress.h include/pdu_option.h \ + include/tcp.h include/udp.h include/icmp.h include/rawpdu.h \ + include/utils.h include/hwaddress.h include/packet_sender.h \ + include/constants.h include/ip.h: @@ -206,6 +212,8 @@ include/endianness.h: include/ipaddress.h: +include/pdu_option.h: + include/tcp.h: include/udp.h: @@ -306,7 +314,7 @@ include/endianness.h: src/snap.o: src/snap.cpp include/snap.h include/pdu.h \ include/endianness.h include/small_uint.h include/constants.h \ include/arp.h include/hwaddress.h include/ipaddress.h include/ip.h \ - include/eapol.h + include/pdu_option.h include/eapol.h include/snap.h: @@ -326,6 +334,8 @@ include/ipaddress.h: include/ip.h: +include/pdu_option.h: + include/eapol.h: src/sniffer.o: src/sniffer.cpp include/sniffer.h include/pdu.h \ include/ethernetII.h include/endianness.h include/hwaddress.h \ @@ -347,8 +357,9 @@ include/ipaddress.h: include/radiotap.h: src/tcp.o: src/tcp.cpp include/tcp.h include/pdu.h include/endianness.h \ - include/small_uint.h include/ip.h include/ipaddress.h \ - include/constants.h include/rawpdu.h include/utils.h include/hwaddress.h + include/small_uint.h include/pdu_option.h include/ip.h \ + include/ipaddress.h include/constants.h include/rawpdu.h include/utils.h \ + include/hwaddress.h include/tcp.h: @@ -358,6 +369,8 @@ include/endianness.h: include/small_uint.h: +include/pdu_option.h: + include/ip.h: include/ipaddress.h: @@ -373,7 +386,7 @@ src/tcp_stream.o: src/tcp_stream.cpp include/rawpdu.h include/pdu.h \ include/tcp_stream.h include/sniffer.h include/ethernetII.h \ include/endianness.h include/hwaddress.h include/network_interface.h \ include/ipaddress.h include/radiotap.h include/tcp.h \ - include/small_uint.h include/ip.h + include/small_uint.h include/pdu_option.h include/ip.h include/rawpdu.h: @@ -399,10 +412,13 @@ include/tcp.h: include/small_uint.h: +include/pdu_option.h: + include/ip.h: src/udp.o: src/udp.cpp include/udp.h include/pdu.h include/endianness.h \ include/constants.h include/utils.h include/ipaddress.h \ - include/hwaddress.h include/ip.h include/small_uint.h include/rawpdu.h + include/hwaddress.h include/ip.h include/small_uint.h \ + include/pdu_option.h include/rawpdu.h include/udp.h: @@ -422,11 +438,14 @@ include/ip.h: include/small_uint.h: +include/pdu_option.h: + include/rawpdu.h: src/utils.o: src/utils.cpp include/utils.h include/ipaddress.h \ include/hwaddress.h include/pdu.h include/ip.h include/pdu.h \ - include/small_uint.h include/endianness.h include/icmp.h include/arp.h \ - include/endianness.h include/network_interface.h include/packet_sender.h + include/small_uint.h include/endianness.h include/pdu_option.h \ + include/icmp.h include/arp.h include/endianness.h \ + include/network_interface.h include/packet_sender.h include/utils.h: @@ -444,6 +463,8 @@ include/small_uint.h: include/endianness.h: +include/pdu_option.h: + include/icmp.h: include/arp.h: diff --git a/include/dhcp.h b/include/dhcp.h index 5642db8..30abc89 100644 --- a/include/dhcp.h +++ b/include/dhcp.h @@ -24,9 +24,9 @@ #include -#include #include #include "bootp.h" +#include "pdu_option.h" namespace Tins { class IPv4Address; @@ -133,34 +133,15 @@ namespace Tins { END = 255 }; - /** - * \brief DHCP options struct. + /** + * The DHCP option type. */ - struct DHCPOption { - /** - * \brief Creates an instance of DHCPOption. - * - * The option's value is copied, therefore the user should - * manually free any memory pointed by the "val" parameter. - * \param opt The option number. - * \param len The length of the option's value in bytes. - * \param val The option's value. - */ - DHCPOption(uint8_t opt, uint8_t len = 0, const uint8_t *val = 0); - - - /** - * \brief The option number. - */ - uint8_t option; - - /** - * \brief The option's value. - */ - std::vector value; - }; + typedef PDUOption dhcp_option; - typedef std::list options_type; + /** + * The type used to store the DHCP options. + */ + typedef std::list options_type; /** * \brief Creates an instance of DHCP. @@ -181,29 +162,22 @@ namespace Tins { /** * \brief Adds a new option to this DHCP PDU. - * - * This copies the value buffer. Adding options may fail if - * there's not enough size to hold a new option. - * \param opt The option identifier. - * \param len The length of the value field. - * \param val The value of this option. - * \return True if the option was added successfully. + * \param option The option to be added. */ - bool add_option(Options opt, uint8_t len, const uint8_t *val); + void add_option(const dhcp_option &option); /** * \brief Searchs for an option that matchs the given flag. * \param opt_flag The flag to be searched. * \return A pointer to the option, or 0 if it was not found. */ - const DHCPOption *search_option(Options opt) const; + const dhcp_option *search_option(Options opt) const; /** * \brief Adds a type option the the option list. * \param type The type of this DHCP PDU. - * \return True if the option was added successfully. \sa DHCP::add_option */ - bool add_type_option(Flags type); + void type(Flags type); /** * \brief Adds an end option the the option list. @@ -211,157 +185,182 @@ namespace Tins { * The END option is not added automatically. You should explicitly * add it at the end of the DHCP options for the PDU to be * standard-compliant. - * - * \return True if the option was added successfully. \sa DHCP::add_option */ - bool add_end_option(); - - /** - * \brief Searchs for a type option. - * \param value A pointer in which the option's value will be stored. - * \return True if the option was found, false otherwise. - */ - bool search_type_option(uint8_t *value); + void end(); /** * \brief Adds a server identifier option. * \param ip The ip of the server. - * \return True if the option was added successfully. \sa DHCP::add_option */ - bool add_server_identifier(ipaddress_type ip); - - /** - * \brief Searchs for a server identifier option. - * \param value A pointer in which the option's value will be stored. - * \return True if the option was found, false otherwise. - */ - bool search_server_identifier(ipaddress_type *value); + void server_identifier(ipaddress_type ip); /** * \brief Adds an IP address lease time option. * \param time The lease time. - * \return True if the option was added successfully. \sa DHCP::add_option */ - bool add_lease_time(uint32_t time); - - /** - * \brief Searchs for a lease time option. - * \param value A pointer in which the option's value will be stored. - * \return True if the option was found, false otherwise. - */ - bool search_lease_time(uint32_t *value); + void lease_time(uint32_t time); /** * \brief Adds a lease renewal time option. * \param time The lease renew time. - * \return True if the option was added successfully. \sa DHCP::add_option */ - bool add_renewal_time(uint32_t time); - - /** - * \brief Searchs for a lease renewal time option. - * \param value A pointer in which the option's value will be stored. - * \return True if the option was found, false otherwise. - */ - bool search_renewal_time(uint32_t *value); + void renewal_time(uint32_t time); /** * \brief Adds a rebind time option. * \param time The lease rebind time. - * \return True if the option was added successfully. \sa DHCP::add_option */ - bool add_rebind_time(uint32_t time); - - /** - * \brief Searchs for a rebind time option. - * \param value A pointer in which the option's value will be stored. - * \return True if the option was found, false otherwise. - */ - bool search_rebind_time(uint32_t *value); + void rebind_time(uint32_t time); /** * \brief Adds a subnet mask option. * \param mask The subnet mask. - * \return True if the option was added successfully. \sa DHCP::add_option */ - bool add_subnet_mask(ipaddress_type mask); - - /** - * \brief Searchs for a subnet mask option. - * \param value A pointer in which the option's value will be stored. - * \return True if the option was found, false otherwise. - */ - bool search_subnet_mask(ipaddress_type *value); + void subnet_mask(ipaddress_type mask); /** * \brief Adds a routers option. * \param routers A list of ip addresses. - * \return True if the option was added successfully. \sa DHCP::add_option */ - bool add_routers_option(const std::list &routers); - - /** - * \brief Searchs for a routers option. - * \param routers A pointer in which the option's value will be stored. - * \return True if the option was found, false otherwise. - */ - bool search_routers_option(std::list *routers); + void routers(const std::list &routers); /** * \brief Adds a domain name servers option. * \param dns A list of ip addresses. - * \return True if the option was added successfully. \sa DHCP::add_option */ - bool add_dns_option(const std::list &dns); - - /** - * \brief Searchs for a dns option. - * \param dns A pointer in which the option's value will be stored. - * \return True if the option was found, false otherwise. - */ - bool search_dns_option(std::list *dns); + void domain_name_servers(const std::list &dns); /** * \brief Adds a broadcast address option. * \param addr The broadcast address. - * \return True if the option was added successfully. \sa DHCP::add_option */ - bool add_broadcast_option(ipaddress_type addr); - - /** - * \brief Searchs for a broadcast option. - * \param value A pointer in which the option's value will be stored. - * \return True if the option was found, false otherwise. - */ - bool search_broadcast_option(ipaddress_type *value); + void broadcast(ipaddress_type addr); /** * \brief Adds a requested address option. * \param addr The requested address. - * \return True if the option was added successfully. \sa DHCP::add_option */ - bool add_requested_ip_option(ipaddress_type addr); - - /** - * \brief Searchs for a requested option. - * \param value A pointer in which the option's value will be stored. - * \return True if the option was found, false otherwise. - */ - bool search_requested_ip_option(ipaddress_type *value); + void requested_ip(ipaddress_type addr); /** * \brief Adds a domain name option. * \param name The domain name. - * \return True if the option was added successfully. \sa DHCP::add_option */ - bool add_domain_name(const std::string &name); + void domain_name(const std::string &name); + + // Option getters + + /** + * \brief Searchs for a type option. + * + * If the option is not found, a option_not_found exception + * is thrown. + * + * \return uint8_t containing the type option. + */ + uint8_t type() const; + + /** + * \brief Searchs for a server identifier option. + * + * If the option is not found, a option_not_found exception + * is thrown. + * + * \return ipaddress_type Containing the server identifier. + */ + ipaddress_type server_identifier() const; + + /** + * \brief Searchs for a lease time option. + * + * If the option is not found, a option_not_found exception + * is thrown. + * + * \return uint32_t Containing the lease time. + */ + uint32_t lease_time() const; + + /** + * \brief Searchs for a lease renewal time option. + * + * If the option is not found, a option_not_found exception + * is thrown. + * + * \return uint32_t Containing the renewal time. + */ + uint32_t renewal_time() const; + + /** + * \brief Searchs for a rebind time option. + * + * If the option is not found, a option_not_found exception + * is thrown. + * + * \return uint32_t Containing the rebind time. + */ + uint32_t rebind_time() const; + + /** + * \brief Searchs for a subnet mask option. + * + * If the option is not found, a option_not_found exception + * is thrown. + * + * \return ipaddress_type Containing the subnet mask. + */ + ipaddress_type subnet_mask() const; + + /** + * \brief Searchs for a routers option. + * + * If the option is not found, a option_not_found exception + * is thrown. + * + * \return std::list Containing the routers + * option data. + */ + std::list routers() const; + + /** + * \brief Searchs for a dns option. + * + * If the option is not found, a option_not_found exception + * is thrown. + * + * \return std::list Contanining the DNS servers + * provided. + */ + std::list domain_name_servers() const; + + /** + * \brief Searchs for a broadcast option. + * + * If the option is not found, a option_not_found exception + * is thrown. + * + * \return ipaddress_type Containing the broadcast address. + */ + ipaddress_type broadcast() const; + + /** + * \brief Searchs for a requested option. + * + * If the option is not found, a option_not_found exception + * is thrown. + * + * \return ipaddress_type Containing the requested IP address. + */ + ipaddress_type requested_ip() const; /** * \brief Searchs for a domain name option. - * \param value A pointer in which the option's value will be stored. - * \return True if the option was found, false otherwise. + * + * If the option is not found, a option_not_found exception + * is thrown. + * + * \return std::string Containing the domain name. */ - bool search_domain_name(std::string *value); + std::string domain_name() const; /** \brief Getter for the options list. * \return The option list. @@ -389,25 +388,26 @@ 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 - bool generic_search(Options opt, T *value) { - const DHCPOption *option = search_option(opt); - if(option && option->value.size() == sizeof(T)) { - *value = *(T*)&option->value[0]; - return true; - } - return false; + T generic_search(Options opt, type2type) const { + const dhcp_option *option = search_option(opt); + if(option && option->data_size() == sizeof(T)) + return *(const T*)option->data_ptr(); + else + throw option_not_found(); } - bool generic_search(Options opt, std::list *container); - bool generic_search(Options opt, std::string *str); - bool generic_search(Options opt, uint32_t *value); - bool generic_search(Options opt, ipaddress_type *value); + std::list generic_search(Options opt, type2type >) const; + std::string generic_search(Options opt, type2type) const; + ipaddress_type generic_search(Options opt, type2type) const; - uint8_t *serialize_list(const std::list &ip_list, uint32_t &sz); + serialization_type serialize_list(const std::list &ip_list); options_type _options; uint32_t _size; diff --git a/include/dot11.h b/include/dot11.h index 04b2b30..c33b0b7 100644 --- a/include/dot11.h +++ b/include/dot11.h @@ -31,6 +31,7 @@ #include "endianness.h" #include "hwaddress.h" #include "small_uint.h" +#include "pdu_option.h" #include "network_interface.h" namespace Tins { @@ -158,39 +159,7 @@ namespace Tins { /** * \brief IEEE 802.11 options struct. */ - struct Dot11Option { - friend class Dot11; - friend class Dot11Beacon; - friend class Dot11ManagementFrame; - /** - * \brief Creates an instance of Dot11Option. - * - * The option's value is copied, therefore the user should - * manually free any memory pointed by the "val" parameter. - * \param opt The option number. - * \param len The length of the option's value in bytes. - * \param val The option's value. - */ - Dot11Option(uint8_t opt, uint8_t len, const uint8_t *val); - - /** - * \brief Getter for Dot11 options' data pointer. - */ - const uint8_t* data_ptr() const { return &value[0]; } - - /** - * \brief Getter for the data size field - */ - uint8_t data_size() const { return value.size(); } - - /** - * \brief Getter for the data size field - */ - uint8_t option() const { return option_id; } - private: - uint8_t option_id; - std::vector value; - }; + typedef PDUOption dot11_option; /** * \brief Constructor for creating an 802.11 PDU @@ -425,7 +394,7 @@ namespace Tins { * \param opt The option identifier. * \return The option found, or 0 if no such option has been set. */ - const Dot11Option *search_option(TaggedOption opt) const; + const dot11_option *search_option(TaggedOption opt) const; /** * \brief Getter for the PDU's type. @@ -506,7 +475,7 @@ namespace Tins { ieee80211_header _header; NetworkInterface _iface; uint32_t _options_size; - std::list _options; + std::list _options; }; /** @@ -1479,7 +1448,7 @@ namespace Tins { } private: static uint8_t *serialize_rates(const rates_type &rates); - static rates_type deserialize_rates(const Dot11Option *option); + static rates_type deserialize_rates(const dot11_option *option); ExtendedHeader _ext_header; address_type _addr4; diff --git a/include/ip.h b/include/ip.h index e28bff2..0d27667 100644 --- a/include/ip.h +++ b/include/ip.h @@ -27,6 +27,7 @@ #include "small_uint.h" #include "endianness.h" #include "ipaddress.h" +#include "pdu_option.h" namespace Tins { @@ -65,7 +66,7 @@ namespace Tins { * * Enum Option indicates the possible IP Options. */ - enum Option { + enum OptionNumber { END = 0, NOOP = 1, SEC = 2, @@ -88,36 +89,105 @@ namespace Tins { }; /** - * \brief This class represents an IP option. + * \brief The type used to represent an option's type. */ - struct IPOption { - friend class IP; - struct { - #if TINS_IS_LITTLE_ENDIAN - unsigned int number:5; - unsigned int op_class:2; - unsigned int copied:1; - #elif TINS_IS_BIG_ENDIAN - unsigned int copied:1; - unsigned int op_class:2; - unsigned int number:5; - #endif - } __attribute__((__packed__)) type; - - uint8_t* write(uint8_t* buffer); + struct option_identifier { + #if TINS_IS_LITTLE_ENDIAN + uint8_t number:5, + op_class:2, + copied:1; + #elif TINS_IS_BIG_ENDIAN + uint8_t copied:1, + op_class:2, + number:5; + #endif + /** + * \brief Default constructor. + * + * Initializes every field to 0. + */ + option_identifier() : number(0), op_class(0), copied(0) {} /** - * Getter for IP options' data pointer. + * \brief Constructs this option from a single uint8_t value. + * + * This parses the value and initializes each field with the + * appropriate value. + * + * \param value The value to be parsed and used for + * initialization */ - const uint8_t* data_ptr() const; + option_identifier(uint8_t value) + : number(value & 0x1f), + op_class((value >> 5) & 0x03), + copied((value >> 7) & 0x01) {} /** - * Getter for the data size field + * Constructor using user provided values for each field. + * \param number The number field value. + * \param op_class The option class field value. + * \param copied The copied field value. */ - uint8_t data_size() const; - private: - std::vector optional_data; + option_identifier(OptionNumber number, OptionClass op_class, + small_uint<1> copied) + : number(number), op_class(op_class), copied(copied) {} + + /** + * \brief Equality operator. + */ + bool operator==(const option_identifier &rhs) const { + return number == rhs.number && op_class == rhs.op_class && copied == rhs.copied; + } + } __attribute__((__packed__)); + + /** + * The IP options type. + */ + typedef PDUOption ip_option; + + /** + * The type of the security option. + */ + struct security_type { + uint16_t security, compartments; + uint16_t handling_restrictions; + small_uint<24> transmission_control; + + security_type(uint16_t sec = 0, uint16_t comp = 0, + uint16_t hand_res = 0, small_uint<24> tcc = 0) + : security(sec), compartments(comp), + handling_restrictions(hand_res), transmission_control(tcc) + {} }; + + /** + * The type of the Loose Source and Record Route + */ + struct generic_route_option_type { + typedef std::vector routes_type; + + uint8_t pointer; + routes_type routes; + + generic_route_option_type(uint8_t ptr = 0, + routes_type rts = routes_type()) + : pointer(ptr), routes(rts) {} + }; + + /** + * The type of the Loose Source and Record Route + */ + typedef generic_route_option_type lsrr_type; + + /** + * The type of the Strict Source and Record Route + */ + typedef generic_route_option_type ssrr_type; + + /** + * The type of the Record Route + */ + typedef generic_route_option_type record_route_type; /** * \brief Constructor for building the IP PDU. @@ -300,42 +370,133 @@ namespace Tins { void version(small_uint<4> ver); /** - * \brief Sets an IP option. - * - * \param copied The copied flag for this option. - * \param op_class The option class to be set. - * \param number The options number to be set. - * \param data The data of this options. - * \param data_size The data size. + * \brief Adds an IP option. + * + * The option is added after the last option in the option + * fields. + * + * \param option The option to be added */ - void set_option(uint8_t copied, OptionClass op_class, Option number, const uint8_t* data = 0, uint32_t data_size = 0); + void add_option(const ip_option &option); /** * \brief Searchs for an option that matchs the given flag. - * \param opt_class The option class to be searched. - * \param opt_number The option number to be searched. - * \return A pointer to the option, or 0 if it was not found. + * \param id The option identifier to be searched. */ - const IPOption *search_option(OptionClass opt_class, Option opt_number) const; + const ip_option *search_option(option_identifier id) const; + + // Option setters + + /** + * \brief Adds an End Of List option. + */ + void eol(); /** - * \brief Sets the End of List option. + * \brief Adds a NOP option. */ - void set_eol_option(); + void noop(); /** - * \brief Sets the NOP option. - */ - void set_noop_option(); - - /** - * \brief Sets the security option. + * \brief Adds a security option. * - * \param data The data for this option - * \param data_len The length of the data. + * \param data The data to be stored in this option. */ - void set_sec_option(const uint8_t* data, uint32_t data_len); - /* Add more option setters */ + void security(const security_type &data); + + /** + * \brief Adds a Loose Source and Record Route option. + * + * \param data The data to be stored in this option. + */ + void lsrr(const lsrr_type &data) { + add_route_option(131, data); + } + + /** + * \brief Adds a Strict Source and Record Route option. + * + * \param data The data to be stored in this option. + */ + void ssrr(const ssrr_type &data) { + add_route_option(137, data); + } + + /** + * \brief Adds a Record Route option. + * + * \param data The data to be stored in this option. + */ + void record_route(const record_route_type &data) { + add_route_option(7, data); + } + + /** + * \brief Adds a Stream Identifier option. + * + * \param stream_id The stream id to be stored in this option. + */ + void stream_identifier(uint16_t stream_id); + + // Option getters + + /** + * \brief Searchs and returns a security option. + * + * If no such option exists, an option_not_found exception + * is thrown. + * + * \return security_type containing the option found. + */ + security_type security() const; + + /** + * \brief Searchs and returns a Loose Source and Record Route + * option. + * + * If no such option exists, an option_not_found exception + * is thrown. + * + * \return lsrr_type containing the option found. + */ + lsrr_type lsrr() const { + return search_route_option(131); + } + + /** + * \brief Searchs and returns a Strict Source and Record Route + * option. + * + * If no such option exists, an option_not_found exception + * is thrown. + * + * \return ssrr_type containing the option found. + */ + ssrr_type ssrr() const { + return search_route_option(137); + } + + /** + * \brief Searchs and returns a Record Route option. + * + * If no such option exists, an option_not_found exception + * is thrown. + * + * \return record_route_type containing the option found. + */ + record_route_type record_route() const { + return search_route_option(7); + } + + /** + * \brief Searchs and returns a Stream Identifier option. + * + * If no such option exists, an option_not_found exception + * is thrown. + * + * \return uint16_t containing the option found. + */ + uint16_t stream_identifier() const; /* Virtual methods */ @@ -418,9 +579,12 @@ namespace Tins { void init_ip_fields(); void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); + uint8_t* write_option(const ip_option &opt, uint8_t* buffer); + void add_route_option(option_identifier id, const generic_route_option_type &data); + generic_route_option_type search_route_option(option_identifier id) const; iphdr _ip; - std::list _ip_options; + std::list _ip_options; uint32_t _options_size, _padded_options_size; }; }; diff --git a/include/pdu_option.h b/include/pdu_option.h new file mode 100644 index 0000000..42d2d57 --- /dev/null +++ b/include/pdu_option.h @@ -0,0 +1,125 @@ +/* + * libtins is a net packet wrapper library for crafting and + * interpreting sniffed packets. + * + * Copyright (C) 2011 Nasel + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef TINS_PDU_OPTION_H +#define TINS_PDU_OPTION_H + +#include +#include +#include + +namespace Tins { +/** + * \brief Exception thrown when an option is not found. + */ +class option_not_found : public std::exception { +public: + const char* what() const throw() { + return "Option not found"; + } +}; + +/** + * \class PDUOption + * \brief Represents a PDU option field. + * + * Several PDUs, such as TCP, IP, Dot11 or DHCP contain options. All + * of them behave exactly the same way. This class represents those + * options. + * + * The OptionType template parameter indicates the type that will be + * used to store this option's identifier. + * + * The Container template parameter indicates the container which will + * be used to store this option's data. The container must + * store data sequentially. std::vector is the default + * container. + */ +template > +class PDUOption { +public: + typedef Container container_type; + typedef typename container_type::value_type data_type; + typedef OptionType option_type; + + /** + * \brief Constructs a PDUOption. + * \param opt The option type. + * \param length The option's data length. + * \param data The option's data(if any). + */ + PDUOption(option_type opt = option_type(), size_t length = 0, const data_type *data = 0) + : option_(opt) { + value_.push_back(length); + if(data) + value_.insert(value_.end(), data, data + length); + } + + /** + * \brief Constructs a PDUOption from iterators, which + * indicate the data to be stored in it. + * + * \param opt The option type. + * \param start The beginning of the option data. + * \param end The end of the option data. + */ + template + PDUOption(option_type opt, ForwardIterator start, ForwardIterator end) + : option_(opt) { + value_.push_back(std::distance(start, end)); + value_.insert(value_.end(), start, end); + } + + /** + * Retrieves this option's type. + * \return uint8_t containing this option's size. + */ + option_type option() const { + return option_; + } + + /** + * Retrieves this option's data. + * + * If this method is called when data_size() == 0, + * dereferencing the returned pointer will result in undefined + * behaviour. + * + * \return const value_type& containing this option's value. + */ + const data_type *data_ptr() const { + return &*(++value_.begin()); + + //return &value_[1]; + } + + /** + * Retrieves the length of this option's data. + */ + size_t data_size() const { + return value_.empty() ? 0 : (value_.size() - 1); + } +private: + option_type option_; + container_type value_; +}; +} // namespace Tins +#endif // TINS_PDU_OPTION_H diff --git a/include/tcp.h b/include/tcp.h index 534cd29..e8c3d05 100644 --- a/include/tcp.h +++ b/include/tcp.h @@ -31,6 +31,7 @@ #include "pdu.h" #include "endianness.h" #include "small_uint.h" +#include "pdu_option.h" namespace Tins { /** @@ -89,98 +90,18 @@ namespace Tins { CHK_16FLETCHER }; - /** - * \brief Class that represents a TCP option field. - */ - class TCPOption { - public: - /** - * \brief Constructs a TCPOption. - * \param opt The option type. - * \param length The option's data length. - * \param data The option's data(if any). - */ - TCPOption(uint8_t opt = 0, uint8_t length = 0, const uint8_t *data = 0) - : option_(opt) { - value_.push_back(length); - if(data) - value_.insert(value_.end(), data, data + length); - } - - /** - * Constructs a TCPOption from iterators, which indicate - * the data to be stored in it. - * \param opt The option type. - * \param start The beginning of the option data. - * \param end The end of the option data. - */ - template - TCPOption(uint8_t opt, ForwardIterator start, ForwardIterator end) - : option_(opt), value_(start, end) { - - } - - /** - * Retrieves this option's type. - * \return uint8_t containing this option's size. - */ - uint8_t option() const { - return option_; - } - - /** - * Retrieves this option's data. - * - * If this method is called when data_size() == 0, - * dereferencing the returned pointer will result in undefined - * behaviour. - * - * \return const value_type& containing this option's value. - */ - const uint8_t *data_ptr() const { - return &value_[1]; - } - - /** - * Retrieves the length of this option's data. - */ - size_t data_size() const { - return value_.size() - 1; - } - - /** - * \brief Writes the option into a buffer. - * \param buffer The buffer in which to write the option. - * \return The buffer pointer incremented by the size of this option. - */ - uint8_t *write(uint8_t *buffer); - private: - typedef std::vector data_type; - - uint8_t option_; - data_type value_; - }; + typedef PDUOption tcp_option; /** * The type used to store the options. */ - typedef std::vector options_type; + typedef std::list options_type; /** * The type used to store the sack option. */ typedef std::vector sack_type; - /** - * \brief Exception thrown when an option is not found. - */ - class OptionNotFound : public std::exception { - public: - const char* what() const throw() { - return "Option not found"; - } - }; - /** * \brief TCP constructor. * @@ -425,11 +346,11 @@ namespace Tins { /** * \brief Adds a TCP option. * - * \param tcp_option The option type flag to be set. + * \param option The option type flag to be set. * \param length The length of this option(optional). * \param data Pointer to this option's data(optional). */ - void add_option(Option tcp_option, uint8_t length = 0, const uint8_t *data = 0); + void add_option(Option option, uint8_t length = 0, const uint8_t *data = 0); /** * \brief Returns the header size. @@ -453,7 +374,7 @@ namespace Tins { * \param opt_flag The flag to be searched. * \return A pointer to the option, or 0 if it was not found. */ - const TCPOption *search_option(Option opt) const; + const tcp_option *search_option(Option opt) const; /** * \sa PDU::clone_pdu @@ -501,17 +422,15 @@ namespace Tins { template T generic_search(Option opt) const { - const TCPOption *option = search_option(opt); + const tcp_option *option = search_option(opt); if(option && option->data_size() == sizeof(T)) return *(const T*)(&option->data_ptr()[0]); - throw OptionNotFound(); + throw option_not_found(); } - /** \brief Serialices this TCP PDU. - * \param buffer The buffer in which the PDU will be serialized. - * \param total_sz The size available in the buffer. - * \param parent The PDU that's one level below this one on the stack. - */ + void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); + + uint8_t *write_option(const tcp_option &opt, uint8_t *buffer); tcphdr _tcp; options_type _options; diff --git a/src/dhcp.cpp b/src/dhcp.cpp index 4ec05cc..35b9655 100644 --- a/src/dhcp.cpp +++ b/src/dhcp.cpp @@ -31,8 +31,6 @@ using std::list; using std::runtime_error; namespace Tins { -const uint32_t DHCP::MAX_DHCP_SIZE = 312; - // Magic cookie: uint32_t. DHCP::DHCP() : _size(sizeof(uint32_t)) { opcode(BOOTREQUEST); @@ -63,148 +61,132 @@ DHCP::DHCP(const uint8_t *buffer, uint32_t total_sz) } if(total_sz < args[1]) throw std::runtime_error("Not enough size for a DHCP header in the buffer."); - add_option((Options)args[0], args[1], buffer); + add_option(dhcp_option((Options)args[0], args[1], buffer)); buffer += args[1]; total_sz -= args[1]; } } -DHCP::DHCPOption::DHCPOption(uint8_t opt, uint8_t len, const uint8_t *val) -: option(opt), value(val, val ? (val + len) : val) { - +void DHCP::add_option(const dhcp_option &option) { + _options.push_back(option); + _size += option.data_size() + (sizeof(uint8_t) << 1); } -bool DHCP::add_option(Options opt, uint8_t len, const uint8_t *val) { - uint32_t opt_size = len + (sizeof(uint8_t) << 1); - if(_size + opt_size > MAX_DHCP_SIZE) - return false; - _options.push_back(DHCPOption((uint8_t)opt, len, val)); - _size += opt_size; - return true; -} - -const DHCP::DHCPOption *DHCP::search_option(Options opt) const{ +const DHCP::dhcp_option *DHCP::search_option(Options opt) const { for(options_type::const_iterator it = _options.begin(); it != _options.end(); ++it) { - if(it->option == opt) + if(it->option() == opt) return &(*it); } return 0; } -bool DHCP::add_type_option(Flags type) { +void DHCP::type(Flags type) { uint8_t int_type = type; - return add_option(DHCP_MESSAGE_TYPE, sizeof(uint8_t), &int_type); + add_option(dhcp_option(DHCP_MESSAGE_TYPE, sizeof(uint8_t), &int_type)); } -bool DHCP::add_end_option() { - return add_option(DHCP_MESSAGE_TYPE, 0, 0); +void DHCP::end() { + add_option(dhcp_option(DHCP_MESSAGE_TYPE)); } -bool DHCP::search_type_option(uint8_t *value) { - return generic_search(DHCP_MESSAGE_TYPE, value); +uint8_t DHCP::type() const { + return generic_search(DHCP_MESSAGE_TYPE, type2type()); } -bool DHCP::add_server_identifier(ipaddress_type ip) { +void DHCP::server_identifier(ipaddress_type ip) { uint32_t ip_int = ip; - return add_option(DHCP_SERVER_IDENTIFIER, sizeof(uint32_t), (const uint8_t*)&ip_int); + add_option(dhcp_option(DHCP_SERVER_IDENTIFIER, sizeof(uint32_t), (const uint8_t*)&ip_int)); } -bool DHCP::search_server_identifier(ipaddress_type *value) { - return generic_search(DHCP_SERVER_IDENTIFIER, value); +DHCP::ipaddress_type DHCP::server_identifier() const { + return generic_search(DHCP_SERVER_IDENTIFIER, type2type()); } -bool DHCP::add_lease_time(uint32_t time) { +void DHCP::lease_time(uint32_t time) { time = Endian::host_to_be(time); - return add_option(DHCP_LEASE_TIME, sizeof(uint32_t), (const uint8_t*)&time); + add_option(dhcp_option(DHCP_LEASE_TIME, sizeof(uint32_t), (const uint8_t*)&time)); } -bool DHCP::search_lease_time(uint32_t *value) { - return generic_search(DHCP_LEASE_TIME, value); +uint32_t DHCP::lease_time() const { + return Endian::host_to_be(generic_search(DHCP_LEASE_TIME, type2type())); } -bool DHCP::add_renewal_time(uint32_t time) { +void DHCP::renewal_time(uint32_t time) { time = Endian::host_to_be(time); - return add_option(DHCP_RENEWAL_TIME, sizeof(uint32_t), (const uint8_t*)&time); + add_option(dhcp_option(DHCP_RENEWAL_TIME, sizeof(uint32_t), (const uint8_t*)&time)); } -bool DHCP::search_renewal_time(uint32_t *value) { - return generic_search(DHCP_RENEWAL_TIME, value); +uint32_t DHCP::renewal_time() const { + return Endian::host_to_be(generic_search(DHCP_RENEWAL_TIME, type2type())); } -bool DHCP::add_subnet_mask(ipaddress_type mask) { +void DHCP::subnet_mask(ipaddress_type mask) { uint32_t mask_int = mask; - return add_option(SUBNET_MASK, sizeof(uint32_t), (const uint8_t*)&mask_int); + add_option(dhcp_option(SUBNET_MASK, sizeof(uint32_t), (const uint8_t*)&mask_int)); } -bool DHCP::search_subnet_mask(ipaddress_type *value) { - return generic_search(SUBNET_MASK, value); +DHCP::ipaddress_type DHCP::subnet_mask() const { + return generic_search(SUBNET_MASK, type2type()); } -bool DHCP::add_routers_option(const list &routers) { - uint32_t size; - uint8_t *buffer = serialize_list(routers, size); - bool ret = add_option(ROUTERS, size, buffer); - delete[] buffer; - return ret; +void DHCP::routers(const list &routers) { + serialization_type buffer = serialize_list(routers); + add_option(dhcp_option(ROUTERS, buffer.begin(), buffer.end())); } -bool DHCP::search_routers_option(std::list *routers) { - return generic_search(ROUTERS, routers); +std::list DHCP::routers() const { + return generic_search(ROUTERS, type2type >()); } -bool DHCP::add_dns_option(const list &dns) { - uint32_t size; - uint8_t *buffer = serialize_list(dns, size); - bool ret = add_option(DOMAIN_NAME_SERVERS, size, buffer); - delete[] buffer; - return ret; +void DHCP::domain_name_servers(const list &dns) { + serialization_type buffer = serialize_list(dns); + add_option(dhcp_option(DOMAIN_NAME_SERVERS, buffer.begin(), buffer.end())); } -bool DHCP::search_dns_option(std::list *dns) { - return generic_search(DOMAIN_NAME_SERVERS, dns); +std::list DHCP::domain_name_servers() const { + return generic_search(DOMAIN_NAME_SERVERS, type2type >()); } -bool DHCP::add_broadcast_option(ipaddress_type addr) { +void DHCP::broadcast(ipaddress_type addr) { uint32_t int_addr = addr; - return add_option(BROADCAST_ADDRESS, sizeof(uint32_t), (uint8_t*)&int_addr); + add_option(dhcp_option(BROADCAST_ADDRESS, sizeof(uint32_t), (uint8_t*)&int_addr)); } -bool DHCP::search_broadcast_option(ipaddress_type *value) { - return generic_search(BROADCAST_ADDRESS, value); +DHCP::ipaddress_type DHCP::broadcast() const { + return generic_search(BROADCAST_ADDRESS, type2type()); } -bool DHCP::add_requested_ip_option(ipaddress_type addr) { +void DHCP::requested_ip(ipaddress_type addr) { uint32_t int_addr = addr; - return add_option(DHCP_REQUESTED_ADDRESS, sizeof(uint32_t), (uint8_t*)&int_addr); + add_option(dhcp_option(DHCP_REQUESTED_ADDRESS, sizeof(uint32_t), (uint8_t*)&int_addr)); } -bool DHCP::search_requested_ip_option(ipaddress_type *value) { - return generic_search(DHCP_REQUESTED_ADDRESS, value); +DHCP::ipaddress_type DHCP::requested_ip() const { + return generic_search(DHCP_REQUESTED_ADDRESS, type2type()); } -bool DHCP::add_domain_name(const string &name) { - return add_option(DOMAIN_NAME, name.size(), (const uint8_t*)name.c_str()); +void DHCP::domain_name(const string &name) { + add_option(dhcp_option(DOMAIN_NAME, name.size(), (const uint8_t*)name.c_str())); } -bool DHCP::search_domain_name(std::string *value) { - return generic_search(DOMAIN_NAME, value); +std::string DHCP::domain_name() const { + return generic_search(DOMAIN_NAME, type2type()); } -bool DHCP::add_rebind_time(uint32_t time) { +void DHCP::rebind_time(uint32_t time) { time = Endian::host_to_be(time); - return add_option(DHCP_REBINDING_TIME, sizeof(uint32_t), (uint8_t*)&time); + add_option(dhcp_option(DHCP_REBINDING_TIME, sizeof(uint32_t), (uint8_t*)&time)); } -bool DHCP::search_rebind_time(uint32_t *value) { - return generic_search(DHCP_REBINDING_TIME, value); +uint32_t DHCP::rebind_time() const { + return Endian::host_to_be(generic_search(DHCP_REBINDING_TIME, type2type())); } -uint8_t *DHCP::serialize_list(const list &ip_list, uint32_t &sz) { - uint8_t *buffer = new uint8_t[ip_list.size() * sizeof(uint32_t)]; - uint32_t *ptr = (uint32_t*)buffer; +PDU::serialization_type DHCP::serialize_list(const list &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) *(ptr++) = *it; - sz = sizeof(uint32_t) * ip_list.size(); return buffer; } @@ -221,52 +203,39 @@ void DHCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *pa // Magic cookie *((uint32_t*)&result[0]) = Endian::host_to_be(0x63825363); for(options_type::const_iterator it = _options.begin(); it != _options.end(); ++it) { - *(ptr++) = it->option; - *(ptr++) = it->value.size(); - std::copy(it->value.begin(), it->value.end(), ptr); - ptr += it->value.size(); + *(ptr++) = it->option(); + *(ptr++) = it->data_size(); + std::copy(it->data_ptr(), it->data_ptr() + it->data_size(), ptr); + ptr += it->data_size(); } } BootP::write_serialization(buffer, total_sz, parent); } -bool DHCP::generic_search(Options opt, std::list *container) { - const DHCPOption *option = search_option(opt); +std::list DHCP::generic_search(Options opt, type2type >) const { + const dhcp_option *option = search_option(opt); if(!option) - return false; - const uint32_t *ptr = (const uint32_t*)&option->value[0]; - uint32_t len = option->value.size(); + throw option_not_found(); + const uint32_t *ptr = (const uint32_t*)option->data_ptr(); + uint32_t len = option->data_size(); if((len % sizeof(uint32_t)) != 0) - return false; + throw option_not_found(); + std::list container; while(len) { - container->push_back(ipaddress_type(*(ptr++))); + container.push_back(ipaddress_type(*(ptr++))); len -= sizeof(uint32_t); } - return true; + return container; } -bool DHCP::generic_search(Options opt, std::string *str) { - const DHCPOption *option = search_option(opt); +std::string DHCP::generic_search(Options opt, type2type) const { + const dhcp_option *option = search_option(opt); if(!option) - return false; - *str = string(option->value.begin(), option->value.end()); - return true; + throw option_not_found(); + return string(option->data_ptr(), option->data_ptr() + option->data_size()); } -bool DHCP::generic_search(Options opt, uint32_t *value) { - if(generic_search(opt, value)) { - *value = Endian::host_to_be(*value); - return true; - } - return false; -} - -bool DHCP::generic_search(Options opt, ipaddress_type *value) { - uint32_t ip_int; - if(generic_search(opt, &ip_int)) { - *value = IPv4Address(Endian::host_to_be(ip_int)); - return true; - } - return false; +DHCP::ipaddress_type DHCP::generic_search(Options opt, type2type) const { + return ipaddress_type(generic_search(opt, type2type())); } } diff --git a/src/dot11.cpp b/src/dot11.cpp index 3c0fa78..3f18f30 100644 --- a/src/dot11.cpp +++ b/src/dot11.cpp @@ -85,19 +85,14 @@ void Dot11::parse_tagged_parameters(const uint8_t *buffer, uint32_t total_sz) { } } -Dot11::Dot11Option::Dot11Option(uint8_t opt, uint8_t len, const uint8_t *val) -: option_id(opt), value(val, val + len) { - -} - void Dot11::add_tagged_option(TaggedOption opt, uint8_t len, const uint8_t *val) { uint32_t opt_size = len + (sizeof(uint8_t) << 1); - _options.push_back(Dot11Option((uint8_t)opt, len, val)); + _options.push_back(dot11_option((uint8_t)opt, len, val)); _options_size += opt_size; } -const Dot11::Dot11Option *Dot11::search_option(TaggedOption opt) const { - for(std::list::const_iterator it = _options.begin(); it != _options.end(); ++it) +const Dot11::dot11_option *Dot11::search_option(TaggedOption opt) const { + for(std::list::const_iterator it = _options.begin(); it != _options.end(); ++it) if(it->option() == (uint8_t)opt) return &(*it); return 0; @@ -188,7 +183,7 @@ void Dot11::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *p uint32_t child_len = write_fixed_parameters(buffer, total_sz - _options_size); buffer += child_len; assert(total_sz >= child_len + _options_size); - for(std::list::const_iterator it = _options.begin(); it != _options.end(); ++it) { + for(std::list::const_iterator it = _options.begin(); it != _options.end(); ++it) { *(buffer++) = it->option(); *(buffer++) = it->data_size(); std::copy(it->data_ptr(), it->data_ptr() + it->data_size(), buffer); @@ -255,8 +250,8 @@ void Dot11::copy_80211_fields(const Dot11 *other) { std::memcpy(&_header, &other->_header, sizeof(_header)); _iface = other->_iface; _options_size = other->_options_size; - for(std::list::const_iterator it = other->_options.begin(); it != other->_options.end(); ++it) - _options.push_back(Dot11Option(it->option(), it->data_size(), it->data_ptr())); + for(std::list::const_iterator it = other->_options.begin(); it != other->_options.end(); ++it) + _options.push_back(dot11_option(it->option(), it->data_size(), it->data_ptr())); } /* Dot11ManagementFrame */ @@ -352,7 +347,7 @@ uint8_t *Dot11ManagementFrame::serialize_rates(const rates_type &rates) { return buffer; } -Dot11ManagementFrame::rates_type Dot11ManagementFrame::deserialize_rates(const Dot11Option *option) { +Dot11ManagementFrame::rates_type Dot11ManagementFrame::deserialize_rates(const dot11_option *option) { rates_type output; const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size(); while(ptr != end) { @@ -574,49 +569,49 @@ void Dot11ManagementFrame::challenge_text(const std::string &text) { // Getters RSNInformation Dot11ManagementFrame::rsn_information() { - const Dot11::Dot11Option *option = search_option(RSN); + const Dot11::dot11_option *option = search_option(RSN); if(!option || option->data_size() < (sizeof(uint16_t) << 1) + sizeof(uint32_t)) throw std::runtime_error("RSN information not set"); return RSNInformation(option->data_ptr(), option->data_size()); } string Dot11ManagementFrame::ssid() const { - const Dot11::Dot11Option *option = search_option(SSID); + const Dot11::dot11_option *option = search_option(SSID); if(!option || option->data_size() == 0) throw std::runtime_error("SSID not set"); return string((const char*)option->data_ptr(), option->data_size()); } Dot11ManagementFrame::rates_type Dot11ManagementFrame::supported_rates() const { - const Dot11::Dot11Option *option = search_option(SUPPORTED_RATES); + const Dot11::dot11_option *option = search_option(SUPPORTED_RATES); if(!option || option->data_size() == 0) throw std::runtime_error("Supported rates not set"); return deserialize_rates(option); } Dot11ManagementFrame::rates_type Dot11ManagementFrame::extended_supported_rates() const { - const Dot11::Dot11Option *option = search_option(EXT_SUPPORTED_RATES); + const Dot11::dot11_option *option = search_option(EXT_SUPPORTED_RATES); if(!option || option->data_size() == 0) throw std::runtime_error("Extended supported rates not set"); return deserialize_rates(option); } uint8_t Dot11ManagementFrame::qos_capability() const { - const Dot11::Dot11Option *option = search_option(QOS_CAPABILITY); + const Dot11::dot11_option *option = search_option(QOS_CAPABILITY); if(!option || option->data_size() != 1) throw std::runtime_error("QOS capability not set"); return *option->data_ptr(); } std::pair Dot11ManagementFrame::power_capability() const { - const Dot11::Dot11Option *option = search_option(POWER_CAPABILITY); + const Dot11::dot11_option *option = search_option(POWER_CAPABILITY); if(!option || option->data_size() != 2) throw std::runtime_error("Power capability not set"); return std::make_pair(*option->data_ptr(), *(option->data_ptr() + 1)); } Dot11ManagementFrame::channels_type Dot11ManagementFrame::supported_channels() const { - const Dot11::Dot11Option *option = search_option(SUPPORTED_CHANNELS); + const Dot11::dot11_option *option = search_option(SUPPORTED_CHANNELS); // We need a multiple of two if(!option || ((option->data_size() & 0x1) == 1)) throw std::runtime_error("Supported channels not set"); @@ -630,7 +625,7 @@ Dot11ManagementFrame::channels_type Dot11ManagementFrame::supported_channels() c } Dot11ManagementFrame::request_info_type Dot11ManagementFrame::request_information() const { - const Dot11::Dot11Option *option = search_option(REQUEST_INFORMATION); + const Dot11::dot11_option *option = search_option(REQUEST_INFORMATION); if(!option || option->data_size() == 0) throw std::runtime_error("Request information not set"); request_info_type output; @@ -640,7 +635,7 @@ Dot11ManagementFrame::request_info_type Dot11ManagementFrame::request_informatio } Dot11ManagementFrame::fh_params_set Dot11ManagementFrame::fh_parameter_set() const { - const Dot11::Dot11Option *option = search_option(FH_SET); + const Dot11::dot11_option *option = search_option(FH_SET); if(!option || option->data_size() != sizeof(fh_params_set)) throw std::runtime_error("FH parameters set not set"); fh_params_set output = *reinterpret_cast(option->data_ptr()); @@ -652,21 +647,21 @@ Dot11ManagementFrame::fh_params_set Dot11ManagementFrame::fh_parameter_set() con } uint8_t Dot11ManagementFrame::ds_parameter_set() const { - const Dot11::Dot11Option *option = search_option(DS_SET); + const Dot11::dot11_option *option = search_option(DS_SET); if(!option || option->data_size() != sizeof(uint8_t)) throw std::runtime_error("DS parameters set not set"); return *option->data_ptr(); } uint16_t Dot11ManagementFrame::ibss_parameter_set() const { - const Dot11::Dot11Option *option = search_option(IBSS_SET); + const Dot11::dot11_option *option = search_option(IBSS_SET); if(!option || option->data_size() != sizeof(uint16_t)) throw std::runtime_error("IBSS parameters set not set"); return Endian::le_to_host(*reinterpret_cast(option->data_ptr())); } Dot11ManagementFrame::ibss_dfs_params Dot11ManagementFrame::ibss_dfs() const { - const Dot11::Dot11Option *option = search_option(IBSS_DFS); + const Dot11::dot11_option *option = search_option(IBSS_DFS); if(!option || option->data_size() < ibss_dfs_params::minimum_size) throw std::runtime_error("IBSS DFS set not set"); ibss_dfs_params output; @@ -684,7 +679,7 @@ Dot11ManagementFrame::ibss_dfs_params Dot11ManagementFrame::ibss_dfs() const { } Dot11ManagementFrame::country_params Dot11ManagementFrame::country() const { - const Dot11::Dot11Option *option = search_option(COUNTRY); + const Dot11::dot11_option *option = search_option(COUNTRY); if(!option || option->data_size() < country_params::minimum_size) throw std::runtime_error("Country option not set"); country_params output; @@ -702,7 +697,7 @@ Dot11ManagementFrame::country_params Dot11ManagementFrame::country() const { } std::pair Dot11ManagementFrame::fh_parameters() const { - const Dot11::Dot11Option *option = search_option(HOPPING_PATTERN_PARAMS); + const Dot11::dot11_option *option = search_option(HOPPING_PATTERN_PARAMS); if(!option || option->data_size() != sizeof(uint8_t) * 2) throw std::runtime_error("FH parameters option not set"); const uint8_t *ptr = option->data_ptr(); @@ -711,7 +706,7 @@ std::pair Dot11ManagementFrame::fh_parameters() const { } Dot11ManagementFrame::fh_pattern_type Dot11ManagementFrame::fh_pattern_table() const { - const Dot11::Dot11Option *option = search_option(HOPPING_PATTERN_TABLE); + const Dot11::dot11_option *option = search_option(HOPPING_PATTERN_TABLE); if(!option || option->data_size() < fh_pattern_type::minimum_size) throw std::runtime_error("FH pattern option not set"); fh_pattern_type output; @@ -727,14 +722,14 @@ Dot11ManagementFrame::fh_pattern_type Dot11ManagementFrame::fh_pattern_table() c } uint8_t Dot11ManagementFrame::power_constraint() const { - const Dot11::Dot11Option *option = search_option(POWER_CONSTRAINT); + const Dot11::dot11_option *option = search_option(POWER_CONSTRAINT); if(!option || option->data_size() != 1) throw std::runtime_error("Power constraint option not set"); return *option->data_ptr(); } Dot11ManagementFrame::channel_switch_type Dot11ManagementFrame::channel_switch() const { - const Dot11::Dot11Option *option = search_option(CHANNEL_SWITCH); + const Dot11::dot11_option *option = search_option(CHANNEL_SWITCH); if(!option || option->data_size() != sizeof(uint8_t) * 3) throw std::runtime_error("Channel switch option not set"); const uint8_t *ptr = option->data_ptr(); @@ -746,7 +741,7 @@ Dot11ManagementFrame::channel_switch_type Dot11ManagementFrame::channel_switch() } Dot11ManagementFrame::quiet_type Dot11ManagementFrame::quiet() const { - const Dot11::Dot11Option *option = search_option(QUIET); + const Dot11::dot11_option *option = search_option(QUIET); if(!option || option->data_size() != (sizeof(uint8_t) * 2 + sizeof(uint16_t) * 2)) throw std::runtime_error("Quiet option not set"); const uint8_t *ptr = option->data_ptr(); @@ -761,7 +756,7 @@ Dot11ManagementFrame::quiet_type Dot11ManagementFrame::quiet() const { } std::pair Dot11ManagementFrame::tpc_report() const { - const Dot11::Dot11Option *option = search_option(TPC_REPORT); + const Dot11::dot11_option *option = search_option(TPC_REPORT); if(!option || option->data_size() != sizeof(uint8_t) * 2) throw std::runtime_error("TPC Report option not set"); const uint8_t *ptr = option->data_ptr(); @@ -770,14 +765,14 @@ std::pair Dot11ManagementFrame::tpc_report() const { } uint8_t Dot11ManagementFrame::erp_information() const { - const Dot11::Dot11Option *option = search_option(ERP_INFORMATION); + const Dot11::dot11_option *option = search_option(ERP_INFORMATION); if(!option || option->data_size() != sizeof(uint8_t)) throw std::runtime_error("ERP Information option not set"); return *option->data_ptr(); } Dot11ManagementFrame::bss_load_type Dot11ManagementFrame::bss_load() const { - const Dot11::Dot11Option *option = search_option(BSS_LOAD); + const Dot11::dot11_option *option = search_option(BSS_LOAD); if(!option || option->data_size() != sizeof(uint8_t) + 2 * sizeof(uint16_t)) throw std::runtime_error("BSS Load option not set"); bss_load_type output; @@ -790,7 +785,7 @@ Dot11ManagementFrame::bss_load_type Dot11ManagementFrame::bss_load() const { } Dot11ManagementFrame::tim_type Dot11ManagementFrame::tim() const { - const Dot11::Dot11Option *option = search_option(TIM); + const Dot11::dot11_option *option = search_option(TIM); if(!option || option->data_size() < 4 * sizeof(uint8_t)) throw std::runtime_error("TIM option not set"); const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size(); @@ -805,7 +800,7 @@ Dot11ManagementFrame::tim_type Dot11ManagementFrame::tim() const { } std::string Dot11ManagementFrame::challenge_text() const { - const Dot11::Dot11Option *option = search_option(CHALLENGE_TEXT); + const Dot11::dot11_option *option = search_option(CHALLENGE_TEXT); if(!option || option->data_size() == 0) throw std::runtime_error("Challenge text option not set"); return std::string(option->data_ptr(), option->data_ptr() + option->data_size()); diff --git a/src/ip.cpp b/src/ip.cpp index 3ec9073..5805a0b 100644 --- a/src/ip.cpp +++ b/src/ip.cpp @@ -53,7 +53,7 @@ IP::IP(address_type ip_dst, address_type ip_src, PDU *child) IP::IP(const uint8_t *buffer, uint32_t total_sz) : PDU(Constants::IP::PROTO_IP) { - static const char *msg("Not enough size for an IP header in the buffer."); + const char *msg = "Not enough size for an IP header in the buffer."; if(total_sz < sizeof(iphdr)) throw std::runtime_error(msg); std::memcpy(&_ip, buffer, sizeof(iphdr)); @@ -71,10 +71,11 @@ IP::IP(const uint8_t *buffer, uint32_t total_sz) _padded_options_size = head_len() * sizeof(uint32_t) - sizeof(iphdr); /* While the end of the options is not reached read an option */ while (ptr_buffer < buffer && (*ptr_buffer != 0)) { - IPOption opt_to_add; - memcpy(&opt_to_add.type, ptr_buffer, sizeof(uint8_t)); + //ip_option opt_to_add; + option_identifier opt_type; + memcpy(&opt_type, ptr_buffer, sizeof(uint8_t)); ptr_buffer++; - switch (opt_to_add.type.number) { + switch (opt_type.number) { /* Multibyte options with length as second byte */ case SEC: case LSSR: @@ -97,18 +98,24 @@ IP::IP(const uint8_t *buffer, uint32_t total_sz) throw std::runtime_error(msg); { - const uint8_t data_size = *ptr_buffer - 1; + const uint8_t data_size = *ptr_buffer - 2; if(data_size > 0) { + ptr_buffer++; if(buffer - ptr_buffer < data_size) throw std::runtime_error(msg); - opt_to_add.optional_data.assign(ptr_buffer, ptr_buffer + data_size); + _ip_options.push_back(ip_option(opt_type, ptr_buffer, ptr_buffer + data_size)); } + else + _ip_options.push_back(ip_option(opt_type)); } - ptr_buffer += opt_to_add.optional_data.size(); + ptr_buffer += _ip_options.back().data_size() + 1; + break; + default: + _ip_options.push_back(ip_option(opt_type)); + break; } - this->_ip_options.push_back(opt_to_add); - this->_options_size += opt_to_add.optional_data.size() + 1; + _options_size += _ip_options.back().data_size() + 2; } // check this line PLX total_sz -= head_len() * sizeof(uint32_t); @@ -132,11 +139,11 @@ IP::IP(const uint8_t *buffer, uint32_t total_sz) void IP::init_ip_fields() { memset(&_ip, 0, sizeof(iphdr)); - this->_ip.version = 4; - this->ttl(DEFAULT_TTL); - this->id(1); - this->_options_size = 0; - this->_padded_options_size = 0; + _ip.version = 4; + ttl(DEFAULT_TTL); + id(1); + _options_size = 0; + _padded_options_size = 0; } /* Setters */ @@ -187,67 +194,126 @@ void IP::version(small_uint<4> ver) { _ip.version = ver; } -void IP::set_eol_option() { - this->set_option(0, IP::CONTROL, IP::END); +void IP::eol() { + add_option(option_identifier(IP::END, IP::CONTROL, 0)); } -void IP::set_noop_option() { - this->set_option(0, IP::CONTROL, IP::NOOP); +void IP::noop() { + add_option(option_identifier(IP::NOOP, IP::CONTROL, 0)); } -void IP::set_sec_option(const uint8_t* data, uint32_t data_len) { - this->set_option(1, IP::CONTROL, IP::SEC, data, data_len); +void IP::security(const security_type &data) { + uint8_t array[9]; + uint16_t *ptr = reinterpret_cast(array); + uint32_t value = data.transmission_control; + *ptr++ = Endian::host_to_be(data.security); + *ptr++ = Endian::host_to_be(data.compartments); + *ptr++ = Endian::host_to_be(data.handling_restrictions); + array[8] = (value & 0xff); + array[7] = ((value >> 8) & 0xff); + array[6] = ((value >> 16) & 0xff); + + add_option( + ip_option( + 130, + sizeof(array), + array + ) + ); } -void IP::set_option(uint8_t copied, - OptionClass op_class, - Option number, - const uint8_t* data, - uint32_t data_size) -{ - IPOption option; - option.type.copied = copied; - option.type.op_class = op_class; - option.type.number = number; - if (data_size) { - option.optional_data.push_back(data_size); - std::copy(data, data + data_size, - std::back_inserter(option.optional_data) - ); - data_size++; +void IP::stream_identifier(uint16_t stream_id) { + stream_id = Endian::host_to_be(stream_id); + add_option( + ip_option( + 136, + sizeof(uint16_t), + (const uint8_t*)&stream_id + ) + ); +} + +void IP::add_route_option(option_identifier id, const generic_route_option_type &data) { + std::vector opt_data(1 + sizeof(uint32_t) * data.routes.size()); + opt_data[0] = data.pointer; + for(size_t i(0); i < data.routes.size(); ++i) { + uint32_t ip = data.routes[i]; + opt_data[1 + i * 4] = ip & 0xff; + opt_data[1 + i * 4 + 1] = (ip >> 8) & 0xff; + opt_data[1 + i * 4 + 2] = (ip >> 16) & 0xff; + opt_data[1 + i * 4 + 3] = (ip >> 24) & 0xff; } + add_option( + ip_option( + id, + opt_data.size(), + &opt_data[0] + ) + ); +} + +IP::generic_route_option_type IP::search_route_option(option_identifier id) const { + const ip_option *option = search_option(id); + if(!option || option->data_size() < 1 + sizeof(uint32_t) || + ((option->data_size() - 1) % sizeof(uint32_t)) != 0) + throw option_not_found(); + generic_route_option_type output; + output.pointer = *option->data_ptr(); + const uint32_t *route = (const uint32_t*)(option->data_ptr() + 1), + *end = route + (option->data_size() - 1) / sizeof(uint32_t); + while(route < end) + output.routes.push_back(address_type(*route++)); + return output; +} + +IP::security_type IP::security() const { + const ip_option *option = search_option(130); + if(!option || option->data_size() < 9) + throw option_not_found(); + security_type output; + const uint16_t *ptr = reinterpret_cast(option->data_ptr()); + output.security = Endian::be_to_host(*ptr++); + output.compartments = Endian::be_to_host(*ptr++); + output.handling_restrictions = Endian::be_to_host(*ptr++); + uint32_t tcc = option->data_ptr()[6]; + tcc = (tcc << 8) | option->data_ptr()[7]; + tcc = (tcc << 8) | option->data_ptr()[8]; + output.transmission_control = tcc; + return output; +} + +uint16_t IP::stream_identifier() const { + const ip_option *option = search_option(136); + if(!option || option->data_size() != sizeof(uint16_t)) + throw option_not_found(); + return Endian::be_to_host(*(const uint16_t*)option->data_ptr()); +} + +void IP::add_option(const ip_option &option) { _ip_options.push_back(option); - _options_size += 1 + (!option.optional_data.empty() ? (data_size) : 0); + _options_size += 1 + option.data_size(); uint8_t padding = _options_size & 3; _padded_options_size = padding ? (_options_size - padding + 4) : _options_size; } -const IP::IPOption *IP::search_option(OptionClass opt_class, Option opt_number) const { - for(std::list::const_iterator it = _ip_options.begin(); it != _ip_options.end(); ++it) { - if(it->type.op_class == (uint8_t)opt_class && it->type.number == (uint8_t)opt_number) +const IP::ip_option *IP::search_option(option_identifier id) const { + for(std::list::const_iterator it = _ip_options.begin(); it != _ip_options.end(); ++it) { + if(it->option() == id) return &(*it); } return 0; } -uint8_t* IP::IPOption::write(uint8_t* buffer) { - memcpy(buffer, &type, 1); - buffer += 1; - if (!optional_data.empty()) { - std::copy(optional_data.begin(), optional_data.end(), buffer); - buffer += optional_data.size(); - } +uint8_t* IP::write_option(const ip_option &opt, uint8_t* buffer) { + option_identifier opt_type = opt.option(); + memcpy(buffer, &opt_type, 1); + buffer++; + *(buffer++) = opt.data_size() + 2; + std::copy(opt.data_ptr(), opt.data_ptr() + opt.data_size(), buffer); + buffer += opt.data_size(); return buffer; } -const uint8_t* IP::IPOption::data_ptr() const { - return !optional_data.empty() ? (&optional_data[1]) : 0; -} - -uint8_t IP::IPOption::data_size() const { - return !optional_data.empty() ? (optional_data.size() - 1) : 0; -} - /* Virtual method overriding. */ uint32_t IP::header_size() const { @@ -296,9 +362,8 @@ void IP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU* pare memcpy(buffer, &_ip, sizeof(_ip)); uint8_t* ptr_buffer = buffer + sizeof(_ip); - for(list::iterator it = _ip_options.begin(); it != _ip_options.end(); ++it) - ptr_buffer = it->write(ptr_buffer); - + for(list::iterator it = _ip_options.begin(); it != _ip_options.end(); ++it) + ptr_buffer = write_option(*it, ptr_buffer); memset(buffer + sizeof(_ip) + _options_size, 0, _padded_options_size - _options_size); if(parent && !_ip.check) { diff --git a/src/tcp.cpp b/src/tcp.cpp index b4572d6..9f03455 100644 --- a/src/tcp.cpp +++ b/src/tcp.cpp @@ -157,9 +157,9 @@ void TCP::sack(const sack_type &edges) { } TCP::sack_type TCP::sack() const { - const TCPOption *option = search_option(SACK); + const tcp_option *option = search_option(SACK); if(!option || (option->data_size() % sizeof(uint32_t)) != 0) - throw OptionNotFound(); + throw option_not_found(); const uint32_t *ptr = (const uint32_t*)option->data_ptr(); const uint32_t *end = ptr + (option->data_size() / sizeof(uint32_t)); sack_type edges(end - ptr); @@ -176,9 +176,9 @@ void TCP::timestamp(uint32_t value, uint32_t reply) { } std::pair TCP::timestamp() const { - const TCPOption *option = search_option(TSOPT); + const tcp_option *option = search_option(TSOPT); if(!option || option->data_size() != (sizeof(uint32_t) << 1)) - throw OptionNotFound(); + throw option_not_found(); uint64_t buffer = *(const uint64_t*)option->data_ptr(); buffer = Endian::be_to_host(buffer); return std::make_pair((buffer >> 32) & 0xffffffff, buffer & 0xffffffff); @@ -254,13 +254,13 @@ void TCP::set_flag(Flags tcp_flag, small_uint<1> value) { }; } -void TCP::add_option(Option tcp_option, uint8_t length, const uint8_t *data) { +void TCP::add_option(Option option, uint8_t length, const uint8_t *data) { uint8_t padding; - _options.push_back(TCPOption(tcp_option, length, data)); + _options.push_back(tcp_option(option, length, data)); _options_size += sizeof(uint8_t); // SACK_OK contains length but not data.... - if(length || tcp_option == SACK_OK) + if(length || option == SACK_OK) _options_size += sizeof(uint8_t); if(data) @@ -280,7 +280,7 @@ void TCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *par buffer += sizeof(tcphdr); _tcp.doff = (sizeof(tcphdr) + _total_options_size) / sizeof(uint32_t); for(options_type::iterator it = _options.begin(); it != _options.end(); ++it) - buffer = it->write(buffer); + buffer = write_option(*it, buffer); if(_options_size < _total_options_size) { uint8_t padding = _options_size; @@ -305,7 +305,7 @@ void TCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *par _tcp.check = 0; } -const TCP::TCPOption *TCP::search_option(Option opt) const { +const TCP::tcp_option *TCP::search_option(Option opt) const { for(options_type::const_iterator it = _options.begin(); it != _options.end(); ++it) { if(it->option() == opt) return &(*it); @@ -313,18 +313,18 @@ const TCP::TCPOption *TCP::search_option(Option opt) const { return 0; } -/* TCPOptions */ +/* tcp_options */ -uint8_t *TCP::TCPOption::write(uint8_t *buffer) { - if(option_ == 0 || option_ == 1) { - *buffer = option_; +uint8_t *TCP::write_option(const tcp_option &opt, uint8_t *buffer) { + if(opt.option() == 0 || opt.option() == 1) { + *buffer = opt.option(); return buffer + 1; } else { - buffer[0] = option_; - buffer[1] = data_size() + (sizeof(uint8_t) << 1); - if(!value_.empty()) - std::copy(value_.begin() + 1, value_.end(), buffer + 2); + buffer[0] = opt.option(); + buffer[1] = opt.data_size() + (sizeof(uint8_t) << 1); + if(opt.data_size() != 0) + std::copy(opt.data_ptr(), opt.data_ptr() + opt.data_size(), buffer + 2); return buffer + buffer[1]; } } diff --git a/tests/depends.d b/tests/depends.d index eedfa22..c38288d 100644 --- a/tests/depends.d +++ b/tests/depends.d @@ -107,7 +107,8 @@ src/ipaddress.o: src/ipaddress.cpp ../include/ipaddress.h \ ../include/hwaddress.h: src/ip.o: src/ip.cpp ../include/ip.h ../include/pdu.h \ ../include/small_uint.h ../include/endianness.h ../include/ipaddress.h \ - ../include/ipaddress.h ../include/utils.h ../include/hwaddress.h + ../include/pdu_option.h ../include/ipaddress.h ../include/utils.h \ + ../include/hwaddress.h ../include/ip.h: @@ -119,6 +120,8 @@ src/ip.o: src/ip.cpp ../include/ip.h ../include/pdu.h \ ../include/ipaddress.h: +../include/pdu_option.h: + ../include/ipaddress.h: ../include/utils.h: @@ -162,8 +165,8 @@ src/snap.o: src/snap.cpp ../include/snap.h ../include/pdu.h \ ../include/hwaddress.h: src/tcp.o: src/tcp.cpp ../include/tcp.h ../include/pdu.h \ - ../include/endianness.h ../include/small_uint.h ../include/utils.h \ - ../include/ipaddress.h ../include/hwaddress.h + ../include/endianness.h ../include/small_uint.h ../include/pdu_option.h \ + ../include/utils.h ../include/ipaddress.h ../include/hwaddress.h ../include/tcp.h: @@ -173,6 +176,8 @@ src/tcp.o: src/tcp.cpp ../include/tcp.h ../include/pdu.h \ ../include/small_uint.h: +../include/pdu_option.h: + ../include/utils.h: ../include/ipaddress.h: @@ -612,9 +617,10 @@ include/tests/dot11.h: include/tests/dot11.h: ../src/arp.o: ../src/arp.cpp ../include/arp.h ../include/pdu.h \ ../include/endianness.h ../include/hwaddress.h ../include/ipaddress.h \ - ../include/ip.h ../include/small_uint.h ../include/ethernetII.h \ - ../include/network_interface.h ../include/rawpdu.h \ - ../include/constants.h ../include/network_interface.h + ../include/ip.h ../include/small_uint.h ../include/pdu_option.h \ + ../include/ethernetII.h ../include/network_interface.h \ + ../include/rawpdu.h ../include/constants.h \ + ../include/network_interface.h ../include/arp.h: @@ -630,6 +636,8 @@ include/tests/dot11.h: ../include/small_uint.h: +../include/pdu_option.h: + ../include/ethernetII.h: ../include/network_interface.h: @@ -740,7 +748,7 @@ include/tests/dot11.h: ../include/pdu.h ../include/endianness.h ../include/hwaddress.h \ ../include/network_interface.h ../include/ipaddress.h \ ../include/packet_sender.h ../include/rawpdu.h ../include/ip.h \ - ../include/small_uint.h ../include/arp.h + ../include/small_uint.h ../include/pdu_option.h ../include/arp.h ../include/ethernetII.h: @@ -762,6 +770,8 @@ include/tests/dot11.h: ../include/small_uint.h: +../include/pdu_option.h: + ../include/arp.h: ../src/icmp.o: ../src/icmp.cpp ../include/icmp.h ../include/pdu.h \ ../include/endianness.h ../include/rawpdu.h ../include/utils.h \ @@ -808,9 +818,9 @@ include/tests/dot11.h: ../include/endianness.h: ../src/ip.o: ../src/ip.cpp ../include/ip.h ../include/pdu.h \ ../include/small_uint.h ../include/endianness.h ../include/ipaddress.h \ - ../include/tcp.h ../include/udp.h ../include/icmp.h ../include/rawpdu.h \ - ../include/utils.h ../include/hwaddress.h ../include/packet_sender.h \ - ../include/constants.h + ../include/pdu_option.h ../include/tcp.h ../include/udp.h \ + ../include/icmp.h ../include/rawpdu.h ../include/utils.h \ + ../include/hwaddress.h ../include/packet_sender.h ../include/constants.h ../include/ip.h: @@ -822,6 +832,8 @@ include/tests/dot11.h: ../include/ipaddress.h: +../include/pdu_option.h: + ../include/tcp.h: ../include/udp.h: @@ -922,7 +934,7 @@ include/tests/dot11.h: ../src/snap.o: ../src/snap.cpp ../include/snap.h ../include/pdu.h \ ../include/endianness.h ../include/small_uint.h ../include/constants.h \ ../include/arp.h ../include/hwaddress.h ../include/ipaddress.h \ - ../include/ip.h ../include/eapol.h + ../include/ip.h ../include/pdu_option.h ../include/eapol.h ../include/snap.h: @@ -942,6 +954,8 @@ include/tests/dot11.h: ../include/ip.h: +../include/pdu_option.h: + ../include/eapol.h: ../src/sniffer.o: ../src/sniffer.cpp ../include/sniffer.h \ ../include/pdu.h ../include/ethernetII.h ../include/endianness.h \ @@ -964,9 +978,9 @@ include/tests/dot11.h: ../include/radiotap.h: ../src/tcp.o: ../src/tcp.cpp ../include/tcp.h ../include/pdu.h \ - ../include/endianness.h ../include/small_uint.h ../include/ip.h \ - ../include/ipaddress.h ../include/constants.h ../include/rawpdu.h \ - ../include/utils.h ../include/hwaddress.h + ../include/endianness.h ../include/small_uint.h ../include/pdu_option.h \ + ../include/ip.h ../include/ipaddress.h ../include/constants.h \ + ../include/rawpdu.h ../include/utils.h ../include/hwaddress.h ../include/tcp.h: @@ -976,6 +990,8 @@ include/tests/dot11.h: ../include/small_uint.h: +../include/pdu_option.h: + ../include/ip.h: ../include/ipaddress.h: @@ -992,7 +1008,7 @@ include/tests/dot11.h: ../include/ethernetII.h ../include/endianness.h ../include/hwaddress.h \ ../include/network_interface.h ../include/ipaddress.h \ ../include/radiotap.h ../include/tcp.h ../include/small_uint.h \ - ../include/ip.h + ../include/pdu_option.h ../include/ip.h ../include/rawpdu.h: @@ -1018,11 +1034,13 @@ include/tests/dot11.h: ../include/small_uint.h: +../include/pdu_option.h: + ../include/ip.h: ../src/udp.o: ../src/udp.cpp ../include/udp.h ../include/pdu.h \ ../include/endianness.h ../include/constants.h ../include/utils.h \ ../include/ipaddress.h ../include/hwaddress.h ../include/ip.h \ - ../include/small_uint.h ../include/rawpdu.h + ../include/small_uint.h ../include/pdu_option.h ../include/rawpdu.h ../include/udp.h: @@ -1042,12 +1060,14 @@ include/tests/dot11.h: ../include/small_uint.h: +../include/pdu_option.h: + ../include/rawpdu.h: ../src/utils.o: ../src/utils.cpp ../include/utils.h \ ../include/ipaddress.h ../include/hwaddress.h ../include/pdu.h \ ../include/ip.h ../include/pdu.h ../include/small_uint.h \ - ../include/endianness.h ../include/icmp.h ../include/arp.h \ - ../include/endianness.h ../include/network_interface.h \ + ../include/endianness.h ../include/pdu_option.h ../include/icmp.h \ + ../include/arp.h ../include/endianness.h ../include/network_interface.h \ ../include/packet_sender.h ../include/utils.h: @@ -1066,6 +1086,8 @@ include/tests/dot11.h: ../include/endianness.h: +../include/pdu_option.h: + ../include/icmp.h: ../include/arp.h: diff --git a/tests/src/dhcp.cpp b/tests/src/dhcp.cpp index 28d22d6..4bacba3 100644 --- a/tests/src/dhcp.cpp +++ b/tests/src/dhcp.cpp @@ -186,44 +186,37 @@ TEST_F(DHCPTest, File) { } void DHCPTest::test_option(const DHCP &dhcp, DHCP::Options opt, uint32_t len, uint8_t *value) { - const DHCP::DHCPOption *option = dhcp.search_option(opt); + const DHCP::dhcp_option *option = dhcp.search_option(opt); ASSERT_TRUE(option != 0); - EXPECT_EQ(option->option, opt); - ASSERT_EQ(option->value.size(), len); - if(len) - EXPECT_TRUE(std::equal(option->value.begin(), option->value.end(), value)); + EXPECT_EQ(option->option(), opt); + ASSERT_EQ(option->data_size(), len); + EXPECT_TRUE(std::equal(option->data_ptr(), option->data_ptr() + option->data_size(), value)); } TEST_F(DHCPTest, TypeOption) { DHCP dhcp; - uint8_t value = DHCP::REQUEST, value_found; - dhcp.add_type_option(DHCP::REQUEST); - ASSERT_TRUE(dhcp.search_type_option(&value_found)); - EXPECT_EQ(value, value_found); + dhcp.type(DHCP::REQUEST); + EXPECT_EQ(dhcp.type(), DHCP::REQUEST); } TEST_F(DHCPTest, ServerIdentifierOption) { DHCP dhcp; - IPv4Address ip = "192.168.0.1", ip_found; - dhcp.add_server_identifier(ip); - ASSERT_TRUE(dhcp.search_server_identifier(&ip_found)); - EXPECT_EQ(ip, ip_found); + dhcp.server_identifier("192.168.0.1"); + EXPECT_EQ(DHCP::ipaddress_type("192.168.0.1"), dhcp.server_identifier()); } TEST_F(DHCPTest, LeaseTimeOption) { DHCP dhcp; - uint32_t ltime = 0x34f1, ltime_found; - dhcp.add_lease_time(ltime); - ASSERT_TRUE(dhcp.search_lease_time(<ime_found)); - EXPECT_EQ(ltime, ltime_found); + uint32_t ltime = 0x34f1; + dhcp.lease_time(ltime); + EXPECT_EQ(ltime, dhcp.lease_time()); } TEST_F(DHCPTest, SubnetMaskOption) { DHCP dhcp; IPv4Address ip = "192.168.0.1", ip_found; - dhcp.add_subnet_mask(ip); - ASSERT_TRUE(dhcp.search_subnet_mask(&ip_found)); - EXPECT_EQ(ip, ip_found); + dhcp.subnet_mask(ip); + EXPECT_EQ(ip, dhcp.subnet_mask()); } TEST_F(DHCPTest, RoutersOption) { @@ -231,10 +224,9 @@ TEST_F(DHCPTest, RoutersOption) { list routers; routers.push_back("192.168.0.253"); routers.push_back("10.123.45.67"); - dhcp.add_routers_option(routers); + dhcp.routers(routers); - list routers2; - ASSERT_TRUE(dhcp.search_routers_option(&routers2)); + list routers2 = dhcp.routers(); ASSERT_EQ(routers.size(), routers2.size()); while(routers.size()) { EXPECT_EQ(routers.front(), routers2.front()); @@ -248,10 +240,9 @@ TEST_F(DHCPTest, DNSOption) { list dns; dns.push_back("192.168.0.253"); dns.push_back("10.123.45.67"); - dhcp.add_dns_option(dns); + dhcp.domain_name_servers(dns); - list dns2; - ASSERT_TRUE(dhcp.search_dns_option(&dns2)); + list dns2 = dhcp.domain_name_servers(); ASSERT_EQ(dns.size(), dns2.size()); while(dns.size()) { EXPECT_EQ(dns.front(), dns2.front()); @@ -263,17 +254,15 @@ TEST_F(DHCPTest, DNSOption) { TEST_F(DHCPTest, DomainNameOption) { DHCP dhcp; string domain = "libtins.test.domain", domain_found; - dhcp.add_domain_name(domain); - ASSERT_TRUE(dhcp.search_domain_name(&domain_found)); - EXPECT_TRUE(domain == domain_found); + dhcp.domain_name(domain); + EXPECT_EQ(domain, dhcp.domain_name()); } TEST_F(DHCPTest, BroadcastOption) { DHCP dhcp; IPv4Address ip = "192.168.0.1", ip_found; - dhcp.add_broadcast_option(ip); - ASSERT_TRUE(dhcp.search_broadcast_option(&ip_found)); - EXPECT_EQ(ip, ip_found); + dhcp.broadcast(ip); + EXPECT_EQ(ip, dhcp.broadcast()); } void DHCPTest::test_equals(const DHCP &dhcp1, const DHCP &dhcp2) { @@ -290,23 +279,22 @@ void DHCPTest::test_equals(const DHCP &dhcp1, const DHCP &dhcp2) { EXPECT_EQ(dhcp1.chaddr(), dhcp2.chaddr()); EXPECT_TRUE(memcmp(dhcp1.sname(), dhcp2.sname(), 64) == 0); EXPECT_TRUE(memcmp(dhcp1.file(), dhcp2.file(), 128) == 0); - const std::list options1(dhcp1.options()); - const std::list options2(dhcp2.options()); + const DHCP::options_type options1(dhcp1.options()); + const DHCP::options_type options2(dhcp2.options()); ASSERT_EQ(options1.size(), options2.size()); - std::list::const_iterator it1, it2; + DHCP::options_type::const_iterator it1, it2; it1 = options1.begin(); it2 = options2.begin(); while(it1 != options1.end()) { - EXPECT_EQ(it1->option, it2->option); - ASSERT_EQ(it1->value.size(), it2->value.size()); - EXPECT_TRUE(std::equal(it1->value.begin(), it1->value.end(), it2->value.begin())); + EXPECT_EQ(it1->option(), it2->option()); + ASSERT_EQ(it1->data_size(), it2->data_size()); + EXPECT_TRUE(std::equal(it1->data_ptr(), it1->data_ptr() + it1->data_size(), it2->data_ptr())); it1++; it2++; } } TEST_F(DHCPTest, ConstructorFromBuffer) { DHCP dhcp1(expected_packet, sizeof(expected_packet)); - IPv4Address ip; std::list routers; IPv4Address expected_routers[] = { "192.168.0.1", "127.0.0.1" }; @@ -321,9 +309,8 @@ TEST_F(DHCPTest, ConstructorFromBuffer) { EXPECT_EQ(dhcp1.yiaddr(), IPv4Address("243.22.34.98")); EXPECT_EQ(dhcp1.giaddr(), IPv4Address("123.43.55.254")); EXPECT_EQ(dhcp1.siaddr(), IPv4Address("167.32.11.154")); - ASSERT_TRUE(dhcp1.search_server_identifier(&ip)); - EXPECT_EQ(ip, IPv4Address("192.168.4.2")); - ASSERT_TRUE(dhcp1.search_routers_option(&routers)); + 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)); diff --git a/tests/src/dot11/dot11.cpp b/tests/src/dot11/dot11.cpp index 7cf8c25..a2be284 100644 --- a/tests/src/dot11/dot11.cpp +++ b/tests/src/dot11/dot11.cpp @@ -152,7 +152,7 @@ TEST_F(Dot11Test, Addr1) { TEST_F(Dot11Test, AddTaggedOption) { Dot11 dot11; dot11.add_tagged_option(Dot11::SSID, hwaddr.size(), hwaddr.begin()); - const Dot11::Dot11Option *option; + const Dot11::dot11_option *option; ASSERT_TRUE((option = dot11.search_option(Dot11::SSID))); EXPECT_EQ(option->data_size(), hwaddr.size()); EXPECT_EQ(option->option(), Dot11::SSID); diff --git a/tests/src/ip.cpp b/tests/src/ip.cpp index 8d3fc72..af40f1e 100644 --- a/tests/src/ip.cpp +++ b/tests/src/ip.cpp @@ -16,10 +16,12 @@ public: void test_equals(const IP &ip1, const IP &ip2); }; -const uint8_t IPTest::expected_packet[] = { '(', '\x7f', '\x00', ' ', -'\x00', 'z', '\x00', 'C', '\x15', '\x01', '\xfb', 'g', 'T', '4', '\xfe', -'\x05', '\xc0', '\xa8', '\t', '+', '\x82', '\x0b', 't', 'j', 'g', '\xab', -'w', '\xab', 'h', 'e', 'l', '\x00' }; +const uint8_t IPTest::expected_packet[] = { + '(', '\x7f', '\x00', ' ', '\x00', 'z', '\x00', 'C', '\x15', '\x01', + '\xfb', 'g', 'T', '4', '\xfe', '\x05', '\xc0', '\xa8', '\t', '+', + '\x82', '\x0b', 't', 'j', 'g', '\xab', 'w', '\xab', 'h', 'e', 'l', + '\x00' +}; TEST_F(IPTest, DefaultConstructor) { @@ -52,7 +54,7 @@ TEST_F(IPTest, NestedCopy) { test_equals(ip1, ip2); } -TEST_F(IPTest, IPIntConstructor) { +TEST_F(IPTest, Constructor) { IP ip("192.168.0.1", "192.168.0.100"); EXPECT_EQ(ip.dst_addr(), "192.168.0.1"); EXPECT_EQ(ip.src_addr(), "192.168.0.100"); @@ -60,15 +62,6 @@ TEST_F(IPTest, IPIntConstructor) { EXPECT_EQ(ip.id(), 1); } -TEST_F(IPTest, IPStringConstructor) { - string ip1 = "154.33.200.55", ip2 = "192.10.11.52"; - IP ip(ip1, ip2); - EXPECT_EQ(ip.dst_addr(), ip1); - EXPECT_EQ(ip.src_addr(), ip2); - EXPECT_EQ(ip.version(), 4); - EXPECT_EQ(ip.id(), 1); -} - TEST_F(IPTest, HeadLen) { IP ip; ip.head_len(14); @@ -150,11 +143,61 @@ TEST_F(IPTest, Version) { } TEST_F(IPTest, SecOption) { + IP ip; + ip.security(IP::security_type(0x746a, 26539, 0x77ab, 0x68656c)); + IP::security_type found = ip.security(); + EXPECT_EQ(found.security, 0x746a); + EXPECT_EQ(found.compartments, 26539); + EXPECT_EQ(found.handling_restrictions, 0x77ab); + EXPECT_EQ(found.transmission_control, 0x68656c); +} + +TEST_F(IPTest, LSRROption) { + IP ip; + IP::lsrr_type lsrr(0x2d); + lsrr.routes.push_back("192.168.2.3"); + lsrr.routes.push_back("192.168.5.1"); + ip.lsrr(lsrr); + IP::lsrr_type found = ip.lsrr(); + EXPECT_EQ(found.pointer, lsrr.pointer); + EXPECT_EQ(found.routes, lsrr.routes); +} + +TEST_F(IPTest, SSRROption) { + IP ip; + IP::ssrr_type ssrr(0x2d); + ssrr.routes.push_back("192.168.2.3"); + ssrr.routes.push_back("192.168.5.1"); + ip.ssrr(ssrr); + IP::ssrr_type found = ip.ssrr(); + EXPECT_EQ(found.pointer, ssrr.pointer); + EXPECT_EQ(found.routes, ssrr.routes); +} + +TEST_F(IPTest, RecordRouteOption) { + IP ip; + IP::record_route_type record_route(0x2d); + record_route.routes.push_back("192.168.2.3"); + record_route.routes.push_back("192.168.5.1"); + ip.record_route(record_route); + IP::record_route_type found = ip.record_route(); + EXPECT_EQ(found.pointer, record_route.pointer); + EXPECT_EQ(found.routes, record_route.routes); +} + +TEST_F(IPTest, StreamIDOption) { + IP ip; + ip.stream_identifier(0x91fa); + EXPECT_EQ(0x91fa, ip.stream_identifier()); +} + +TEST_F(IPTest, AddOption) { IP ip; const uint8_t data[] = { 0x15, 0x17, 0x94, 0x66, 0xff }; - ip.set_sec_option(data, sizeof(data)); - const IP::IPOption *option; - ASSERT_TRUE((option = ip.search_option(IP::CONTROL, IP::SEC))); + IP::option_identifier id(IP::SEC, IP::CONTROL, 1); + ip.add_option(IP::ip_option(id, data, data + sizeof(data))); + const IP::ip_option *option; + ASSERT_TRUE((option = ip.search_option(id))); ASSERT_EQ(option->data_size(), sizeof(data)); EXPECT_TRUE(memcmp(option->data_ptr(), data, sizeof(data)) == 0); } @@ -171,23 +214,22 @@ void IPTest::test_equals(const IP &ip1, const IP &ip2) { } TEST_F(IPTest, ConstructorFromBuffer) { - IP ip1(expected_packet, sizeof(expected_packet)); - const uint8_t opt_sec[] = { 't', 'j', 'g', '\xab', 'w', '\xab', 'h', 'e', 'l' }; + IP ip(expected_packet, sizeof(expected_packet)); - EXPECT_EQ(ip1.dst_addr(), "192.168.9.43"); - EXPECT_EQ(ip1.src_addr(), "84.52.254.5"); - EXPECT_EQ(ip1.id(), 0x7a); - EXPECT_EQ(ip1.tos(), 0x7f); - EXPECT_EQ(ip1.frag_off(), 0x43); - EXPECT_EQ(ip1.protocol(), 1); - EXPECT_EQ(ip1.ttl(), 0x15); - EXPECT_EQ(ip1.version(), 2); - const IP::IPOption *option; - ASSERT_TRUE((option = ip1.search_option(IP::CONTROL, IP::SEC))); - EXPECT_EQ(option->type.number, IP::SEC); - EXPECT_EQ(option->type.op_class, IP::CONTROL); - ASSERT_EQ(option->data_size(), sizeof(opt_sec)); - EXPECT_TRUE(std::equal(option->data_ptr(), option->data_ptr() + option->data_size(), opt_sec)); + EXPECT_EQ(ip.dst_addr(), "192.168.9.43"); + EXPECT_EQ(ip.src_addr(), "84.52.254.5"); + EXPECT_EQ(ip.id(), 0x7a); + EXPECT_EQ(ip.tos(), 0x7f); + EXPECT_EQ(ip.frag_off(), 0x43); + EXPECT_EQ(ip.protocol(), 1); + EXPECT_EQ(ip.ttl(), 0x15); + EXPECT_EQ(ip.version(), 2); + + IP::security_type sec = ip.security(); + EXPECT_EQ(sec.security, 0x746a); + EXPECT_EQ(sec.compartments, 26539); + EXPECT_EQ(sec.handling_restrictions, 0x77ab); + EXPECT_EQ(sec.transmission_control, 0x68656c); } TEST_F(IPTest, Serialize) {