diff --git a/include/ieee802-11.h b/include/ieee802-11.h index acaf283..dcdd6de 100644 --- a/include/ieee802-11.h +++ b/include/ieee802-11.h @@ -591,6 +591,113 @@ namespace Tins { std::list _options; }; + /** + * \brief Class that models the RSN information structure. + */ + class RSNInformation { + public: + /** + * \brief Enum that represents the different cypher suites. + */ + enum CypherSuites { + WEP_40 = 0x01ac0f00, + TKIP = 0x02ac0f00, + CCMP = 0x04ac0f00, + WEP_104 = 0x05ac0f00 + }; + + /** + * \brief Enum that represents the different akm suites. + */ + enum AKMSuites { + PMKSA = 0x01ac0f00, + PSK = 0x02ac0f00 + }; + + /** + * \brief Creates an instance of RSNInformation. + * + * By default, the version is set to 1. + */ + RSNInformation(); + + /** + * \brief Helper function to create a WPA2-PSK RSNInformation + * \return An instance RSNInformation which contains information + * for a WPA2-PSK AP. + */ + static RSNInformation wpa2_psk(); + + /** + * \brief Adds a pairwise cypher suite. + * \param cypher The pairwise cypher suite to be added. + */ + void add_pairwise_cypher(CypherSuites cypher); + + /** + * \brief Adds a akm suite. + * \param akm The akm suite to be added. + */ + void add_akm_cypher(AKMSuites akm); + + /** + * \brief Sets the group suite cypher. + * \param group The group suite cypher to be set. + */ + void group_suite(CypherSuites group); + + /** + * \brief Sets the version. + * \param ver The version to be set. + */ + void version(uint16_t ver); + + /** + * \brief Sets the capabilities field. + * \param cap The capabilities to be set. + */ + void capabilities(uint16_t cap); + + /* Getters */ + + /** + * \brief Getter for the group suite field. + * \return The group suite field. + */ + inline CypherSuites group_suite() const { return _group_suite; } + + /** + * \brief Getter for the version field. + * \return The version field. + */ + inline uint16_t version() const { return _version; } + + /** + * \brief Getter for the pairwise cypher suite list. + * \return A list of pairwise cypher suites. + */ + inline const std::list &pairwise_cyphers() const { return _pairwise_cyphers; } + + /** + * \brief Getter for the akm suite list. + * \return A list of akm suites. + */ + inline const std::list &akm_cyphers() const { return _akm_cyphers; } + + /** + * \brief Serializes this object. + * \param size Output parameter which will contain the size of + * the allocated buffer. + * \return The result of the serialization. This pointer should + * be free'd using operator delete[]. + */ + uint8_t *serialize(uint32_t &size) const; + private: + uint16_t _version, _capabilities; + CypherSuites _group_suite; + std::list _akm_cyphers; + std::list _pairwise_cyphers; + }; /** * \brief Abstract class that englobes all Management frames in the 802.11 protocol. @@ -889,118 +996,23 @@ namespace Tins { ManagementFrame(const std::string &iface, const uint8_t *dst_hw_addr, const uint8_t *src_hw_addr) throw (std::runtime_error); ManagementFrame(const uint8_t *buffer, uint32_t total_sz); + void ssid(const std::string &new_ssid); + void rates(const std::list &new_rates); + void channel(uint8_t new_channel); + void rsn_information(const RSNInformation& info); + void supported_rates(const std::list &new_rates); + void extended_supported_rates(const std::list &new_rates); + void qos_capabilities(uint8_t new_qos_capabilities); + void power_capabilities(uint8_t min_power, uint8_t max_power); + void supported_channels(const std::list > &new_channels); + void edca_parameter_set(uint32_t ac_be, uint32_t ac_bk, uint32_t ac_vi, uint32_t ac_vo); + + private: }; - /** - * \brief Class that models the RSN information structure. - */ - class RSNInformation { - public: - /** - * \brief Enum that represents the different cypher suites. - */ - enum CypherSuites { - WEP_40 = 0x01ac0f00, - TKIP = 0x02ac0f00, - CCMP = 0x04ac0f00, - WEP_104 = 0x05ac0f00 - }; - - /** - * \brief Enum that represents the different akm suites. - */ - enum AKMSuites { - PMKSA = 0x01ac0f00, - PSK = 0x02ac0f00 - }; - - /** - * \brief Creates an instance of RSNInformation. - * - * By default, the version is set to 1. - */ - RSNInformation(); - - /** - * \brief Helper function to create a WPA2-PSK RSNInformation - * \return An instance RSNInformation which contains information - * for a WPA2-PSK AP. - */ - static RSNInformation wpa2_psk(); - - /** - * \brief Adds a pairwise cypher suite. - * \param cypher The pairwise cypher suite to be added. - */ - void add_pairwise_cypher(CypherSuites cypher); - - /** - * \brief Adds a akm suite. - * \param akm The akm suite to be added. - */ - void add_akm_cypher(AKMSuites akm); - - /** - * \brief Sets the group suite cypher. - * \param group The group suite cypher to be set. - */ - void group_suite(CypherSuites group); - - /** - * \brief Sets the version. - * \param ver The version to be set. - */ - void version(uint16_t ver); - - /** - * \brief Sets the capabilities field. - * \param cap The capabilities to be set. - */ - void capabilities(uint16_t cap); - - /* Getters */ - - /** - * \brief Getter for the group suite field. - * \return The group suite field. - */ - inline CypherSuites group_suite() const { return _group_suite; } - - /** - * \brief Getter for the version field. - * \return The version field. - */ - inline uint16_t version() const { return _version; } - - /** - * \brief Getter for the pairwise cypher suite list. - * \return A list of pairwise cypher suites. - */ - inline const std::list &pairwise_cyphers() const { return _pairwise_cyphers; } - - /** - * \brief Getter for the akm suite list. - * \return A list of akm suites. - */ - inline const std::list &akm_cyphers() const { return _akm_cyphers; } - - /** - * \brief Serializes this object. - * \param size Output parameter which will contain the size of - * the allocated buffer. - * \return The result of the serialization. This pointer should - * be free'd using operator delete[]. - */ - uint8_t *serialize(uint32_t &size) const; - private: - uint16_t _version, _capabilities; - CypherSuites _group_suite; - std::list _akm_cyphers; - std::list _pairwise_cyphers; - }; /** * \brief Class representing a Beacon in the IEEE 802.11 Protocol. @@ -1227,7 +1239,7 @@ namespace Tins { IEEE802_11_Assoc_Request(const std::string& iface, const uint8_t* dst_hw_addr = 0, const uint8_t* src_hw_addr = 0) throw (std::runtime_error); /** - * \brief Constructor which creates a IEEE802_11_Assoc_Request object from a + * \brief Constructor which creates a IEEE802_11_Assoc_Request object from a * buffer and adds all identifiable PDUs found in the buffer as children of this one. * * \param buffer The buffer from which this PDU will be constructed. @@ -1331,6 +1343,126 @@ namespace Tins { AssocReqBody _body; }; + /** + * \brief Class representing an Association Response frame in the IEEE 802.11 Protocol. + * + */ + class IEEE802_11_Assoc_Response : public ManagementFrame { + + public: + + /** + * \brief Default constructor for the Association Response frame. + * + */ + IEEE802_11_Assoc_Response(); + + /** + * \brief Constructor for creating a 802.11 Association Response. + * + * Constructor that builds a 802.11 Association Response taking the interface name, + * destination's and source's MAC. + * + * \param iface string containing the interface's name from where to send the packet. + * \param dst_hw_addr uint8_t array of 6 bytes containing the destination's MAC(optional). + * \param src_hw_addr uint8_t array of 6 bytes containing the source's MAC(optional). + */ + IEEE802_11_Assoc_Response(const std::string& iface, const uint8_t* dst_hw_addr = 0, const uint8_t* src_hw_addr = 0) throw (std::runtime_error); + + /** + * \brief Constructor which creates a IEEE802_11_Assoc_Response object from a + * buffer and adds all identifiable PDUs found in the buffer as children of this one. + * + * \param buffer The buffer from which this PDU will be constructed. + * \param total_sz The total size of the buffer. + */ + IEEE802_11_Assoc_Response(const uint8_t *buffer, uint32_t total_sz); + + /** + * \brief Getter for the Capabilities Information. + * + * \return CapabilityInformation Structure in a CapabilityInformation&. + */ + inline const CapabilityInformation& capabilities() const { return this->_body.capability;} + + /** + * \brief Getter for the Capabilities Information. + * + * \return CapabilityInformation Structure in a CapabilityInformation&. + */ + inline CapabilityInformation& capabilities() { return this->_body.capability;} + + /** + * \brief Getter for the status code. + * + * \return The status code in an uint16_t. + */ + inline uint16_t status_code() const { return this->_body.status_code; } + + /** + * \brief Getter for the AID field. + * + * \return The AID field value in an uint16_t. + */ + inline uint16_t aid() const { return this->_body.aid; } + + /** + * \brief Setter for the status code. + * + * \param new_status_code uint16_t with the new status code. + */ + void status_code(uint16_t new_status_code); + + /** + * \brief Setter for the AID field. + * + * \param new_aid uint16_t with the new AID value. + */ + void aid(uint16_t new_aid); + + /** + * \brief Helper method to set the supported rates. + * + * \param new_rates A list of rates to be set. + */ + void supported_rates(const std::list &new_rates); + + /** + * \brief Helper method to set the extended supported rates. + * + * \param new_rates A list of rates to be set. + */ + void extended_supported_rates(const std::list &new_rates); + + /** + * \brief Helper method to set the EDCA Parameter Set. + * + * \param ac_be uint32_t with the value of the ac_be field. + * \param ac_bk uint32_t with the value of the ac_bk field. + * \param ac_vi uint32_t with the value of the ac_vi field. + * \param ac_vo uint32_t with the value of the ac_vo field. + */ + void edca_parameter_set(uint32_t ac_be, uint32_t ac_bk, uint32_t ac_vi, uint32_t ac_vo); + + /** + * \brief Returns the frame's header length. + * + * \return An uint32_t with the header's size. + * \sa PDU::header_size() + */ + uint32_t header_size() const; + private: + struct AssocRespBody { + CapabilityInformation capability; + uint16_t status_code; + uint16_t aid; + }; + + uint32_t write_fixed_parameters(uint8_t *buffer, uint32_t total_sz); + + AssocRespBody _body; + }; + class IEEE802_11_QoS_Data : public IEEE802_11 { public: diff --git a/src/ieee802-11.cpp b/src/ieee802-11.cpp index d99cbe0..e8ab425 100644 --- a/src/ieee802-11.cpp +++ b/src/ieee802-11.cpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #ifndef WIN32 #include @@ -74,7 +74,7 @@ Tins::IEEE802_11::IEEE802_11(const ieee80211_header *header_ptr) : PDU(ETHERTYPE Tins::IEEE802_11::IEEE802_11(const uint8_t *buffer, uint32_t total_sz) : PDU(ETHERTYPE_IP), _options_size(0) { if(total_sz < sizeof(_header.control)) throw std::runtime_error("Not enough size for an IEEE 802.11 header in the buffer."); - uint32_t sz = std::min(sizeof(_header), total_sz); + uint32_t sz = std::min((uint32_t)sizeof(_header), total_sz); std::memcpy(&_header, buffer, sz); buffer += sz; total_sz -= sz; @@ -247,7 +247,7 @@ void Tins::IEEE802_11::write_serialization(uint8_t *buffer, uint32_t total_sz, c Tins::PDU *Tins::IEEE802_11::from_bytes(const uint8_t *buffer, uint32_t total_sz) { // We only need the control field, the length of the PDU will depend on the flags set. - if(total_sz < sizeof(ieee80211_header::control)) + if(total_sz < sizeof(ieee80211_header::control)) throw std::runtime_error("Not enough size for a IEEE 802.11 header in the buffer."); const ieee80211_header *hdr = (const ieee80211_header*)buffer; PDU *ret = 0; @@ -280,6 +280,90 @@ Tins::ManagementFrame::ManagementFrame(const std::string &iface, this->type(IEEE802_11::MANAGEMENT); } +void Tins::ManagementFrame::ssid(const std::string &new_ssid) { + add_tagged_option(IEEE802_11::SSID, new_ssid.size(), (const uint8_t*)new_ssid.c_str()); +} + +void Tins::ManagementFrame::rates(const std::list &new_rates) { + uint8_t *buffer = new uint8_t[new_rates.size()], *ptr = buffer; + for(std::list::const_iterator it = new_rates.begin(); it != new_rates.end(); ++it) { + uint8_t result = 0x80, left = *it / 0.5; + if(*it - left > 0) + left++; + *(ptr++) = (result | left); + } + add_tagged_option(SUPPORTED_RATES, new_rates.size(), buffer); + delete[] buffer; +} + +void Tins::ManagementFrame::channel(uint8_t new_channel) { + add_tagged_option(DS_SET, 1, &new_channel); +} + +void Tins::ManagementFrame::rsn_information(const RSNInformation& info) { + uint32_t size; + uint8_t *buffer = info.serialize(size); + add_tagged_option(RSN, size, buffer); + delete[] buffer; +} + +void Tins::ManagementFrame::supported_rates(const std::list &new_rates) { + uint8_t *buffer = new uint8_t[new_rates.size()], *ptr = buffer; + for(std::list::const_iterator it = new_rates.begin(); it != new_rates.end(); ++it) { + uint8_t result = 0x80, left = *it / 0.5; + if(*it - left > 0) + left++; + *(ptr++) = (result | left); + } + add_tagged_option(SUPPORTED_RATES, new_rates.size(), buffer); + delete[] buffer; +} + +void Tins::ManagementFrame::extended_supported_rates(const std::list &new_rates) { + uint8_t *buffer = new uint8_t[new_rates.size()], *ptr = buffer; + for(std::list::const_iterator it = new_rates.begin(); it != new_rates.end(); ++it) { + uint8_t result = 0x80, left = *it / 0.5; + if(*it - left > 0) + left++; + *(ptr++) = (result | left); + } + add_tagged_option(EXT_SUPPORTED_RATES, new_rates.size(), buffer); + delete[] buffer; +} + +void Tins::ManagementFrame::qos_capabilities(uint8_t new_qos_capabilities) { + add_tagged_option(QOS_CAPABILITY, 1, &new_qos_capabilities); +} + +void Tins::ManagementFrame::power_capabilities(uint8_t min_power, uint8_t max_power) { + uint8_t buffer[2]; + buffer[0] = min_power; + buffer[1] = max_power; + add_tagged_option(POWER_CAPABILITY, 2, buffer); +} + +void Tins::ManagementFrame::supported_channels(const std::list > &new_channels) { + uint8_t* buffer = new uint8_t[new_channels.size() * 2]; + uint8_t* ptr = buffer; + for(std::list >::const_iterator it = new_channels.begin(); it != new_channels.end(); ++it) { + *(ptr++) = it->first; + *(ptr++) = it->second; + } + add_tagged_option(SUPPORTED_CHANNELS, new_channels.size() * 2, buffer); + delete[] buffer; +} + +void Tins::ManagementFrame::edca_parameter_set(uint32_t ac_be, uint32_t ac_bk, uint32_t ac_vi, uint32_t ac_vo) { + uint8_t* buffer = new uint8_t[18]; + buffer[0] = 0; + uint32_t* ptr = (uint32_t*)(buffer + 1); + *(ptr++) = ac_be; + *(ptr++) = ac_bk; + *(ptr++) = ac_vi; + *(ptr++) = ac_vo; + add_tagged_option(EDCA, 18, buffer); + delete[] buffer; +} /* * Beacon @@ -317,30 +401,19 @@ void Tins::IEEE802_11_Beacon::interval(uint16_t new_interval) { } void Tins::IEEE802_11_Beacon::essid(const std::string &new_essid) { - add_tagged_option(IEEE802_11::SSID, new_essid.size(), (const uint8_t*)new_essid.c_str()); + ManagementFrame::ssid(new_essid); } void Tins::IEEE802_11_Beacon::rates(const std::list &new_rates) { - uint8_t *buffer = new uint8_t[new_rates.size()], *ptr = buffer; - for(std::list::const_iterator it = new_rates.begin(); it != new_rates.end(); ++it) { - uint8_t result = 0x80, left = *it / 0.5; - if(*it - left > 0) - left++; - *(ptr++) = (result | left); - } - add_tagged_option(SUPPORTED_RATES, new_rates.size(), buffer); - delete[] buffer; + ManagementFrame::rates(new_rates); } void Tins::IEEE802_11_Beacon::channel(uint8_t new_channel) { - add_tagged_option(DS_SET, 1, &new_channel); + ManagementFrame::channel(new_channel); } void Tins::IEEE802_11_Beacon::rsn_information(const RSNInformation& info) { - uint32_t size; - uint8_t *buffer = info.serialize(size); - add_tagged_option(RSN, size, buffer); - delete[] buffer; + ManagementFrame::rsn_information(info); } string Tins::IEEE802_11_Beacon::essid() const { @@ -488,7 +561,7 @@ Tins::RSNInformation Tins::RSNInformation::wpa2_psk() { return info; } -Tins::IEEE802_11_Assoc_Request::IEEE802_11_Assoc_Request() { +Tins::IEEE802_11_Assoc_Request::IEEE802_11_Assoc_Request() : ManagementFrame() { this->subtype(IEEE802_11::ASSOC_REQ); memset(&_body, 0, sizeof(_body)); } @@ -516,61 +589,31 @@ void Tins::IEEE802_11_Assoc_Request::listen_interval(uint16_t new_listen_interva } void Tins::IEEE802_11_Assoc_Request::ssid(const std::string &new_ssid) { - add_tagged_option(IEEE802_11::SSID, new_ssid.size(), (const uint8_t*)new_ssid.c_str()); + ManagementFrame::ssid(new_ssid); } void Tins::IEEE802_11_Assoc_Request::supported_rates(const std::list &new_rates) { - uint8_t *buffer = new uint8_t[new_rates.size()], *ptr = buffer; - for(std::list::const_iterator it = new_rates.begin(); it != new_rates.end(); ++it) { - uint8_t result = 0x80, left = *it / 0.5; - if(*it - left > 0) - left++; - *(ptr++) = (result | left); - } - add_tagged_option(SUPPORTED_RATES, new_rates.size(), buffer); - delete[] buffer; + ManagementFrame::supported_rates(new_rates); } void Tins::IEEE802_11_Assoc_Request::extended_supported_rates(const std::list &new_rates) { - uint8_t *buffer = new uint8_t[new_rates.size()], *ptr = buffer; - for(std::list::const_iterator it = new_rates.begin(); it != new_rates.end(); ++it) { - uint8_t result = 0x80, left = *it / 0.5; - if(*it - left > 0) - left++; - *(ptr++) = (result | left); - } - add_tagged_option(EXT_SUPPORTED_RATES, new_rates.size(), buffer); - delete[] buffer; + ManagementFrame::extended_supported_rates(new_rates); } void Tins::IEEE802_11_Assoc_Request::power_capabilities(uint8_t min_power, uint8_t max_power) { - uint8_t buffer[2]; - buffer[0] = min_power; - buffer[1] = max_power; - add_tagged_option(POWER_CAPABILITY, 2, buffer); + ManagementFrame::power_capabilities(min_power, max_power); } void Tins::IEEE802_11_Assoc_Request::supported_channels(const std::list > &new_channels) { - - uint8_t* buffer = new uint8_t[new_channels.size() * 2]; - uint8_t* ptr = buffer; - for(std::list >::const_iterator it = new_channels.begin(); it != new_channels.end(); ++it) { - *(ptr++) = it->first; - *(ptr++) = it->second; - } - add_tagged_option(SUPPORTED_CHANNELS, new_channels.size() * 2, buffer); - + ManagementFrame::supported_channels(new_channels); } void Tins::IEEE802_11_Assoc_Request::rsn_information(const RSNInformation& info) { - uint32_t size; - uint8_t *buffer = info.serialize(size); - add_tagged_option(RSN, size, buffer); - delete[] buffer; + ManagementFrame::rsn_information(info); } void Tins::IEEE802_11_Assoc_Request::qos_capabilities(uint8_t new_qos_capabilities) { - add_tagged_option(QOS_CAPABILITY, 1, &new_qos_capabilities); + ManagementFrame::qos_capabilities(new_qos_capabilities); } uint32_t Tins::IEEE802_11_Assoc_Request::header_size() const { @@ -584,6 +627,60 @@ uint32_t Tins::IEEE802_11_Assoc_Request::write_fixed_parameters(uint8_t *buffer, return sz; } +Tins::IEEE802_11_Assoc_Response::IEEE802_11_Assoc_Response() : ManagementFrame() { + this->subtype(IEEE802_11::ASSOC_RESP); + memset(&_body, 0, sizeof(_body)); +} + +Tins::IEEE802_11_Assoc_Response::IEEE802_11_Assoc_Response(const std::string& iface, + const uint8_t* dst_hw_addr, + const uint8_t* src_hw_addr) throw (std::runtime_error) : ManagementFrame(iface, dst_hw_addr, src_hw_addr) { + this->subtype(IEEE802_11::ASSOC_RESP); + memset(&_body, 0, sizeof(_body)); +} + +Tins::IEEE802_11_Assoc_Response::IEEE802_11_Assoc_Response(const uint8_t *buffer, uint32_t total_sz) : ManagementFrame(buffer, total_sz) { + buffer += sizeof(ieee80211_header); + total_sz -= sizeof(ieee80211_header); + if(total_sz < sizeof(_body)) + throw std::runtime_error("Not enough size for an IEEE 802.11 association response header in the buffer."); + memcpy(&_body, buffer, sizeof(_body)); + buffer += sizeof(_body); + total_sz -= sizeof(_body); + parse_tagged_parameters(buffer, total_sz); +} + +void Tins::IEEE802_11_Assoc_Response::status_code(uint16_t new_status_code) { + this->_body.status_code = new_status_code; +} + +void Tins::IEEE802_11_Assoc_Response::aid(uint16_t new_aid) { + this->_body.aid = new_aid; +} + +void Tins::IEEE802_11_Assoc_Response::supported_rates(const std::list &new_rates) { + ManagementFrame::supported_rates(new_rates); +} + +void Tins::IEEE802_11_Assoc_Response::extended_supported_rates(const std::list &new_rates) { + ManagementFrame::extended_supported_rates(new_rates); +} + +void Tins::IEEE802_11_Assoc_Response::edca_parameter_set(uint32_t ac_be, uint32_t ac_bk, uint32_t ac_vi, uint32_t ac_vo) { + ManagementFrame::edca_parameter_set(ac_be, ac_bk, ac_vi, ac_vo); +} + +uint32_t Tins::IEEE802_11_Assoc_Response::header_size() const { + return IEEE802_11::header_size() + sizeof(AssocRespBody); +} + +uint32_t Tins::IEEE802_11_Assoc_Response::write_fixed_parameters(uint8_t *buffer, uint32_t total_sz) { + uint32_t sz = sizeof(AssocRespBody); + assert(sz <= total_sz); + memcpy(buffer, &this->_body, sz); + return sz; +} + Tins::IEEE802_11_QoS_Data::IEEE802_11_QoS_Data(const uint8_t* dst_hw_addr, const uint8_t* src_hw_addr, PDU* child) : IEEE802_11(dst_hw_addr, src_hw_addr, child) { this->type(IEEE802_11::DATA); this->subtype(IEEE802_11::QOS_DATA_DATA);