diff --git a/include/dot11.h b/include/dot11.h index ee40657..6e786f8 100644 --- a/include/dot11.h +++ b/include/dot11.h @@ -307,7 +307,7 @@ namespace Tins { * * \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); } + inline uint16_t duration_id() const { return this->_header.duration_id; } /** * \brief Getter for the first address. @@ -938,7 +938,7 @@ namespace Tins { * * \return The sequence number as an uint16_t. */ - inline uint16_t seq_num() const { return Utils::net_to_host_s(this->_ext_header.seq_control.seq_number); } + inline uint16_t seq_num() const { return this->_ext_header.seq_control.seq_number; } /** * \brief Getter for the fourth address. @@ -995,11 +995,11 @@ namespace Tins { uint8_t addr3[6]; struct { #if __BYTE_ORDER == __LITTLE_ENDIAN - unsigned int seq_number:12; unsigned int frag_number:4; + unsigned int seq_number:12; #elif __BYTE_ORDER == __BIG_ENDIAN - unsigned int frag_number:4; unsigned int seq_number:12; + unsigned int frag_number:4; #endif } __attribute__((__packed__)) seq_control; } __attribute__((__packed__)); @@ -1042,125 +1042,6 @@ namespace Tins { uint32_t write_ext_header(uint8_t *buffer, uint32_t total_sz); void copy_ext_header(const Dot11ManagementFrame *other); - private: - ExtendedHeader _ext_header; - uint8_t _addr4[6]; - - }; - - class Dot11DataFrame : public Dot11 { - public: - /** - * \brief Constructor which creates a Dot11DataFrame 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. - */ - Dot11DataFrame(uint32_t iface_index, const uint8_t *dst_hw_addr = 0, const uint8_t *src_hw_addr = 0, PDU* child = 0); - Dot11DataFrame(const uint8_t *dst_hw_addr = 0, const uint8_t *src_hw_addr = 0, PDU* child = 0); - Dot11DataFrame(const std::string &iface, const uint8_t *dst_hw_addr, const uint8_t *src_hw_addr, PDU* child = 0) throw (std::runtime_error); - Dot11DataFrame(const uint8_t *buffer, uint32_t total_sz); - Dot11DataFrame(const Dot11DataFrame &other); - /** - * \brief Getter for the second address. - * - * \return The second address as a constant uint8_t pointer. - */ - inline const uint8_t* addr2() const { return this->_ext_header.addr2; } - - /** - * \brief Getter for the third address. - * - * \return The third address as a constant uint8_t pointer. - */ - inline const uint8_t* addr3() const { return this->_ext_header.addr3; } - - /** - * \brief Getter for the fragment number. - * - * \return The fragment number as an uint8_t. - */ - inline uint8_t frag_num() const { return this->_ext_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->_ext_header.seq_control.seq_number); } - - /** - * \brief Getter for the fourth address. - * - * \return The fourth address as a constant uint8_t pointer. - */ - inline const uint8_t* addr4() const { return this->_addr4; } - - /** - * \brief Setter for the second address. - * - * \param new_addr2 const uint8_t array of 6 bytes containing the new second's address. - */ - void addr2(const uint8_t* new_addr2); - - /** - * \brief Setter for the third address. - * - * \param new_addr3 const uint8_t array of 6 bytes containing the new third address. - */ - void addr3(const uint8_t* new_addr3); - - /** - * \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 fourth address. - * - * \param new_addr4 const uint8_t array of 6 bytes containing the new fourth address. - */ - void addr4(const uint8_t* new_addr4); - - /** - * \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; - - /** - * \brief Getter for the PDU's type. - * \sa PDU::pdu_type - */ - PDUType pdu_type() const { return PDU::DOT11_DATA; } - protected: - struct ExtendedHeader { - uint8_t addr2[6]; - uint8_t addr3[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 - } __attribute__((__packed__)) seq_control; - } __attribute__((__packed__)); - - uint32_t write_ext_header(uint8_t *buffer, uint32_t total_sz); - void copy_ext_header(const Dot11DataFrame *other); private: ExtendedHeader _ext_header; @@ -1224,7 +1105,7 @@ namespace Tins { /** * \brief Getter for the interval field. * - * \return Timestamp value in an uint64_t. + * \return Timestamp value in an uint16_t. */ inline uint16_t interval() const { return Utils::net_to_host_s(this->_body.interval); } @@ -1304,6 +1185,19 @@ namespace Tins { * \sa PDU::header_size() */ uint32_t header_size() const; + + /** + * \brief Clones this PDU. + * + * \sa PDU::clone_pdu + */ + PDU *clone_pdu() const; + + /** + * \brief Getter for the PDU's type. + * \sa PDU::pdu_type + */ + PDUType pdu_type() const { return PDU::DOT11_BEACON; } private: struct BeaconBody { uint64_t timestamp; @@ -1374,6 +1268,13 @@ namespace Tins { * \sa PDU::header_size() */ uint32_t header_size() const; + + /** + * \brief Clones this PDU. + * + * \sa PDU::clone_pdu + */ + PDU *clone_pdu() const; private: struct DisassocBody { uint16_t reason_code; @@ -1516,6 +1417,13 @@ namespace Tins { * \sa PDU::header_size() */ uint32_t header_size() const; + + /** + * \brief Clones this PDU. + * + * \sa PDU::clone_pdu + */ + PDU *clone_pdu() const; private: struct AssocReqBody { CapabilityInformation capability; @@ -1646,6 +1554,13 @@ namespace Tins { * \sa PDU::header_size() */ uint32_t header_size() const; + + /** + * \brief Clones this PDU. + * + * \sa PDU::clone_pdu + */ + PDU *clone_pdu() const; private: struct AssocRespBody { CapabilityInformation capability; @@ -1659,303 +1574,129 @@ namespace Tins { AssocRespBody _body; }; - /** - * \brief Class representing an ReAssociation Request frame in the IEEE 802.11 Protocol. - * - */ - class Dot11ReAssocRequest : public Dot11ManagementFrame { - + class Dot11Data : public Dot11 { public: /** - * \brief Default constructor for the ReAssociation Request frame. - * - */ - Dot11ReAssocRequest(); - - /** - * \brief Constructor for creating a 802.11 ReAssociation Request. - * - * Constructor that builds a 802.11 ReAssociation Request 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). - */ - Dot11ReAssocRequest(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 Dot11ReAssocRequest object from a - * buffer and adds all identifiable PDUs found in the buffer as children of this one. - * + * \brief Constructor which creates a Dot11Data 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. */ - Dot11ReAssocRequest(const uint8_t *buffer, uint32_t total_sz); - + Dot11Data(uint32_t iface_index, const uint8_t *dst_hw_addr = 0, const uint8_t *src_hw_addr = 0, PDU* child = 0); + Dot11Data(const uint8_t *dst_hw_addr = 0, const uint8_t *src_hw_addr = 0, PDU* child = 0); + Dot11Data(const std::string &iface, const uint8_t *dst_hw_addr, const uint8_t *src_hw_addr, PDU* child = 0) throw (std::runtime_error); + Dot11Data(const uint8_t *buffer, uint32_t total_sz); /** - * \brief Copy constructor. - */ - Dot11ReAssocRequest(const Dot11ReAssocRequest &other); - - /** - * \brief Copy assignment operator. - */ - Dot11ReAssocRequest &operator= (const Dot11ReAssocRequest &other); - - /** - * \brief Getter for the Capabilities Information. + * \brief Getter for the second address. * - * \return CapabilityInformation Structure in a CapabilityInformation&. + * \return The second address as a constant uint8_t pointer. */ - inline const CapabilityInformation& capabilities() const { return this->_body.capability;} + inline const uint8_t* addr2() const { return this->_ext_header.addr2; } /** - * \brief Getter for the Capabilities Information. + * \brief Getter for the third address. * - * \return CapabilityInformation Structure in a CapabilityInformation&. + * \return The third address as a constant uint8_t pointer. */ - inline CapabilityInformation& capabilities() { return this->_body.capability;} + inline const uint8_t* addr3() const { return this->_ext_header.addr3; } /** - * \brief Getter for the listen interval. + * \brief Getter for the fragment number. * - * \return The listen interval in an uint16_t. + * \return The fragment number as an uint8_t. */ - inline uint16_t listen_interval() const { return this->_body.listen_interval; } + inline uint8_t frag_num() const { return this->_ext_header.seq_control.frag_number; } /** - * \brief Getter for the current AP field. + * \brief Getter for the sequence number. * - * \return The current AP value in an uint8_t*. + * \return The sequence number as an uint16_t. */ - inline const uint8_t* current_ap() const {return this->_body.current_ap; } + inline uint16_t seq_num() const { return this->_ext_header.seq_control.seq_number; } /** - * \brief Setter for the listen interval. + * \brief Getter for the fourth address. * - * \param new_listen_interval uint16_t with the new listen interval. + * \return The fourth address as a constant uint8_t pointer. */ - void listen_interval(uint16_t new_listen_interval); + inline const uint8_t* addr4() const { return this->_addr4; } /** - * \brief Setter for the current AP field. + * \brief Setter for the second address. * - * \param new_current_ap uint8_t array of 6 bytes with the new current_ap + * \param new_addr2 const uint8_t array of 6 bytes containing the new second's address. */ - void current_ap(const uint8_t* new_current_ap); + void addr2(const uint8_t* new_addr2); /** - * \brief Helper method to set the essid. + * \brief Setter for the third address. * - * \param new_ssid The ssid to be set. + * \param new_addr3 const uint8_t array of 6 bytes containing the new third address. */ - void ssid(const std::string &new_ssid); + void addr3(const uint8_t* new_addr3); /** - * \brief Helper method to set the supported rates. + * \brief Setter for the fragment number. * - * \param new_rates A list of rates to be set. + * \param new_frag_num uint8_t with the new fragment number. */ - void supported_rates(const std::list &new_rates); + void frag_num(uint8_t new_frag_num); /** - * \brief Helper method to set the extended supported rates. + * \brief Setter for the sequence number. * - * \param new_rates A list of rates to be set. + * \param new_seq_num uint16_t with the new sequence number. */ - void extended_supported_rates(const std::list &new_rates); + void seq_num(uint16_t new_seq_num); /** - * \brief Helper method to set the power capabilities. + * \brief Setter for the fourth address. * - * \param min_power uint8_t indicating the minimum transmiting power capability. - * \param max_power uint8_t indicating the maximum transmiting power capability. + * \param new_addr4 const uint8_t array of 6 bytes containing the new fourth address. */ - void power_capabilities(uint8_t min_power, uint8_t max_power); + void addr4(const uint8_t* new_addr4); /** - * \brief Helper method to set the supported channels. - * - * \param new_channels A list of channels to be set. - */ - void supported_channels(const std::list > &new_channels); - - /** - * \brief Helper method to set the RSN information option. - * - * \param info The RSNInformation structure to be set. - */ - void rsn_information(const RSNInformation& info); - - /** - * \brief Helper method to set the QoS capabilities. - * - * \param new_qos_capabilities uint8_t with the capabilities. - */ - void qos_capabilities(uint8_t new_qos_capabilities); - - /** - * \brief Returns the frame's header length. + * \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; + /** + * \brief Getter for the PDU's type. + * \sa PDU::pdu_type + */ + PDUType pdu_type() const { return PDU::DOT11_DATA; } + /** + * \brief Clones this PDU. + * + * \sa PDU::clone_pdu + */ + PDU *clone_pdu() const; protected: + struct ExtendedHeader { + uint8_t addr2[6]; + uint8_t addr3[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 + } __attribute__((__packed__)) seq_control; + } __attribute__((__packed__)); - + uint32_t write_ext_header(uint8_t *buffer, uint32_t total_sz); + void copy_ext_header(const Dot11Data *other); private: - struct ReAssocReqBody { - CapabilityInformation capability; - uint16_t listen_interval; - uint8_t current_ap[6]; - }; - - void copy_fields(const Dot11ReAssocRequest* other); - uint32_t write_fixed_parameters(uint8_t* buffer, uint32_t total_sz); - - ReAssocReqBody _body; - - }; - - /** - * \brief Class representing an ReAssociation Response frame in the IEEE 802.11 Protocol. - * - */ - class Dot11ReAssocResponse : public Dot11ManagementFrame { - - public: - /** - * \brief Default constructor for the Association Response frame. - * - */ - Dot11ReAssocResponse(); - - /** - * \brief Constructor for creating a 802.11 ReAssociation Response. - * - * Constructor that builds a 802.11 ReAssociation 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). - */ - Dot11ReAssocResponse(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 Dot11ReAssocResponse 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. - */ - Dot11ReAssocResponse(const uint8_t *buffer, uint32_t total_sz); - - /** - * \brief Copy constructor. - */ - Dot11ReAssocResponse(const Dot11ReAssocResponse &other); - - /** - * \brief Copy assignment operator - */ - Dot11ReAssocResponse &operator= (const Dot11ReAssocResponse &other); - - /** - * \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; - - - protected: - - private: - - struct ReAssocRespBody { - CapabilityInformation capability; - uint16_t status_code; - uint16_t aid; - }; - - void copy_fields(const Dot11ReAssocResponse *other); - uint32_t write_fixed_parameters(uint8_t *buffer, uint32_t total_sz); - - ReAssocRespBody _body; - + ExtendedHeader _ext_header; + uint8_t _addr4[6]; }; /** @@ -2093,7 +1834,7 @@ namespace Tins { }; - class Dot11QoSData : public Dot11DataFrame { + class Dot11QoSData : public Dot11Data { public: @@ -2174,6 +1915,13 @@ namespace Tins { */ uint32_t header_size() const; + /** + * \brief Clones this PDU. + * + * \sa PDU::clone_pdu + */ + PDU *clone_pdu() const; + /** * \brief Getter for the PDU's type. * \sa PDU::pdu_type @@ -2369,6 +2117,13 @@ namespace Tins { */ Dot11RTS(const uint8_t *buffer, uint32_t total_sz); + /** + * \brief Clones this PDU. + * + * \sa PDU::clone_pdu + */ + PDU *clone_pdu() const; + /** * \brief Getter for the PDU's type. * \sa PDU::pdu_type @@ -2422,6 +2177,13 @@ namespace Tins { * \param total_sz The total size of the buffer. */ Dot11PSPoll(const uint8_t *buffer, uint32_t total_sz); + + /** + * \brief Clones this PDU. + * + * \sa PDU::clone_pdu + */ + PDU *clone_pdu() const; }; class Dot11CFEnd : public Dot11ControlTA { @@ -2470,6 +2232,13 @@ namespace Tins { * \param total_sz The total size of the buffer. */ Dot11CFEnd(const uint8_t *buffer, uint32_t total_sz); + + /** + * \brief Clones this PDU. + * + * \sa PDU::clone_pdu + */ + PDU *clone_pdu() const; }; class Dot11EndCFAck : public Dot11ControlTA { @@ -2515,6 +2284,13 @@ namespace Tins { * \param total_sz The total size of the buffer. */ Dot11EndCFAck(const uint8_t *buffer, uint32_t total_sz); + + /** + * \brief Clones this PDU. + * + * \sa PDU::clone_pdu + */ + PDU *clone_pdu() const; }; class Dot11Ack : public Dot11Control { @@ -2567,6 +2343,14 @@ namespace Tins { * \sa PDU::pdu_type */ PDUType pdu_type() const { return PDU::DOT11_ACK; } + + /** + * \brief Clones this PDU. + * + * \sa PDU::clone_pdu + */ + PDU *clone_pdu() const; + }; /** @@ -2650,6 +2434,13 @@ namespace Tins { * \param bar The new start sequence field. */ void start_sequence(uint16_t seq); + + /** + * \brief Clones this PDU. + * + * \sa PDU::clone_pdu + */ + PDU *clone_pdu() const; protected: /** * \brief Getter for the control ta additional fields size. @@ -2746,6 +2537,13 @@ namespace Tins { * \sa PDU::pdu_type */ PDUType pdu_type() const { return PDU::DOT11_BLOCK_ACK; } + + /** + * \brief Clones this PDU. + * + * \sa PDU::clone_pdu + */ + PDU *clone_pdu() const; private: uint32_t write_ext_header(uint8_t *buffer, uint32_t total_sz); diff --git a/include/pdu.h b/include/pdu.h index 7f5ca29..137c2ef 100644 --- a/include/pdu.h +++ b/include/pdu.h @@ -55,6 +55,7 @@ namespace Tins { DOT11, DOT11_DATA, DOT11_QOS_DATA, + DOT11_BEACON, DOT11_CONTROL, DOT11_ACK, DOT11_BLOCK_ACK, @@ -174,7 +175,7 @@ namespace Tins { /* Should be pure virtual. It's this way to avoid compiling issues. * Once every pdu has implemented it, make it pure virtual. */ return 0; - } + } /** \brief Send the stack of PDUs through a PacketSender. * @@ -259,27 +260,6 @@ namespace Tins { * \param parent The PDU that's one level below this one on the stack. Might be 0. */ 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. - * \param start The pointer to the start of the buffer. - * \param end The pointer to the end of the buffer(excluding the last element). - * \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. - * \param flag The flag to use in the protocol field of the pseudo header. - * \return The pseudo header checksum. - */ - static uint32_t pseudoheader_checksum(uint32_t source_ip, uint32_t dest_ip, uint32_t len, uint32_t flag); private: uint32_t _flag; PDU *_inner_pdu; diff --git a/include/radiotap.h b/include/radiotap.h index ef08d7b..f0985f0 100644 --- a/include/radiotap.h +++ b/include/radiotap.h @@ -29,6 +29,11 @@ namespace Tins { /** * \brief Class that represents the IEEE 802.11 radio tap header. + * + * By default, RadioTap PDUs set the necesary fields to send an 802.11 + * PDU as its inner pdu, avoiding packet drops. As a consequence, + * the FCS-at-end flag is on, the channel is set to 1, TSFT is set to 0, + * dbm_signal is set to 0xce, and the rx_flag and antenna fields to 0. */ class RadioTap : public PDU { public: @@ -88,14 +93,16 @@ namespace Tins { /** * \brief Creates an instance of RadioTap. * \param iface The name of the interface in which to send this PDU. + * \param child The child PDU.(optional) */ - RadioTap(const std::string &iface) throw (std::runtime_error); + RadioTap(const std::string &iface, PDU *child = 0) throw (std::runtime_error); /** * \brief Creates an instance of RadioTap. * \param iface_index The index of the interface in which to send this PDU. + * \param child The child PDU.(optional) */ - RadioTap(uint32_t iface_index); + RadioTap(uint32_t iface_index, PDU *child = 0); /** * \brief Constructor which creates a RadioTap object from a buffer and adds all @@ -297,6 +304,7 @@ namespace Tins { ext:1; } __attribute__((__packed__)); + void init(); void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); diff --git a/include/sniffer.h b/include/sniffer.h index 8782d8f..7e1ebbe 100644 --- a/include/sniffer.h +++ b/include/sniffer.h @@ -26,6 +26,7 @@ #include #include +#include #include "pdu.h" namespace Tins { @@ -65,8 +66,9 @@ namespace Tins { * \brief Creates an instance of sniffer. * \param device The device which will be sniffed. * \param max_packet_size The maximum packet size to be read. + * \param filter A capture filter to compile and use for sniffing sessions.(optional); */ - Sniffer(const std::string &device, unsigned max_packet_size); + Sniffer(const std::string &device, unsigned max_packet_size, const std::string &filter = "") throw(std::runtime_error); /** * \brief Sniffer destructor. @@ -77,15 +79,13 @@ namespace Tins { /** * \brief Compiles a filter and uses it to capture one packet. * - * This method returns the first sniffed PDU that matches the given - * filter. If no filter is given, the previously set filter will be used. - * If no filter has been set, then no filtering is applied to sniffed - * packets. - * \param filter The filter which will be used while sniffing. + * This method returns the first sniffed packet that matches the + * sniffer's filter, or the first sniffed packet if no filter has + * been set. * \return The captured packet, matching the given filter, 0 if an * error occured(probably compiling the filter). */ - PDU *next_packet(const std::string &filter = ""); + PDU *next_packet(); /** * \brief Starts a sniffing loop, using a callback object for every @@ -95,10 +95,9 @@ namespace Tins { * or it could be a specific SnifferHandler specialization. This method deletes * packets after they are handled, therefore the handlers MUST NOT delete them. * \param cback_handler The callback handler object which should process packets. - * \param filter The filter to use when sniffing(optional). * \param max_packets The maximum amount of packets to sniff. 0 == infinite. */ - void sniff_loop(AbstractSnifferHandler *cback_handler, const std::string &filter = "", uint32_t max_packets = 0); + void sniff_loop(AbstractSnifferHandler *cback_handler, uint32_t max_packets = 0); /** * \brief Sets a filter on this sniffer. diff --git a/include/tcp.h b/include/tcp.h index 99cd572..c091a66 100644 --- a/include/tcp.h +++ b/include/tcp.h @@ -368,6 +368,8 @@ namespace Tins { static const uint16_t DEFAULT_WINDOW; void copy_fields(const TCP *other); + + void cleanup(); /** \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. diff --git a/include/utils.h b/include/utils.h index 9c82b97..16f13f4 100644 --- a/include/utils.h +++ b/include/utils.h @@ -177,6 +177,27 @@ namespace Tins { */ uint16_t channel_to_mhz(uint16_t channel); + /** \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. + * \param start The pointer to the start of the buffer. + * \param end The pointer to the end of the buffer(excluding the last element). + * \return Returns the checksum between start and end(non inclusive). + */ + 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. + * \param flag The flag to use in the protocol field of the pseudo header. + * \return The pseudo header checksum. + */ + uint32_t pseudoheader_checksum(uint32_t source_ip, uint32_t dest_ip, uint32_t len, uint32_t flag); + /** \brief Generic function to iterate through interface and collect * data. * diff --git a/src/dot11.cpp b/src/dot11.cpp index 893a0f0..79b99c2 100644 --- a/src/dot11.cpp +++ b/src/dot11.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #ifndef WIN32 #include #include @@ -42,8 +43,10 @@ const uint8_t *Tins::Dot11::BROADCAST = (const uint8_t*)"\xff\xff\xff\xff\xff\xf Tins::Dot11::Dot11(const uint8_t* dst_hw_addr, PDU* child) : PDU(ETHERTYPE_IP, child), _options_size(0) { memset(&this->_header, 0, sizeof(ieee80211_header)); - if(dst_hw_addr) + if(dst_hw_addr) { + this->addr1(dst_hw_addr); + } } Tins::Dot11::Dot11(const std::string& iface, const uint8_t* dst_hw_addr, PDU* child) throw (std::runtime_error) : PDU(ETHERTYPE_IP, child), _options_size(0) { @@ -72,10 +75,6 @@ Tins::Dot11::Dot11(const uint8_t *buffer, uint32_t total_sz) : PDU(ETHERTYPE_IP) std::memcpy(&_header, buffer, sz); buffer += sz; total_sz -= sz; - if(type() == 2 && subtype() < 4) { - // It's a data packet - inner_pdu(new Tins::SNAP(buffer, total_sz)); - } } Tins::Dot11::Dot11(const Dot11 &other) : PDU(other) { @@ -169,7 +168,7 @@ void Tins::Dot11::order(bool new_value) { } void Tins::Dot11::duration_id(uint16_t new_duration_id) { - this->_header.duration_id = Utils::net_to_host_s(new_duration_id); + this->_header.duration_id = new_duration_id; } void Tins::Dot11::addr1(const uint8_t* new_addr1) { @@ -240,7 +239,7 @@ Tins::PDU *Tins::Dot11::from_bytes(const uint8_t *buffer, uint32_t total_sz) { } else if(hdr->control.type == DATA){ if(hdr->control.subtype <= 4) - ret = new Dot11DataFrame(buffer, total_sz); + ret = new Dot11Data(buffer, total_sz); else ret = new Dot11QoSData(buffer, total_sz); } @@ -273,12 +272,16 @@ void Tins::Dot11::copy_80211_fields(const Dot11 *other) { _options.push_back(Dot11_Option(it->option, it->length, it->value)); } -/* - * Dot11ManagementFrame - */ +/* Dot11ManagementFrame */ Tins::Dot11ManagementFrame::Dot11ManagementFrame(const uint8_t *buffer, uint32_t total_sz) : Dot11(buffer, total_sz) { - + buffer += sizeof(ieee80211_header); + total_sz -= sizeof(ieee80211_header); + if(total_sz < sizeof(_ext_header)) + throw std::runtime_error("Not enough size for an IEEE 802.11 header in the buffer."); + std::memcpy(&_ext_header, buffer, sizeof(_ext_header)); + if(from_ds() && to_ds()) + std::memcpy(_addr4, buffer + sizeof(_ext_header), sizeof(_addr4)); } Tins::Dot11ManagementFrame::Dot11ManagementFrame(const uint8_t *dst_hw_addr, const uint8_t *src_hw_addr) : Dot11(dst_hw_addr) { @@ -290,8 +293,8 @@ Tins::Dot11ManagementFrame::Dot11ManagementFrame(const uint8_t *dst_hw_addr, con } Tins::Dot11ManagementFrame::Dot11ManagementFrame(const std::string &iface, - const uint8_t *dst_hw_addr, - const uint8_t *src_hw_addr) throw (std::runtime_error) : Dot11(iface, dst_hw_addr) { + const uint8_t *dst_hw_addr, + const uint8_t *src_hw_addr) throw (std::runtime_error) : Dot11(iface, dst_hw_addr) { this->type(Dot11::MANAGEMENT); if(src_hw_addr) addr2(src_hw_addr); @@ -329,7 +332,7 @@ void Tins::Dot11ManagementFrame::frag_num(uint8_t new_frag_num) { } void Tins::Dot11ManagementFrame::seq_num(uint16_t new_seq_num) { - this->_ext_header.seq_control.seq_number = Utils::net_to_host_s(new_seq_num); + this->_ext_header.seq_control.seq_number = new_seq_num; } void Tins::Dot11ManagementFrame::addr4(const uint8_t* new_addr4) { @@ -589,82 +592,6 @@ void Tins::Dot11ManagementFrame::tpc_report(uint8_t transmit_power, uint8_t link } -/* - * Dot11DataFrame - */ - -Tins::Dot11DataFrame::Dot11DataFrame(const uint8_t *buffer, uint32_t total_sz) : Dot11(buffer, total_sz) { - -} - -Tins::Dot11DataFrame::Dot11DataFrame(uint32_t iface_index, const uint8_t *dst_hw_addr, const uint8_t *src_hw_addr, PDU* child) : Dot11(iface_index, dst_hw_addr, child) { - this->type(Dot11::DATA); - this->addr2(src_hw_addr); -} - -Tins::Dot11DataFrame::Dot11DataFrame(const uint8_t *dst_hw_addr, const uint8_t *src_hw_addr, PDU* child) : Dot11(dst_hw_addr, child) { - this->type(Dot11::DATA); - this->addr2(src_hw_addr); -} - - -Tins::Dot11DataFrame::Dot11DataFrame(const std::string &iface, - const uint8_t *dst_hw_addr, - const uint8_t *src_hw_addr, - PDU* child) throw (std::runtime_error) : Dot11(iface, dst_hw_addr, child) { - this->type(Dot11::DATA); - this->addr2(src_hw_addr); -} - -Tins::Dot11DataFrame::Dot11DataFrame(const Dot11DataFrame &other) : Dot11(other) { - -} - -void Tins::Dot11DataFrame::copy_ext_header(const Dot11DataFrame* other) { - Dot11::copy_80211_fields(other); - std::memcpy(&this->_ext_header, &other->_ext_header, sizeof(this->_ext_header)); - std::memcpy(this->_addr4, other->_addr4, 6); -} - -uint32_t Tins::Dot11DataFrame::header_size() const { - uint32_t sz = Dot11::header_size() + sizeof(_ext_header); - if (this->from_ds() && this->to_ds()) - sz += 6; - return sz; -} - -void Tins::Dot11DataFrame::addr2(const uint8_t* new_addr2) { - memcpy(this->_ext_header.addr2, new_addr2, 6); -} - -void Tins::Dot11DataFrame::addr3(const uint8_t* new_addr3) { - memcpy(this->_ext_header.addr3, new_addr3, 6); -} - -void Tins::Dot11DataFrame::frag_num(uint8_t new_frag_num) { - this->_ext_header.seq_control.frag_number = new_frag_num; -} - -void Tins::Dot11DataFrame::seq_num(uint16_t new_seq_num) { - this->_ext_header.seq_control.seq_number = Utils::net_to_host_s(new_seq_num); -} - -void Tins::Dot11DataFrame::addr4(const uint8_t* new_addr4) { - memcpy(this->_addr4, new_addr4, 6); -} - -uint32_t Tins::Dot11DataFrame::write_ext_header(uint8_t *buffer, uint32_t total_sz) { - uint32_t written = sizeof(this->_ext_header); - memcpy(buffer, &this->_ext_header, sizeof(this->_ext_header)); - buffer += sizeof(this->_ext_header); - if (this->from_ds() && this->to_ds()) { - written += 6; - memcpy(buffer, this->_addr4, 6); - } - return written; - -} - /* Dot11Beacon */ Tins::Dot11Beacon::Dot11Beacon(const uint8_t* dst_hw_addr, const uint8_t* src_hw_addr) : Dot11ManagementFrame() { @@ -680,8 +607,9 @@ Tins::Dot11Beacon::Dot11Beacon(const std::string& iface, } Tins::Dot11Beacon::Dot11Beacon(const uint8_t *buffer, uint32_t total_sz) : Dot11ManagementFrame(buffer, total_sz) { - buffer += sizeof(ieee80211_header); - total_sz -= sizeof(ieee80211_header); + uint32_t sz = Dot11ManagementFrame::header_size(); + buffer += sz; + total_sz -= sz; if(total_sz < sizeof(_body)) throw std::runtime_error("Not enough size for a IEEE 802.11 beacon header in the buffer."); memcpy(&_body, buffer, sizeof(_body)); @@ -786,6 +714,12 @@ uint32_t Tins::Dot11Beacon::write_fixed_parameters(uint8_t *buffer, uint32_t tot return sz; } +Tins::PDU *Tins::Dot11Beacon::clone_pdu() const { + Dot11Beacon *new_pdu = new Dot11Beacon(); + new_pdu->copy_80211_fields(this); + return new_pdu; +} + /* 802.11 diassoc */ Tins::Dot11Disassoc::Dot11Disassoc() : Dot11ManagementFrame() { @@ -830,9 +764,14 @@ uint32_t Tins::Dot11Disassoc::write_fixed_parameters(uint8_t *buffer, uint32_t t return sz; } -/* - * RSNInformation class - */ +Tins::PDU *Tins::Dot11Disassoc::clone_pdu() const { + Dot11Disassoc *new_pdu = new Dot11Disassoc(); + new_pdu->copy_80211_fields(this); + return new_pdu; +} + +/* RSNInformation */ + Tins::RSNInformation::RSNInformation() : _version(1), _capabilities(0) { } @@ -906,8 +845,9 @@ Tins::Dot11AssocRequest::Dot11AssocRequest(const std::string& iface, } Tins::Dot11AssocRequest::Dot11AssocRequest(const uint8_t *buffer, uint32_t total_sz) : Dot11ManagementFrame(buffer, total_sz) { - buffer += sizeof(ieee80211_header); - total_sz -= sizeof(ieee80211_header); + uint32_t sz = Dot11ManagementFrame::header_size(); + buffer += sz; + total_sz -= sz; if(total_sz < sizeof(_body)) throw std::runtime_error("Not enough size for an IEEE 802.11 association header in the buffer."); memcpy(&_body, buffer, sizeof(_body)); @@ -974,6 +914,12 @@ uint32_t Tins::Dot11AssocRequest::write_fixed_parameters(uint8_t *buffer, uint32 return sz; } +Tins::PDU *Tins::Dot11AssocRequest::clone_pdu() const { + Dot11AssocRequest *new_pdu = new Dot11AssocRequest(); + new_pdu->copy_80211_fields(this); + return new_pdu; +} + /* Assoc response. */ Tins::Dot11AssocResponse::Dot11AssocResponse() : Dot11ManagementFrame() { @@ -1045,164 +991,116 @@ uint32_t Tins::Dot11AssocResponse::write_fixed_parameters(uint8_t *buffer, uint3 return sz; } -/* ReAssoc Request */ - -Tins::Dot11ReAssocRequest::Dot11ReAssocRequest() : Dot11ManagementFrame() { - this->subtype(Dot11::REASSOC_REQ); - memset(&_body, 0, sizeof(_body)); +Tins::PDU *Tins::Dot11AssocResponse::clone_pdu() const { + Dot11AssocResponse *new_pdu = new Dot11AssocResponse(); + new_pdu->copy_80211_fields(this); + return new_pdu; } -Tins::Dot11ReAssocRequest::Dot11ReAssocRequest(const std::string& iface, - const uint8_t* dst_hw_addr, - const uint8_t* src_hw_addr) throw (std::runtime_error) : Dot11ManagementFrame(iface, dst_hw_addr, src_hw_addr) { - this->subtype(Dot11::REASSOC_REQ); - memset(&_body, 0, sizeof(_body)); -} +/* Dot11Data */ -Tins::Dot11ReAssocRequest::Dot11ReAssocRequest(const uint8_t *buffer, uint32_t total_sz) : Dot11ManagementFrame(buffer, total_sz) { - uint32_t sz = Dot11ManagementFrame::header_size(); +Tins::Dot11Data::Dot11Data(const uint8_t *buffer, uint32_t total_sz) : Dot11(buffer, total_sz) { + uint32_t sz = Dot11::header_size(); buffer += sz; total_sz -= sz; - if(total_sz < sizeof(_body)) - throw std::runtime_error("Not enough size for an IEEE 802.11 association header in the buffer."); - memcpy(&_body, buffer, sizeof(_body)); - buffer += sizeof(_body); - total_sz -= sizeof(_body); - parse_tagged_parameters(buffer, total_sz); + if(total_sz < sizeof(_ext_header)) + throw std::runtime_error("Not enough size for an IEEE 802.11 data header in the buffer."); + std::memcpy(&_ext_header, buffer, sizeof(_ext_header)); + buffer += sizeof(_ext_header); + total_sz -= sizeof(_ext_header); + if(from_ds() && to_ds()) { + if(total_sz < sizeof(_addr4)) + throw std::runtime_error("Not enough size for an IEEE 802.11 data header in the buffer."); + std::memcpy(&_addr4, buffer, sizeof(_addr4)); + buffer += sizeof(_addr4); + total_sz -= sizeof(_addr4); + } + inner_pdu(new Tins::SNAP(buffer, total_sz)); } -Tins::Dot11ReAssocRequest::Dot11ReAssocRequest(const Dot11ReAssocRequest &other) : Dot11ManagementFrame(other) { - copy_fields(&other); +Tins::Dot11Data::Dot11Data(uint32_t iface_index, const uint8_t *dst_hw_addr, const uint8_t *src_hw_addr, PDU* child) : Dot11(iface_index, dst_hw_addr, child) { + this->type(Dot11::DATA); + if(src_hw_addr) + this->addr2(src_hw_addr); + else + std::memset(_ext_header.addr2, 0, sizeof(_ext_header.addr2)); } -Tins::Dot11ReAssocRequest &Tins::Dot11ReAssocRequest::operator= (const Dot11ReAssocRequest &other) { - copy_inner_pdu(other); - copy_fields(&other); - return *this; +Tins::Dot11Data::Dot11Data(const uint8_t *dst_hw_addr, const uint8_t *src_hw_addr, PDU* child) : Dot11(dst_hw_addr, child) { + this->type(Dot11::DATA); + if(src_hw_addr) + this->addr2(src_hw_addr); + else + std::memset(_ext_header.addr2, 0, sizeof(_ext_header.addr2)); } -void Tins::Dot11ReAssocRequest::copy_fields(const Dot11ReAssocRequest *other) { - Dot11ManagementFrame::copy_ext_header(other); - std::memcpy(&_body, &other->_body, sizeof(_body)); + +Tins::Dot11Data::Dot11Data(const std::string &iface, + const uint8_t *dst_hw_addr, + const uint8_t *src_hw_addr, + PDU* child) throw (std::runtime_error) : Dot11(iface, dst_hw_addr, child) { + this->type(Dot11::DATA); + if(src_hw_addr) + this->addr2(src_hw_addr); + else + std::memset(_ext_header.addr2, 0, sizeof(_ext_header.addr2)); } -void Tins::Dot11ReAssocRequest::listen_interval(uint16_t new_listen_interval) { - this->_body.listen_interval = new_listen_interval; +void Tins::Dot11Data::copy_ext_header(const Dot11Data* other) { + Dot11::copy_80211_fields(other); + std::memcpy(&this->_ext_header, &other->_ext_header, sizeof(this->_ext_header)); + std::memcpy(this->_addr4, other->_addr4, 6); } -void Tins::Dot11ReAssocRequest::current_ap(const uint8_t* new_current_ap) { - memcpy(this->_body.current_ap, new_current_ap, 6); -} - -void Tins::Dot11ReAssocRequest::ssid(const std::string &new_ssid) { - Dot11ManagementFrame::ssid(new_ssid); -} - -void Tins::Dot11ReAssocRequest::supported_rates(const std::list &new_rates) { - Dot11ManagementFrame::supported_rates(new_rates); -} - -void Tins::Dot11ReAssocRequest::extended_supported_rates(const std::list &new_rates) { - Dot11ManagementFrame::extended_supported_rates(new_rates); -} - -void Tins::Dot11ReAssocRequest::power_capabilities(uint8_t min_power, uint8_t max_power) { - Dot11ManagementFrame::power_capabilities(min_power, max_power); -} - -void Tins::Dot11ReAssocRequest::supported_channels(const std::list > &new_channels) { - Dot11ManagementFrame::supported_channels(new_channels); -} - -void Tins::Dot11ReAssocRequest::rsn_information(const RSNInformation& info) { - Dot11ManagementFrame::rsn_information(info); -} - -void Tins::Dot11ReAssocRequest::qos_capabilities(uint8_t new_qos_capabilities) { - Dot11ManagementFrame::qos_capabilities(new_qos_capabilities); -} - -uint32_t Tins::Dot11ReAssocRequest::header_size() const { - return Dot11ManagementFrame::header_size() + sizeof(this->_body); -} - -uint32_t Tins::Dot11ReAssocRequest::write_fixed_parameters(uint8_t *buffer, uint32_t total_sz) { - uint32_t sz = sizeof(this->_body); - assert(sz <= total_sz); - memcpy(buffer, &this->_body, sz); +uint32_t Tins::Dot11Data::header_size() const { + uint32_t sz = Dot11::header_size() + sizeof(_ext_header); + if (this->from_ds() && this->to_ds()) + sz += 6; return sz; } -/* ReAssociation Response */ - -Tins::Dot11ReAssocResponse::Dot11ReAssocResponse() : Dot11ManagementFrame() { - this->subtype(Dot11::REASSOC_RESP); - memset(&_body, 0, sizeof(_body)); +void Tins::Dot11Data::addr2(const uint8_t* new_addr2) { + memcpy(this->_ext_header.addr2, new_addr2, 6); } -Tins::Dot11ReAssocResponse::Dot11ReAssocResponse(const std::string& iface, - const uint8_t* dst_hw_addr, - const uint8_t* src_hw_addr) throw (std::runtime_error) : Dot11ManagementFrame(iface, dst_hw_addr, src_hw_addr) { - this->subtype(Dot11::REASSOC_RESP); - memset(&_body, 0, sizeof(_body)); +void Tins::Dot11Data::addr3(const uint8_t* new_addr3) { + memcpy(this->_ext_header.addr3, new_addr3, 6); } -Tins::Dot11ReAssocResponse::Dot11ReAssocResponse(const uint8_t *buffer, uint32_t total_sz) : Dot11ManagementFrame(buffer, total_sz) { - uint32_t sz = Dot11ManagementFrame::header_size(); - buffer += sz; - total_sz -= sz; - if(total_sz < sizeof(_body)) - throw std::runtime_error("Not enough size for an IEEE 802.11 reassociation 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::Dot11Data::frag_num(uint8_t new_frag_num) { + this->_ext_header.seq_control.frag_number = new_frag_num; } -Tins::Dot11ReAssocResponse::Dot11ReAssocResponse(const Dot11ReAssocResponse &other) : Dot11ManagementFrame(other) { - copy_fields(&other); +void Tins::Dot11Data::seq_num(uint16_t new_seq_num) { + this->_ext_header.seq_control.seq_number = new_seq_num; } -Tins::Dot11ReAssocResponse &Tins::Dot11ReAssocResponse::operator= (const Dot11ReAssocResponse &other) { - copy_inner_pdu(other); - copy_fields(&other); - return *this; +void Tins::Dot11Data::addr4(const uint8_t* new_addr4) { + memcpy(this->_addr4, new_addr4, 6); } -void Tins::Dot11ReAssocResponse::copy_fields(const Dot11ReAssocResponse *other) { - Dot11ManagementFrame::copy_ext_header(other); - std::memcpy(&_body, &other->_body, sizeof(_body)); +uint32_t Tins::Dot11Data::write_ext_header(uint8_t *buffer, uint32_t total_sz) { + uint32_t written = sizeof(this->_ext_header); + memcpy(buffer, &this->_ext_header, sizeof(this->_ext_header)); + buffer += sizeof(this->_ext_header); + if (this->from_ds() && this->to_ds()) { + written += 6; + memcpy(buffer, this->_addr4, 6); + } + return written; + } -void Tins::Dot11ReAssocResponse::status_code(uint16_t new_status_code) { - this->_body.status_code = new_status_code; +Tins::PDU *Tins::Dot11Data::clone_pdu() const { + Dot11Data *new_pdu = new Dot11Data(); + new_pdu->copy_80211_fields(this); + return new_pdu; } -void Tins::Dot11ReAssocResponse::aid(uint16_t new_aid) { - this->_body.aid = new_aid; -} +/* QoS data. */ -void Tins::Dot11ReAssocResponse::supported_rates(const std::list &new_rates) { - Dot11ManagementFrame::supported_rates(new_rates); -} +Tins::Dot11QoSData::Dot11QoSData(const uint8_t* dst_hw_addr, const uint8_t* src_hw_addr, PDU* child) : Dot11Data(dst_hw_addr, src_hw_addr, child) { -void Tins::Dot11ReAssocResponse::extended_supported_rates(const std::list &new_rates) { - Dot11ManagementFrame::extended_supported_rates(new_rates); -} - -void Tins::Dot11ReAssocResponse::edca_parameter_set(uint32_t ac_be, uint32_t ac_bk, uint32_t ac_vi, uint32_t ac_vo) { - Dot11ManagementFrame::edca_parameter_set(ac_be, ac_bk, ac_vi, ac_vo); -} - -uint32_t Tins::Dot11ReAssocResponse::header_size() const { - return Dot11ManagementFrame::header_size() + sizeof(this->_body); -} - -uint32_t Tins::Dot11ReAssocResponse::write_fixed_parameters(uint8_t *buffer, uint32_t total_sz) { - uint32_t sz = sizeof(this->_body); - assert(sz <= total_sz); - memcpy(buffer, &this->_body, sz); - return sz; } /* Probe Request */ @@ -1245,18 +1143,18 @@ Tins::PDU* Tins::Dot11ProbeRequest::clone_pdu() const { /* QoS data. */ -Tins::Dot11QoSData::Dot11QoSData(const std::string& iface, const uint8_t* dst_hw_addr, const uint8_t* src_hw_addr, PDU* child) throw (std::runtime_error) : Dot11DataFrame(iface, dst_hw_addr, src_hw_addr, child) { +Tins::Dot11QoSData::Dot11QoSData(const std::string& iface, const uint8_t* dst_hw_addr, const uint8_t* src_hw_addr, PDU* child) throw (std::runtime_error) : Dot11Data(iface, dst_hw_addr, src_hw_addr, child) { this->subtype(Dot11::QOS_DATA_DATA); this->_qos_control = 0; } -Tins::Dot11QoSData::Dot11QoSData(uint32_t iface_index, const uint8_t* dst_hw_addr, const uint8_t* src_hw_addr, PDU* child) : Dot11DataFrame(iface_index, dst_hw_addr, src_hw_addr, child) { +Tins::Dot11QoSData::Dot11QoSData(uint32_t iface_index, const uint8_t* dst_hw_addr, const uint8_t* src_hw_addr, PDU* child) : Dot11Data(iface_index, dst_hw_addr, src_hw_addr, child) { this->subtype(Dot11::QOS_DATA_DATA); this->_qos_control = 0; } -Tins::Dot11QoSData::Dot11QoSData(const uint8_t *buffer, uint32_t total_sz) : Dot11DataFrame(buffer, total_sz) { - uint32_t sz = Dot11DataFrame::header_size(); +Tins::Dot11QoSData::Dot11QoSData(const uint8_t *buffer, uint32_t total_sz) : Dot11Data(buffer, total_sz) { + uint32_t sz = Dot11Data::header_size(); buffer += sz; total_sz -= sz; assert(total_sz >= sizeof(this->_qos_control)); @@ -1267,7 +1165,7 @@ Tins::Dot11QoSData::Dot11QoSData(const uint8_t *buffer, uint32_t total_sz) : Dot inner_pdu(new Tins::SNAP(buffer, total_sz)); } -Tins::Dot11QoSData::Dot11QoSData(const Dot11QoSData &other) : Dot11DataFrame(other) { +Tins::Dot11QoSData::Dot11QoSData(const Dot11QoSData &other) : Dot11Data(other) { copy_fields(&other); } @@ -1278,7 +1176,7 @@ Tins::Dot11QoSData &Tins::Dot11QoSData::operator= (const Dot11QoSData &other) { } void Tins::Dot11QoSData::copy_fields(const Dot11QoSData *other) { - Dot11DataFrame::copy_ext_header(other); + Dot11Data::copy_ext_header(other); _qos_control = other->_qos_control; } @@ -1297,7 +1195,14 @@ uint32_t Tins::Dot11QoSData::write_fixed_parameters(uint8_t *buffer, uint32_t to return sz; } +Tins::PDU *Tins::Dot11QoSData::clone_pdu() const { + Dot11QoSData *new_pdu = new Dot11QoSData(); + new_pdu->copy_80211_fields(this); + return new_pdu; +} + /* Dot11Control */ + Tins::Dot11Control::Dot11Control(const uint8_t* dst_addr, PDU* child) : Dot11(dst_addr, child) { type(CONTROL); } @@ -1375,6 +1280,12 @@ Tins::Dot11RTS::Dot11RTS(const uint8_t *buffer, uint32_t total_sz) : Dot11Contro } +Tins::PDU *Tins::Dot11RTS::clone_pdu() const { + Dot11RTS *new_pdu = new Dot11RTS(); + new_pdu->copy_80211_fields(this); + return new_pdu; +} + /* Dot11PSPoll */ Tins::Dot11PSPoll::Dot11PSPoll(const uint8_t* dst_addr , const uint8_t* target_addr, PDU* child) : Dot11ControlTA(dst_addr, target_addr, child) { @@ -1393,6 +1304,12 @@ Tins::Dot11PSPoll::Dot11PSPoll(const uint8_t *buffer, uint32_t total_sz) : Dot11 } +Tins::PDU *Tins::Dot11PSPoll::clone_pdu() const { + Dot11PSPoll *new_pdu = new Dot11PSPoll(); + new_pdu->copy_80211_fields(this); + return new_pdu; +} + /* Dot11CFEnd */ Tins::Dot11CFEnd::Dot11CFEnd(const uint8_t* dst_addr , const uint8_t* target_addr, PDU* child) : Dot11ControlTA(dst_addr, target_addr, child) { @@ -1411,6 +1328,12 @@ Tins::Dot11CFEnd::Dot11CFEnd(const uint8_t *buffer, uint32_t total_sz) : Dot11Co } +Tins::PDU *Tins::Dot11CFEnd::clone_pdu() const { + Dot11CFEnd *new_pdu = new Dot11CFEnd(); + new_pdu->copy_80211_fields(this); + return new_pdu; +} + /* Dot11EndCFAck */ Tins::Dot11EndCFAck::Dot11EndCFAck(const uint8_t* dst_addr , const uint8_t* target_addr, PDU* child) : Dot11ControlTA(dst_addr, target_addr, child) { @@ -1429,6 +1352,12 @@ Tins::Dot11EndCFAck::Dot11EndCFAck(const uint8_t *buffer, uint32_t total_sz) : D } +Tins::PDU *Tins::Dot11EndCFAck::clone_pdu() const { + Dot11EndCFAck *new_pdu = new Dot11EndCFAck(); + new_pdu->copy_80211_fields(this); + return new_pdu; +} + /* Dot11Ack */ Tins::Dot11Ack::Dot11Ack(const uint8_t* dst_addr, PDU* child) : Dot11Control(dst_addr, child) { @@ -1447,6 +1376,12 @@ Tins::Dot11Ack::Dot11Ack(const uint8_t *buffer, uint32_t total_sz) : Dot11Contro } +Tins::PDU *Tins::Dot11Ack::clone_pdu() const { + Dot11Ack *ack = new Dot11Ack(); + ack->copy_80211_fields(this); + return ack; +} + /* Dot11BlockAck */ Tins::Dot11BlockAckRequest::Dot11BlockAckRequest(const uint8_t* dst_addr , const uint8_t* target_addr, PDU* child) : Dot11ControlTA(dst_addr, target_addr, child) { @@ -1499,6 +1434,12 @@ uint32_t Tins::Dot11BlockAckRequest::header_size() const { return Dot11ControlTA::header_size() + sizeof(_start_sequence) + sizeof(_start_sequence); } +Tins::PDU *Tins::Dot11BlockAckRequest::clone_pdu() const { + Dot11BlockAckRequest *new_pdu = new Dot11BlockAckRequest(); + new_pdu->copy_80211_fields(this); + return new_pdu; +} + /* Dot11BlockAck */ Tins::Dot11BlockAck::Dot11BlockAck(const uint8_t* dst_addr , const uint8_t* target_addr, PDU* child) : Dot11BlockAckRequest(dst_addr, target_addr, child) { subtype(BLOCK_ACK); @@ -1538,3 +1479,9 @@ uint32_t Tins::Dot11BlockAck::write_ext_header(uint8_t *buffer, uint32_t total_s uint32_t Tins::Dot11BlockAck::header_size() const { return Dot11BlockAckRequest::header_size() + sizeof(_bitmap); } + +Tins::PDU *Tins::Dot11BlockAck::clone_pdu() const { + Dot11BlockAck *new_pdu = new Dot11BlockAck(); + new_pdu->copy_80211_fields(this); + return new_pdu; +} diff --git a/src/icmp.cpp b/src/icmp.cpp index 52254b1..ff5e3c2 100644 --- a/src/icmp.cpp +++ b/src/icmp.cpp @@ -177,7 +177,8 @@ void Tins::ICMP::set_redirect(uint8_t icode, uint32_t address) { void Tins::ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) { assert(total_sz >= sizeof(icmphdr)); if(!_icmp.check) { - uint32_t checksum = PDU::do_checksum(buffer + sizeof(icmphdr), buffer + total_sz) + PDU::do_checksum((uint8_t*)&_icmp, ((uint8_t*)&_icmp) + sizeof(icmphdr)); + uint32_t checksum = Utils::do_checksum(buffer + sizeof(icmphdr), buffer + total_sz) + + Utils::do_checksum((uint8_t*)&_icmp, ((uint8_t*)&_icmp) + sizeof(icmphdr)); while (checksum >> 16) checksum = (checksum & 0xffff) + (checksum >> 16); _icmp.check = Utils::net_to_host_s(~checksum); diff --git a/src/ip.cpp b/src/ip.cpp index 6ce362a..e955b1a 100644 --- a/src/ip.cpp +++ b/src/ip.cpp @@ -105,23 +105,22 @@ Tins::IP::IP(const uint8_t *buffer, uint32_t total_sz) : PDU(IPPROTO_IP) { this->_ip_options.push_back(opt_to_add); this->_options_size += 1 + opt_to_add.optional_data_size; } - total_sz -= head_len() * sizeof(uint32_t); - if (total_sz == 0) - return; - switch(_ip.protocol) { - case IPPROTO_TCP: - inner_pdu(new Tins::TCP(buffer, total_sz)); - break; - case IPPROTO_UDP: - inner_pdu(new Tins::UDP(buffer, total_sz)); - break; - case IPPROTO_ICMP: - inner_pdu(new Tins::ICMP(buffer, total_sz)); - break; - default: - inner_pdu(new Tins::RawPDU(buffer, total_sz)); - break; + if (total_sz) { + switch(_ip.protocol) { + case IPPROTO_TCP: + inner_pdu(new Tins::TCP(buffer, total_sz)); + break; + case IPPROTO_UDP: + inner_pdu(new Tins::UDP(buffer, total_sz)); + break; + case IPPROTO_ICMP: + inner_pdu(new Tins::ICMP(buffer, total_sz)); + break; + default: + inner_pdu(new Tins::RawPDU(buffer, total_sz)); + break; + } } } @@ -302,7 +301,7 @@ void Tins::IP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU memset(buffer + sizeof(iphdr) + this->_options_size, 0, this->_padded_options_size - this->_options_size); if (parent && !_ip.check) { - uint32_t checksum = PDU::do_checksum(buffer, buffer + sizeof(iphdr) + _padded_options_size); + uint32_t checksum = Utils::do_checksum(buffer, buffer + sizeof(iphdr) + _padded_options_size); while (checksum >> 16) checksum = (checksum & 0xffff) + (checksum >> 16); ((iphdr*)buffer)->check = Utils::net_to_host_s(~checksum); diff --git a/src/pdu.cpp b/src/pdu.cpp index c5b8831..2ec2d40 100644 --- a/src/pdu.cpp +++ b/src/pdu.cpp @@ -102,30 +102,3 @@ Tins::PDU *Tins::PDU::clone_packet() const { } return ret; } - -/* Static methods */ -uint32_t Tins::PDU::do_checksum(uint8_t *start, uint8_t *end) { - uint32_t checksum(0); - uint16_t *ptr = (uint16_t*)start, *last = (uint16_t*)end, padding(0); - if(((end - start) & 1) == 1) { - last = (uint16_t*)end - 1; - padding = *(end - 1) << 8; - } - while(ptr < last) - checksum += Utils::net_to_host_s(*(ptr++)); - return checksum + padding; -} - -uint32_t Tins::PDU::pseudoheader_checksum(uint32_t source_ip, uint32_t dest_ip, uint32_t len, uint32_t flag) { - uint32_t checksum(0); - source_ip = Utils::net_to_host_l(source_ip); - dest_ip = Utils::net_to_host_l(dest_ip); - uint16_t *ptr = (uint16_t*)&source_ip; - - checksum += (uint32_t)(*ptr) + (uint32_t)(*(ptr+1)); - ptr = (uint16_t*)&dest_ip; - checksum += (uint32_t)(*ptr) + (uint32_t)(*(ptr+1)); - checksum += flag + len; - return checksum; -} - diff --git a/src/radiotap.cpp b/src/radiotap.cpp index b18258e..6f1b4b9 100644 --- a/src/radiotap.cpp +++ b/src/radiotap.cpp @@ -30,14 +30,16 @@ #include "utils.h" -Tins::RadioTap::RadioTap(const std::string &iface) throw (std::runtime_error) : PDU(0xff), _options_size(0) { +Tins::RadioTap::RadioTap(const std::string &iface, PDU *child) throw (std::runtime_error) : PDU(0xff, child), _options_size(0) { if(!Utils::interface_id(iface, _iface_index)) throw std::runtime_error("Invalid interface name!"); std::memset(&_radio, 0, sizeof(_radio)); + init(); } -Tins::RadioTap::RadioTap(uint32_t iface_index) : PDU(0xff), _iface_index(iface_index) { +Tins::RadioTap::RadioTap(uint32_t iface_index, PDU *child) : PDU(0xff, child), _iface_index(iface_index) { std::memset(&_radio, 0, sizeof(_radio)); + init(); } Tins::RadioTap::RadioTap(const uint8_t *buffer, uint32_t total_sz) : PDU(0xff) { @@ -111,6 +113,15 @@ Tins::RadioTap::RadioTap(const uint8_t *buffer, uint32_t total_sz) : PDU(0xff) { inner_pdu(Dot11::from_bytes(buffer, total_sz)); } +void Tins::RadioTap::init() { + channel(Utils::channel_to_mhz(1), 0xa0); + flags(FCS); + tsft(0); + dbm_signal(0xce); + rx_flag(0); + antenna(0); +} + void Tins::RadioTap::version(uint8_t new_version) { _radio.it_version = new_version; } diff --git a/src/sniffer.cpp b/src/sniffer.cpp index 0ca64c0..b494f35 100644 --- a/src/sniffer.cpp +++ b/src/sniffer.cpp @@ -20,7 +20,6 @@ */ -#include #include "sniffer.h" #include "ethernetII.h" #include "radiotap.h" @@ -41,7 +40,7 @@ struct LoopData { /** \endcond */ -Tins::Sniffer::Sniffer(const string &device, unsigned max_packet_size) { +Tins::Sniffer::Sniffer(const string &device, unsigned max_packet_size, const string &filter) throw(std::runtime_error) { char error[PCAP_ERRBUF_SIZE]; if (pcap_lookupnet(device.c_str(), &ip, &mask, error) == -1) { ip = 0; @@ -52,6 +51,8 @@ Tins::Sniffer::Sniffer(const string &device, unsigned max_packet_size) { throw runtime_error(error); wired = (pcap_datalink (handle) != DLT_IEEE802_11_RADIO); //better plx actual_filter.bf_insns = 0; + if(filter.size() && !set_filter(filter)) + throw runtime_error("Invalid filter"); } Tins::Sniffer::~Sniffer() { @@ -65,9 +66,7 @@ bool Tins::Sniffer::compile_set_filter(const string &filter, bpf_program &prog) return (pcap_compile(handle, &prog, filter.c_str(), 0, ip) != -1 && pcap_setfilter(handle, &prog) != -1); } -Tins::PDU *Tins::Sniffer::next_packet(const string &filter) { - if(filter.size()) - set_filter(filter); +Tins::PDU *Tins::Sniffer::next_packet() { pcap_pkthdr header; PDU *ret = 0; while(!ret) { @@ -91,9 +90,7 @@ void Tins::Sniffer::stop_sniff() { pcap_breakloop(handle); } -void Tins::Sniffer::sniff_loop(AbstractSnifferHandler *cback_handler, const string &filter, uint32_t max_packets) { - if(filter.size()) - set_filter(filter); +void Tins::Sniffer::sniff_loop(AbstractSnifferHandler *cback_handler, uint32_t max_packets) { LoopData data(handle, cback_handler, wired); pcap_loop(handle, max_packets, Sniffer::callback_handler, (u_char*)&data); } diff --git a/src/tcp.cpp b/src/tcp.cpp index c7fdbd0..c17a580 100644 --- a/src/tcp.cpp +++ b/src/tcp.cpp @@ -56,48 +56,58 @@ Tins::TCP::TCP(const uint8_t *buffer, uint32_t total_sz) : PDU(IPPROTO_TCP) { if(total_sz < sizeof(tcphdr)) throw std::runtime_error("Not enough size for an TCP header in the buffer."); std::memcpy(&_tcp, buffer, sizeof(tcphdr)); - - buffer += sizeof(tcphdr); - total_sz -= sizeof(tcphdr); - - uint32_t index = 0, header_end = (data_offset() * sizeof(uint32_t)) - sizeof(tcphdr); - if(total_sz >= header_end) { - uint8_t args[2] = {0}; - while(index < header_end) { - for(unsigned i(0); i < 2 && args[0] != NOP; ++i) { - args[i] = buffer[index++]; - if(index == header_end) - throw std::runtime_error("Not enought size for a TCP header in the buffer."); - } - // We don't want to store NOPs and EOLs - if(args[0] != NOP && args[0] != EOL) { - if(args[1]) { - // Not enough size for this option - if(header_end - index < args[1] - (sizeof(uint8_t) << 1)) { + try { + buffer += sizeof(tcphdr); + total_sz -= sizeof(tcphdr); + + _total_options_size = 0; + _options_size = 0; + + uint32_t index = 0, header_end = (data_offset() * sizeof(uint32_t)) - sizeof(tcphdr); + if(total_sz >= header_end) { + uint8_t args[2] = {0}; + while(index < header_end) { + for(unsigned i(0); i < 2 && args[0] != NOP; ++i) { + args[i] = buffer[index++]; + if(index == header_end) throw std::runtime_error("Not enought size for a TCP header in the buffer."); - } - args[1] -= (sizeof(uint8_t) << 1); - add_option((Options)args[0], args[1], buffer + index); } - index += args[1]; + // We don't want to store NOPs and EOLs + if(args[0] != NOP && args[0] != EOL) { + args[1] -= (sizeof(uint8_t) << 1); + if(args[1]) { + // Not enough size for this option + if(header_end - index < args[1]) + throw std::runtime_error("Not enought size for a TCP header in the buffer."); + add_option((Options)args[0], args[1], buffer + index); + } + index += args[1]; + } + else if(args[0] == EOL) + index = header_end; + else // Skip the NOP + args[0] = 0; } - else if(args[0] == EOL) - index = header_end; - else // Skip the NOP - args[0] = 0; + buffer += index; + total_sz -= index; } - buffer += index; - total_sz -= index; - _total_options_size = header_end; - _options_size = (_total_options_size / 4) * 4; + } + catch(std::runtime_error &err) { + cleanup(); + throw; } if(total_sz) inner_pdu(new RawPDU(buffer, total_sz)); } Tins::TCP::~TCP() { + cleanup(); +} + +void Tins::TCP::cleanup() { for(std::list::iterator it = _options.begin(); it != _options.end(); ++it) delete[] it->data; + _options.clear(); } void Tins::TCP::dport(uint16_t new_dport) { @@ -208,8 +218,11 @@ void Tins::TCP::set_flag(Flags tcp_flag, uint8_t value) { } void Tins::TCP::add_option(Options tcp_option, uint8_t length, const uint8_t *data) { - uint8_t *new_data = new uint8_t[length], padding; - memcpy(new_data, data, length); + uint8_t *new_data = 0, padding; + if(length) { + new_data = new uint8_t[length]; + memcpy(new_data, data, length); + } _options.push_back(TCPOption(tcp_option, length, new_data)); _options_size += length + (sizeof(uint8_t) << 1); padding = _options_size & 3; @@ -239,8 +252,8 @@ void Tins::TCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PD const Tins::IP *ip_packet = dynamic_cast(parent); memcpy(tcp_start, &_tcp, sizeof(tcphdr)); if(!_tcp.check && ip_packet) { - uint32_t checksum = PDU::pseudoheader_checksum(ip_packet->src_addr(), ip_packet->dst_addr(), size(), IPPROTO_TCP) + - PDU::do_checksum(tcp_start, tcp_start + total_sz); + uint32_t checksum = Utils::pseudoheader_checksum(ip_packet->src_addr(), ip_packet->dst_addr(), size(), IPPROTO_TCP) + + Utils::do_checksum(tcp_start, tcp_start + total_sz); while (checksum >> 16) checksum = (checksum & 0xffff) + (checksum >> 16); ((tcphdr*)tcp_start)->check = Utils::net_to_host_s(~checksum); @@ -259,8 +272,9 @@ uint8_t *Tins::TCP::TCPOption::write(uint8_t *buffer) { else { buffer[0] = kind; buffer[1] = length + (sizeof(uint8_t) << 1); - memcpy(buffer + 2, data, length); - return buffer + length + (sizeof(uint8_t) << 1); + if(data) + memcpy(buffer + 2, data, length); + return buffer + buffer[1]; } } diff --git a/src/udp.cpp b/src/udp.cpp index 7f0ede3..161aa75 100644 --- a/src/udp.cpp +++ b/src/udp.cpp @@ -83,8 +83,8 @@ void Tins::UDP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PD length(sizeof(udphdr) + inner_pdu()->size()); std::memcpy(buffer, &_udp, sizeof(udphdr)); if(!_udp.check && ip_packet) { - uint32_t checksum = PDU::pseudoheader_checksum(ip_packet->src_addr(), ip_packet->dst_addr(), size(), IPPROTO_UDP) + - PDU::do_checksum(buffer, buffer + total_sz); + uint32_t checksum = Utils::pseudoheader_checksum(ip_packet->src_addr(), ip_packet->dst_addr(), size(), IPPROTO_UDP) + + Utils::do_checksum(buffer, buffer + total_sz); while (checksum >> 16) checksum = (checksum & 0xffff)+(checksum >> 16); ((udphdr*)buffer)->check = Utils::net_to_host_s(~checksum); diff --git a/src/utils.cpp b/src/utils.cpp index adcc1ce..83bc2bc 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -252,6 +252,31 @@ uint16_t Tins::Utils::channel_to_mhz(uint16_t channel) { return 2407 + (channel * 5); } +uint32_t Tins::Utils::do_checksum(uint8_t *start, uint8_t *end) { + uint32_t checksum(0); + uint16_t *ptr = (uint16_t*)start, *last = (uint16_t*)end, padding(0); + if(((end - start) & 1) == 1) { + last = (uint16_t*)end - 1; + padding = *(end - 1) << 8; + } + while(ptr < last) + checksum += Utils::net_to_host_s(*(ptr++)); + return checksum + padding; +} + +uint32_t Tins::Utils::pseudoheader_checksum(uint32_t source_ip, uint32_t dest_ip, uint32_t len, uint32_t flag) { + uint32_t checksum(0); + source_ip = Utils::net_to_host_l(source_ip); + dest_ip = Utils::net_to_host_l(dest_ip); + uint16_t *ptr = (uint16_t*)&source_ip; + + checksum += (uint32_t)(*ptr) + (uint32_t)(*(ptr+1)); + ptr = (uint16_t*)&dest_ip; + checksum += (uint32_t)(*ptr) + (uint32_t)(*(ptr+1)); + checksum += flag + len; + return checksum; +} + uint32_t Tins::Utils::crc32(uint8_t* data, uint32_t data_size) { uint32_t i, crc = 0; static uint32_t crc_table[] = {