diff --git a/include/ieee802-11.h b/include/ieee802-11.h new file mode 100644 index 0000000..66d1043 --- /dev/null +++ b/include/ieee802-11.h @@ -0,0 +1,412 @@ +/* + * 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 __IEEE802_11_h +#define __IEEE802_11_h + +#include +#include + +#include "pdu.h" +#include "utils.h" + +namespace Tins { + + /** + * \brief Class representing an 802.11 frame. + */ + class IEEE802_11 : public PDU { + + public: + + /** + * \brief Constructor for creating a 802.11 PDU + * + * Constructor that builds a 802.11 PDU 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). + * \param child PDU* with the PDU contained by the 802.11 PDU (optional). + */ + IEEE802_11(const std::string& iface, const uint8_t* dst_hw_addr = 0, const uint8_t* src_hw_addr = 0, PDU* child = 0) throw (std::runtime_error); + + /** + * \brief Constructor for creating an 802.11 PDU + * + * Constructor that builds an 802.11 PDU taking the interface index, + * destination's and source's MAC. + * + * \param iface_index const uint32_t with the interface's index 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). + * \param child PDU* with the PDU contained by the 802.11 PDU (optional). + */ + IEEE802_11(uint32_t iface_index, const uint8_t* dst_hw_addr = 0, const uint8_t* src_hw_addr = 0, PDU* child = 0); + + /** + * \brief Constructor which creates an 802.11 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(const uint8_t *buffer, uint32_t total_sz); + + /** + * \brief Getter for the protocol version. + * + * \return The protocol version in an uint8_t. + */ + inline uint8_t protocol() const { return this->_header.control.protocol; } + + /** + * \brief Getter for the 802.11 frame's type. + * + * \return The type of the 802.11 frame in an uint8_t. + */ + inline uint8_t type() const { return this->_header.control.type; } + + /** + * \brief Getter for the 802.11 frame's subtype. + * + * \return The subtype of the 802.11 frame in an uint8_t. + */ + inline uint8_t subtype() const { return this->_header.control.subtype; } + + /** + * \brief Getter for the 802.11 frame's "To DS" bit. + * + * \return Boolean indicating if the "To DS" bit is set. + */ + inline bool to_ds() const { return this->_header.control.to_ds; } + + /** + * \brief Getter for the 802.11 frame's "From DS" bit. + * + * \return Boolean indicating if the "From DS" bit is set. + */ + inline bool from_ds() const { return this->_header.control.from_ds; } + + /** + * \brief Getter for the 802.11 frame's "More Frag" bit. + * + * \return Boolean indicating if the "More Frag" bit is set. + */ + inline bool more_frag() const { return this->_header.control.more_frag; } + + /** + * \brief Getter for the 802.11 frame's "Retry" bit. + * + * \return Boolean indicating if the "Retry" bit is set. + */ + inline bool retry() const { return this->_header.control.retry; } + + /** + * \brief Getter for the 802.11 frame's "Power Management" bit. + * + * \return Boolean indicating if the "Power Management" bit is set. + */ + inline bool power_mgmt() const { return this->_header.control.power_mgmt; } + + /** + * \brief Getter for the 802.11 frame's "WEP" bit. + * + * \return Boolean indicating if the "WEP" bit is set. + */ + inline bool wep() const { return this->_header.control.wep; } + + /** + * \brief Getter for the 802.11 frame's "Order" bit. + * + * \return Boolean indicating if the "Order" bit is set. + */ + inline bool order() const { return this->_header.control.order; } + + /** + * \brief Getter for the duration/id field. + * + * \return The value of the duration/id field in an uint16_t. + */ + inline uint16_t duration_id() const { return Utils::net_to_host_s(this->_header.duration_id); } + + /** + * \brief Getter for the destination's address. + * + * \return The destination's address as a constant uint8_t pointer. + */ + inline const uint8_t* dst_addr() const { return this->_header.dst_addr; } + + /** + * \brief Getter for the source's address. + * + * \return The source's address as a constant uint8_t pointer. + */ + inline const uint8_t* src_addr() const { return this->_header.src_addr; } + + /** + * \brief Getter for the filtering's address. + * + * \return The filtering's address as a constant uint8_t pointer. + */ + inline const uint8_t* filter_addr() const { return this->_header.filter_addr; } + + /** + * \brief Getter for the fragment number. + * + * \return The fragment number as an uint8_t. + */ + inline uint8_t frag_num() const { return this->_header.seq_control.frag_number; } + + /** + * \brief Getter for the sequence number. + * + * \return The sequence number as an uint16_t. + */ + inline uint16_t seq_num() const { return Utils::net_to_host_s(this->_header.seq_control.seq_number); } + + /** + * \brief Getter for the optional address. + * + * \return The optional address as a constant uint8_t pointer. + */ + inline const uint8_t* opt_addr() const { return this->_header.opt_addr; } + + /** + * \brief Getter for the interface. + * + * \return The interface's index as an uint32_t. + */ + inline uint32_t iface() const { return this->_iface_index; } + + /** + * \brief Setter for the protocol version. + * + * \param new_proto uint8_t with the new protocol version. + */ + void protocol(uint8_t new_proto); + + /** + * \brief Setter for the 802.11 frame's type. + * + * \param new_type uint8_t with the new type of the 802.11 frame. + */ + void type(uint8_t new_type); + + /** + * \brief Setter for the 802.11 frame's subtype. + * + * \param new_subtype uint8_t with the new subtype of the 802.11 frame. + */ + void subtype(uint8_t new_subtype); + + /** + * \brief Setter for the 802.11 frame's "To DS" bit. + * + * \param new_value bool indicating the new value of the flag. + */ + void to_ds(bool new_value); + + /** + * \brief Setter for the 802.11 frame's "From DS" bit. + * + * \param new_value bool indicating the new value of the flag. + */ + void from_ds(bool new_value); + + /** + * \brief Setter for the 802.11 frame's "More Frag" bit. + * + * \param new_value bool indicating the new value of the flag. + */ + void more_frag(bool new_value); + + /** + * \brief Setter for the 802.11 frame's "Retry" bit. + * + * \param new_value bool indicating the new value of the flag. + */ + void retry(bool new_value); + + /** + * \brief Setter for the 802.11 frame's "Power Management" bit. + * + * \param new_value bool indicating the new value of the flag. + */ + void power_mgmt(bool new_value); + + /** + * \brief Setter for the 802.11 frame's "WEP" bit. + * + * \param new_value bool indicating the new value of the flag. + */ + void wep(bool new_value); + + /** + * \brief Setter for the 802.11 frame's "Order" bit. + * + * \param new_value bool indicating the new value of the flag. + */ + void order(bool new_value); + + /** + * \brief Setter for the duration/id field. + * + * \param new_duration_id uint16_t with the new value of the duration/id field. + */ + void duration_id(uint16_t new_duration_id); + + /** + * \brief Setter for the destination's address. + * + * \param new_dst_addr const uint8_t array of 6 bytes containing the new destination's address. + */ + void dst_addr(const uint8_t* new_dst_addr); + + /** + * \brief Setter for the source's address. + * + * \param new_src_addr const uint8_t array of 6 bytes containing the new source's address. + */ + void src_addr(const uint8_t* new_src_addr); + + /** + * \brief Setter for the filtering's address. + * + * \param new_filter_addr const uint8_t array of 6 bytes containing the new filtering's address. + */ + void filter_addr(const uint8_t* new_filter_addr); + + /** + * \brief Setter for the fragment number. + * + * \param new_frag_num uint8_t with the new fragment number. + */ + void frag_num(uint8_t new_frag_num); + + /** + * \brief Setter for the sequence number. + * + * \param new_seq_num uint16_t with the new sequence number. + */ + void seq_num(uint16_t new_seq_num); + + /** + * \brief Setter for the optional address. + * + * \param new_opt_addr const uint8_t array of 6 bytes containing the new optional address. + */ + void opt_addr(const uint8_t* new_opt_addr); + + /** + * \brief Setter for the interface. + * + * \param new_iface_index uint32_t containing the new interface index. + */ + void iface(uint32_t new_iface_index); + + /** + * \brief Setter for the interface. + * + * \param new_iface string reference containing the new interface name. + */ + void iface(const std::string& new_iface) throw (std::runtime_error); + + /* Virtual methods */ + /** + * \brief Returns the 802.11 frame's header length. + * + * \return An uint32_t with the header's size. + * \sa PDU::header_size() + */ + uint32_t header_size() const; + + /** + * \sa PDU::send() + */ + bool send(PacketSender* sender); + + /** + * \brief Getter for the PDU's type. + * \sa PDU::pdu_type + */ + PDUType pdu_type() const { return PDU::IEEE802_11; } + + private: + /** + * Struct that represents the 802.11 header + */ + struct ieee80211_header { + struct { + #if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int order:1; + unsigned int wep:1; + unsigned int more_data:1; + unsigned int power_mgmt:1; + unsigned int retry:1; + unsigned int more_frag:1; + unsigned int from_ds:1; + unsigned int to_ds:1; + unsigned int subtype:4; + unsigned int type:2; + unsigned int protocol:2; + #elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int protocol:2; + unsigned int type:2; + unsigned int subtype:4; + unsigned int to_ds:1; + unsigned int from_ds:1; + unsigned int more_frag:1; + unsigned int retry:1; + unsigned int power_mgmt:1; + unsigned int more_data:1; + unsigned int wep:1; + unsigned int order:1; + #endif + } control; + uint16_t duration_id; + uint8_t dst_addr[6]; + uint8_t src_addr[6]; + uint8_t filter_addr[6]; + struct { + #if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int seq_number:12; + unsigned int frag_number:4; + #elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int frag_number:4; + unsigned int seq_number:12; + #endif + } seq_control; + uint8_t opt_addr[6]; + + } __attribute__((__packed__)); + + IEEE802_11(const ieee80211_header *header_ptr); + + void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); + + ieee80211_header _header; + uint32_t _iface_index; + }; + +} + +#endif diff --git a/include/pdu.h b/include/pdu.h index 078af65..86ccf16 100644 --- a/include/pdu.h +++ b/include/pdu.h @@ -52,6 +52,7 @@ namespace Tins { enum PDUType { RAW, ETHERNET_II, + IEEE802_11, IP, ARP, TCP, @@ -67,10 +68,10 @@ namespace Tins { * \param next_pdu The child PDU. Can be obviated. */ PDU(uint32_t flag, PDU *next_pdu = 0); - + /** \brief PDU destructor. - * - * Deletes the inner pdu, as a consequence every child pdu is + * + * Deletes the inner pdu, as a consequence every child pdu is * deleted. */ virtual ~PDU(); @@ -159,7 +160,7 @@ namespace Tins { /** \brief Clones this pdu, filling the corresponding header with data * extracted from a buffer. - * + * * \param ptr The pointer to the from from which the data will be extracted. * \param total_sz The size of the buffer. * \return The cloned PDU. @@ -167,15 +168,15 @@ namespace Tins { virtual PDU *clone_packet(const uint8_t *ptr, uint32_t total_sz) { return 0; } protected: /** \brief Serializes this PDU and propagates this action to child PDUs. - * + * * \param buffer The buffer in which to store this PDU's serialization. * \param total_sz The total size of the buffer. * \param parent The parent PDU. Will be 0 if there's the parent does not exist. */ void serialize(uint8_t *buffer, uint32_t total_sz, const PDU *parent); - + /** \brief Clones the inner pdu(if any). - * + * * This method clones the inner pdu using data from a buffer. * \param ptr The pointer from which the child PDU must be cloned. * \param total_sz The total size of the buffer. @@ -194,7 +195,7 @@ namespace Tins { virtual void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) = 0; /** \brief Does the 16 bits sum of all 2 bytes elements between start and end. - * + * * This is the checksum used by IP, UDP and TCP. If there's and odd number of * bytes, the last one is padded and added to the checksum. The checksum is performed * using network endiannes. @@ -203,9 +204,9 @@ namespace Tins { * \return Returns the checksum between start and end(non inclusive). */ static uint32_t do_checksum(uint8_t *start, uint8_t *end); - + /** \brief Performs the pseudo header checksum used in TCP and UDP PDUs. - * + * * \param source_ip The source ip address. * \param dest_ip The destination ip address. * \param len The length to be included in the pseudo header. diff --git a/src/ieee802-11.cpp b/src/ieee802-11.cpp new file mode 100644 index 0000000..183d014 --- /dev/null +++ b/src/ieee802-11.cpp @@ -0,0 +1,167 @@ +/* + * 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 + */ + +#include +#include +#include + +#ifndef WIN32 + #include + #include + #include +#endif + +#include "ieee802-11.h" +#include "rawpdu.h" +#include "utils.h" + +using namespace std; + +Tins::IEEE802_11::IEEE802_11(const std::string& iface, const uint8_t* dst_hw_addr, const uint8_t* src_hw_addr, PDU* child) throw (std::runtime_error) : PDU(ETHERTYPE_IP, child) { + memset(&this->_header, 0, sizeof(ieee80211_header)); + if(dst_hw_addr) + this->dst_addr(dst_hw_addr); + if(src_hw_addr) + this->src_addr(src_hw_addr); + this->iface(iface); + +} + + +Tins::IEEE802_11::IEEE802_11(uint32_t iface_index, const uint8_t* dst_hw_addr, const uint8_t* src_hw_addr, PDU* child) : PDU(ETHERTYPE_IP, child) { + memset(&this->_header, 0, sizeof(ieee80211_header)); + if(dst_hw_addr) + this->dst_addr(dst_hw_addr); + if(src_hw_addr) + this->src_addr(src_hw_addr); + this->iface(iface_index); +} + +Tins::IEEE802_11::IEEE802_11(const uint8_t *buffer, uint32_t total_sz) : PDU(ETHERTYPE_IP) { + +} + +void Tins::IEEE802_11::protocol(uint8_t new_proto) { + this->_header.control.protocol = new_proto; +} + +void Tins::IEEE802_11::type(uint8_t new_type) { + this->_header.control.type = new_type; +} + +void Tins::IEEE802_11::subtype(uint8_t new_subtype) { + this->_header.control.subtype = new_subtype; +} + +void Tins::IEEE802_11::to_ds(bool new_value) { + this->_header.control.to_ds = (new_value)? 1 : 0; +} + +void Tins::IEEE802_11::from_ds(bool new_value) { + this->_header.control.from_ds = (new_value)? 1 : 0; +} + +void Tins::IEEE802_11::more_frag(bool new_value) { + this->_header.control.more_frag = (new_value)? 1 : 0; +} + +void Tins::IEEE802_11::retry(bool new_value) { + this->_header.control.retry = (new_value)? 1 : 0; +} + +void Tins::IEEE802_11::power_mgmt(bool new_value) { + this->_header.control.power_mgmt = (new_value)? 1 : 0; +} + +void Tins::IEEE802_11::wep(bool new_value) { + this->_header.control.wep = (new_value)? 1 : 0; +} + +void Tins::IEEE802_11::order(bool new_value) { + this->_header.control.order = (new_value)? 1 : 0; +} + +void Tins::IEEE802_11::duration_id(uint16_t new_duration_id) { + this->_header.duration_id = Utils::net_to_host_s(new_duration_id); +} + +void Tins::IEEE802_11::dst_addr(const uint8_t* new_dst_addr) { + memcpy(this->_header.dst_addr, new_dst_addr, 6); +} + +void Tins::IEEE802_11::src_addr(const uint8_t* new_src_addr) { + memcpy(this->_header.src_addr, new_src_addr, 6); +} + +void Tins::IEEE802_11::filter_addr(const uint8_t* new_filter_addr) { + memcpy(this->_header.filter_addr, new_filter_addr, 6); +} + +void Tins::IEEE802_11::frag_num(uint8_t new_frag_num) { + this->_header.seq_control.frag_number = new_frag_num; +} + +void Tins::IEEE802_11::seq_num(uint16_t new_seq_num) { + this->_header.seq_control.seq_number = Utils::net_to_host_s(new_seq_num); +} + +void Tins::IEEE802_11::opt_addr(const uint8_t* new_opt_addr) { + memcpy(this->_header.opt_addr, new_opt_addr, 6); +} + +void Tins::IEEE802_11::iface(uint32_t new_iface_index) { + this->_iface_index = new_iface_index; +} + +void Tins::IEEE802_11::iface(const std::string& new_iface) throw (std::runtime_error) { + if (!Tins::Utils::interface_id(new_iface, this->_iface_index)) { + throw std::runtime_error("Invalid interface name!"); + } +} + +uint32_t Tins::IEEE802_11::header_size() const { + return sizeof(ieee80211_header); +} + +bool Tins::IEEE802_11::send(PacketSender* sender) { + struct sockaddr_ll addr; + + memset(&addr, 0, sizeof(struct sockaddr_ll)); + + addr.sll_family = Utils::net_to_host_s(PF_PACKET); + addr.sll_protocol = Utils::net_to_host_s(ETH_P_ALL); + addr.sll_halen = 6; + addr.sll_ifindex = this->_iface_index; + memcpy(&(addr.sll_addr), this->_header.dst_addr, 6); + + return sender->send_l2(this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr)); +} + +void Tins::IEEE802_11::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { + uint32_t my_sz = header_size(); + assert(total_sz >= my_sz); + + memcpy(buffer, &this->_header, sizeof(ieee80211_header)); +} + +Tins::IEEE802_11::IEEE802_11(const ieee80211_header *header_ptr) : PDU(ETHERTYPE_IP) { + +}