1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 02:35:57 +01:00

Moved headers to include/tins.

This commit is contained in:
Matias Fontanini
2014-10-17 12:14:00 -03:00
parent a1636896aa
commit 9ee90755d1
72 changed files with 20 additions and 10 deletions

View File

@@ -0,0 +1,7 @@
FILE(GLOB INCLUDE_FILES "*.h")
INSTALL(
FILES ${INCLUDE_FILES}
DESTINATION include/tins
COMPONENT Headers
)
ADD_SUBDIRECTORY(dot11)

View File

@@ -0,0 +1,331 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_ADDRESS_RANGE
#define TINS_ADDRESS_RANGE
#include <stdexcept>
#include <iterator>
#include "endianness.h"
#include "internals.h"
namespace Tins {
/**
* \brief AddressRange iterator class.
*/
template<typename Address>
class AddressRangeIterator : public std::iterator<std::forward_iterator_tag, const Address> {
public:
typedef typename std::iterator<std::forward_iterator_tag, const Address>::value_type value_type;
struct end_iterator {
};
/**
* Constructs an iterator.
*
* \param first The address held by this iterator.
*/
AddressRangeIterator(const value_type &addr)
: addr(addr), reached_end(false)
{
}
/**
* Constructs an iterator.
*
* \param first The address held by this iterator.
*/
AddressRangeIterator(const value_type &address, end_iterator)
: addr(address)
{
reached_end = Internals::increment(addr);
}
/**
* Retrieves the current address pointed by this iterator.
*/
const value_type& operator*() const {
return addr;
}
/**
* Retrieves a pointer to the current address pointed by this iterator.
*/
const value_type* operator->() const {
return &addr;
}
/**
* Compares two iterators for equality.
*
* \param rhs The iterator with which to compare.
*/
bool operator==(const AddressRangeIterator &rhs) const {
return reached_end == rhs.reached_end && addr == rhs.addr;
}
/**
* Compares two iterators for inequality.
*
* \param rhs The iterator with which to compare.
*/
bool operator!=(const AddressRangeIterator &rhs) const {
return !(*this == rhs);
}
/**
* Increments this iterator.
*/
AddressRangeIterator& operator++() {
reached_end = Internals::increment(addr);
return *this;
}
/**
* Increments this iterator.
*/
AddressRangeIterator operator++(int) {
AddressRangeIterator copy(*this);
(*this)++;
return copy;
}
private:
Address addr;
bool reached_end;
};
/**
* \brief Represents a range of addresses.
*
* This class provides a begin()/end() interface which allows
* iterating through every address stored in it.
*
* Note that when iterating a range that was created using
* operator/(IPv4Address, int) and the analog for IPv6, the
* network and broadcast addresses are discarded:
*
* \code
* auto range = IPv4Address("192.168.5.0") / 24;
* for(const auto &addr : range) {
* // process 192.168.5.1-254, .0 and .255 are discarded
* process(addr);
* }
*
* // That's only valid for iteration, not for AddressRange<>::contains
*
* assert(range.contains("192.168.5.0")); // works
* assert(range.contains("192.168.5.255")); // works
* \endcode
*
* Ranges created using AddressRange(address_type, address_type)
* will allow the iteration over the entire range:
*
* \code
* AddressRange<IPv4Address> range("192.168.5.0", "192.168.5.255");
* for(const auto &addr : range) {
* // process 192.168.5.0-255, no addresses are discarded
* process(addr);
* }
*
* assert(range.contains("192.168.5.0")); // still valid
* assert(range.contains("192.168.5.255")); // still valid
* \endcode
*
*/
template<typename Address>
class AddressRange {
public:
/**
* The type of addresses stored in the range.
*/
typedef Address address_type;
/**
* The iterator type.
*/
typedef AddressRangeIterator<address_type> const_iterator;
/**
* \brief The iterator type.
*
* This is the same type as const_iterator, since the
* addresses stored in this range are read only.
*/
typedef const_iterator iterator;
/**
* \brief Constructs an address range from two addresses.
*
* The range will consist of the addresses [first, last].
*
* If only_hosts is true, then the network and broadcast addresses
* will not be available when iterating the range.
*
* If last < first, an std::runtime_error exception is thrown.
*
* \param first The first address in the range.
* \param last The last address(inclusive) in the range.
* \param only_hosts Indicates whether only host addresses
* should be accessed when using iterators.
*/
AddressRange(const address_type &first, const address_type &last, bool only_hosts = false)
: first(first), last(last), only_hosts(only_hosts)
{
if(last < first)
throw std::runtime_error("Invalid address range");
}
/**
* \brief Creates an address range from a base address
* and a network mask.
*
* \param first The base address.
* \param mask The network mask to be used.
*/
static AddressRange from_mask(const address_type &first, const address_type &mask) {
return AddressRange<address_type>(
first,
Internals::last_address_from_mask(first, mask),
true
);
}
/**
* \brief Indicates whether an address is included in this range.
* \param addr The address to test.
* \return a bool indicating whether the address is in the range.
*/
bool contains(const address_type &addr) const {
return (first < addr && addr < last) || addr == first || addr == last;
}
/**
* \brief Returns an interator to the beginning of this range.
* \brief const_iterator pointing to the beginning of this range.
*/
const_iterator begin() const {
address_type addr = first;
if(only_hosts)
Internals::increment(addr);
return const_iterator(addr);
}
/**
* \brief Returns an interator to the end of this range.
* \brief const_iterator pointing to the end of this range.
*/
const_iterator end() const {
address_type addr = last;
if(only_hosts)
Internals::decrement(addr);
return const_iterator(addr, typename const_iterator::end_iterator());
}
/**
* \brief Indicates whether this range is iterable.
*
* Iterable ranges are those for which there is at least one
* address that could represent a host. For IPv4 ranges, a /31 or
* /32 ranges does not contain any, therefore it's not iterable.
* The same is true for /127 and /128 IPv6 ranges.
*
* If is_iterable returns false for a range, then iterating it
* through the iterators returned by begin() and end() is
* undefined.
*
* \return bool indicating whether this range is iterable.
*/
bool is_iterable() const {
// Since first < last, it's iterable
if(!only_hosts)
return true;
// We need that distance(first, last) >= 4
address_type addr(first);
for(int i = 0; i < 3; ++i) {
// If there's overflow before the last iteration, we're done
if(Internals::increment(addr) && i != 2)
return false;
}
// If addr <= last, it's OK.
return addr < last || addr == last;
}
private:
address_type first, last;
bool only_hosts;
};
/**
* An IPv4 address range.
*/
typedef AddressRange<IPv4Address> IPv4Range;
/**
* An IPv6 address range.
*/
typedef AddressRange<IPv6Address> IPv6Range;
/**
* \brief Constructs an AddressRange from a base address and a mask.
* \param addr The range's first address.
* \param mask The bit-length of the prefix.
*/
template<size_t n>
AddressRange<HWAddress<n> > operator/(const HWAddress<n> &addr, int mask) {
if(mask > 48)
throw std::logic_error("Prefix length cannot exceed 48");
HWAddress<n> last_addr;
typename HWAddress<n>::iterator it = last_addr.begin();
while(mask > 8) {
*it = 0xff;
++it;
mask -= 8;
}
*it = 0xff << (8 - mask);
return AddressRange<HWAddress<6> >::from_mask(addr, last_addr);
}
/**
* \brief Constructs an IPv6Range from a base IPv6Address and a mask.
* \param addr The range's first address.
* \param mask The bit-length of the prefix.
*/
IPv6Range operator/(const IPv6Address &addr, int mask);
/**
* \brief Constructs an IPv4Range from a base IPv4Address and a mask.
* \param addr The range's first address.
* \param mask The bit-length of the prefix.
*/
IPv4Range operator/(const IPv4Address &addr, int mask);
} // namespace Tins
#endif // TINS_ADDRESS_RANGE

317
include/tins/arp.h Normal file
View File

@@ -0,0 +1,317 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_ARP_H
#define TINS_ARP_H
#include "macros.h"
#include "pdu.h"
#include "endianness.h"
#include "hw_address.h"
#include "ip_address.h"
namespace Tins {
class NetworkInterface;
class EthernetII;
/**
* \class ARP
* \brief Represents an ARP PDU.
*
*/
class ARP : public PDU {
public:
/**
* The type of the hardware address.
*/
typedef HWAddress<6> hwaddress_type;
/**
* The type of the IP address.
*/
typedef IPv4Address ipaddress_type;
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::ARP;
/**
* \brief Enum which indicates the type of ARP packet.
*/
enum Flags {
REQUEST = 0x0001,
REPLY = 0x0002
};
/**
* \brief Constructs an ARP object using the provided addresses.
*
* ARP requests and replies can be constructed easily using
* ARP::make_arp_request/reply static member functions.
*
* \sa ARP::make_arp_request
* \sa ARP::make_arp_reply
*
* \param target_ip The target IP address.
* \param sender_ip The sender IP address.
* \param target_hw The target hardware address.
* \param sender_hw The sender hardware address.
*/
ARP(ipaddress_type target_ip = ipaddress_type(),
ipaddress_type sender_ip = ipaddress_type(),
const hwaddress_type &target_hw = hwaddress_type(),
const hwaddress_type &sender_hw = hwaddress_type());
/**
* \brief Constructs an ARP object from a buffer.
*
* If there is not enough size for an ARP header in the buffer,
* a malformed_packet exception is thrown.
*
* If the buffer is bigger than the size of the ARP header,
* then the extra data is stored in a RawPDU.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
ARP(const uint8_t *buffer, uint32_t total_sz);
/* Getters */
/**
* \brief Getter for the sender's hardware address.
*
* \return The sender hardware address.
*/
hwaddress_type sender_hw_addr() const { return _arp.ar_sha; }
/**
* \brief Getter for the sender's IP address.
*
* \return The sender IP address.
*/
ipaddress_type sender_ip_addr() const { return ipaddress_type(_arp.ar_sip); }
/**
* \brief Getter for the target's hardware address.
*
* \return The target hardware address.
*/
hwaddress_type target_hw_addr() const { return _arp.ar_tha; }
/**
* \brief Getter for the target's IP address.
*
* \return The target IP address.
*/
ipaddress_type target_ip_addr() const { return ipaddress_type(_arp.ar_tip); }
/**
* \brief Getter for the hardware address format field.
*
* \return The hardware address format.
*/
uint16_t hw_addr_format() const { return Endian::be_to_host(_arp.ar_hrd); }
/**
* \brief Getter for the protocol address format field.
*
* \return The protocol address format.
*/
uint16_t prot_addr_format() const { return Endian::be_to_host(_arp.ar_pro); }
/**
* \brief Getter for the hardware address length field.
*
* \return The hardware address length.
*/
uint8_t hw_addr_length() const { return _arp.ar_hln; }
/**
* \brief Getter for the protocol address length field.
*
* \return The protocol address length.
*/
uint8_t prot_addr_length() const { return _arp.ar_pln; }
/**
* \brief Getter for the ARP opcode field.
*
* \return The ARP opcode.
*/
uint16_t opcode() const { return Endian::be_to_host(_arp.ar_op); }
/**
* \brief Getter for the header size.
* \return Returns the ARP header size.
* \sa PDU::header_size
*/
uint32_t header_size() const;
/* Setters */
/**
* \brief Setter for the sender's hardware address.
*
* \param new_snd_hw_addr The new sender hardware address.
*/
void sender_hw_addr(const hwaddress_type &new_snd_hw_addr);
/**
* \brief Setter for the sender's IP address.
*
* \param new_snd_ip_addr The new sender IP address.
*/
void sender_ip_addr(ipaddress_type new_snd_ip_addr);
/**
* \brief Setter for the target's hardware address.
*
* \param new_tgt_hw_addr The new target hardware address.
*/
void target_hw_addr(const hwaddress_type &new_tgt_hw_addr);
/**
* \brief Setter for the target's IP address.
*
* \param new_tgt_ip_addr The new target IP address.
*/
void target_ip_addr(ipaddress_type new_tgt_ip_addr);
/**
* \brief Setter for the hardware address format field.
*
* \param new_hw_addr_fmt The new hardware address format.
*/
void hw_addr_format(uint16_t new_hw_addr_fmt);
/**
* \brief Setter for the protocol address format field.
*
* \param new_prot_addr_fmt The new protocol address format.
*/
void prot_addr_format(uint16_t new_prot_addr_fmt);
/**
* \brief Setter for the hardware address length field.
*
* \param new_hw_addr_len The new hardware address length.
*/
void hw_addr_length(uint8_t new_hw_addr_len);
/**
* \brief Setter for the protocol address length field.
*
* \param new_prot_addr_len The new protocol address length.
*/
void prot_addr_length(uint8_t new_prot_addr_len);
/**
* \brief Setter for the ARP opcode field.
*
* \param new_opcode Flag enum value of the ARP opcode to set.
*/
void opcode(Flags new_opcode);
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Creates an ARP Request within an EthernetII PDU.
*
* Creates an ARP Request PDU and embeds it inside an EthernetII
* PDU.
*
* \param target The target's IP address.
* \param sender The sender's IP address.
* \param hw_snd The sender's hardware address.
* \return EthernetII object containing the ARP Request.
*/
static EthernetII make_arp_request(ipaddress_type target,
ipaddress_type sender, const hwaddress_type &hw_snd = hwaddress_type());
/**
* \brief Creates an ARP Reply within an EthernetII PDU.
*
* Creates an ARP Reply PDU and embeds it inside an EthernetII
* PDU.
*
* \param target The target's IP address.
* \param sender The sender's IP address.
* \param hw_tgt The target's hardware address.
* \param hw_snd The sender's hardware address.
* \return EthetnetII containing the ARP Replay.
*/
static EthernetII make_arp_reply(ipaddress_type target,
ipaddress_type sender, const hwaddress_type &hw_tgt = hwaddress_type(),
const hwaddress_type &hw_snd = hwaddress_type());
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \sa PDU::clone
*/
ARP *clone() const {
return new ARP(*this);
}
private:
TINS_BEGIN_PACK
struct arphdr {
uint16_t ar_hrd; /* format of hardware address */
uint16_t ar_pro; /* format of protocol address */
uint8_t ar_hln; /* length of hardware address */
uint8_t ar_pln; /* length of protocol address */
uint16_t ar_op; /* ARP opcode (command) */
/* sender hardware address */
uint8_t ar_sha[hwaddress_type::address_size];
/* sender IP address */
uint32_t ar_sip;
/* target hardware address */
uint8_t ar_tha[hwaddress_type::address_size];
/* target IP address */
uint32_t ar_tip;
} TINS_END_PACK;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
arphdr _arp;
};
}
#endif //TINS_ARP_H

363
include/tins/bootp.h Normal file
View File

@@ -0,0 +1,363 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_BOOTP_H
#define TINS_BOOTP_H
#include <stdint.h>
#include <algorithm>
#include <vector>
#include "pdu.h"
#include "macros.h"
#include "endianness.h"
#include "ip_address.h"
#include "hw_address.h"
namespace Tins {
/**
* \class BootP
* \brief Class representing a BootP packet.
*/
class BootP : public PDU {
public:
/**
* The type of the IP addresses.
*/
typedef IPv4Address ipaddress_type;
/**
* The type of the chaddr field.
*/
typedef HWAddress<16> chaddr_type;
/**
* The type of the vend field.
*/
typedef std::vector<uint8_t> vend_type;
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::BOOTP;
/**
* \brief Enum which contains the different opcodes BootP messages.
*/
enum OpCodes {
BOOTREQUEST = 1,
BOOTREPLY = 2
};
/**
* \brief Creates an instance of BootP.
*
* This sets the size of the vend field to 64, as the BootP RFC
* states.
*/
BootP();
/**
* \brief Constructs a BootP object from a buffer .
*
* If there's not enough size for a BootP header, then a
* malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
* \param vend_field_size The vend field size to allocate.
* Subclasses might use 0 to provide their own interpretation of this field.
*/
BootP(const uint8_t *buffer, uint32_t total_sz, uint32_t vend_field_size = 64);
/* Getters */
/**
* \brief Getter for the opcode field.
* \return The opcode field for this BootP PDU.
*/
uint8_t opcode() const { return _bootp.opcode; }
/**
* \brief Getter for the htype field.
* \return The htype field for this BootP PDU.
*/
uint8_t htype() const { return _bootp.htype; }
/**
* \brief Getter for the hlen field.
* \return The hlen field for this BootP PDU.
*/
uint8_t hlen() const { return _bootp.hlen; }
/**
* \brief Getter for the hops field.
* \return The hops field for this BootP PDU.
*/
uint8_t hops() const { return _bootp.hops; }
/**
* \brief Getter for the xid field.
* \return The xid field for this BootP PDU.
*/
uint32_t xid() const { return Endian::be_to_host(_bootp.xid); }
/**
* \brief Getter for the secs field.
* \return The secs field for this BootP PDU.
*/
uint16_t secs() const { return Endian::be_to_host(_bootp.secs); }
/** \brief Getter for the padding field.
* \return The padding field for this BootP PDU.
*/
uint16_t padding() const { return Endian::be_to_host(_bootp.padding); }
/**
* \brief Getter for the ciaddr field.
* \return The ciaddr field for this BootP PDU.
*/
ipaddress_type ciaddr() const { return ipaddress_type(_bootp.ciaddr); }
/**
* \brief Getter for the yiaddr field.
* \return The yiaddr field for this BootP PDU.
*/
ipaddress_type yiaddr() const { return ipaddress_type(_bootp.yiaddr); }
/**
* \brief Getter for the siaddr field.
* \return The siaddr field for this BootP PDU.
*/
ipaddress_type siaddr() const { return ipaddress_type(_bootp.siaddr); }
/**
* \brief Getter for the giaddr field.
* \return The giaddr field for this BootP PDU.
*/
ipaddress_type giaddr() const { return ipaddress_type(_bootp.giaddr); }
/**
* \brief Getter for the chaddr field.
* \return The chddr field for this BootP PDU.
*/
chaddr_type chaddr() const { return _bootp.chaddr; }
/**
* \brief Getter for the sname field.
* \return The sname field for this BootP PDU.
*/
const uint8_t *sname() const { return _bootp.sname; }
/**
* \brief Getter for the file field.
* \return The file field for this BootP PDU.
*/
const uint8_t *file() const { return _bootp.file; }
/**
* \brief Getter for the vend field.
* \return The vend field for this BootP PDU.
*/
const vend_type &vend() const { return _vend; }
/**
* \brief Getter for the header size.
* \return Returns the BOOTP header size.
* \sa PDU::header_size
*/
uint32_t header_size() const;
/* Setters */
/**
* \brief Setter for the opcode field.
* \param new_opcode The opcode to be set.
*/
void opcode(uint8_t new_opcode);
/**
* \brief Setter for the htype field.
* \param new_htype The htype to be set.
*/
void htype(uint8_t new_htype);
/**
* \brief Setter for the hlen field.
* \param new_hlen The hlen to be set.
*/
void hlen(uint8_t new_hlen);
/**
* \brief Setter for the hops field.
* \param new_hops The hops to be set.
*/
void hops(uint8_t new_hops);
/**
* \brief Setter for the xid field.
* \param new_xid The xid to be set.
*/
void xid(uint32_t new_xid);
/**
* \brief Setter for the secs field.
* \param new_secs The secs to be set.
*/
void secs(uint16_t new_secs);
/**
* \brief Setter for the padding field.
* \param new_padding The padding to be set.
*/
void padding(uint16_t new_padding);
/**
* \brief Setter for the ciaddr field.
* \param new_ciaddr The ciaddr to be set.
*/
void ciaddr(ipaddress_type new_ciaddr);
/**
* \brief Setter for the yiaddr field.
* \param new_yiaddr The yiaddr to be set.
*/
void yiaddr(ipaddress_type new_yiaddr);
/**
* \brief Setter for the siaddr field.
* \param new_siaddr The siaddr to be set.
*/
void siaddr(ipaddress_type new_siaddr);
/**
* \brief Setter for the giaddr field.
* \param new_giaddr The giaddr to be set.
*/
void giaddr(ipaddress_type new_giaddr);
/**
* \brief Setter for the chaddr field.
* The new_chaddr pointer must be at least BOOTP::hlen() bytes long.
* \param new_chaddr The chaddr to be set.
*/
template<size_t n>
void chaddr(const HWAddress<n> &new_chaddr) {
// Copy the new addr
uint8_t *end = std::copy(
new_chaddr.begin(),
new_chaddr.begin() + std::min(n, sizeof(_bootp.chaddr)),
_bootp.chaddr
);
// Fill what's left with zeros
if(end < _bootp.chaddr + chaddr_type::address_size)
std::fill(end, _bootp.chaddr + chaddr_type::address_size, 0);
}
/**
* \brief Setter for the sname field.
* \param new_sname The sname to be set.
*/
void sname(const uint8_t *new_sname);
/**
* \brief Setter for the file field.
* \param new_file The file to be set.
*/
void file(const uint8_t *new_file);
/**
* \brief Setter for the vend field.
* \param new_vend The vend to be set.
*/
void vend(const vend_type &new_vend);
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* This returns true if the xid field is equal.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \sa PDU::clone
*/
BootP *clone() const {
return new BootP(*this);
}
protected:
/**
* \brief Getter for the vend field.
*
* This getter can be used by subclasses to avoid copying the
* vend field around.
*
* \return The vend field for this BootP PDU.
*/
vend_type &vend() { return _vend; }
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
private:
/**
* Struct that represents the Bootp datagram.
*/
TINS_BEGIN_PACK
struct bootphdr {
uint8_t opcode;
uint8_t htype;
uint8_t hlen;
uint8_t hops;
uint32_t xid;
uint16_t secs;
uint16_t padding;
uint32_t ciaddr;
uint32_t yiaddr;
uint32_t siaddr;
uint32_t giaddr;
uint8_t chaddr[16];
uint8_t sname[64];
uint8_t file[128];
} TINS_END_PACK;
bootphdr _bootp;
vend_type _vend;
};
}
#endif // TINS_BOOTP_H

9
include/tins/config.h Normal file
View File

@@ -0,0 +1,9 @@
/* Define if the compiler supports basic C++11 syntax */
#define HAVE_CXX11
/* Have IEEE 802.11 support */
#define HAVE_DOT11
/* Have WPA2 decryption library */
#define HAVE_WPA2_DECRYPTION

9
include/tins/config.h.in Normal file
View File

@@ -0,0 +1,9 @@
/* Define if the compiler supports basic C++11 syntax */
#cmakedefine HAVE_CXX11
/* Have IEEE 802.11 support */
#cmakedefine HAVE_DOT11
/* Have WPA2 decryption library */
#cmakedefine HAVE_WPA2_DECRYPTION

160
include/tins/constants.h Normal file
View File

@@ -0,0 +1,160 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_CONSTANTS_H
#define TINS_CONSTANTS_H
namespace Tins {
/**
* \brief Constants used in protocols.
*/
namespace Constants {
/** \cond */
struct IP {
/** \endcond */
enum e {
PROTO_IP = 0, /* Dummy protocol for TCP. */
PROTO_HOPOPTS = 0, /* IPv6 Hop-by-Hop options. */
PROTO_ICMP = 1, /* Internet Control Message Protocol. */
PROTO_IGMP = 2, /* Internet Group Management Protocol. */
PROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94). */
PROTO_TCP = 6, /* Transmission Control Protocol. */
PROTO_EGP = 8, /* Exterior Gateway Protocol. */
PROTO_PUP = 12, /* PUP protocol. */
PROTO_UDP = 17, /* User Datagram Protocol. */
PROTO_IDP = 22, /* XNS IDP protocol. */
PROTO_TP = 29, /* SO Transport Protocol Class 4. */
PROTO_DCCP = 33, /* Datagram Congestion Control Protocol. */
PROTO_IPV6 = 41, /* IPv6 header. */
PROTO_ROUTING = 43, /* IPv6 routing header. */
PROTO_FRAGMENT = 44, /* IPv6 fragmentation header. */
PROTO_RSVP = 46, /* Reservation Protocol. */
PROTO_GRE = 47, /* General Routing Encapsulation. */
PROTO_ESP = 50, /* encapsulating security payload. */
PROTO_AH = 51, /* authentication header. */
PROTO_ICMPV6 = 58, /* ICMPv6. */
PROTO_NONE = 59, /* IPv6 no next header. */
PROTO_DSTOPTS = 60, /* IPv6 destination options. */
PROTO_MTP = 92, /* Multicast Transport Protocol. */
PROTO_ENCAP = 98, /* Encapsulation Header. */
PROTO_PIM = 103, /* Protocol Independent Multicast. */
PROTO_COMP = 108, /* Compression Header Protocol. */
PROTO_SCTP = 132, /* Stream Control Transmission Protocol. */
PROTO_UDPLITE = 136, /* UDP-Lite protocol. */
PROTO_RAW = 255 /* Raw IP packets. */
};
};
struct Ethernet {
enum e {
UNKNOWN = 0,
//~ PUP = 0x0200, /* Xerox PUP */
SPRITE = 0x0500, /* Sprite */
IP = 0x0800, /* IP */
ARP = 0x0806, /* Address resolution */
REVARP = 0x8035, /* Reverse ARP */
AT = 0x809B, /* AppleTalk protocol */
AARP = 0x80F3, /* AppleTalk ARP */
VLAN = 0x8100, /* IEEE 802.1Q VLAN tagging */
IPX = 0x8137, /* IPX */
IPV6 = 0x86dd, /* IP protocol version 6 */
PPPOED = 0x8863, /* PPPoE Discovery */
PPPOES = 0x8864, /* PPPoE Session */
EAPOL = 0x888e, /* EAPOL */
LOOPBACK = 0x9000 /* used to test interfaces */
};
};
struct ARP {
enum e {
NETROM = 0, /* From KA9Q: NET/ROM pseudo. */
ETHER = 1, /* Ethernet 10/100Mbps. */
EETHER = 2, /* Experimental Ethernet. */
AX25 = 3, /* AX.25 Level 2. */
PRONET = 4, /* PROnet token ring. */
CHAOS = 5, /* Chaosnet. */
IEEE802 = 6, /* IEEE 802.2 Ethernet/TR/TB. */
ARCNET = 7, /* ARCnet. */
APPLETLK = 8, /* APPLEtalk. */
DLCI = 15, /* Frame Relay DLCI. */
ATM = 19, /* ATM. */
METRICOM = 23, /* Metricom STRIP (new IANA id). */
IEEE1394 = 24, /* IEEE 1394 IPv4 - RFC 2734. */
EUI64 = 27, /* EUI-64. */
INFINIBAND = 32, /* InfiniBand. */
SLIP = 256,
CSLIP = 257,
SLIP6 = 258,
CSLIP6 = 259,
RSRVD = 260, /* Notional KISS type. */
ADAPT = 264,
ROSE = 270,
X25 = 271, /* CCITT X.25. */
HWX25 = 272, /* Boards with X.25 in firmware. */
PPP = 512,
CISCO = 513, /* Cisco HDLC. */
HDLC = CISCO,
LAPB = 516, /* LAPB. */
DDCMP = 517, /* Digital's DDCMP. */
RAWHDLC = 518, /* Raw HDLC. */
TUNNEL = 768, /* IPIP tunnel. */
TUNNEL6 = 769, /* IPIP6 tunnel. */
FRAD = 770, /* Frame Relay Access Device. */
SKIP = 771, /* SKIP vif. */
LOOPBACK = 772, /* Loopback device. */
LOCALTLK = 773, /* Localtalk device. */
FDDI = 774, /* Fiber Distributed Data Interface. */
BIF = 775, /* AP1000 BIF. */
SIT = 776, /* sit0 device - IPv6-in-IPv4. */
IPDDP = 777, /* IP-in-DDP tunnel. */
IPGRE = 778, /* GRE over IP. */
PIMREG = 779, /* PIMSM register interface. */
HIPPI = 780, /* High Performance Parallel I'face. */
ASH = 781, /* (Nexus Electronics) Ash. */
ECONET = 782, /* Acorn Econet. */
IRDA = 783, /* Linux-IrDA. */
FCPP = 784, /* Point to point fibrechanel. */
FCAL = 785, /* Fibrechanel arbitrated loop. */
FCPL = 786, /* Fibrechanel public loop. */
FCFABRIC = 787, /* Fibrechanel fabric. */
IEEE802_TR = 800, /* Magic type ident for TR. */
IEEE80211 = 801, /* IEEE 802.11. */
IEEE80211_PRISM = 802, /* IEEE 802.11 + Prism2 header. */
IEEE80211_RADIOTAP = 803, /* IEEE 802.11 + radiotap header. */
IEEE802154 = 804, /* IEEE 802.15.4 header. */
IEEE802154_PHY = 805, /* IEEE 802.15.4 PHY header. */
VOID_TYPE = 0xFFFF, /* Void type, nothing is known. */
NONE = 0xFFFE /* Zero header length. */
};
};
}
}
#endif // TINS_CONSTANTS_H

415
include/tins/crypto.h Normal file
View File

@@ -0,0 +1,415 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "config.h"
#if !defined(TINS_CRYPTO_H) && defined(HAVE_DOT11)
#define TINS_CRYPTO_H
#include <map>
#include <string>
#include <algorithm>
#include <vector>
#include "utils.h"
#include "snap.h"
#include "rawpdu.h"
#include "handshake_capturer.h"
namespace Tins {
class PDU;
class Dot11;
class Dot11Data;
namespace Crypto {
/**
* \cond
*/
struct RC4Key;
#ifdef HAVE_WPA2_DECRYPTION
namespace WPA2 {
class invalid_handshake : public std::exception {
public:
const char *what() const throw() {
return "invalid handshake";
}
};
class SessionKeys {
public:
typedef Internals::byte_array<80> ptk_type;
typedef Internals::byte_array<32> pmk_type;
SessionKeys();
SessionKeys(const RSNHandshake &hs, const pmk_type &pmk);
SNAP *decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) const;
private:
SNAP *ccmp_decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) const;
SNAP *tkip_decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) const;
RC4Key generate_rc4_key(const Dot11Data &dot11, const RawPDU &raw) const;
ptk_type ptk;
bool is_ccmp;
};
class SupplicantData {
public:
typedef HWAddress<6> address_type;
typedef SessionKeys::pmk_type pmk_type;
SupplicantData(const std::string &psk, const std::string &ssid);
const pmk_type &pmk() const;
private:
pmk_type pmk_;
};
}
#endif // HAVE_WPA2_DECRYPTION
/**
* \endcond
*/
/**
* \brief RC4 Key abstraction.
*/
struct RC4Key {
static const size_t data_size = 256;
/**
* \brief Initializes the key using the provided iterator range.
*
* \param start The start of the range.
* \param end The end of the range.
*/
template<typename ForwardIterator>
RC4Key(ForwardIterator start, ForwardIterator end);
/**
* The actual key data.
*/
uint8_t data[data_size];
};
/**
* \brief Decrypts WEP-encrypted traffic.
*/
class WEPDecrypter {
public:
typedef HWAddress<6> address_type;
/**
* \brief Constructs a WEPDecrypter object.
*/
WEPDecrypter();
/**
* \brief Adds a decryption password.
*
* \param addr The access point's BSSID.
* \param password The password which will be used to decrypt
* packets sent from and to the AP identifier by the BSSID addr.
*/
void add_password(const address_type &addr, const std::string &password);
/**
* \brief Removes a decryption password
*
* \param addr The BSSID of the access point.
*/
void remove_password(const address_type &addr);
/**
* \brief Decrypts the provided PDU.
*
* A Dot11Data PDU is looked up inside the provided PDU chain.
* If no such PDU exists or there is no password associated
* with the Dot11 packet's BSSID, then the PDU is left intact.
*
* Otherwise, the packet is decrypted using the given password.
* If the CRC found after decrypting is invalid, false is
* returned.
*
* \return false if no decryption was performed or decryption
* failed, true otherwise.
*/
bool decrypt(PDU &pdu);
private:
typedef std::map<address_type, std::string> passwords_type;
PDU *decrypt(RawPDU &raw, const std::string &password);
passwords_type passwords;
std::vector<uint8_t> key_buffer;
};
#ifdef HAVE_WPA2_DECRYPTION
/**
* \brief Decrypts WPA2-encrypted traffic.
*
* This class takes valid PSK and SSID tuples, captures client handshakes,
* and decrypts their traffic afterwards.
*/
class WPA2Decrypter {
public:
/*
* \brief The type used to store Dot11 addresses.
*/
typedef HWAddress<6> address_type;
/**
* \brief Adds an access points's information.
*
* This associates an SSID with a PSK, and allows the decryption of
* any BSSIDs that broadcast the same SSID.
*
* The decrypter will inspect beacon frames, looking for SSID tags
* that contain the given SSID.
*
* Note that using this overload, the decryption of data frames and
* handshake capturing will be disabled until any access point
* broadcasts the provided SSID(this shouldn't take long at all).
* If this is not the desired behaviour, then you should check out
* the ovther add_ap_data overload.
*
* \param psk The PSK associated with the SSID.
* \param ssid The network's SSID.
*/
void add_ap_data(const std::string &psk, const std::string &ssid);
/**
* \brief Adds a access points's information, including its BSSID.
*
* This overload can be used if the BSSID associated with this SSID is
* known beforehand. The addr parameter indicates which specific BSSID
* is associated to the SSID.
*
* Note that if any other access point broadcasts the provided SSID,
* it will be taken into account as well.
*
* \param psk The PSK associated with this SSID.
* \param ssid The network's SSID.
* \param addr The access point's BSSID.
*/
void add_ap_data(const std::string &psk, const std::string &ssid, const address_type &addr);
/**
* \brief Decrypts the provided PDU.
*
* A Dot11Data PDU is looked up inside the provided PDU chain.
* If no such PDU exists or no PSK was associated with the SSID
* broadcasted by the Dot11 packet's BSSID, or no EAPOL handshake
* was captured for the client involved in the communication,
* then the PDU is left intact.
*
* Otherwise, the packet is decrypted using the generated PTK.
* If the resulting MIC is invalid, then the packet is left intact.
*
* \return false if no decryption was performed, or the decryption
* failed, true otherwise.
*/
bool decrypt(PDU &pdu);
private:
typedef std::map<std::string, WPA2::SupplicantData> pmks_map;
typedef std::map<address_type, WPA2::SupplicantData> bssids_map;
typedef std::pair<address_type, address_type> addr_pair;
typedef std::map<addr_pair, WPA2::SessionKeys> keys_map;
void try_add_keys(const Dot11Data &dot11, const RSNHandshake &hs);
addr_pair make_addr_pair(const address_type &addr1, const address_type &addr2) {
return (addr1 < addr2) ?
std::make_pair(addr1, addr2) :
std::make_pair(addr2, addr1);
}
addr_pair extract_addr_pair(const Dot11Data &dot11);
addr_pair extract_addr_pair_dst(const Dot11Data &dot11);
bssids_map::const_iterator find_ap(const Dot11Data &dot11);
void add_access_point(const std::string &ssid, const address_type &addr);
RSNHandshakeCapturer capturer;
pmks_map pmks;
bssids_map aps;
keys_map keys;
};
#endif // HAVE_WPA2_DECRYPTION
/**
* \brief Pluggable decrypter object which can be used to decrypt
* data on sniffing sessions.
*
* This class holds a decrypter object and a functor, and implements
* a suitable operator() to be used on BaseSniffer::sniff_loop, which
* decrypts packets and forwards them to the given functor.
*/
template<typename Functor, typename Decrypter>
class DecrypterProxy {
public:
/**
* The type of the functor object.
*/
typedef Functor functor_type;
/**
* The type of the decrypter object.
*/
typedef Decrypter decrypter_type;
/**
* \brief Constructs an object from a functor and a decrypter.
* \param func The functor to be used to forward decrypted
* packets.
* \param decrypter The decrypter which will be used to decrypt
* packets
*/
DecrypterProxy(const functor_type &func,
const decrypter_type &decr = decrypter_type());
/**
* \brief Retrieves a reference to the decrypter object.
*/
decrypter_type &decrypter();
/**
* \brief Retrieves a const reference to the decrypter object.
*/
const decrypter_type &decrypter() const;
/**
* \brief The operator() which decrypts packets and forwards
* them to the functor.
*/
bool operator() (PDU &pdu);
private:
Functor functor_;
decrypter_type decrypter_;
};
/**
* \brief Performs RC4 encription/decryption of the given byte range,
* using the provided key.
*
* The decrypted range will be copied to the OutputIterator provided.
*
* \param start The beginning of the range.
* \param start The end of the range.
* \param key The key to be used.
* \param output The iterator in which to write the output.
*/
template<typename ForwardIterator, typename OutputIterator>
void rc4(ForwardIterator start, ForwardIterator end, RC4Key &key, OutputIterator output);
/**
* \brief Wrapper function to create a DecrypterProxy using a
* WEPDecrypter as the Decrypter template parameter.
*
* \param functor The functor to be forwarded to the DecrypterProxy
* constructor.
*/
template<typename Functor>
DecrypterProxy<Functor, WEPDecrypter> make_wep_decrypter_proxy(const Functor &functor);
#ifdef HAVE_WPA2_DECRYPTION
/**
* \brief Wrapper function to create a DecrypterProxy using a
* WPA2Decrypter as the Decrypter template parameter.
*
* \param functor The functor to be forwarded to the DecrypterProxy
* constructor.
*/
template<typename Functor>
DecrypterProxy<Functor, WPA2Decrypter> make_wpa2_decrypter_proxy(const Functor &functor) {
return DecrypterProxy<Functor, WPA2Decrypter>(functor);
}
#endif // HAVE_WPA2_DECRYPTION
// Implementation section
// DecrypterProxy
template<typename Functor, typename Decrypter>
DecrypterProxy<Functor, Decrypter>::DecrypterProxy(
const functor_type &func, const decrypter_type& decr)
: functor_(func), decrypter_(decr)
{
}
template<typename Functor, typename Decrypter>
typename DecrypterProxy<Functor, Decrypter>::decrypter_type &
DecrypterProxy<Functor, Decrypter>::decrypter()
{
return decrypter_;
}
template<typename Functor, typename Decrypter>
const typename DecrypterProxy<Functor, Decrypter>::decrypter_type &
DecrypterProxy<Functor, Decrypter>::decrypter() const
{
return decrypter_;
}
template<typename Functor, typename Decrypter>
bool DecrypterProxy<Functor, Decrypter>::operator() (PDU &pdu)
{
return decrypter_.decrypt(pdu) ? functor_(pdu) : true;
}
template<typename Functor>
DecrypterProxy<Functor, WEPDecrypter> make_wep_decrypter_proxy(const Functor &functor)
{
return DecrypterProxy<Functor, WEPDecrypter>(functor);
}
// RC4 stuff
template<typename ForwardIterator>
RC4Key::RC4Key(ForwardIterator start, ForwardIterator end) {
for(size_t i = 0; i < data_size; ++i)
data[i] = i;
size_t j = 0;
ForwardIterator iter = start;
for(size_t i = 0; i < data_size; ++i) {
j = (j + data[i] + *iter++) % 256;
if(iter == end)
iter = start;
std::swap(data[i], data[j]);
}
}
template<typename ForwardIterator, typename OutputIterator>
void rc4(ForwardIterator start, ForwardIterator end, RC4Key &key, OutputIterator output) {
size_t i = 0, j = 0;
while(start != end) {
i = (i + 1) % RC4Key::data_size;
j = (j + key.data[i]) % RC4Key::data_size;
std::swap(key.data[i], key.data[j]);
*output++ = *start++ ^ key.data[(key.data[i] + key.data[j]) % RC4Key::data_size];
}
}
}
}
#endif // TINS_CRYPTO_H

58
include/tins/cxxstd.h Normal file
View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_CXXSTD_H
#define TINS_CXXSTD_H
#include <memory>
#ifdef __GXX_EXPERIMENTAL_CXX0X__
#define TINS_CXXSTD_GCC_FIX 1
#else
#define TINS_CXXSTD_GCC_FIX 0
#endif // __GXX_EXPERIMENTAL_CXX0X__
#ifndef TINS_IS_CXX11
#define TINS_IS_CXX11 (__cplusplus > 199711L || TINS_CXXSTD_GCC_FIX == 1 || _MSC_VER >= 1800)
#endif // TINS_IS_CXX11
namespace Tins{
namespace Internals {
template<typename T>
struct smart_ptr {
#if TINS_IS_CXX11
typedef std::unique_ptr<T> type;
#else
typedef std::auto_ptr<T> type;
#endif
};
}
}
#endif // TINS_CXXSTD_H

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_DATA_LINK_TYPE_H
#define TINS_DATA_LINK_TYPE_H
#include <pcap.h>
namespace Tins {
class EthernetII;
class RadioTap;
class Dot11;
class Dot3;
class SLL;
class Loopback;
class PPI;
/**
* \struct DataLinkType
* \brief Maps a libtins link layer PDU to a libpcap data link identifier.
*
* This is an empty class that should be instantiated with any object that
* represents a link layer PDU (EthernetII, Dot11, RadioTap, etc):
*
* \code
* // Instantiate it and pass it to PacketWriter's constructor.
* PacketWriter writer("file.pcap", DataLinkType<RadioTap>());
* \endcode
*/
template<typename T>
struct DataLinkType;
#define TINS_MAKE_DATA_LINK_TYPE(tins_type, pcap_type) \
template<> \
struct DataLinkType<tins_type> { \
static const int type = pcap_type; \
int get_type() const { \
return type; \
} \
};
TINS_MAKE_DATA_LINK_TYPE(EthernetII, DLT_EN10MB)
TINS_MAKE_DATA_LINK_TYPE(Dot3, DLT_EN10MB)
TINS_MAKE_DATA_LINK_TYPE(SLL, DLT_LINUX_SLL)
TINS_MAKE_DATA_LINK_TYPE(Loopback, DLT_LOOP)
TINS_MAKE_DATA_LINK_TYPE(PPI, DLT_PPI)
TINS_MAKE_DATA_LINK_TYPE(Dot11, DLT_IEEE802_11)
TINS_MAKE_DATA_LINK_TYPE(RadioTap, DLT_IEEE802_11_RADIO)
#undef TINS_MAKE_DATA_LINK_TYPE
} // Tins
#endif // TINS_DATA_LINK_TYPE_H

510
include/tins/dhcp.h Normal file
View File

@@ -0,0 +1,510 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_DHCP_H
#define TINS_DHCP_H
#include <list>
#include <vector>
#include <string>
#include "bootp.h"
#include "pdu_option.h"
#include "cxxstd.h"
namespace Tins {
/**
* \class DHCP
* \brief Represents the DHCP PDU.
*
* This class represents a DHCP PDU. It contains helpers methods
* which make it easy to set/get specific option values.
*
* Note that when adding options, the "End" option is not added
* automatically, so you will have to add it yourself.
*
* Options can be retrieved easily from DHCP PDUs:
*
* \code
* // Sniff a packet from somewhere
* DHCP dhcp = get_dhcp_from_somewhere();
*
* // This retrieves the Domain Name Servers option and converts
* // it to a std::vector<IPv4Address>. Note that if this option
* // is not present, an option_not_found exception is thrown.
* for(const auto& address : dhcp.domain_name_servers()) {
* // address is an ip
* }
*
* \endcode
*/
class DHCP : public BootP {
public:
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DHCP;
/**
* DHCP flags.
*/
enum Flags {
DISCOVER = 1,
OFFER = 2,
REQUEST = 3,
DECLINE = 4,
ACK = 5,
NAK = 6,
RELEASE = 7,
INFORM = 8
};
/**
* \brief DHCP options enum.
*/
enum OptionTypes {
PAD,
SUBNET_MASK,
TIME_OFFSET,
ROUTERS,
TIME_SERVERS,
NAME_SERVERS,
DOMAIN_NAME_SERVERS,
LOG_SERVERS,
COOKIE_SERVERS,
LPR_SERVERS,
IMPRESS_SERVERS,
RESOURCE_LOCATION_SERVERS,
HOST_NAME,
BOOT_SIZE,
MERIT_DUMP,
DOMAIN_NAME,
SWAP_SERVER,
ROOT_PATH,
EXTENSIONS_PATH,
IP_FORWARDING,
NON_LOCAL_SOURCE_ROUTING,
POLICY_FILTER,
MAX_DGRAM_REASSEMBLY,
DEFAULT_IP_TTL,
PATH_MTU_AGING_TIMEOUT,
PATH_MTU_PLATEAU_TABLE,
INTERFACE_MTU,
ALL_SUBNETS_LOCAL,
BROADCAST_ADDRESS,
PERFORM_MASK_DISCOVERY,
MASK_SUPPLIER,
ROUTER_DISCOVERY,
ROUTER_SOLICITATION_ADDRESS,
STATIC_ROUTES,
TRAILER_ENCAPSULATION,
ARP_CACHE_TIMEOUT,
IEEE802_3_ENCAPSULATION,
DEFAULT_TCP_TTL,
TCP_KEEPALIVE_INTERVAL,
TCP_KEEPALIVE_GARBAGE,
NIS_DOMAIN,
NIS_SERVERS,
NTP_SERVERS,
VENDOR_ENCAPSULATED_OPTIONS,
NETBIOS_NAME_SERVERS,
NETBIOS_DD_SERVER,
NETBIOS_NODE_TYPE,
NETBIOS_SCOPE,
FONT_SERVERS,
X_DISPLAY_MANAGER,
DHCP_REQUESTED_ADDRESS,
DHCP_LEASE_TIME,
DHCP_OPTION_OVERLOAD,
DHCP_MESSAGE_TYPE,
DHCP_SERVER_IDENTIFIER,
DHCP_PARAMETER_REQUEST_LIST,
DHCP_MESSAGE,
DHCP_MAX_MESSAGE_SIZE,
DHCP_RENEWAL_TIME,
DHCP_REBINDING_TIME,
VENDOR_CLASS_IDENTIFIER,
DHCP_CLIENT_IDENTIFIER,
NWIP_DOMAIN_NAME,
NWIP_SUBOPTIONS,
USER_CLASS = 77,
FQDN = 81,
DHCP_AGENT_OPTIONS = 82,
SUBNET_SELECTION = 118,
AUTHENTICATE = 210,
END = 255
};
/**
* The DHCP option type.
*/
typedef PDUOption<uint8_t, DHCP> option;
/**
* The type used to store the DHCP options.
*/
typedef std::list<option> options_type;
/**
* \brief Creates an instance of DHCP.
*
* This sets the hwtype and hlen fields to match the ethernet
* type and length.
*/
DHCP();
/**
* \brief Constructs a DHCP object from a buffer.
*
* If there is not enough size for a BootP header, or any of
* the TLV options contains an invalid size field, then a
* malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
DHCP(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Adds a new option to this DHCP PDU.
* \param opt The option to be added.
*/
void add_option(const option &opt);
#if TINS_IS_CXX11
/**
* \brief Adds a new option to this DHCP PDU.
*
* The option is move-constructed.
*
* \param opt The option to be added.
*/
void add_option(option &&opt) {
internal_add_option(opt);
_options.push_back(std::move(opt));
}
#endif
/**
* \brief Searchs for an option that matchs the given flag.
* \param opt_flag The flag to be searched.
* \return A pointer to the option, or 0 if it was not found.
*/
const option *search_option(OptionTypes opt) const;
/**
* \brief Adds a type option to the option list.
*
* The new option is appended at the end of the list.
*
* \param type The type of this DHCP PDU.
*/
void type(Flags type);
/**
* \brief Adds an end option to the option list.
*
* The new option is appended at the end of the list.
*
* The END option is not added automatically. You should explicitly
* add it at the end of the DHCP options for the PDU to be
* standard-compliant.
*/
void end();
/**
* \brief Adds a server identifier option.
*
* The new option is appended at the end of the list.
*
* \param ip The server's IP address.
*/
void server_identifier(ipaddress_type ip);
/**
* \brief Adds an IP address lease time option.
*
* The new option is appended at the end of the list.
*
* \param time The lease time.
*/
void lease_time(uint32_t time);
/**
* \brief Adds a lease renewal time option.
*
* The new option is appended at the end of the list.
*
* \param time The lease renew time.
*/
void renewal_time(uint32_t time);
/**
* \brief Adds a rebind time option.
*
* The new option is appended at the end of the list.
*
* \param time The lease rebind time.
*/
void rebind_time(uint32_t time);
/**
* \brief Adds a subnet mask option.
*
* The new option is appended at the end of the list.
*
* \param mask The subnet mask.
*/
void subnet_mask(ipaddress_type mask);
/**
* \brief Adds a routers option.
*
* The new option is appended at the end of the list.
*
* \param routers A list of ip addresses.
*/
void routers(const std::vector<ipaddress_type> &routers);
/**
* \brief Adds a domain name servers option.
*
* The new option is appended at the end of the list.
*
* \param dns A list of ip addresses.
*/
void domain_name_servers(const std::vector<ipaddress_type> &dns);
/**
* \brief Adds a broadcast address option.
*
* The new option is appended at the end of the list.
*
* \param addr The broadcast address.
*/
void broadcast(ipaddress_type addr);
/**
* \brief Adds a requested address option.
*
* The new option is appended at the end of the list.
*
* \param addr The requested address.
*/
void requested_ip(ipaddress_type addr);
/**
* \brief Adds a domain name option.
*
* The new option is appended at the end of the list.
*
* \param name The domain name.
*/
void domain_name(const std::string &name);
/**
* \brief Adds a hostname option.
*
* The new option is appended at the end of the list.
*
* \param name The hostname.
*/
void hostname(const std::string &name);
// Option getters
/**
* \brief Searchs for a type option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return uint8_t containing the type option.
*/
uint8_t type() const;
/**
* \brief Searchs for a server identifier option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return ipaddress_type Containing the server identifier.
*/
ipaddress_type server_identifier() const;
/**
* \brief Searchs for a lease time option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return uint32_t Containing the lease time.
*/
uint32_t lease_time() const;
/**
* \brief Searchs for a lease renewal time option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return uint32_t Containing the renewal time.
*/
uint32_t renewal_time() const;
/**
* \brief Searchs for a rebind time option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return uint32_t Containing the rebind time.
*/
uint32_t rebind_time() const;
/**
* \brief Searchs for a subnet mask option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return ipaddress_type Containing the subnet mask.
*/
ipaddress_type subnet_mask() const;
/**
* \brief Searchs for a routers option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return std::vector<ipaddress_type> Containing the routers
* option data.
*/
std::vector<ipaddress_type> routers() const;
/**
* \brief Searchs for a dns option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return std::list<ipaddress_type> Contanining the DNS servers
* provided.
*/
std::vector<ipaddress_type> domain_name_servers() const;
/**
* \brief Searchs for a broadcast option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return ipaddress_type Containing the broadcast address.
*/
ipaddress_type broadcast() const;
/**
* \brief Searchs for a requested option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return ipaddress_type Containing the requested IP address.
*/
ipaddress_type requested_ip() const;
/**
* \brief Searchs for a domain name option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return std::string Containing the domain name.
*/
std::string domain_name() const;
/**
* \brief Searchs for a hostname option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return std::string Containing the hostname.
*/
std::string hostname() const;
/**
* \brief Getter for the options list.
* \return The option list.
*/
const options_type options() const { return _options; }
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Getter for the header size.
* \return Returns the BOOTP header size.
* \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \sa PDU::clone
*/
DHCP *clone() const {
return new DHCP(*this);
}
private:
static const uint32_t MAX_DHCP_SIZE;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
template<class T>
T search_and_convert(OptionTypes opt) const {
const option *option = search_option(opt);
if(!option)
throw option_not_found();
return option->to<T>();
}
void internal_add_option(const option &opt);
serialization_type serialize_list(const std::vector<ipaddress_type> &ip_list);
options_type _options;
uint32_t _size;
};
}
#endif // TINS_DHCP_H

929
include/tins/dhcpv6.h Normal file
View File

@@ -0,0 +1,929 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_DHCPV6_H
#define TINS_DHCPV6_H
#include <cstring>
#include <list>
#include "pdu.h"
#include "endianness.h"
#include "small_uint.h"
#include "ipv6_address.h"
#include "pdu_option.h"
namespace Tins {
/**
* \class DHCPv6
* \brief Represents a DHCPv6 PDU.
*/
class DHCPv6 : public PDU {
public:
/**
* Represents a DHCPv6 option.
*/
typedef PDUOption<uint16_t, DHCPv6> option;
/**
* The message types.
*/
enum MessageType {
SOLICIT = 1,
ADVERTISE,
REQUEST,
CONFIRM,
RENEW,
REBIND,
REPLY,
RELEASE,
DECLINE,
RECONFIGURE,
INFO_REQUEST,
RELAY_FORWARD,
RELAY_REPLY,
LEASE_QUERY,
LEASE_QUERY_REPLY,
LEASE_QUERY_DONE,
LEASE_QUERY_DATA
};
/**
* The DHCPv6 options.
*/
enum OptionTypes {
CLIENTID = 1,
SERVERID,
IA_NA,
IA_TA,
IA_ADDR,
OPTION_REQUEST,
PREFERENCE,
ELAPSED_TIME,
RELAY_MSG,
AUTH = 11,
UNICAST,
STATUS_CODE,
RAPID_COMMIT,
USER_CLASS,
VENDOR_CLASS,
VENDOR_OPTS,
INTERFACE_ID,
RECONF_MSG,
RECONF_ACCEPT,
SIP_SERVER_D,
SIP_SERVER_A,
DNS_SERVERS,
DOMAIN_LIST,
IA_PD,
IAPREFIX,
NIS_SERVERS,
NISP_SERVERS,
NIS_DOMAIN_NAME,
NISP_DOMAIN_NAME,
SNTP_SERVERS,
INFORMATION_REFRESH_TIME,
BCMCS_SERVER_D,
BCMCS_SERVER_A,
GEOCONF_CIVIC = 36,
REMOTE_ID,
SUBSCRIBER_ID,
CLIENT_FQDN,
PANA_AGENT,
NEW_POSIX_TIMEZONE,
NEW_TZDB_TIMEZONE,
ERO,
LQ_QUERY,
CLIENT_DATA,
CLT_TIME,
LQ_RELAY_DATA,
LQ_CLIENT_LINK,
MIP6_HNIDF,
MIP6_VDINF,
V6_LOST,
CAPWAP_AC_V6,
RELAY_ID,
NTP_SERVER,
V6_ACCESS_DOMAIN,
SIP_UA_CS_LIST,
BOOTFILE_URL,
BOOTFILE_PARAM,
CLIENT_ARCH_TYPE,
NII,
GEOLOCATION,
AFTR_NAME,
ERP_LOCAL_DOMAIN_NAME,
RSOO,
PD_EXCLUDE,
VSS,
MIP6_IDINF,
MIP6_UDINF,
MIP6_HNP,
MIP6_HAA,
MIP6_HAF,
RDNSS_SELECTION,
KRB_PRINCIPAL_NAME,
KRB_REALM_NAME,
KRB_DEFAULT_REALM_NAME,
KRB_KDC
};
/**
* The type used to store the DHCPv6 options.
*/
typedef std::list<option> options_type;
/**
* The type used to store IP addresses.
*/
typedef IPv6Address ipaddress_type;
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DHCPv6;
/**
* The type used to store the Identity Association for Non-Temporary
* Addresses option.
*/
struct ia_na_type {
typedef std::vector<uint8_t> options_type;
uint32_t id, t1, t2;
options_type options;
ia_na_type(uint32_t id = 0, uint32_t t1 = 0, uint32_t t2 = 0,
const options_type& options = options_type())
: id(id), t1(t1), t2(t2), options(options) {}
static ia_na_type from_option(const option &opt);
};
/**
* The type used to store the Identity Association for Temporary
* Addresses option.
*/
struct ia_ta_type {
typedef std::vector<uint8_t> options_type;
uint32_t id;
options_type options;
ia_ta_type(uint32_t id = 0,
const options_type& options = options_type())
: id(id), options(options) {}
static ia_ta_type from_option(const option &opt);
};
/**
* The type used to store the Identity Association Address option.
*/
struct ia_address_type {
typedef std::vector<uint8_t> options_type;
ipaddress_type address;
uint32_t preferred_lifetime, valid_lifetime;
options_type options;
ia_address_type(ipaddress_type address = ipaddress_type(),
uint32_t preferred_lifetime = 0, uint32_t valid_lifetime = 0,
const options_type& options = options_type())
: address(address), preferred_lifetime(preferred_lifetime),
valid_lifetime(valid_lifetime), options(options) {}
static ia_address_type from_option(const option &opt);
};
/**
* The type used to store the Authentication option.
*/
struct authentication_type {
typedef std::vector<uint8_t> auth_info_type;
uint8_t protocol, algorithm, rdm;
uint64_t replay_detection;
auth_info_type auth_info;
authentication_type(uint8_t protocol = 0, uint8_t algorithm = 0,
uint8_t rdm = 0, uint64_t replay_detection = 0,
const auth_info_type &auth_info = auth_info_type())
: protocol(protocol), algorithm(algorithm), rdm(rdm),
replay_detection(replay_detection), auth_info(auth_info) {}
static authentication_type from_option(const option &opt);
};
/**
* The type used to store the Status Code option.
*/
struct status_code_type {
uint16_t code;
std::string message;
status_code_type(uint16_t code = 0, const std::string &message = "")
: code(code), message(message) { }
static status_code_type from_option(const option &opt);
};
/**
* The type used to store the Vendor-specific Information option.
*/
struct vendor_info_type {
typedef std::vector<uint8_t> data_type;
uint32_t enterprise_number;
data_type data;
vendor_info_type(uint32_t enterprise_number = 0,
const data_type &data = data_type())
: enterprise_number(enterprise_number), data(data) { }
static vendor_info_type from_option(const option &opt);
};
/**
* The type used to store the User Class option's user class data.
*/
typedef std::vector<uint8_t> class_option_data_type;
/**
* The type used to store the User Class option.
*/
//typedef std::vector<class_option_data_type> user_class_type;
struct user_class_type {
typedef std::vector<class_option_data_type> data_type;
data_type data;
user_class_type(const data_type &data = data_type())
: data(data)
{
}
static user_class_type from_option(const option &opt);
};
/**
* The type used to store the Vendor Class option.
*/
struct vendor_class_type {
typedef std::vector<class_option_data_type> class_data_type;
uint32_t enterprise_number;
class_data_type vendor_class_data;
vendor_class_type(uint32_t enterprise_number = 0,
const class_data_type &vendor_class_data = class_data_type())
: enterprise_number(enterprise_number),
vendor_class_data(vendor_class_data) { }
static vendor_class_type from_option(const option &opt);
};
/**
* The type used to represent DUIDs Based on Link-layer Address Plus
* Time.
*/
struct duid_llt {
static const uint16_t duid_id = 1;
typedef std::vector<uint8_t> lladdress_type;
uint16_t hw_type;
uint32_t time;
lladdress_type lladdress;
duid_llt(uint16_t hw_type = 0, uint32_t time = 0,
const lladdress_type &lladdress = lladdress_type())
: hw_type(hw_type), time(time), lladdress(lladdress) {}
PDU::serialization_type serialize() const;
static duid_llt from_bytes(const uint8_t *buffer, uint32_t total_sz);
};
/**
* The type used to represent DUIDs Based on Enterprise Number
*/
struct duid_en {
static const uint16_t duid_id = 2;
typedef std::vector<uint8_t> identifier_type;
uint32_t enterprise_number;
identifier_type identifier;
duid_en(uint32_t enterprise_number = 0,
const identifier_type &identifier = identifier_type())
: enterprise_number(enterprise_number), identifier(identifier) {}
PDU::serialization_type serialize() const;
static duid_en from_bytes(const uint8_t *buffer, uint32_t total_sz);
};
/**
* The type used to represent DUIDs Based on Link-layer Address.
*/
struct duid_ll {
static const uint16_t duid_id = 3;
typedef std::vector<uint8_t> lladdress_type;
uint16_t hw_type;
lladdress_type lladdress;
duid_ll(uint16_t hw_type = 0,
const lladdress_type &lladdress = lladdress_type())
: hw_type(hw_type), lladdress(lladdress) {}
PDU::serialization_type serialize() const;
static duid_ll from_bytes(const uint8_t *buffer, uint32_t total_sz);
};
/**
* Type type used to represent DUIDs. This will be stored as the
* value for the Client/Server Identifier options.
*/
struct duid_type {
typedef PDU::serialization_type data_type;
uint16_t id;
data_type data;
duid_type(uint16_t id = 0, const data_type &data = data_type())
: id(id), data(data) {}
duid_type(const duid_llt &identifier)
: id(duid_llt::duid_id), data(identifier.serialize()) {}
duid_type(const duid_en &identifier)
: id(duid_en::duid_id), data(identifier.serialize()) {}
duid_type(const duid_ll &identifier)
: id(duid_en::duid_id), data(identifier.serialize()) {}
static duid_type from_option(const option &opt);
};
/**
* The type used to store the Option Request option.
*/
typedef std::vector<uint16_t> option_request_type;
/**
* The type used to store the Relay Message option.
*/
typedef std::vector<uint8_t> relay_msg_type;
/**
* The type used to store the Interface-ID option.
*/
typedef std::vector<uint8_t> interface_id_type;
/**
* Default constructor.
*/
DHCPv6();
/**
* \brief Constructs a DHCPv6 object from a buffer.
*
* If there is not enough size for the DHCPv6 header, or any
* of the TLV options contains an invalid size field, a
* malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
DHCPv6(const uint8_t *buffer, uint32_t total_sz);
// Getters
/**
* \brief Getter for the message type field.
*
* \return The stored message type field.
*/
MessageType msg_type() const {
return static_cast<MessageType>(header_data[0]);
}
/**
* \brief Getter for the hop count field.
*
* \return The stored hop count field.
*/
uint8_t hop_count() const { return header_data[1]; }
/**
* \brief Getter for the transaction id field.
*
* \return The stored transaction id field.
*/
small_uint<24> transaction_id() const {
return (header_data[1] << 16) | (header_data[2] << 8) | header_data[3];
}
/**
* \brief Getter for the peer address field.
*
* \return The stored peer address field.
*/
const ipaddress_type &peer_address() const { return peer_addr; }
/**
* \brief Getter for the link address field.
*
* \return The stored link address field.
*/
const ipaddress_type &link_address() const { return link_addr; }
/**
* \brief Getter for the DHCPv6 options.
*
* \return The stored options.
*/
const options_type &options() const { return options_; }
// Setters
/**
* \brief Setter for the message type field.
*
* \param type The new message type.
*/
void msg_type(MessageType type);
/**
* \brief Setter for the hop count field.
*
* \param count The new hop count.
*/
void hop_count(uint8_t count);
/**
* \brief Setter for the transaction id field.
*
* \param id The new transaction id.
*/
void transaction_id(small_uint<24> id);
/**
* \brief Setter for the peer address field.
*
* \param count The new peer address.
*/
void peer_address(const ipaddress_type &addr);
/**
* \brief Setter for the link address field.
*
* \param count The new link address.
*/
void link_address(const ipaddress_type &addr);
// Option getters
/**
* \brief Getter for the Identity Association for Non-Temporary
* Addresses option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
ia_na_type ia_na() const;
/**
* \brief Getter for the Identity Association for Temporary
* Addresses option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
ia_ta_type ia_ta() const;
/**
* \brief Getter for the Identity Association Address option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
ia_address_type ia_address() const;
/**
* \brief Getter for the Option Request option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
option_request_type option_request() const;
/**
* \brief Getter for the Preference option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
uint8_t preference() const;
/**
* \brief Getter for the Elapsed Time option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
uint16_t elapsed_time() const;
/**
* \brief Getter for the Relay Message option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
relay_msg_type relay_message() const;
/**
* \brief Getter for the Authentication option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
authentication_type authentication() const;
/**
* \brief Getter for the Server Unicast option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
ipaddress_type server_unicast() const;
/**
* \brief Getter for the Server Unicast option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
status_code_type status_code() const;
/**
* \brief Getter for the Rapid Commit option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
bool has_rapid_commit() const;
/**
* \brief Getter for the User Class option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
user_class_type user_class() const;
/**
* \brief Getter for the Vendor Class option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
vendor_class_type vendor_class() const;
/**
* \brief Getter for the Vendor-specific Information option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
vendor_info_type vendor_info() const;
/**
* \brief Getter for the Interface ID option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
interface_id_type interface_id() const;
/**
* \brief Getter for the Reconfigure Message option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
uint8_t reconfigure_msg() const;
/**
* \brief Getter for the Reconfigure Accept option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
bool has_reconfigure_accept() const;
/**
* \brief Getter for the Client Identifier option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
duid_type client_id() const;
/**
* \brief Getter for the Server Identifier option.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
duid_type server_id() const;
// Option setters
/**
* \brief Setter for the Identity Association for Non-Temporary
* Addresses option.
*
* \param value The new IA_NA option data.
*/
void ia_na(const ia_na_type &value);
/**
* \brief Setter for the Identity Association for Temporary
* Addresses option.
*
* \param value The new IA_TA option data.
*/
void ia_ta(const ia_ta_type &value);
/**
* \brief Setter for the Identity Association Address option.
*
* \param value The new IA Address option data.
*/
void ia_address(const ia_address_type &value);
/**
* \brief Setter for the Identity Association Address option.
*
* \param value The new Option Request option data.
*/
void option_request(const option_request_type &value);
/**
* \brief Setter for the Preference option.
*
* \param value The new Preference option data.
*/
void preference(uint8_t value);
/**
* \brief Setter for the Elapsed Time option.
*
* \param value The new Elapsed Time option data.
*/
void elapsed_time(uint16_t value);
/**
* \brief Setter for the Relay Message option.
*
* \param value The new Relay Message option data.
*/
void relay_message(const relay_msg_type &value);
/**
* \brief Setter for the Authentication option.
*
* \param value The new Authentication option data.
*/
void authentication(const authentication_type &value);
/**
* \brief Setter for the Server Unicast option.
*
* \param value The new Server Unicast option data.
*/
void server_unicast(const ipaddress_type &value);
/**
* \brief Setter for the Status Code option.
*
* \param value The new Status Code option data.
*/
void status_code(const status_code_type &value);
/**
* \brief Adds a Rapid Commit option.
*/
void rapid_commit();
/**
* \brief Setter for the User Class option.
*
* \param value The new User Class option data.
*/
void user_class(const user_class_type &value);
/**
* \brief Setter for the Vendor Class option.
*
* \param value The new Vendor Class option data.
*/
void vendor_class(const vendor_class_type &value);
/**
* \brief Setter for the Vendor-specific Information option.
*
* \param value The new Vendor-specific Information option data.
*/
void vendor_info(const vendor_info_type &value);
/**
* \brief Setter for the Interface ID option.
*
* \param value The new Interface ID option data.
*/
void interface_id(const interface_id_type &value);
/**
* \brief Setter for the Reconfigure Message option.
*
* \param value The new Reconfigure Message option data.
*/
void reconfigure_msg(uint8_t value);
/**
* \brief Adds a Reconfigure Accept option.
*/
void reconfigure_accept();
/**
* \brief Setter for the Client Identifier option.
*
* \param value The new Client Identifier option data.
*/
void client_id(const duid_type &value);
/**
* \brief Setter for the Server Identifier option.
*
* \param value The new Server Identifier option data.
*/
void server_id(const duid_type &value);
// Other stuff
/**
* Indicates whether this is a relay agent/server message
*/
bool is_relay_message() const;
/**
* \brief Adds a DHCPv6 option.
*
* The option is added after the last option in the option
* fields.
*
* \param opt The option to be added
*/
void add_option(const option &opt);
/**
* \brief Searchs for an option that matchs the given flag.
*
* If the option is not found, a null pointer is returned.
* Deleting the returned pointer will result in <b>undefined
* behaviour</b>.
*
* \param id The option identifier to be searched.
*/
const option *search_option(OptionTypes id) const;
// PDU stuff
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \sa PDU::clone
*/
DHCPv6 *clone() const {
return new DHCPv6(*this);
}
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *);
uint8_t* write_option(const option &option, uint8_t* buffer) const;
template<template <typename> class Functor>
const option *safe_search_option(OptionTypes opt, uint32_t size) const {
const option *option = search_option(opt);
if(!option || Functor<uint32_t>()(option->data_size(), size))
throw option_not_found();
return option;
}
template<typename T>
T search_and_convert(OptionTypes opt) const {
const option *option = search_option(opt);
if(!option)
throw option_not_found();
return option->to<T>();
}
uint8_t header_data[4];
uint32_t options_size;
ipaddress_type link_addr, peer_addr;
options_type options_;
};
namespace Internals {
template<typename InputIterator>
void class_option_data2option(InputIterator start, InputIterator end,
std::vector<uint8_t>& buffer, size_t start_index = 0)
{
size_t index = start_index;
uint16_t uint16_t_buffer;
while(start != end) {
buffer.resize(buffer.size() + sizeof(uint16_t) + start->size());
uint16_t_buffer = Endian::host_to_be<uint16_t>(start->size());
std::memcpy(&buffer[index], &uint16_t_buffer, sizeof(uint16_t));
index += sizeof(uint16_t);
std::copy(start->begin(), start->end(), buffer.begin() + index);
index += start->size();
start++;
}
}
template<typename OutputType>
OutputType option2class_option_data(const uint8_t *ptr, uint32_t total_sz)
{
typedef typename OutputType::value_type value_type;
OutputType output;
size_t index = 0;
while(index + 2 < total_sz) {
uint16_t size;
std::memcpy(&size, ptr + index, sizeof(uint16_t));
size = Endian::be_to_host(size);
index += sizeof(uint16_t);
if(index + size > total_sz)
throw option_not_found();
output.push_back(
value_type(ptr + index, ptr + index + size)
);
index += size;
}
if(index != total_sz)
throw malformed_option();
return output;
}
}
}
#endif // TINS_DHCPV6_H

693
include/tins/dns.h Normal file
View File

@@ -0,0 +1,693 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_DNS_H
#define TINS_DNS_H
#include <stdint.h>
#include <list>
#include <vector>
#include <cstring>
#include <string>
#include <map>
#include "macros.h"
#include "pdu.h"
#include "endianness.h"
namespace Tins {
class IPv4Address;
class IPv6Address;
/**
* \class DNS
* \brief Represents a DNS PDU.
*
* This class represents the DNS PDU, and allows easy access
* to queries and answer records.
*
* The DNS PDU is not parsed automatically while sniffing, so you will
* have to parse it manually from an UDP packet's payload, for example:
*
* \code
* // Assume we get an udp packet from somewhere.
* UDP udp = get_udp_packet();
*
* // Now:
* // 1 - Get the RawPDU layer (contains the payload).
* // 2 - Construct a DNS object over its contents.
* DNS dns = udp.rfind_pdu<RawPDU>().to<DNS>();
*
* // Now use the DNS object!
* for(const auto& query : dns.queries()) {
* // Process a query
* }
* \endcode
*/
class DNS : public PDU {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DNS;
/**
* The DNS type.
*/
enum QRType {
QUERY = 0,
RESPONSE = 1
};
/**
* \brief Query types enum.
*/
enum QueryType {
A = 1,
NS,
MD,
MF,
CNAME,
SOA,
MB,
MG,
MR,
NULL_R,
WKS,
PTR,
HINFO,
MINFO,
MX,
TXT,
RP,
AFSDB,
X25,
ISDN,
RT,
NSAP,
NSAP_PTR,
SIG,
KEY,
PX,
GPOS,
AAAA,
LOC,
NXT,
EID,
NIMLOC,
SRV,
ATMA,
NAPTR,
KX,
CERT,
A6,
DNAM,
SINK,
OPT,
APL,
DS,
SSHFP,
IPSECKEY,
RRSIG,
NSEC,
DNSKEY,
DHCID,
NSEC3,
NSEC3PARAM
};
enum QueryClass {
IN = 1,
CH = 3,
HS = 4,
ANY = 255
};
/**
* \brief Struct that represent DNS queries.
*/
class Query {
public:
/**
* \brief Constructs a DNS query.
*
* \param nm The name of the domain being resolved.
* \param tp The query type.
* \param cl The query class.
*/
Query(const std::string &nm, QueryType tp, QueryClass cl)
: name_(nm), type_(tp), qclass_(cl) {}
/**
* \brief Default constructs this Query.
*/
Query() : type_(), qclass_() {}
/**
* \brief Setter for the name field.
*
* \param nm The name to be set.
*/
void dname(const std::string &nm) {
name_ = nm;
}
/**
* \brief Setter for the query type field.
*
* \param tp The query type to be set.
*/
void type(QueryType tp) {
type_ = tp;
}
/**
* \brief Setter for the query class field.
*
* \param cl The query class to be set.
*/
void query_class(QueryClass cl) {
qclass_ = cl;
}
/**
* \brief Getter for the name field.
*/
const std::string &dname() const { return name_; }
/**
* \brief Getter for the query type field.
*/
QueryType type() const { return type_; }
/**
* \brief Getter for the query class field.
*/
QueryClass query_class() const { return qclass_; }
private:
std::string name_;
QueryType type_;
QueryClass qclass_;
};
/**
* \brief Struct that represent DNS resource records.
*/
class Resource {
public:
/**
* Constructs a Resource object.
*
* \param dname The domain name for which this records
* provides an answer.
* \param data The resource's payload.
* \param type The type of this record.
* \param rclass The class of this record.
* \param ttl The time-to-live of this record.
*/
Resource(const std::string &dname, const std::string &data,
uint16_t type, uint16_t rclass, uint32_t ttl)
: dname_(dname), data_(data), type_(type), qclass_(rclass), ttl_(ttl) {}
Resource() : type_(), qclass_(), ttl_() {}
/**
* \brief Getter for the domain name field.
*
* This returns the domain name for which this record
* provides an answer.
*/
const std::string &dname() const { return dname_; }
/**
* Getter for the data field.
*/
const std::string &data() const { return data_; }
/**
* Getter for the query type field.
*/
uint16_t type() const { return type_; }
/**
* Getter for the query class field.
*/
uint16_t query_class() const { return qclass_; }
/**
* Getter for the type field.
*/
uint32_t ttl() const { return ttl_; }
/**
* Setter for the domain name field.
*/
void dname(const std::string &data) {
dname_ = data;
}
/**
* \brief Setter for the data field.
*
* The data will be encoded properly by the DNS class before
* being added to this packet. That means that if the type is
* A or AAAA, it will be properly encoded as an IPv4 or
* IPv6 address.
*
* The same happens for records that contain domain names,
* such as NS or CNAME. This data will be encoded using
* DNS domain name encoding.
*/
void data(const std::string &data) {
data_ = data;
}
/**
* Setter for the type field.
*/
void type(uint16_t data) {
type_ = data;
}
/**
* Setter for the class field.
*/
void query_class(uint16_t data) {
qclass_ = data;
}
/**
* Setter for the time-to-live field.
*/
void ttl(uint16_t data) {
ttl_ = data;
}
private:
std::string dname_, data_;
uint16_t type_, qclass_;
uint32_t ttl_;
};
typedef std::list<Query> queries_type;
typedef std::list<Resource> resources_type;
typedef IPv4Address address_type;
typedef IPv6Address address_v6_type;
/**
* \brief Default constructor.
*
* This constructor initializes every field to 0.
*/
DNS();
/**
* \brief Constructs a DNS object from a buffer.
*
* If there's not enough size for the DNS header, or any of the
* records are malformed, a malformed_packet is be thrown.
*
* \param buffer The buffer from which this PDU will be
* constructed.
* \param total_sz The total size of the buffer.
*/
DNS(const uint8_t *buffer, uint32_t total_sz);
// Getters
/**
* \brief Setter for the id field.
*
* \return uint16_t containing the value of the id field.
*/
uint16_t id() const { return Endian::be_to_host(dns.id); }
/**
* \brief Setter for the query response field.
*
* \return QRType containing the value of the query response
* field.
*/
QRType type() const { return static_cast<QRType>(dns.qr); }
/**
* \brief Setter for the opcode field.
*
* \return uint8_t containing the value of the opcode field.
*/
uint8_t opcode() const { return dns.opcode; }
/**
* \brief Setter for the authoritative answer field.
*
* \return uint8_t containing the value of the authoritative
* answer field.
*/
uint8_t authoritative_answer() const { return dns.aa; }
/**
* \brief Setter for the truncated field.
*
* \return uint8_t containing the value of the truncated field.
*/
uint8_t truncated() const { return dns.tc; }
/**
* \brief Setter for the recursion desired field.
*
* \return uint8_t containing the value of the recursion
* desired field.
*/
uint8_t recursion_desired() const { return dns.rd; }
/**
* \brief Setter for the recursion available field.
*
* \return uint8_t containing the value of the recursion
* available field.
*/
uint8_t recursion_available() const { return dns.ra; }
/**
* \brief Setter for the z desired field.
*
* \return uint8_t containing the value of the z field.
*/
uint8_t z() const { return dns.z; }
/**
* \brief Setter for the authenticated data field.
*
* \return uint8_t containing the value of the authenticated
* data field.
*/
uint8_t authenticated_data() const { return dns.ad; }
/**
* \brief Setter for the checking disabled field.
*
* \return uint8_t containing the value of the checking
* disabled field.
*/
uint8_t checking_disabled() const { return dns.cd; }
/**
* \brief Setter for the rcode field.
*
* \return uint8_t containing the value of the rcode field.
*/
uint8_t rcode() const { return dns.rcode; }
/**
* \brief Setter for the questions field.
*
* \return uint16_t containing the value of the questions field.
*/
uint16_t questions_count() const { return Endian::be_to_host(dns.questions); }
/**
* \brief Setter for the answers field.
*
* \return uint16_t containing the value of the answers field.
*/
uint16_t answers_count() const { return Endian::be_to_host(dns.answers); }
/**
* \brief Setter for the authority field.
*
* \return uint16_t containing the value of the authority field.
*/
uint16_t authority_count() const { return Endian::be_to_host(dns.authority); }
/**
* \brief Setter for the additional field.
*
* \return uint16_t containing the value of the additional field.
*/
uint16_t additional_count() const { return Endian::be_to_host(dns.additional); }
/**
* \brief Getter for the PDU's type.
*
* \return Returns the PDUType corresponding to the PDU.
*/
PDUType pdu_type() const { return PDU::DNS; }
/**
* \brief The header's size
*/
uint32_t header_size() const;
// Setters
/**
* \brief Setter for the id field.
*
* \param new_id The new id to be set.
*/
void id(uint16_t new_id);
/**
* \brief Setter for the query response field.
*
* \param new_qr The new qr to be set.
*/
void type(QRType new_qr);
/**
* \brief Setter for the opcode field.
*
* \param new_opcode The new opcode to be set.
*/
void opcode(uint8_t new_opcode);
/**
* \brief Setter for the authoritative answer field.
*
* \param new_aa The new authoritative answer field value to
* be set.
*/
void authoritative_answer(uint8_t new_aa);
/**
* \brief Setter for the truncated field.
*
* \param new_tc The new truncated field value to
* be set.
*/
void truncated(uint8_t new_tc);
/**
* \brief Setter for the recursion desired field.
*
* \param new_rd The new recursion desired value to
* be set.
*/
void recursion_desired(uint8_t new_rd);
/**
* \brief Setter for the recursion available field.
*
* \param new_ra The new recursion available value to
* be set.
*/
void recursion_available(uint8_t new_ra);
/**
* \brief Setter for the z(reserved) field.
*
* \param new_z The new z value to be set.
*/
void z(uint8_t new_z);
/**
* \brief Setter for the authenticated data field.
*
* \param new_ad The new authenticated data value to
* be set.
*/
void authenticated_data(uint8_t new_ad);
/**
* \brief Setter for the checking disabled field.
*
* \param new_z The new checking disabled value to be set.
*/
void checking_disabled(uint8_t new_cd);
/**
* \brief Setter for the rcode field.
*
* \param new_rcode The new rcode value to be set.
*/
void rcode(uint8_t new_rcode);
// Methods
/**
* \brief Add a query to perform.
*
* \param query The query to be added.
*/
void add_query(const Query &query);
/**
* \brief Add an answer resource record.
*
* \param resource The resource to be added.
*/
void add_answer(const Resource &resource);
/**
* \brief Add an authority resource record.
*
* \param resource The resource to be added.
*/
void add_authority(const Resource &resource);
/**
* \brief Add an additional resource record.
*
* \param resource The resource to be added.
*/
void add_additional(const Resource &resource);
/**
* \brief Getter for this PDU's DNS queries.
*
* \return The query records in this PDU.
*/
queries_type queries() const;
/**
* \brief Getter for this PDU's DNS answers
*
* \return The answer records in this PDU.
*/
resources_type answers() const;
/**
* \brief Getter for this PDU's DNS authority records.
*
* \return The authority records in this PDU.
*/
resources_type authority() const;
/**
* \brief Getter for this PDU's DNS additional records.
*
* \return The additional records in this PDU.
*/
resources_type additional() const;
/**
* \brief Encodes a domain name.
*
* This processes the input domain name and returns the encoded
* version. Each label in the original domain name will be
* prefixed with a byte that indicates the label's length.
* The null-terminator byte <b>will</b> be included in the encoded
* string. No compression is performed.
*
* For example, given the input "www.example.com", the output would
* be "\x03www\x07example\x03com\x00".
*
* \param domain_name The domain name to encode.
* \return The encoded domain name.
*/
static std::string encode_domain_name(const std::string &domain_name);
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \sa PDU::clone
*/
DNS *clone() const {
return new DNS(*this);
}
private:
TINS_BEGIN_PACK
struct dnshdr {
uint16_t id;
#if TINS_IS_LITTLE_ENDIAN
uint16_t
rd:1,
tc:1,
aa:1,
opcode:4,
qr:1,
rcode:4,
cd:1,
ad:1,
z:1,
ra:1;
#elif TINS_IS_BIG_ENDIAN
uint16_t
qr:1,
opcode:4,
aa:1,
tc:1,
rd:1,
ra:1,
z:1,
ad:1,
cd:1,
rcode:4;
#endif
uint16_t questions, answers,
authority, additional;
} TINS_END_PACK;
typedef std::list<Query> QueriesType;
typedef std::vector<std::pair<uint32_t*, uint32_t> > sections_type;
const uint8_t* compose_name(const uint8_t *ptr, char *out_ptr) const;
void convert_records(const uint8_t *ptr, const uint8_t *end, resources_type &res) const;
const uint8_t* find_section_end(const uint8_t *ptr, const uint32_t num_records) const;
const uint8_t* find_dname_end(const uint8_t *ptr) const;
void update_records(uint32_t &section_start, uint32_t num_records, uint32_t threshold, uint32_t offset);
uint8_t *update_dname(uint8_t *ptr, uint32_t threshold, uint32_t offset);
static void inline_convert_v4(uint32_t value, char *output);
static bool contains_dname(uint16_t type);
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
void add_record(const Resource &resource, const sections_type &sections);
dnshdr dns;
byte_array records_data;
uint32_t answers_idx, authority_idx, additional_idx;
};
}
#endif // TINS_DNS_H

44
include/tins/dot11.h Normal file
View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "config.h"
#if !defined(TINS_DOT_11) && defined(HAVE_DOT11)
#define TINS_DOT_11
#include "dot11/dot11_base.h"
#include "dot11/dot11_data.h"
#include "dot11/dot11_mgmt.h"
#include "dot11/dot11_beacon.h"
#include "dot11/dot11_assoc.h"
#include "dot11/dot11_auth.h"
#include "dot11/dot11_probe.h"
#include "dot11/dot11_control.h"
#endif // TINS_DOT_11

View File

@@ -0,0 +1,6 @@
FILE(GLOB INCLUDE_FILES "*.h")
INSTALL(
FILES ${INCLUDE_FILES}
DESTINATION include/tins/dot11
COMPONENT Headers
)

View File

@@ -0,0 +1,622 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "../config.h"
#if !defined(TINS_DOT11_DOT11_ASSOC_H) && defined(HAVE_DOT11)
#define TINS_DOT11_DOT11_ASSOC_H
#include "../dot11/dot11_mgmt.h"
namespace Tins {
/**
* \brief Class representing a Disassociation frame in the IEEE 802.11 Protocol.
*
*/
class Dot11Disassoc : public Dot11ManagementFrame {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_DIASSOC;
/**
* \brief Constructor for creating a 802.11 Disassociation.
*
* Constructs a 802.11 Disassociation taking the destination
* and source hardware address.
*
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11Disassoc(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructs a Dot11Disassoc object from a buffer and
* adds all identifiable PDUs found in the buffer as children
* of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11Disassoc(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Getter for the reason code field.
*
* \return The stored reason code.
*/
uint16_t reason_code() const { return Endian::le_to_host(_body.reason_code); }
/**
* \brief Setter for the reason code field.
*
* \param new_reason_code The reason code to be set.
*/
void reason_code(uint16_t new_reason_code);
/**
* \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;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11ManagementFrame::matches_flag(flag);
}
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11Disassoc *clone() const {
return new Dot11Disassoc(*this);
}
private:
struct DisassocBody {
uint16_t reason_code;
};
uint32_t write_fixed_parameters(uint8_t *buffer, uint32_t total_sz);
DisassocBody _body;
};
/**
* \brief Class representing an Association Request frame in the IEEE 802.11 Protocol.
*
*/
class Dot11AssocRequest : public Dot11ManagementFrame {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_ASSOC_REQ;
/**
* \brief Constructor for creating a 802.11 Association Request.
*
* Constructs a 802.11 Association Request taking the
* destination and source hardware address.
*
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11AssocRequest(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructs a Dot11AssocRequest object from a buffer
* and adds all identifiable PDUs found in the buffer as children
* of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11AssocRequest(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Getter for the Capabilities Information.
*
* \return A constant refereence to the stored Capabilities
* Information field.
*/
const capability_information& capabilities() const { return _body.capability;}
/**
* \brief Getter for the Capabilities Information.
*
* \return A refereence to the stored Capabilities Information
* field.
*/
capability_information& capabilities() { return _body.capability;}
/**
* \brief Getter for the listen interval field.
*
* \return The stored listen interval field.
*/
uint16_t listen_interval() const { return Endian::le_to_host(_body.listen_interval); }
/**
* \brief Setter for the listen interval field.
*
* \param new_listen_interval The listen interval to be set.
*/
void listen_interval(uint16_t new_listen_interval);
/**
* \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;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11ManagementFrame::matches_flag(flag);
}
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11AssocRequest *clone() const {
return new Dot11AssocRequest(*this);
}
private:
struct AssocReqBody {
capability_information capability;
uint16_t listen_interval;
};
uint32_t write_fixed_parameters(uint8_t *buffer, uint32_t total_sz);
AssocReqBody _body;
};
/**
* \brief Class representing an Association Response frame in the IEEE 802.11 Protocol.
*
*/
class Dot11AssocResponse : public Dot11ManagementFrame {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_ASSOC_RESP;
/**
* \brief Constructor for creating a 802.11 Association Response.
*
* Constructors a 802.11 Association Response taking destination
* and source hardware address.
*
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11AssocResponse(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructor which creates a Dot11AssocResponse object
* from a buffer and adds all identifiable PDUs found in the
* buffer as children of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11AssocResponse(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Getter for the Capabilities Information field.
*
* \return A constant reference to the stored Capabilities
* Information field.
*/
const capability_information& capabilities() const { return _body.capability;}
/**
* \brief Getter for the Capabilities Information field.
*
* \return A reference to the stored Capabilities
* Information field.
*/
capability_information& capabilities() { return _body.capability;}
/**
* \brief Getter for the status code field.
*
* \return The stored status code.
*/
uint16_t status_code() const { return Endian::le_to_host(_body.status_code); }
/**
* \brief Getter for the AID field.
*
* \return The stored AID field.
*/
uint16_t aid() const { return Endian::le_to_host(_body.aid); }
/**
* \brief Setter for the status code.
*
* \param new_status_code The status code to be set.
*/
void status_code(uint16_t new_status_code);
/**
* \brief Setter for the AID field.
*
* \param new_aid The AID value to be set.
*/
void aid(uint16_t new_aid);
/**
* \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;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11ManagementFrame::matches_flag(flag);
}
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11AssocResponse *clone() const {
return new Dot11AssocResponse(*this);
}
private:
struct AssocRespBody {
capability_information capability;
uint16_t status_code;
uint16_t aid;
};
uint32_t write_fixed_parameters(uint8_t *buffer, uint32_t total_sz);
AssocRespBody _body;
};
/**
* \brief Class representing an ReAssociation Request frame in the IEEE 802.11 Protocol.
*
*/
class Dot11ReAssocRequest : public Dot11ManagementFrame {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_REASSOC_REQ;
/**
* \brief Constructor for creating a 802.11 ReAssociation Request.
*
* Constructors a 802.11 Association Request taking the destination
* and source hardware address.
*
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11ReAssocRequest(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructs a Dot11AssocRequest object from a buffer
* and adds all identifiable PDUs found in the buffer as
* children of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \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);
/**
* \brief Getter for the Capabilities Information.
*
* \return A constant reference to the stored Capabilities
* Information field.
*/
const capability_information& capabilities() const { return _body.capability;}
/**
* \brief Getter for the Capabilities Information.
*
* \return A reference to the stored Capabilities Information
* field.
*/
capability_information& capabilities() { return _body.capability;}
/**
* \brief Getter for the listen interval field.
*
* \return The stored listen interval.
*/
uint16_t listen_interval() const { return Endian::le_to_host(_body.listen_interval); }
/**
* \brief Getter for the current ap field.
*
* \return The current ap.
*/
address_type current_ap() const { return _body.current_ap; }
/**
* \brief Setter for the listen interval field.
*
* \param new_listen_interval The listen interval to be set.
*/
void listen_interval(uint16_t new_listen_interval);
/**
* \brief Setter for the current ap.
*
* \param new_current_ap The address of the current ap.
*/
void current_ap(const address_type &new_current_ap);
/**
* \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;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11ManagementFrame::matches_flag(flag);
}
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11ReAssocRequest *clone() const {
return new Dot11ReAssocRequest(*this);
}
private:
struct ReAssocReqBody {
capability_information capability;
uint16_t listen_interval;
uint8_t current_ap[address_type::address_size];
};
uint32_t write_fixed_parameters(uint8_t *buffer, uint32_t total_sz);
ReAssocReqBody _body;
};
/**
* \brief IEEE 802.11 ReAssociation Response frame.
*
*/
class Dot11ReAssocResponse : public Dot11ManagementFrame {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_REASSOC_RESP;
/**
* \brief Constructor for creating a 802.11 Association Response.
*
* Constructs a 802.11 ReAssociation Response taking the
* destination and source hardware address.
*
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11ReAssocResponse(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructs a Dot11ReAssocResponse object from a buffer
* and adds all identifiable PDUs found in the buffer as children
* of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \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 Getter for the Capabilities Information.
*
* \return A constant reference to the stored Capabilities
* Information field.
*/
const capability_information& capabilities() const { return _body.capability;}
/**
* \brief Getter for the Capabilities Information.
*
* \return A reference to the stored Capabilities Information
* field.
*/
capability_information& capabilities() { return _body.capability;}
/**
* \brief Getter for the status code field.
*
* \return The stored status code.
*/
uint16_t status_code() const { return Endian::le_to_host(_body.status_code); }
/**
* \brief Getter for the AID field.
*
* \return The stored AID field value.
*/
uint16_t aid() const { return Endian::le_to_host(_body.aid); }
/**
* \brief Setter for the status code field.
*
* \param new_status_code The status code to be set.
*/
void status_code(uint16_t new_status_code);
/**
* \brief Setter for the AID field.
*
* \param new_aid The AID to be set.
*/
void aid(uint16_t new_aid);
/**
* \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;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11ManagementFrame::matches_flag(flag);
}
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11ReAssocResponse *clone() const {
return new Dot11ReAssocResponse(*this);
}
private:
struct ReAssocRespBody {
capability_information capability;
uint16_t status_code;
uint16_t aid;
};
uint32_t write_fixed_parameters(uint8_t *buffer, uint32_t total_sz);
ReAssocRespBody _body;
};
} // namespace Tins
#endif // TINS_DOT11_DOT11_ASSOC_H

View File

@@ -0,0 +1,260 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "../config.h"
#if !defined(TINS_DOT11_DOT11_AUTH_H) && defined(HAVE_DOT11)
#define TINS_DOT11_DOT11_AUTH_H
#include "../dot11/dot11_mgmt.h"
namespace Tins {
/**
* \brief IEEE 802.11 Authentication Request frame.
*/
class Dot11Authentication : public Dot11ManagementFrame {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_AUTH;
/**
* \brief Constructor for creating a 802.11 Authentication.
*
* Constructs a 802.11 Dot11Authentication taking the
* destination and source hardware address.
*
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11Authentication(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructs a Dot11Authentication object from a buffer
* and adds all identifiable PDUs found in the buffer as children
* of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11Authentication(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Getter for the Authetication Algorithm Number field.
*
* \return The stored authentication algorithm number.
*/
uint16_t auth_algorithm() const {return Endian::le_to_host(_body.auth_algorithm); }
/**
* \brief Getter for the Authetication Sequence Number field.
*
* \return The stored authentication sequence number.
*/
uint16_t auth_seq_number() const {return Endian::le_to_host(_body.auth_seq_number); }
/**
* \brief Getter for the status code field.
*
* \return The stored status code.
*/
uint16_t status_code() const { return Endian::le_to_host(_body.status_code); }
/**
* \brief Setter for the Authetication Algorithm Number field.
*
* \param new_auth_algorithm The Authetication Algorithm Number
* to be set.
*/
void auth_algorithm(uint16_t new_auth_algorithm);
/**
* \brief Setter for the Authetication Sequence Number field.
*
* \param new_auth_seq_number The Authetication Sequence Number
* to be set.
*/
void auth_seq_number(uint16_t new_auth_seq_number);
/**
* \brief Setter for the status code field.
*
* \param new_status_code The status code to be set.
*/
void status_code(uint16_t new_status_code);
/**
* \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;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11ManagementFrame::matches_flag(flag);
}
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11Authentication *clone() const {
return new Dot11Authentication(*this);
}
private:
struct AuthBody {
uint16_t auth_algorithm;
uint16_t auth_seq_number;
uint16_t status_code;
};
uint32_t write_fixed_parameters(uint8_t *buffer, uint32_t total_sz);
AuthBody _body;
};
/**
* \brief IEEE 802.11 Deauthentication frame.
*
*/
class Dot11Deauthentication : public Dot11ManagementFrame {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_DEAUTH;
/**
* \brief Constructor for creating a 802.11 Deauthentication.
*
* Constructs a 802.11 Deauthentication taking the
* destination and source hardware address.
*
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11Deauthentication(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructs a Dot11Deauthentication object from a buffer
* and adds all identifiable PDUs found in the buffer as children
* of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11Deauthentication(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Getter for the reason code field.
*
* \return The reason code to be set.
*/
uint16_t reason_code() const { return Endian::le_to_host(_body.reason_code); }
/**
* \brief Setter for the reason code field.
*
* \param new_reason_code The reason code to be set.
*/
void reason_code(uint16_t new_reason_code);
/**
* \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;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11ManagementFrame::matches_flag(flag);
}
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11Deauthentication *clone() const {
return new Dot11Deauthentication(*this);
}
private:
struct DeauthBody {
uint16_t reason_code;
};
uint32_t write_fixed_parameters(uint8_t *buffer, uint32_t total_sz);
DeauthBody _body;
};
} // namespace Tins
#endif // TINS_DOT11_DOT11_AUTH_H

View File

@@ -0,0 +1,522 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "../config.h"
#if !defined(TINS_DOT11_DOT11_H) && defined(HAVE_DOT11)
#define TINS_DOT11_DOT11_H
#include <list>
#include "../pdu.h"
#include "../pdu_option.h"
#include "../small_uint.h"
#include "../hw_address.h"
#include "../endianness.h"
#include "../cxxstd.h"
#include "../macros.h"
namespace Tins {
class RSNInformation;
/**
* \brief Class representing an 802.11 frame.
*/
class Dot11 : public PDU {
public:
/**
* The type used to store hardware addresses.
*/
typedef HWAddress<6> address_type;
/**
* \brief IEEE 802.11 options struct.
*/
typedef PDUOption<uint8_t, Dot11> option;
/**
* The type used to store tagged options.
*/
typedef std::list<option> options_type;
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11;
/**
* \brief Broadcast hardware address.
*/
static const address_type BROADCAST;
/**
* The endianness used by Dot11.
*/
static const endian_type endianness = LE;
/**
* \brief Enum for the different types of 802.11 frames.
*
*/
enum Types {
MANAGEMENT = 0,
CONTROL = 1,
DATA = 2
};
/**
* \brief Enum for the different types of tagged options.
*/
enum OptionTypes {
SSID,
SUPPORTED_RATES,
FH_SET,
DS_SET,
CF_SET,
TIM,
IBSS_SET,
COUNTRY,
HOPPING_PATTERN_PARAMS,
HOPPING_PATTERN_TABLE,
REQUEST_INFORMATION,
BSS_LOAD,
EDCA,
TSPEC,
TCLAS,
SCHEDULE,
CHALLENGE_TEXT,
POWER_CONSTRAINT = 32,
POWER_CAPABILITY,
TPC_REQUEST,
TPC_REPORT,
SUPPORTED_CHANNELS,
CHANNEL_SWITCH,
MEASUREMENT_REQUEST,
MEASUREMENT_REPORT,
QUIET,
IBSS_DFS,
ERP_INFORMATION,
TS_DELAY,
TCLAS_PROCESSING,
QOS_CAPABILITY = 46,
RSN = 48,
EXT_SUPPORTED_RATES = 50,
VENDOR_SPECIFIC = 221
};
/**
* \brief Enum for the different subtypes of 802.11 management frames.
*
*/
enum ManagementSubtypes {
ASSOC_REQ = 0,
ASSOC_RESP = 1,
REASSOC_REQ = 2,
REASSOC_RESP = 3,
PROBE_REQ = 4,
PROBE_RESP = 5,
BEACON = 8,
ATIM = 9,
DISASSOC = 10,
AUTH = 11,
DEAUTH = 12
};
/**
* \brief Enum for the different subtypes of 802.11 control frames.
*
*/
enum ControlSubtypes {
BLOCK_ACK_REQ = 8,
BLOCK_ACK = 9,
PS = 10,
RTS = 11,
CTS = 12,
ACK = 13,
CF_END = 14,
CF_END_ACK = 15
};
/**
* \brief Enum fro the different subtypes of 802.11 data frames.
*
*/
enum DataSubtypes {
DATA_DATA = 0,
DATA_CF_ACK = 1,
DATA_CF_POLL = 2,
DATA_CF_ACK_POLL = 3,
DATA_NULL = 4,
CF_ACK = 5,
CF_POLL = 6,
CF_ACK_POLL = 7,
QOS_DATA_DATA = 8,
QOS_DATA_CF_ACK = 9,
QOS_DATA_CF_POLL = 10,
QOS_DATA_CF_ACK_POLL = 11,
QOS_DATA_NULL = 12
};
/**
* \brief Constructs an 802.11 PDU.
*
* \param dst_hw_addr The destination hardware address.
*/
Dot11(const address_type &dst_hw_addr = address_type());
/**
* \brief Constructs 802.11 PDU from a buffer and adds all
* identifiable PDUs found in the buffer as children of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for a 802.11 header in the
* buffer, a malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Getter for the protocol version field.
*
* \return The stored protocol version field.
*/
small_uint<2> protocol() const { return _header.control.protocol; }
/**
* \brief Getter for the Type field.
*
* \return The stored Type field.
*/
small_uint<2> type() const { return _header.control.type; }
/**
* \brief Getter for the Subtype field.
*
* \return The stored Subtype field.
*/
small_uint<4> subtype() const { return _header.control.subtype; }
/**
* \brief Getter for the To-DS field.
*
* \return The stored To-DS field.
*/
small_uint<1> to_ds() const { return _header.control.to_ds; }
/**
* \brief Getter for the From-DS field.
*
* \return The stored From-DS field.
*/
small_uint<1> from_ds() const { return _header.control.from_ds; }
/**
* \brief Getter for the More-Frag field.
*
* \return The stored More-Frag field.
*/
small_uint<1> more_frag() const { return _header.control.more_frag; }
/**
* \brief Getter for the Retry field.
*
* \return The stored Retry field.
*/
small_uint<1> retry() const { return _header.control.retry; }
/**
* \brief Getter for the Power-Management field.
*
* \return The stored Power-Management field.
*/
small_uint<1> power_mgmt() const { return _header.control.power_mgmt; }
/**
* \brief Getter for the WEP field.
*
* \return The stored WEP field.
*/
small_uint<1> wep() const { return _header.control.wep; }
/**
* \brief Getter for the Order field.
*
* \return The stored Order field.
*/
small_uint<1> order() const { return _header.control.order; }
/**
* \brief Getter for the Duration-ID field.
*
* \return The stored Duration-ID field.
*/
uint16_t duration_id() const { return Endian::le_to_host(_header.duration_id); }
/**
* \brief Getter for the first address.
*
* \return The stored first address.
*/
address_type addr1() const { return _header.addr1; }
// Setters
/**
* \brief Setter for the protocol version field.
*
* \param new_proto The new protocol version field value.
*/
void protocol(small_uint<2> new_proto);
/**
* \brief Setter for the type field.
*
* \param new_type The new type field value.
*/
void type(small_uint<2> new_type);
/**
* \brief Setter for the subtype field.
*
* \param new_subtype The new subtype field value.
*/
void subtype(small_uint<4> new_subtype);
/**
* \brief Setter for the To-DS field.
*
* \param new_value The new To-DS field value.
*/
void to_ds(small_uint<1> new_value);
/**
* \brief Setter for the From-DS field.
*
* \param new_value The new From-DS field value.
*/
void from_ds(small_uint<1> new_value);
/**
* \brief Setter for the More-Frag field.
*
* \param new_value The new More-Frag field value.
*/
void more_frag(small_uint<1> new_value);
/**
* \brief Setter for the Retry field.
*
* \param new_value The new Retry field value.
*/
void retry(small_uint<1> new_value);
/**
* \brief Setter for the Power-Management field.
*
* \param new_value The new Power-Management field value.
*/
void power_mgmt(small_uint<1> new_value);
/**
* \brief Setter for the WEP field.
*
* \param new_value The new WEP field value.
*/
void wep(small_uint<1> new_value);
/**
* \brief Setter for the Order field.
*
* \param new_value The new Order field value.
*/
void order(small_uint<1> new_value);
/**
* \brief Setter for the Duration-ID field.
*
* \param new_duration_id The new Duration-ID field value.
*/
void duration_id(uint16_t new_duration_id);
/**
* \brief Setter for the first address.
*
* \param new_addr1 The new first address.
*/
void addr1(const address_type &new_addr1);
/* 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;
#ifndef WIN32
/**
* \sa PDU::send()
*/
void send(PacketSender &sender, const NetworkInterface &iface);
#endif // WIN32
/**
* \brief Adds a new option to this Dot11 PDU.
* \param opt The option to be added.
*/
void add_option(const option &opt);
#if TINS_IS_CXX11
/**
* \brief Adds a new option to this Dot11 PDU.
*
* The option is move-constructed
*
* \param opt The option to be added.
*/
void add_option(option &&opt) {
internal_add_option(opt);
_options.push_back(std::move(opt));
}
#endif
/**
* \brief Looks up a tagged option in the option list.
*
* The returned pointer <b>must not</b> be free'd.
*
* \param opt The option identifier.
* \return The option found, or 0 if no such option has been set.
*/
const option *search_option(OptionTypes opt) const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \sa PDU::clone
*/
Dot11 *clone() const {
return new Dot11(*this);
}
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag;
}
/**
* \brief Getter for the option list.
*
* \return The options list.
*/
const options_type &options() const { return _options; }
/**
* \brief Allocates an Dot11 PDU from a buffer.
*
* This can be used somehow as a "virtual constructor". This
* method instantiates the appropriate subclass of Dot11 from the
* given buffer.
*
* The allocated class' type will be figured out from the
* information provided in the buffer.
*
* \param buffer The buffer from which to take the PDU data.
* \param total_sz The total size of the buffer.
* \return The allocated Dot11 PDU.
*/
static Dot11 *from_bytes(const uint8_t *buffer, uint32_t total_sz);
protected:
virtual uint32_t write_ext_header(uint8_t *buffer, uint32_t total_sz) { return 0; }
virtual uint32_t write_fixed_parameters(uint8_t *buffer, uint32_t total_sz) { return 0; }
void parse_tagged_parameters(const uint8_t *buffer, uint32_t total_sz);
void add_tagged_option(OptionTypes opt, uint8_t len, const uint8_t *val);
protected:
/**
* Struct that represents the 802.11 header
*/
TINS_BEGIN_PACK
struct ieee80211_header {
TINS_BEGIN_PACK
struct {
#if TINS_IS_LITTLE_ENDIAN
uint16_t protocol:2,
type:2,
subtype:4,
to_ds:1,
from_ds:1,
more_frag:1,
retry:1,
power_mgmt:1,
more_data:1,
wep:1,
order:1;
#elif TINS_IS_BIG_ENDIAN
uint16_t subtype:4,
type:2,
protocol:2,
order:1,
wep:1,
more_data:1,
power_mgmt:1,
retry:1,
more_frag:1,
from_ds:1,
to_ds:1;
#endif
} TINS_END_PACK control;
uint16_t duration_id;
uint8_t addr1[address_type::address_size];
} TINS_END_PACK;
private:
Dot11(const ieee80211_header *header_ptr);
void internal_add_option(const option &opt);
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
ieee80211_header _header;
uint32_t _options_size;
options_type _options;
};
}
#endif // TINS_DOT11_DOT11_H

View File

@@ -0,0 +1,166 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "../config.h"
#if !defined(TINS_DOT11_DOT11_BEACON_H) && defined(HAVE_DOT11)
#define TINS_DOT11_DOT11_BEACON_H
#include "../dot11/dot11_mgmt.h"
namespace Tins {
/**
* \brief Class representing an 802.11 Beacon.
*
*/
class Dot11Beacon : public Dot11ManagementFrame {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_BEACON;
/**
* \brief Constructor for creating a 802.11 Beacon.
*
* Constructs a 802.11 Beacon taking destination and source
* hardware address.
*
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11Beacon(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructs a Dot11Beacon object from a buffer and adds
* all identifiable PDUs found in the buffer as children of this
* one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11Beacon(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Getter for the timestamp field.
*
* \return The stored timestamp value.
*/
uint64_t timestamp() const { return Endian::le_to_host(_body.timestamp); }
/**
* \brief Getter for the interval field.
*
* \return The stored interval value.
*/
uint16_t interval() const { return Endian::le_to_host(_body.interval); }
/**
* \brief Getter for the Capabilities Information structure.
*
* \return A constant refereence to the stored Capabilities
* Information field.
*/
const capability_information& capabilities() const { return _body.capability; }
/**
* \brief Getter for the Capabilities Information.
*
* \return A refereence to the stored Capabilities Information
* field.
*/
capability_information& capabilities() { return _body.capability; }
/**
* \brief Setter for the timestamp field.
*
* \param new_timestamp The timestamp to be set.
*/
void timestamp(uint64_t new_timestamp);
/**
* \brief Setter for the interval field.
*
* \param new_interval The interval to be set.
*/
void interval(uint16_t new_interval);
/**
* \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;
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11ManagementFrame::matches_flag(flag);
}
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11Beacon *clone() const {
return new Dot11Beacon(*this);
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
private:
TINS_BEGIN_PACK
struct BeaconBody {
uint64_t timestamp;
uint16_t interval;
capability_information capability;
} TINS_END_PACK;
uint32_t write_fixed_parameters(uint8_t *buffer, uint32_t total_sz);
BeaconBody _body;
};
} // namespace Tins
#endif // TINS_DOT11_DOT11_BEACON_H

View File

@@ -0,0 +1,746 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "../config.h"
#if !defined(TINS_DOT11_DOT11_CONTROL_H) && defined(HAVE_DOT11)
#define TINS_DOT11_DOT11_CONTROL_H
#include "../dot11/dot11_base.h"
namespace Tins {
/**
* \brief Class that represents an 802.11 control frame.
*/
class Dot11Control : public Dot11 {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_CONTROL;
/**
* \brief Constructor for creating a 802.11 control frame PDU
*
* Constructs a 802.11 Control PDU taking the destination and
* source hardware addresses.
*
* \param dst_addr The destination hardware address.
*/
Dot11Control(const address_type &dst_addr = address_type());
/**
* \brief Constructs a Dot11Control object from a buffer and
* adds all identifiable PDUs found in the buffer as children
* of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11Control(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::DOT11_CONTROL; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == PDU::DOT11_CONTROL || Dot11::matches_flag(flag);
}
};
/**
* \brief Class that represents an abstraction of the 802.11 control frames
* that contain a target address.
*/
class Dot11ControlTA : public Dot11Control {
public:
/**
* \brief Getter for the target address field.
*/
address_type target_addr() const { return _taddr; }
/**
* \brief Setter for the target address field.
* \param addr The new target address.
*/
void target_addr(const address_type &addr);
protected:
/**
* \brief Constructor for creating a 802.11 control frame TA PDU
*
* Constructs a 802.11 PDU taking the destination and source
* hardware addresses.
*
* \param dst_addr The destination hardware address.
* \param target_addr The source hardware address.
*/
Dot11ControlTA(const address_type &dst_addr = address_type(),
const address_type &target_addr = address_type());
/**
* \brief Constructs a Dot11ControlTA object from a buffer and
* adds all identifiable PDUs found in the buffer as children
* of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11ControlTA(const uint8_t *buffer, uint32_t total_sz);
/**
* \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;
protected:
/**
* \brief Getter for the control ta additional fields size.
*/
uint32_t controlta_size() const { return _taddr.size() + sizeof(ieee80211_header); }
uint32_t write_ext_header(uint8_t *buffer, uint32_t total_sz);
private:
address_type _taddr;
};
/**
* \brief IEEE 802.11 RTS frame.
*/
class Dot11RTS : public Dot11ControlTA {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_RTS;
/**
* \brief Constructor for creating a 802.11 RTS frame PDU
*
* Constructs a 802.11 RTS PDU taking the destination and source
* hardware addresses.
*
* \param dst_addr The destination hardware address.
* \param target_addr The source hardware address.
*/
Dot11RTS(const address_type &dst_addr = address_type(),
const address_type &target_addr = address_type());
/**
* \brief Constructs a Dot11RTS object from a buffer and adds all
* identifiable PDUs found in the buffer as children of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11RTS(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11RTS *clone() const {
return new Dot11RTS(*this);
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11Control::matches_flag(flag);
}
};
class Dot11PSPoll : public Dot11ControlTA {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_PS_POLL;
/**
* \brief Constructor for creating a 802.11 PS-Poll frame PDU
*
* Constructs a 802.11 PDU taking the destination and source
* hardware addresses.
*
* \param dst_addr The destination hardware address.
* \param target_addr The source hardware address.
*/
Dot11PSPoll(const address_type &dst_addr = address_type(),
const address_type &target_addr = address_type());
/**
* \brief Constructs a Dot11PSPoll object from a buffer and
* adds all identifiable PDUs found in the buffer as children of
* this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \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
*/
Dot11PSPoll *clone() const {
return new Dot11PSPoll(*this);
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11Control::matches_flag(flag);
}
};
class Dot11CFEnd : public Dot11ControlTA {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_CF_END;
/**
* \brief Constructor for creating a 802.11 CF-End frame PDU
*
* Constructs a 802.11 PDU taking the destination and source
* hardware addresses.
*
* \param dst_addr The destination hardware address.
* \param target_addr The source hardware address.
*/
Dot11CFEnd(const address_type &dst_addr = address_type(),
const address_type &target_addr = address_type());
/**
* \brief Constructs a Dot11CFEnd object from a buffer and adds
* all identifiable PDUs found in the buffer as children of this
* one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \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
*/
Dot11CFEnd *clone() const {
return new Dot11CFEnd(*this);
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11Control::matches_flag(flag);
}
};
class Dot11EndCFAck : public Dot11ControlTA {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_END_CF_ACK;
/**
* \brief Constructor for creating a 802.11 End-CF-Ack frame PDU
*
* Constructs a 802.11 PDU taking the destination and source
* hardware addresses.
*
* \param dst_addr The destination hardware address.
* \param target_addr The source hardware address.
*/
Dot11EndCFAck(const address_type &dst_addr = address_type(),
const address_type &target_addr = address_type());
/**
* \brief Constructs a Dot11EndCFAck frame object from a buffer
* and adds all identifiable PDUs found in the buffer as children
* of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \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
*/
Dot11EndCFAck *clone() const {
return new Dot11EndCFAck(*this);
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11Control::matches_flag(flag);
}
};
class Dot11Ack : public Dot11Control {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_ACK;
/**
* \brief Constructor for creating a 802.11 Ack frame PDU
*
* Constructs a 802.11 PDU taking the destination and source
* hardware addresses.
*
* \param dst_addr The destination hardware address.
*/
Dot11Ack(const address_type &dst_addr = address_type());
/**
* \brief Constructs a Dot11Ack frame object from a buffer and
* adds all identifiable PDUs found in the buffer as children of
* this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11Ack(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11Ack *clone() const {
return new Dot11Ack(*this);
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11Control::matches_flag(flag);
}
};
/**
* \brief Class that represents an 802.11 Block Ack Request PDU.
*/
class Dot11BlockAckRequest : public Dot11ControlTA {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_BLOCK_ACK_REQ;
/**
* \brief Constructor for creating a 802.11 Block Ack request frame PDU
*
* Constructs a 802.11 PDU taking the destination and source
* hardware addresses.
*
* \param dst_addr The destination hardware address.
* \param target_addr The source hardware address.
*/
Dot11BlockAckRequest(const address_type &dst_addr = address_type(),
const address_type &target_addr = address_type());
/**
* \brief Constructs a Dot11BlockAckRequest object from a buffer
* and adds all identifiable PDUs found in the buffer as children
* of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11BlockAckRequest(const uint8_t *buffer, uint32_t total_sz);
/* Getter */
/**
* \brief Getter for the bar control field.
* \return The stored bar control field.
*/
small_uint<4> bar_control() const {
#if TINS_IS_LITTLE_ENDIAN
return _bar_control & 0xf;
#else
return (_bar_control >> 8) & 0xf;
#endif
}
/**
* \brief Getter for the start sequence field.
* \return The stored start sequence.
*/
small_uint<12> start_sequence() const {
#if TINS_IS_LITTLE_ENDIAN
return (_start_sequence >> 4) & 0xfff;
#else
return (Endian::le_to_host<uint16_t>(_start_sequence) >> 4) & 0xfff;
#endif
}
/**
* \brief Getter for the fragment number field.
* \return The stored fragment number field.
*/
small_uint<4> fragment_number() const {
#if TINS_IS_LITTLE_ENDIAN
return _start_sequence & 0xf;
#else
return (_start_sequence >> 8) & 0xf;
#endif
}
/**
* \brief Returns the 802.11 frame's header length.
*
* \return The header's size.
* \sa PDU::header_size()
*/
uint32_t header_size() const;
/* Setter */
/**
* \brief Setter for the bar control field.
* \param bar The bar control field to be set.
*/
void bar_control(small_uint<4> bar);
/**
* \brief Setter for the start sequence field.
* \param bar The start sequence field to be set.
*/
void start_sequence(small_uint<12> seq);
/**
* \brief Setter for the fragment number field.
* \param frag The fragment number field to be set.
*/
void fragment_number(small_uint<4> frag);
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11BlockAckRequest *clone() const {
return new Dot11BlockAckRequest(*this);
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11Control::matches_flag(flag);
}
protected:
uint32_t write_ext_header(uint8_t *buffer, uint32_t total_sz);
private:
void init_block_ack();
uint16_t _bar_control;
uint16_t _start_sequence;
};
/**
* \brief Class that represents an 802.11 block ack frame.
*/
class Dot11BlockAck : public Dot11ControlTA {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_BLOCK_ACK;
/**
* The size of the bitmap field.
*/
static const size_t bitmap_size = 8;
/**
* \brief Constructor for creating a 802.11 Block Ack frame PDU
*
* Constructs a 802.11 PDU taking the destination and source
* hardware addresses.
*
* \param dst_addr The destination hardware address.
* \param target_addr The source hardware address.
*/
Dot11BlockAck(const address_type &dst_addr = address_type(),
const address_type &target_addr = address_type());
/**
* \brief Constructs a Dot11BlockAck frame object from a buffer
* and adds all identifiable PDUs found in the buffer as children
* of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11BlockAck(const uint8_t *buffer, uint32_t total_sz);
/* Getters */
/**
* \brief Getter for the bar control field.
* \return The stored bar control field.
*/
small_uint<4> bar_control() const {
#if TINS_IS_LITTLE_ENDIAN
return _bar_control & 0xf;
#else
return (_bar_control >> 8) & 0xf;
#endif
}
/**
* \brief Getter for the start sequence field.
* \return The stored start sequence.
*/
small_uint<12> start_sequence() const {
#if TINS_IS_LITTLE_ENDIAN
return (_start_sequence >> 4) & 0xfff;
#else
return (Endian::le_to_host<uint16_t>(_start_sequence) >> 4) & 0xfff;
#endif
}
/**
* \brief Getter for the fragment number field.
* \return The stored fragment number field.
*/
small_uint<4> fragment_number() const {
#if TINS_IS_LITTLE_ENDIAN
return _start_sequence & 0xf;
#else
return (_start_sequence >> 8) & 0xf;
#endif
}
/**
* \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;
/* Setters */
/**
* \brief Setter for the bar control field.
* \param bar The bar control field to be set.
*/
void bar_control(small_uint<4> bar);
/**
* \brief Setter for the start sequence field.
* \param bar The start sequence field to be set.
*/
void start_sequence(small_uint<12> seq);
/**
* \brief Setter for the fragment number field.
* \param frag The fragment number field to be set.
*/
void fragment_number(small_uint<4> frag);
/**
* \brief Getter for the bitmap field.
*
* The returned pointer <b>must not</b> be free'd.
*
* \return The bitmap field.
*/
const uint8_t *bitmap() const { return _bitmap; }
/**
* \brief Setter for the bitmap field.
* \param bit The new bitmap field to be set.
*/
void bitmap(const uint8_t *bit);
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11Control::matches_flag(flag);
}
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11BlockAck *clone() const {
return new Dot11BlockAck(*this);
}
private:
void init_block_ack();
uint32_t write_ext_header(uint8_t *buffer, uint32_t total_sz);
uint16_t _bar_control, _start_sequence;
uint8_t _bitmap[bitmap_size];
};
} // namespace Tins
#endif // TINS_DOT11_DOT11_CONTROL_H

View File

@@ -0,0 +1,345 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "../config.h"
#if !defined(TINS_DOT11_DOT11_DATA_H) && defined(HAVE_DOT11)
#define TINS_DOT11_DOT11_DATA_H
#include "../dot11/dot11_base.h"
namespace Tins {
class Dot11Data : public Dot11 {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_DATA;
/**
* \brief Constructor for creating a 802.11 Data frame.
*
* Constructs a 802.11 Data frame taking the
* destination and source hardware addresses.
*
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11Data(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructs a Dot11Data object from a buffer and adds
* all identifiable PDUs found in the buffer as children of
* this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11Data(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Getter for the second address.
*
* \return The stored second address.
*/
address_type addr2() const { return _ext_header.addr2; }
/**
* \brief Getter for the third address.
*
* \return The stored third address.
*/
address_type addr3() const { return _ext_header.addr3; }
/**
* \brief Getter for the fragment number field.
*
* \return The stored fragment number.
*/
small_uint<4> frag_num() const {
#if TINS_IS_LITTLE_ENDIAN
return _ext_header.frag_seq & 0xf;
#else
return (_ext_header.frag_seq >> 8) & 0xf;
#endif
}
/**
* \brief Getter for the sequence number field.
*
* \return The stored sequence number.
*/
small_uint<12> seq_num() const {
#if TINS_IS_LITTLE_ENDIAN
return (_ext_header.frag_seq >> 4) & 0xfff;
#else
return (Endian::le_to_host<uint16_t>(_ext_header.frag_seq) >> 4) & 0xfff;
#endif
}
/**
* \brief Getter for the fourth address.
*
* \return The fourth address.
*/
address_type addr4() const { return _addr4; }
/**
* \brief Setter for the second address.
*
* \param new_addr2 The second address to be set.
*/
void addr2(const address_type &new_addr2);
/**
* \brief Setter for the third address.
*
* \param new_addr3 The third address to be set.
*/
void addr3(const address_type &new_addr3);
/**
* \brief Setter for the fragment number field.
*
* \param new_frag_num The fragment number to be set.
*/
void frag_num(small_uint<4> new_frag_num);
/**
* \brief Setter for the sequence number field.
*
* \param new_seq_num The sequence number to be set.
*/
void seq_num(small_uint<12> new_seq_num);
/**
* \brief Setter for the fourth address field.
*
* \param new_addr4 The fourth address to be set.
*/
void addr4(const address_type &new_addr4);
/**
* \brief Retrieves the frame's source address.
*
* This is a wrapper over the addr* member functions which
* takes into account the value of the FromDS and ToDS bits.
*
* If FromDS == ToDS == 1, the return value is not defined.
*/
address_type src_addr() const {
if(!from_ds() && !to_ds())
return addr2();
if(!from_ds() && to_ds())
return addr2();
return addr3();
}
/**
* \brief Retrieves the frame's destination address.
*
* This is a wrapper over the addr* member functions which
* takes into account the value of the FromDS and ToDS bits.
*
* If FromDS == ToDS == 1, the return value is not defined.
*/
address_type dst_addr() const {
if(!from_ds() && !to_ds())
return addr1();
if(!from_ds() && to_ds())
return addr3();
return addr1();
}
/**
* \brief Retrieves the frame's BSSID address.
*
* This is a wrapper over the addr* member functions which
* takes into account the value of the FromDS and ToDS bits.
*
* If FromDS == ToDS == 1, the return value is not defined.
*/
address_type bssid_addr() const {
if(!from_ds() && !to_ds())
return addr3();
if(!from_ds() && to_ds())
return addr1();
return addr2();
}
/**
* \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_flag; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11::matches_flag(flag);
}
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11Data *clone() const {
return new Dot11Data(*this);
}
protected:
TINS_BEGIN_PACK
struct ExtendedHeader {
uint8_t addr2[address_type::address_size];
uint8_t addr3[address_type::address_size];
uint16_t frag_seq;
} TINS_END_PACK;
struct no_inner_pdu { };
Dot11Data(const uint8_t *buffer, uint32_t total_sz, no_inner_pdu);
uint32_t init(const uint8_t *buffer, uint32_t total_sz);
uint32_t write_ext_header(uint8_t *buffer, uint32_t total_sz);
uint32_t data_frame_size() {
return Dot11::header_size() + sizeof(_ext_header) +
((from_ds() && to_ds()) ? _addr4.size() : 0);
}
private:
ExtendedHeader _ext_header;
address_type _addr4;
};
class Dot11QoSData : public Dot11Data {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_QOS_DATA;
/**
* \brief Constructor for creating a 802.11 QoS Data PDU
*
* Constructs a 802.11 QoS Data PDU taking the
* destination and source hardware addresses.
*
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11QoSData(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructors Dot11QoSData object from a buffer and adds
* all identifiable PDUs found in the buffer as children of this
* one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11QoSData(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Getter for the QOS Control field.
*
* \return The stored QOS Control field value.
*/
uint16_t qos_control() const { return Endian::le_to_host(_qos_control); }
/**
* \brief Setter for the QOS Control field.
*
* \param new_qos_control The QOS Control to be set.
*/
void qos_control(uint16_t new_qos_control);
/**
* \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;
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11QoSData *clone() const {
return new Dot11QoSData(*this);
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::DOT11_QOS_DATA; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == PDU::DOT11_QOS_DATA || Dot11Data::matches_flag(flag);
}
private:
uint32_t write_fixed_parameters(uint8_t *buffer, uint32_t total_sz);
uint16_t _qos_control;
};
}
#endif // TINS_DOT11_DOT11_DATA_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,233 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "../config.h"
#if !defined(TINS_DOT11_DOT11_PROBE_H) && defined(HAVE_DOT11)
#define TINS_DOT11_DOT11_PROBE_H
#include "../dot11/dot11_mgmt.h"
namespace Tins {
/**
* \brief Class representing an Probe Request frame in the IEEE 802.11 Protocol.
*
*/
class Dot11ProbeRequest : public Dot11ManagementFrame {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_PROBE_REQ;
/**
* \brief Constructor for creating a 802.11 Probe Request.
*
* Constructs a 802.11 Probe Request taking the
* destination and source hardware address.
*
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11ProbeRequest(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructs a Dot11ProbeRequest object from a buffer
* and adds all identifiable PDUs found in the buffer as children
* of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11ProbeRequest(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::DOT11_PROBE_REQ; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11ManagementFrame::matches_flag(flag);
}
/**
* \brief Clones this PDU.
*
* \sa PDU::clone()
*/
Dot11ProbeRequest* clone() const {
return new Dot11ProbeRequest(*this);
}
};
/**
* \brief Class representing an Probe Response frame in the IEEE 802.11 Protocol.
*
*/
class Dot11ProbeResponse : public Dot11ManagementFrame {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_PROBE_RESP;
/**
* \brief Constructor for creating a 802.11 Probe Response.
*
* Constructs a 802.11 Probe Response taking the
* destination and source hardware addresses.
*
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11ProbeResponse(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructs a Dot11ProbeResponse object from a buffer
* and adds all identifiable PDUs found in the buffer as children
* of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11ProbeResponse(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Getter for the timestamp field.
*
* \return The stored timestamp value.
*/
uint64_t timestamp() const { return Endian::le_to_host(_body.timestamp); }
/**
* \brief Getter for the interval field.
*
* \return The stored interval value.
*/
uint16_t interval() const { return Endian::le_to_host(_body.interval); }
/**
* \brief Getter for the Capabilities Information.
*
* \return A constant reference to the stored Capabilities
* Information field.
*/
const capability_information& capabilities() const { return _body.capability;}
/**
* \brief Getter for the Capabilities Information.
*
* \return A reference to the stored Capabilities Information
* field.
*/
capability_information& capabilities() { return _body.capability;}
/**
* \brief Setter for the timestamp field.
*
* \param new_timestamp The timestamp to be set.
*/
void timestamp(uint64_t new_timestamp);
/**
* \brief Setter for the interval field.
*
* \param new_interval The interval to be set.
*/
void interval(uint16_t new_interval);
/**
* \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;
/**
* \brief Clones this PDU.
*
* \sa PDU::clone()
*/
Dot11ProbeResponse* clone() const {
return new Dot11ProbeResponse(*this);
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11ManagementFrame::matches_flag(flag);
}
protected:
private:
TINS_BEGIN_PACK
struct ProbeResp {
uint64_t timestamp;
uint16_t interval;
capability_information capability;
} TINS_END_PACK;
ProbeResp _body;
uint32_t write_fixed_parameters(uint8_t *buffer, uint32_t total_sz);
};
} // namespace Tins
#endif // TINS_DOT11_DOT11_PROBE_H

213
include/tins/dot1q.h Normal file
View File

@@ -0,0 +1,213 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_DOT1Q_H
#define TINS_DOT1Q_H
#include "pdu.h"
#include "endianness.h"
#include "small_uint.h"
namespace Tins {
/**
* \class Dot1Q
* Represents an IEEE 802.1q PDU.
*/
class Dot1Q : public PDU {
public:
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT1Q;
/**
* Default constructor
*/
Dot1Q(small_uint<12> tag_id = 0, bool append_pad = true);
/**
* \brief Constructs a Dot1Q object from a buffer and adds all
* identifiable PDUs found in the buffer as children of this
* one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for a Dot1Q header in the buffer,
* a malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot1Q(const uint8_t *buffer, uint32_t total_sz);
// Getters
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Returns the frame's trailer size.
* \return The trailer's size.
*/
uint32_t trailer_size() const;
/**
* \brief Getter for the priority field.
* \return The stored priority field value.
*/
small_uint<3> priority() const {
return _header.priority;
}
/**
* \brief Getter for the Canonical Format Identifier field.
* \return The stored CFI field value.
*/
small_uint<1> cfi() const {
return _header.cfi;
}
/**
* \brief Getter for the VLAN ID field.
* \return The stored VLAN ID field value.
*/
small_uint<12> id() const {
#if TINS_IS_LITTLE_ENDIAN
return _header.idL | (_header.idH << 8);
#else
return _header.id;
#endif
}
/**
* \brief Getter for the payload type field.
* \return The stored type field value.
*/
uint16_t payload_type() const {
return Endian::be_to_host(_header.type);
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \sa PDU::clone
*/
Dot1Q *clone() const {
return new Dot1Q(*this);
}
/**
* \brief Retrieves the flag indicating whether padding will be
* appended at the end of this packet.
*/
bool append_padding() const {
return _append_padding;
}
// Setters
/**
* \brief Setter for the priority field.
* \param new_priority The new priority field value.
*/
void priority(small_uint<3> new_priority);
/**
* \brief Setter for the Canonical Format Identifie field.
* \param new_cfi The new CFI field value.
*/
void cfi(small_uint<1> new_cfi);
/**
* \brief Setter for the VLAN ID field.
* \param new_id The new VLAN ID field value.
*/
void id(small_uint<12> new_id);
/**
* \brief Setter for the payload type field.
* \param new_type The new type field value.
*/
void payload_type(uint16_t new_type);
/**
* \brief Indicates whether the appropriate padding will be
* at the end of the packet.
*
* This flag could be disabled in case two or more contiguous Dot1Q
* PDUs are added to a packet. In that case, only the Dot1Q which is
* closer to the link layer should add the padding at the end.
*
* \param value A boolean indicating whether padding will be appended.
*/
void append_padding(bool value);
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
TINS_BEGIN_PACK
struct dot1q_hdr {
#if TINS_IS_BIG_ENDIAN
uint16_t priority:3,
cfi:1,
id:12;
uint16_t type;
#else
uint16_t idH:4,
cfi:1,
priority:3,
idL:8;
uint16_t type;
#endif
} TINS_END_PACK;
static uint16_t get_id(const dot1q_hdr *hdr);
dot1q_hdr _header;
bool _append_padding;
};
}
#endif // TINS_DOT1Q_H

194
include/tins/dot3.h Normal file
View File

@@ -0,0 +1,194 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_DOT3_H
#define TINS_DOT3_H
#include <stdint.h>
#include "macros.h"
#include "pdu.h"
#include "endianness.h"
#include "hw_address.h"
namespace Tins {
/**
* \class Dot3
* \brief Class representing an IEEE 802.3 PDU.
*/
class Dot3 : public PDU {
public:
/**
* \brief The address type.
*/
typedef HWAddress<6> address_type;
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::IEEE802_3;
/**
* \brief Represents the Dot3 broadcast address.
*/
static const address_type BROADCAST;
/**
* \brief Constructor for creating an Dot3 PDU
*
* Constructor that builds an Dot3 PDU taking the interface name,
* destination's and source's MAC.
*
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
* \param child The PDU which will be set as the inner PDU.
*/
Dot3(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructs a Dot3 object from a buffer and adds a
* LLC object with the remaining data as the inner PDU.
*
* If there is not enough size for a Dot3 header, a
* malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot3(const uint8_t *buffer, uint32_t total_sz);
/* Getters */
/**
* \brief Getter for the destination hardware address.
*
* \return The destination hardware address.
*/
address_type dst_addr() const { return _eth.dst_mac; }
/**
* \brief Getter for the source hardware address.
*
* \return The source hardware address.
*/
address_type src_addr() const { return _eth.src_mac; }
/**
* \brief Getter for the length field.
* \return The length field value.
*/
uint16_t length() const { return Endian::be_to_host(_eth.length); };
/* Setters */
/**
* \brief Setter for the destination hardware address.
*
* \param new_dst_mac The new destination hardware address.
*/
void dst_addr(const address_type &new_dst_mac);
/**
* \brief Setter for the source hardware address.
*
* \param new_src_mac The new source hardware address.
*/
void src_addr(const address_type &new_src_mac);
/**
* \brief Setter for the length field.
*
* \param new_length uint16_t with the new value of the length field.
*/
void length(uint16_t new_length);
/* Virtual methods */
/**
* \brief Returns the Dot3 frame's header length.
*
* \return An uint32_t with the header's size.
* \sa PDU::header_size()
*/
uint32_t header_size() const;
#ifndef WIN32
/**
* \sa PDU::send()
*/
void send(PacketSender &sender, const NetworkInterface &iface);
#endif // WIN32
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
#ifndef WIN32
/**
* \sa PDU::recv_response
*/
PDU *recv_response(PacketSender &sender, const NetworkInterface &iface);
#endif // WIN32
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \sa PDU::clone
*/
Dot3 *clone() const {
return new Dot3(*this);
}
private:
/**
* Struct that represents the Ethernet II header
*/
TINS_BEGIN_PACK
struct ethhdr {
uint8_t dst_mac[address_type::address_size];
uint8_t src_mac[address_type::address_size];
uint16_t length;
} TINS_END_PACK;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
ethhdr _eth;
};
}
#endif // TINS_DOT3_H

742
include/tins/eapol.h Normal file
View File

@@ -0,0 +1,742 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_EAPOL_H
#define TINS_EAPOL_H
#include <stdint.h>
#include "pdu.h"
#include "macros.h"
#include "small_uint.h"
#include "endianness.h"
namespace Tins {
/** \cond
* Forward declaration. Avoid header inclusion.
*/
class RSNInformation;
/** \endcond */
/**
* \class EAPOL
* \brief Represents the EAP encapsulation over LAN.
*/
class EAPOL : public PDU {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::EAPOL;
/**
* The EAPOL type enum.
*/
enum EAPOLTYPE {
RC4 = 1,
RSN,
EAPOL_WPA = 254
};
/**
* \brief Static method to instantiate the correct EAPOL subclass
* based on a raw buffer.
*
* If no valid EAPOL type is detected, a null pointer is returned.
*
* \sa RC4EAPOL
* \sa RSNEAPOL
*
* \param buffer The buffer from which the data will be taken.
* \param total_sz The total size of the buffer.
*/
static EAPOL *from_bytes(const uint8_t *buffer, uint32_t total_sz);
/* Getters */
/**
* \brief Getter for the version field.
* \return The version field.
*/
uint8_t version() const { return _header.version; }
/**
* \brief Getter for the packet type field.
* \return The packet type field.
*/
uint8_t packet_type() const { return _header.packet_type; }
/**
* \brief Getter for the length field.
* \return The length field.
*/
uint16_t length() const { return Endian::be_to_host(_header.length); }
/**
* \brief Getter for the type field.
* \return The type field.
*/
uint8_t type() const { return _header.type; }
/* Setters */
/**
* \brief Sets the version field.
* \param new_version The new version to be set.
*/
void version(uint8_t new_version);
/**
* \brief Sets the packet type field.
* \param new_ptype The new packet type to be set.
*/
void packet_type(uint8_t new_ptype);
/**
* \brief Sets the length field.
* \param new_length The new length to be set.
*/
void length(uint16_t new_length);
/**
* \brief Sets the type field.
* \param new_type The new type to be set.
*/
void type(uint8_t new_type);
/**
* \brief Getter for the PDU's type.
* \return Returns the PDUType corresponding to the PDU.
*/
PDUType pdu_type() const { return PDU::EAPOL; }
protected:
/**
* \brief Protected constructor that sets the packet_type and type fields.
*/
EAPOL(uint8_t packet_type, EAPOLTYPE type);
/**
* \brief Constructor which creates an EAPOL object from a buffer.
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
EAPOL(const uint8_t *buffer, uint32_t total_sz);
TINS_BEGIN_PACK
struct eapolhdr {
uint8_t version, packet_type;
uint16_t length;
uint8_t type;
} TINS_END_PACK;
/**
* \brief Virtual method which should serialize the subclass specific
* body and save it in a byte array.
*
* \param buffer The pointer in which to save the serialization.
* \param total_sz The total size of the buffer.
*/
virtual void write_body(uint8_t *buffer, uint32_t total_sz) = 0;
private:
/**
* \brief Serialices this EAPOL PDU.
* \param buffer The buffer in which the PDU will be serialized.
* \param total_sz The size available in the buffer.
* \param parent The PDU that's one level below this one on the stack.
*/
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
eapolhdr _header;
};
/**
* \brief Class that represents the RC4 EAPOL PDU.
*/
class RC4EAPOL : public EAPOL {
public:
/**
* The type used to store the key.
*/
typedef std::vector<uint8_t> key_type;
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::RC4EAPOL;
/**
* The length of the key IV field
*/
static const size_t key_iv_size = 16;
/**
* The length of the key sign field
*/
static const size_t key_sign_size = 16;
/**
* \brief Default constructor.
*/
RC4EAPOL();
/**
* \brief Constructs a RC4EAPOL object from a buffer.
*
* If there is not enough size for a RC4EAPOL header in the
* buffer, a malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
RC4EAPOL(const uint8_t *buffer, uint32_t total_sz);
/* Getters */
/**
* \brief Getter for the key length field.
* \return The key length field.
*/
uint16_t key_length() const { return Endian::be_to_host(_header.key_length); }
/**
* \brief Getter for the replay counter field.
* \return The replay counter field.
*/
uint64_t replay_counter() const { return Endian::be_to_host(_header.replay_counter); }
/**
* \brief Getter for the key IV field.
* \return The key IV field.
*/
const uint8_t *key_iv() const { return _header.key_iv; }
/**
* \brief Getter for the key flag field.
* \return The key flag field.
*/
small_uint<1> key_flag() const { return _header.key_flag; }
/**
* \brief Getter for the key index field.
* \return The key index field.
*/
small_uint<7> key_index() const { return _header.key_index; }
/**
* \brief Getter for the key signature field.
* \return The key signature field.
*/
const uint8_t *key_sign() const { return _header.key_sign; }
/**
* \brief Getter for the key field.
* \return The key field.
*/
const key_type &key() const { return _key; }
/* Setters */
/**
* \brief Sets the key length field.
* \param new_key_length The new key length to be set.
*/
void key_length(uint16_t new_key_length);
/**
* \brief Sets the replay counter field.
* \param new_replay_counter The new replay counter to be set.
*/
void replay_counter(uint64_t new_replay_counter);
/**
* \brief Sets the key IV field.
* \param new_key_iv The new key IV to be set.
*/
void key_iv(const uint8_t *new_key_iv);
/**
* \brief Sets the key flag field.
* \param new_key_flag The new key flag to be set.
*/
void key_flag(small_uint<1> new_key_flag);
/**
* \brief Sets the key index field.
* \param new_key_index The new key index to be set.
*/
void key_index(small_uint<7> new_key_index);
/**
* \brief Sets the key signature field.
* \param new_key_sign The new key signature to be set.
*/
void key_sign(const uint8_t *new_key_sign);
/**
* \brief Sets the key field.
* \param new_key The new key to be set.
*/
void key(const key_type &new_key);
/* Virtual method override. */
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. This size includes the
* payload and options size.
*
* \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Getter for the PDU's type.
* \return Returns the PDUType corresponding to the PDU.
*/
PDUType pdu_type() const { return PDU::RC4EAPOL; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == PDU::RC4EAPOL || EAPOL::matches_flag(flag);
}
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
RC4EAPOL *clone() const {
return new RC4EAPOL(*this);
}
private:
TINS_BEGIN_PACK
struct rc4hdr {
uint16_t key_length;
uint64_t replay_counter;
uint8_t key_iv[key_iv_size];
uint8_t key_index:7,
key_flag:1;
uint8_t key_sign[16];
} TINS_END_PACK;
void write_body(uint8_t *buffer, uint32_t total_sz);
key_type _key;
rc4hdr _header;
};
/**
* \brief Class that represents the RSN EAPOL PDU.
*/
class RSNEAPOL : public EAPOL {
public:
/**
* The type used to store the key.
*/
typedef std::vector<uint8_t> key_type;
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::RSNEAPOL;
/**
* The length of the key IV field
*/
static const size_t key_iv_size = 16;
/**
* The length of the nonce field
*/
static const size_t nonce_size = 32;
/**
* The length of the mic field
*/
static const size_t mic_size = 16;
/**
* The length of the rsc field
*/
static const size_t rsc_size = 8;
/**
* The length of the id field
*/
static const size_t id_size = 8;
/**
* \brief Creates an instance of RSNEAPOL.
*/
RSNEAPOL();
/**
* \brief Constructs a RSNEAPOL object from a buffer.
*
* If there is not enough size for the RSNEAPOL header, a
* malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
RSNEAPOL(const uint8_t *buffer, uint32_t total_sz);
/* Getters */
/**
* \brief Getter for the key length field.
* \return The key length field.
*/
uint16_t key_length() const { return Endian::be_to_host(_header.key_length); }
/**
* \brief Getter for the replay counter field.
* \return The replay counter field.
*/
uint64_t replay_counter() const { return Endian::be_to_host(_header.replay_counter); }
/**
* \brief Getter for the key IV field.
* \return The key IV field.
*/
const uint8_t *key_iv() const { return _header.key_iv; }
/**
* \brief Getter for the nonce field.
* \return The nonce field.
*/
const uint8_t *nonce() const { return _header.nonce; }
/**
* \brief Getter for the rsc field.
* \return The rsc field.
*/
const uint8_t *rsc() const { return _header.rsc; }
/**
* \brief Getter for the id field.
* \return The id field.
*/
const uint8_t *id() const { return _header.id; }
/**
* \brief Getter for the mic field.
* \return The mic field.
*/
const uint8_t *mic() const { return _header.mic; }
/**
* \brief Getter for the wpa length field.
* \return The wpa length field.
*/
uint16_t wpa_length() const { return Endian::be_to_host(_header.wpa_length); }
/**
* \brief Getter for the key field.
* \return The key field.
*/
const key_type &key() const { return _key; }
/**
* \brief Getter for the key mic field.
* \return 1 if this EAPOL PDU contains a valid MIC, 0 otherwise.
*/
small_uint<1> key_mic() const { return _header.key_mic; };
/**
* \brief Getter for the secure field.
* \return The secure field.
*/
small_uint<1> secure() const { return _header.secure; };
/**
* \brief Getter for the error field.
* \return The error field.
*/
small_uint<1> error() const { return _header.error; };
/**
* \brief Getter for the request field.
* \return The request field.
*/
small_uint<1> request() const { return _header.request; };
/**
* \brief Getter for the encrypted field.
* \return The encrypted field.
*/
small_uint<1> encrypted() const { return _header.encrypted; };
/**
* \brief Getter for the key descriptor field.
* \return The key descriptor field.
*/
small_uint<3> key_descriptor() const { return _header.key_descriptor; };
/**
* \brief Getter for the key type field.
*
* \return 1 if this is a pairwise key, 0 otherwise.
*/
small_uint<1> key_t() const { return _header.key_t; };
/**
* \brief Getter for the key_index field.
* \return The key_index field.
*/
small_uint<2> key_index() const { return _header.key_index; };
/**
* \brief Getter for the install field.
* \return The install field.
*/
small_uint<1> install() const { return _header.install; };
/**
* \brief Getter for the key_ack field.
* \return The key_ack field.
*/
small_uint<1> key_ack() const { return _header.key_ack; };
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. This size includes the
* payload and options size.
*
* \sa PDU::header_size
*/
uint32_t header_size() const;
/* Setters */
/**
* \brief Sets the key length field.
* \param new_key_length The new key length to be set.
*/
void key_length(uint16_t new_key_length);
/**
* \brief Sets the replay counter field.
* \param new_replay_counter The new replay counter to be set.
*/
void replay_counter(uint64_t new_replay_counter);
/**
* \brief Sets the key IV field.
* \param new_key_iv The new key IV to be set.
*/
void key_iv(const uint8_t *new_key_iv);
/**
* \brief Sets the nonce field.
*
* This method sets the nonce field. This field is 32 bytes long,
* therefore the input buffer should be at least that length.
* \param new_nonce The new nonce to be set.
*/
void nonce(const uint8_t *new_nonce);
/**
* \brief Sets the rsc field.
* \param new_rsc The new rsc to be set.
*/
void rsc(const uint8_t *new_rsc);
/**
* \brief Sets the id field.
* \param new_id The new id to be set.
*/
void id(const uint8_t *new_id);
/**
* \brief Sets the mic field.
*
* This method sets the mic field. This field is 16 bytes long,
* therefore the input buffer should be at least that length.
* \param new_mic The new mic to be set.
*/
void mic(const uint8_t *new_mic);
/**
* \brief Sets the wpa length field.
* \param new_wpa_length The new wpa length to be set.
*/
void wpa_length(uint16_t new_wpa_length);
/**
* \brief Sets the key field.
* \param new_key The new key to be set.
*/
void key(const key_type &new_key);
/**
* \brief Setter for the key_mic field.
* \param new_key_mic The new to be set.
*/
void key_mic(small_uint<1> new_key_mic);
/**
* \brief Setter for the secure field.
* \param new_secure The new to be set.
*/
void secure(small_uint<1> new_secure);
/**
* \brief Setter for the error field.
* \param new_error The new to be set.
*/
void error(small_uint<1> new_error);
/**
* \brief Setter for the request field.
* \param new_request The new to be set.
*/
void request(small_uint<1> new_request);
/**
* \brief Setter for the encrypted field.
* \param new_encrypted The new to be set.
*/
void encrypted(small_uint<1 > new_encrypted);
/**
* \brief Setter for the key_descriptor field.
* \param new_key_descriptor The new to be set.
*/
void key_descriptor(small_uint<3> new_key_descriptor);
/**
* \brief Setter for the key_t field.
* \param new_key_t The new to be set.
*/
void key_t(small_uint<1> new_key_t);
/**
* \brief Setter for the key_index field.
* \param new_key_index The new to be set.
*/
void key_index(small_uint<2> new_key_index);
/**
* \brief Setter for the install field.
* \param new_install The new to be set.
*/
void install(small_uint<1> new_install);
/**
* \brief Setter for the key_ack field.
* \param new_key_ack The new to be set.
*/
void key_ack(small_uint<1> new_key_ack);
/**
* \brief Getter for the PDU's type.
* \return Returns the PDUType corresponding to the PDU.
*/
PDUType pdu_type() const { return PDU::RSNEAPOL; }
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == PDU::RSNEAPOL || EAPOL::matches_flag(flag);
}
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
RSNEAPOL *clone() const {
return new RSNEAPOL(*this);
}
private:
TINS_BEGIN_PACK
struct rsnhdr {
#if TINS_IS_LITTLE_ENDIAN
uint16_t key_mic:1,
secure:1,
error:1,
request:1,
encrypted:1,
reserved:3,
key_descriptor:3,
key_t:1,
key_index:2,
install:1,
key_ack:1;
uint16_t key_length;
uint64_t replay_counter;
uint8_t nonce[nonce_size], key_iv[key_iv_size];
uint8_t rsc[rsc_size], id[id_size];
uint8_t mic[mic_size];
uint16_t wpa_length;
#else
uint16_t reserved:3,
encrypted:1,
request:1,
error:1,
secure:1,
key_mic:1,
key_ack:1,
install:1,
key_index:2,
key_t:1,
key_descriptor:3;
uint16_t key_length;
uint64_t replay_counter;
uint8_t nonce[nonce_size], key_iv[key_iv_size];
uint8_t rsc[rsc_size], id[id_size];
uint8_t mic[mic_size];
uint16_t wpa_length;
#endif
} TINS_END_PACK;
void write_body(uint8_t *buffer, uint32_t total_sz);
rsnhdr _header;
key_type _key;
};
}
#endif // TINS_EAPOL_H

237
include/tins/endianness.h Normal file
View File

@@ -0,0 +1,237 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_ENDIANNESS_H
#define TINS_ENDIANNESS_H
#include <stdint.h>
#include "macros.h"
#if defined(__APPLE__)
#include <sys/types.h>
#define TINS_IS_LITTLE_ENDIAN (BYTE_ORDER == LITTLE_ENDIAN)
#define TINS_IS_BIG_ENDIAN (BYTE_ORDER == BIG_ENDIAN)
#elif defined(BSD)
#include <sys/endian.h>
#define TINS_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN)
#define TINS_IS_BIG_ENDIAN (_BYTE_ORDER == _BIG_ENDIAN)
#elif defined(WIN32)
// Assume windows == little endian. fixme later
#define TINS_IS_LITTLE_ENDIAN 1
#define TINS_IS_BIG_ENDIAN 0
#else
#include <endian.h>
#define TINS_IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN)
#define TINS_IS_BIG_ENDIAN (__BYTE_ORDER == __BIG_ENDIAN)
#endif
namespace Tins {
namespace Endian {
/**
* \brief "Changes" a 8-bit integral value's endianess. This is an
* identity function.
*
* \param data The data to convert.
*/
inline uint8_t do_change_endian(uint8_t data) {
return data;
}
/**
* \brief Changes a 16-bit integral value's endianess.
*
* \param data The data to convert.
*/
inline uint16_t do_change_endian(uint16_t data) {
return ((data & 0xff00) >> 8) | ((data & 0x00ff) << 8);
}
/**
* \brief Changes a 32-bit integral value's endianess.
*
* \param data The data to convert.
*/
inline uint32_t do_change_endian(uint32_t data) {
return (((data & 0xff000000) >> 24) | ((data & 0x00ff0000) >> 8) |
((data & 0x0000ff00) << 8) | ((data & 0x000000ff) << 24));
}
/**
* \brief Changes a 64-bit integral value's endianess.
*
* \param data The data to convert.
*/
inline uint64_t do_change_endian(uint64_t data) {
return (((uint64_t)(do_change_endian((uint32_t)(data & 0xffffffff))) << 32) |
(do_change_endian(((uint32_t)(data >> 32)))));
}
/**
* \cond
*/
// Helpers to convert
template<typename T>
struct conversion_dispatch_helper {
static T dispatch(T data) {
return do_change_endian(data);
}
};
template<size_t>
struct conversion_dispatcher;
template<>
struct conversion_dispatcher<sizeof(uint8_t)>
: public conversion_dispatch_helper<uint8_t>
{ };
template<>
struct conversion_dispatcher<sizeof(uint16_t)>
: public conversion_dispatch_helper<uint16_t>
{ };
template<>
struct conversion_dispatcher<sizeof(uint32_t)>
: public conversion_dispatch_helper<uint32_t>
{ };
template<>
struct conversion_dispatcher<sizeof(uint64_t)>
: public conversion_dispatch_helper<uint64_t>
{ };
/**
* \endcond
*/
/**
* \brief Changes an integral value's endianess.
*
* This dispatchs to the corresponding function.
*
* \param data The data to convert.
*/
template<typename T>
inline T change_endian(T data) {
return conversion_dispatcher<sizeof(T)>::dispatch(data);
}
#if TINS_IS_LITTLE_ENDIAN
/**
* \brief Convert any integral type to big endian.
*
* \param data The data to convert.
*/
template<typename T>
inline T host_to_be(T data) {
return change_endian(data);
}
/**
* \brief Convert any integral type to little endian.
*
* On little endian platforms, the parameter is simply returned.
*
* \param data The data to convert.
*/
template<typename T>
inline T host_to_le(T data) {
return data;
}
/**
* \brief Convert any big endian value to the host's endianess.
*
* \param data The data to convert.
*/
template<typename T>
inline T be_to_host(T data) {
return change_endian(data);
}
/**
* \brief Convert any little endian value to the host's endianess.
*
* \param data The data to convert.
*/
template<typename T>
inline T le_to_host(T data) {
return data;
}
#elif TINS_IS_BIG_ENDIAN
/**
* \brief Convert any integral type to big endian.
*
* \param data The data to convert.
*/
template<typename T>
inline T host_to_be(T data) {
return data;
}
/**
* \brief Convert any integral type to little endian.
*
* On little endian platforms, the parameter is simply returned.
*
* \param data The data to convert.
*/
template<typename T>
inline T host_to_le(T data) {
return change_endian(data);
}
/**
* \brief Convert any big endian value to the host's endianess.
*
* \param data The data to convert.
*/
template<typename T>
inline T be_to_host(T data) {
return data;
}
/**
* \brief Convert any little endian value to the host's endianess.
*
* \param data The data to convert.
*/
template<typename T>
inline T le_to_host(T data) {
return change_endian(data);
}
#endif
}
}
#endif // TINS_ENDIANNESS_H

205
include/tins/ethernetII.h Normal file
View File

@@ -0,0 +1,205 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_ETHERNET_II_H
#define TINS_ETHERNET_II_H
#include <stdint.h>
#include "macros.h"
#include "pdu.h"
#include "endianness.h"
#include "hw_address.h"
namespace Tins {
/**
* \class EthernetII
* \brief Represents an Ethernet II PDU.
*/
class EthernetII : public PDU {
public:
/**
* \brief The hardware address type.
*/
typedef HWAddress<6> address_type;
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::ETHERNET_II;
/**
* \brief Represents the ethernetII broadcast address.
*/
static const address_type BROADCAST;
/**
* \brief Constructs an ethernet II PDU.
*
* \param dst_hw_addr address_type containing the destination's MAC.
* \param src_hw_addr address_type containing the source's MAC.
*/
EthernetII(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructs a EthernetII object from a buffer and adds
* all identifiable PDUs found in the buffer as children of
* this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for a EthernetII header in the
* buffer, a malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
EthernetII(const uint8_t *buffer, uint32_t total_sz);
/* Getters */
/**
* \brief Getter for the destination's hardware address.
*
* \return address_type containing the destination hardware
* address.
*/
address_type dst_addr() const { return _eth.dst_mac; }
/**
* \brief Getter for the source's hardware address.
*
* \return address_type containing the source hardware address.
*/
address_type src_addr() const { return _eth.src_mac; }
/**
* \brief Getter for the payload_type
* \return The payload type.
*/
uint16_t payload_type() const { return Endian::be_to_host(_eth.payload_type); };
/* Setters */
/**
* \brief Setter for the destination hardware address.
*
* \param new_dst_addr the destination hardware address to be set.
*/
void dst_addr(const address_type &new_dst_addr);
/**
* \brief Setter for the source hardware address.
*
* \param new_src_addr the source hardware address to be set.
*/
void src_addr(const address_type &new_src_addr);
/**
* \brief Setter for the payload type.
*
* \param new_payload_type the new value of the payload type field.
*/
void payload_type(uint16_t new_payload_type);
/* Virtual methods */
/**
* \brief Returns the ethernet frame's header length.
*
* \return An uint32_t with the header's size.
* \sa PDU::header_size()
*/
uint32_t header_size() const;
/**
* \brief Returns the ethernet II frame's padding.
*
* \return An uint32_t with the padding size.
* \sa PDU::trailer_size()
*/
uint32_t trailer_size() const;
// Windows does not support sending L2 PDUs.
#ifndef WIN32
/**
* \sa PDU::send()
*/
void send(PacketSender &sender, const NetworkInterface &iface);
#endif // WIN32
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
#ifndef WIN32
/**
* \brief Receives a matching response for this packet.
*
* \sa PDU::recv_response
*/
PDU *recv_response(PacketSender &sender, const NetworkInterface &iface);
#endif // WIN32
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::ETHERNET_II; }
/**
* \sa PDU::clone
*/
EthernetII *clone() const {
return new EthernetII(*this);
}
private:
/**
* Struct that represents the Ethernet II header
*/
TINS_BEGIN_PACK
struct ethhdr {
uint8_t dst_mac[address_type::address_size];
uint8_t src_mac[address_type::address_size];
uint16_t payload_type;
} TINS_END_PACK;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
ethhdr _eth;
};
}
#endif // TINS_ETHERNET_II_H

173
include/tins/exceptions.h Normal file
View File

@@ -0,0 +1,173 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_EXCEPTIONS_H
#define TINS_EXCEPTIONS_H
#include <string>
#include <stdexcept>
namespace Tins {
/**
* \brief Exception thrown when an option is not found.
*/
class option_not_found : public std::runtime_error {
public:
option_not_found()
: std::runtime_error(std::string()) { }
// try to avoid allocations by doing this.
const char* what() const throw() {
return "Option not found";
}
};
/**
* \brief Exception thrown when a malformed packet is parsed.
*/
class malformed_packet : public std::runtime_error {
public:
malformed_packet()
: std::runtime_error(std::string()) { }
const char* what() const throw() {
return "Malformed packet";
}
};
/**
* \brief Exception thrown when a PDU is not found when using PDU::rfind_pdu.
*/
class pdu_not_found : public std::runtime_error {
public:
pdu_not_found()
: std::runtime_error(std::string()) { }
const char* what() const throw() {
return "PDU not found";
}
};
/**
* \brief Exception thrown when PDU::send requires a valid interface,
* but an invalid is used.
*/
class invalid_interface : public std::runtime_error {
public:
invalid_interface()
: std::runtime_error(std::string()) { }
const char* what() const throw() {
return "Invalid interface";
}
};
/**
* \brief Exception thrown when PacketSender fails to open a socket.
*/
class socket_open_error : public std::runtime_error {
public:
socket_open_error(const std::string &msg)
: std::runtime_error(msg) { }
};
/**
* \brief Exception thrown when PacketSender fails to close a socket.
*/
class socket_close_error : public std::runtime_error {
public:
socket_close_error(const std::string &msg)
: std::runtime_error(msg) { }
};
/**
* \brief Exception thrown when PacketSender fails to write on a socket.
*/
class socket_write_error : public std::runtime_error {
public:
socket_write_error(const std::string &msg)
: std::runtime_error(msg) { }
};
/**
* \brief Exception thrown when an invalid socket type is provided
* to PacketSender.
*/
class invalid_socket_type : public std::exception {
public:
const char *what() const throw() {
return "The provided socket type is invalid";
}
};
/**
* \brief Exception thrown when an unkown link layer PDU type is
* found while sniffing.
*/
class unknown_link_type : public std::exception {
public:
const char *what() const throw() {
return "The sniffed link layer PDU type is unknown";
}
};
/**
* \brief Exception thrown when a malformed option is found.
*/
class malformed_option : public std::exception {
public:
const char *what() const throw() {
return "Malformed option";
}
};
/**
* \brief Exception thrown when a call to tins_cast fails.
*/
class bad_tins_cast : public std::exception {
public:
const char *what() const throw() {
return "Bad Tins cast";
}
};
/**
* \brief Exception thrown when sniffing a protocol that
* has been disabled at compile time.
*/
class protocol_disabled : public std::exception {
public:
const char *what() const throw() {
return "Protocol disabled";
}
};
} // Tins
#endif // TINS_EXCEPTIONS_H

View File

@@ -0,0 +1,169 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "config.h"
#if !defined(TINS_HANDSHAKE_CAPTURER_H) && defined(HAVE_DOT11)
#define TINS_HANDSHAKE_CAPTURER_H
#include <vector>
#include <map>
#include <utility>
#include "hw_address.h"
#include "eapol.h"
// .h
namespace Tins {
/**
* \brief Generic EAPOL handshake.
*
* Stores both the client and supplicant addresses, as well as
* all of the EAPOL packets used during the handshake.
*/
template<typename T>
class EAPOLHandshake {
public:
typedef std::vector<T> container_type;
typedef HWAddress<6> address_type;
/**
* \brief Default constructor.
*/
EAPOLHandshake() { }
/**
* Constructs an EAPOLHandshake object.
*
* \param client_address The client address.
* \param supplicant_address The supplicant address.
* \param cont The container that holds the EAPOL packets used
* in the handshake.
*/
EAPOLHandshake(const address_type &client_address,
const address_type &supplicant_address, const container_type &cont)
: cl_address_(client_address), suppl_address_(supplicant_address),
handshake_(cont)
{
}
/**
* \return const address_type&
*/
const address_type &client_address() const {
return cl_address_;
}
/**
* \return const address_type&
*/
const address_type &supplicant_address() const {
return suppl_address_;
}
/**
* \return const container_type&
*/
const container_type &handshake() const {
return handshake_;
}
private:
address_type cl_address_, suppl_address_;
container_type handshake_;
};
/**
* The type used to store RSN handshakes.
*/
typedef EAPOLHandshake<RSNEAPOL> RSNHandshake;
/**
* Captures 802.1X RSN handshakes.
*/
class RSNHandshakeCapturer {
public:
/**
* The type of handshakes that will be captured.
*/
typedef RSNHandshake handshake_type;
/**
* The type in which all of the captured handshakes
* will be stored.
*/
typedef std::vector<handshake_type> handshakes_type;
/**
* \brief Processes a packet.
*
* This will fetch the RSNEAPOL layer, if any, and store
* it in an intermediate storage. When a handshake is
* completed, it will be stored separately.
*
* \sa RSNHandshakeCapturer::handshakes
*/
bool process_packet(const PDU &pdu);
/**
* \brief Retrieves the completed handshakes.
*
* This will return the handshakes that have been completed
* so far. A handshake is completed when the 4-way handshake
* is captured.
*
* \sa RSNHandshakeCapturer::clear_handshakes
*/
const handshakes_type &handshakes() const {
return completed_handshakes_;
}
/**
* \brief Clears the completed handshakes.
*
* Since completed handshakes are stored in a std::vector,
* it is advisable to remove all of them once they have been
* processed.
*/
void clear_handshakes() {
completed_handshakes_.clear();
}
private:
typedef handshake_type::address_type address_type;
typedef handshake_type::container_type eapol_list;
typedef std::map<std::pair<address_type, address_type>, eapol_list> handshake_map;
bool do_insert(const handshake_map::key_type &key, const RSNEAPOL *eapol,
size_t expected);
handshake_map handshakes_;
handshakes_type completed_handshakes_;
};
}
#endif // TINS_HANDSHAKE_CAPTURER_H

404
include/tins/hw_address.h Normal file
View File

@@ -0,0 +1,404 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_HWADDRESS_H
#define TINS_HWADDRESS_H
#include <stdint.h>
#include <stdexcept>
#include <iterator>
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <sstream>
#include "cxxstd.h"
namespace Tins {
/**
* \class HWAddress
* \brief Represents a hardware address.
*
* This class represents a hardware (MAC) address. It can
* be constructed from it's string representation and you can
* iterate over the bytes that compose it.
*
* For example:
*
* \code
* // Construct it from a string.
* HWAddress<6> address("00:01:fa:9e:1a:cd");
*
* // Iterate over its bytes.
* for(auto element : address) {
* // element will be each of the bytes(\x00, \x01, \xfa, etc)
* }
* \endcode
*/
template<size_t n, typename Storage = uint8_t>
class HWAddress {
public:
/**
* \brief The type of the elements stored in the hardware address.
*
* This is the same as the template parameter Storage.
*/
typedef Storage storage_type;
/**
* \brief The random access iterator type.
*/
typedef storage_type* iterator;
/**
* \brief Const iterator type.
*/
typedef const storage_type* const_iterator;
/**
* \brief Non-member constant indicating the amount of storage_type
* elements in this address.
*/
static const size_t address_size = n;
/**
* \brief The broadcast address.
*/
static const HWAddress<n, Storage> broadcast;
/**
* \brief Constructor from a const storage_type*.
*
* If no pointer or a null pointer is provided, the address is
* initialized to 00:00:00:00:00:00.
*
* This constructor is very usefull when passing zero initialized
* addresses as arguments to other functions. You can use a
* literal 0, which will be implicitly converted to the empty address.
*
* If a pointer is provided, address_size storage_type elements
* are copied from the pointer, into the internal address representation.
*
* \param ptr The pointer from which to construct this address.
*/
HWAddress(const storage_type* ptr = 0) {
if(ptr)
std::copy(ptr, ptr + address_size, buffer);
else
std::fill(begin(), end(), storage_type());
}
/**
* \brief Constructs an address from a hex-notation address.
*
* This constructor will parse strings in the form:
*
* "00:01:da:fa:..."
*
* And initialize the internal representation accordingly.
*
* \param address The hex-notation address to be parsed.
*/
HWAddress(const std::string &address) {
convert(address, buffer);
}
/**
* \brief Overload provided basically for string literals.
*
* This constructor takes a const char array of i elements in
* hex-notation. \sa HWAddress::HWAddress(const std::string &address)
*
* This is mostly used when providing string literals. If this where
* a const char*, then there would be an ambiguity when providing
* a null pointer.
*
* \param address The array of chars containing the hex-notation
* cstring to be parsed.
*/
template<size_t i>
HWAddress(const char (&address)[i]) {
convert(address, buffer);
}
/**
* \brief Copy construct from a HWAddress of length i.
*
* If i is lower or equal than address_size, then i storage_type
* elements are copied, and the last (n - i) are initialized to
* the default storage_type value(0 most of the times).
*
* If i is larger than address_size, then only the first address_size
* elements are copied.
*
* \param rhs The HWAddress to be constructed from.
*/
template<size_t i>
HWAddress(const HWAddress<i> &rhs) {
// Fill extra bytes
std::fill(
// Copy as most as we can
std::copy(
rhs.begin(),
rhs.begin() + std::min(i, n),
begin()
),
end(),
0
);
}
/**
* \brief Retrieves an iterator pointing to the begining of the
* address.
*
* \return iterator.
*/
iterator begin() {
return buffer;
}
/**
* \brief Retrieves a const iterator pointing to the begining of
* the address.
*
* \return const_iterator.
*/
const_iterator begin() const {
return buffer;
}
/**
* \brief Retrieves an iterator pointing one-past-the-end of the
* address.
*
* \return iterator.
*/
iterator end() {
return buffer + address_size;
}
/**
* \brief Retrieves a const iterator pointing one-past-the-end of
* the address.
*
* \return const_iterator.
*/
const_iterator end() const {
return buffer + address_size;
}
/**
* \brief Compares this HWAddress for equality.
*
* \param rhs The HWAddress to be compared to.
*
* \return bool indicating whether addresses are equal.
*/
bool operator==(const HWAddress &rhs) const {
return std::equal(begin(), end(), rhs.begin());
}
/**
* \brief Compares this HWAddress for in-equality.
*
* \param rhs The HWAddress to be compared to.
*
* \return bool indicating whether addresses are distinct.
*/
bool operator!=(const HWAddress &rhs) const {
return !(*this == rhs);
}
/**
* \brief Compares this HWAddress for less-than inequality.
*
* \param rhs The HWAddress to be compared to.
*
* \return bool indicating whether this address is less-than rhs.
*/
bool operator<(const HWAddress &rhs) const {
return std::lexicographical_compare(begin(), end(), rhs.begin(), rhs.end());
}
/**
* \brief Retrieves the size of this address.
*
* This effectively returns the address_size constant.
*/
const size_t size() const {
return address_size;
}
/**
* \brief Indicates whether this is a broadcast address.
*/
bool is_broadcast() const {
return *this == broadcast;
}
/**
* \brief Indicates whether this is a multicast address.
*/
bool is_multicast() const {
return (buffer[0] & 0x01);
}
/**
* \brief Indicates whether this is an unicast address.
*/
bool is_unicast() const {
return !is_broadcast() && !is_multicast();
}
/**
* \brief Convert this address to a hex-notation std::string address.
*
* \return std::string containing the hex-notation address.
*/
std::string to_string() const {
std::ostringstream oss;
oss << *this;
return oss.str();
}
/**
* \brief Retrieves the i-th storage_type in this address.
*
* \param i The element to retrieve.
*/
storage_type operator[](size_t i) const {
return buffer[i];
}
/**
* \brief Writes this HWAddress in hex-notation to a std::ostream.
*
* \param os The stream in which to write the address.
* \param addr The parameter to be written.
* \return std::ostream& pointing to the os parameter.
*/
friend std::ostream &operator<<(std::ostream &os, const HWAddress &addr) {
std::transform(
addr.begin(),
addr.end() - 1,
std::ostream_iterator<std::string>(os, ":"),
&HWAddress::storage_to_string
);
return os << storage_to_string(addr.buffer[HWAddress::address_size-1]);
}
/**
* \brief Helper function which copies the address into an output
* iterator.
*
* This is the same as:
*
* std::copy(begin(), end(), iter);
*
* But since some PDUs return a HWAddress<> by value, this function
* can be used to avoid temporaries.
*
* \param iter The output iterator in which to store this address.
* \return OutputIterator pointing to one-past the last position
* written.
*/
template<typename OutputIterator>
OutputIterator copy(OutputIterator iter) const {
return std::copy(begin(), end(), iter);
}
private:
template<typename OutputIterator>
static void convert(const std::string &hw_addr, OutputIterator output);
static std::string storage_to_string(storage_type element) {
std::ostringstream oss;
oss << std::hex;
if(element < 0x10)
oss << '0';
oss << (unsigned)element;
return oss.str();
}
storage_type buffer[n];
};
template<size_t n, typename Storage>
template<typename OutputIterator>
void HWAddress<n, Storage>::convert(const std::string &hw_addr,
OutputIterator output)
{
unsigned i(0);
size_t count(0);
storage_type tmp;
while(i < hw_addr.size() && count < n) {
const unsigned end = i+2;
tmp = storage_type();
while(i < end) {
if(hw_addr[i] >= 'a' && hw_addr[i] <= 'f')
tmp = (tmp << 4) | (hw_addr[i] - 'a' + 10);
else if(hw_addr[i] >= 'A' && hw_addr[i] <= 'F')
tmp = (tmp << 4) | (hw_addr[i] - 'A' + 10);
else if(hw_addr[i] >= '0' && hw_addr[i] <= '9')
tmp = (tmp << 4) | (hw_addr[i] - '0');
else if(hw_addr[i] == ':')
break;
else
throw std::runtime_error("Invalid byte found");
i++;
}
*(output++) = tmp;
count++;
if(i < hw_addr.size()) {
if(hw_addr[i] == ':')
i++;
else
throw std::runtime_error("Invalid separator");
}
}
while(count++ < n) {
*(output++) = storage_type();
}
}
template<size_t n, typename Storage>
const HWAddress<n, Storage> HWAddress<n, Storage>::broadcast("ff:ff:ff:ff:ff:ff");
} // namespace Tins
#if TINS_IS_CXX11
namespace std
{
template<size_t n>
struct hash<Tins::HWAddress<n>> {
size_t operator()(const Tins::HWAddress<n> &addr) const {
return std::hash<std::string>()(addr.to_string());
}
};
} // namespace std
#endif
#endif // TINS_HWADDRESS_H

408
include/tins/icmp.h Normal file
View File

@@ -0,0 +1,408 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_ICMP_H
#define TINS_ICMP_H
// Windows likes to define macros with not-so-common-names, which break
// this code
#ifdef WIN32
#ifdef TIMESTAMP_REQUEST
#undef TIMESTAMP_REQUEST
#endif // TIMESTAMP_REQUEST
#ifdef TIMESTAMP_REPLY
#undef TIMESTAMP_REPLY
#endif // TIMESTAMP_REPLY
#endif // WIN32
#include "macros.h"
#include "pdu.h"
#include "endianness.h"
#include "ip_address.h"
namespace Tins {
/**
* \class ICMP
* \brief Class that represents an ICMP PDU.
*
* ICMP is the representation of the ICMP PDU. Instances of this class
* must be sent over a level 3 PDU, this will otherwise fail.
*/
class ICMP : public PDU {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::ICMP;
/**
* The type used to store addresses.
*/
typedef IPv4Address address_type;
/** \brief ICMP flags
*/
enum Flags {
ECHO_REPLY = 0,
DEST_UNREACHABLE = 3,
SOURCE_QUENCH = 4,
REDIRECT = 5,
ECHO_REQUEST = 8,
TIME_EXCEEDED = 11,
PARAM_PROBLEM = 12,
TIMESTAMP_REQUEST = 13,
TIMESTAMP_REPLY = 14,
INFO_REQUEST = 15,
INFO_REPLY = 16,
ADDRESS_MASK_REQUEST = 17,
ADDRESS_MASK_REPLY = 18
};
/**
* \brief Creates an instance of ICMP.
*
* If no flag is specified, then ECHO_REQUEST will be used.
* \param flag The type flag which will be set.
*/
ICMP(Flags flag = ECHO_REQUEST);
/**
* \brief Constructs an ICMP object from a buffer.
*
* If there is not enough size for an ICMP header, a
* malformed_packet exception is thrown.
*
* Any extra data in the buffer will be stored in a RawPDU.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
ICMP(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Sets the code field.
*
* \param new_code The code which will be stored in the ICMP struct.
*/
void code(uint8_t new_code);
/** \brief Sets the type field.
*
* \param type The type which will be stored in the ICMP struct.
*/
void type(Flags type);
/**
* \brief Setter for the id field.
*
* \param new_id uint16_t with the new id.
*/
void id(uint16_t new_id);
/**
* \brief Setter for the sequence field.
*
* \param new_seq uint16_t with the new sequence.
*/
void sequence(uint16_t new_seq);
/**
* \brief Setter for the gateway field.
*
* \param new_gw The new value for the gateway field.
*/
void gateway(address_type new_gw);
/**
* \brief Setter for the mtu field.
*
* \param new_mtu uint16_t with the new sequence.
*/
void mtu(uint16_t new_mtu);
/**
* \brief Setter for the pointer field.
*
* \param new_pointer uint8_t with the new pointer.
*/
void pointer(uint8_t new_pointer);
/**
* \brief Setter for the original timestamp field.
*
* \param new_timestamp the value to be set.
*/
void original_timestamp(uint32_t new_timestamp);
/**
* \brief Setter for the receive timestamp field.
*
* \param new_timestamp the value to be set.
*/
void receive_timestamp(uint32_t new_timestamp);
/**
* \brief Setter for the transmit timestamp field.
*
* \param new_timestamp the value to be set.
*/
void transmit_timestamp(uint32_t new_timestamp);
/**
* \brief Setter for the address mask field.
*
* \param new_mask the value to be set.
*/
void address_mask(address_type new_mask);
/**
* \brief Sets echo request flag for this PDU.
*
* \param id The identifier for this request.
* \param seq The sequence number for this request.
*/
void set_echo_request(uint16_t id, uint16_t seq);
/**
* \brief Sets echo reply flag for this PDU.
*
* \param id The identifier for this request.
* \param seq The sequence number for this request.
*/
void set_echo_reply(uint16_t id, uint16_t seq);
/**
* \brief Sets information request flag for this PDU.
*
* \param id The identifier for this request.
* \param seq The sequence number for this request.
*/
void set_info_request(uint16_t id, uint16_t seq);
/**
* \brief Sets information reply flag for this PDU.
*
* \param id The identifier for this request.
* \param seq The sequence number for this request.
*/
void set_info_reply(uint16_t id, uint16_t seq);
/**
* \brief Sets destination unreachable for this PDU.
*/
void set_dest_unreachable();
/**
* \brief Sets time exceeded flag for this PDU.
*
* \param ttl_exceeded If true this PDU will represent a ICMP ttl
* exceeded, otherwise it will represent a fragment reassembly
* time exceeded.
*/
void set_time_exceeded(bool ttl_exceeded = true);
/**
* \brief Sets parameter problem flag for this PDU.
*
* \param set_pointer Indicates wether a pointer to the bad octet
* is provided.
* \param bad_octet Identifies the octet in which the error was
* detected. If set_pointer == false, it is ignored.
*/
void set_param_problem(bool set_pointer = false, uint8_t bad_octet = 0);
/**
* \brief Sets source quench flag for this PDU.
*/
void set_source_quench();
/**
* \brief Sets redirect flag for this PDU.
*
* \param icode The code to be set.
* \param address Address of the gateway to which traffic should
* be sent.
*/
void set_redirect(uint8_t icode, address_type address);
/**
* \brief Getter for the ICMP type flag.
*
* \return The type flag for this ICMP PDU.
*/
Flags type() const { return (Flags)_icmp.type; }
/**
* \brief Getter for the ICMP code flag.
*
* \return The code flag for this ICMP PDU.
*/
uint8_t code() const { return _icmp.code; }
/**
* \brief Getter for the checksum field.
*
* \return Returns the checksum as an unit16_t.
*/
uint16_t checksum() const { return Endian::be_to_host(_icmp.check); }
/**
* \brief Getter for the echo id.
*
* \return Returns the echo id.
*/
uint16_t id() const { return Endian::be_to_host(_icmp.un.echo.id); }
/**
* \brief Getter for the echo sequence number.
*
* \return Returns the echo sequence number.
*/
uint16_t sequence() const { return Endian::be_to_host(_icmp.un.echo.sequence); }
/**
* \brief Getter for the gateway field.
*
* \return Returns the gateway field value.
*/
address_type gateway() const {
return address_type(Endian::be_to_host(_icmp.un.gateway));
}
/**
* \brief Getter for the pointer field.
*
* \return Returns the pointer field value.
*/
uint8_t pointer() const { return this->_icmp.un.pointer; }
/**
* \brief Getter for the mtu field.
*
* \return Returns the mtu field value.
*/
uint16_t mtu() const { return Endian::be_to_host(_icmp.un.frag.mtu); }
/**
* \brief Getter for the original timestamp field.
*
* \return Returns the original timestamp value.
*/
uint32_t original_timestamp() const { return Endian::be_to_host(_orig_timestamp_or_address_mask); }
/**
* \brief Getter for the receive timestamp field.
*
* \return Returns the receive timestamp value.
*/
uint32_t receive_timestamp() const { return Endian::be_to_host(_recv_timestamp); }
/**
* \brief Getter for the transmit timestamp field.
*
* \return Returns the transmit timestamp value.
*/
uint32_t transmit_timestamp() const { return Endian::be_to_host(_trans_timestamp); }
/**
* \brief Getter for the address mask field.
*
* \return Returns the address mask value.
*/
address_type address_mask() const {
return address_type(Endian::be_to_host(_orig_timestamp_or_address_mask));
}
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. This size includes the
* payload and options size. \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Getter for the PDU's type.
*
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::ICMP; }
/**
* \sa PDU::clone
*/
ICMP *clone() const {
return new ICMP(*this);
}
private:
TINS_BEGIN_PACK
struct icmphdr {
uint8_t type;
uint8_t code;
uint16_t check;
union {
struct {
uint16_t id;
uint16_t sequence;
} echo;
uint32_t gateway;
struct {
uint16_t unused;
uint16_t mtu;
} frag;
uint8_t pointer;
} un;
} TINS_END_PACK;
void checksum(uint16_t new_check);
/** \brief Serialices this ICMP PDU.
* \param buffer The buffer in which the PDU will be serialized.
* \param total_sz The size available in the buffer.
* \param parent The PDU that's one level below this one on the stack.
*/
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
icmphdr _icmp;
uint32_t _orig_timestamp_or_address_mask, _recv_timestamp, _trans_timestamp;
};
}
#endif // TINS_ICMP_H

1338
include/tins/icmpv6.h Normal file

File diff suppressed because it is too large Load Diff

40
include/tins/ieee802_3.h Normal file
View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_IEEE802_3_H
#define TINS_IEEE802_3_H
#include "dot3.h"
namespace Tins {
typedef Dot3 IEEE802_3;
}
#endif // TINS_IEEE802_3_H

207
include/tins/internals.h Normal file
View File

@@ -0,0 +1,207 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_INTERNALS_H
#define TINS_INTERNALS_H
#include <sstream>
#include <string>
#include <stdint.h>
#include "constants.h"
#include "pdu.h"
#include "hw_address.h"
/**
* \cond
*/
namespace Tins {
class IPv4Address;
class IPv6Address;
namespace Internals {
template<size_t n>
class byte_array {
public:
typedef uint8_t* iterator;
typedef const uint8_t* const_iterator;
byte_array() {
std::fill(begin(), end(), 0);
}
template<typename InputIterator>
byte_array(InputIterator start, InputIterator last) {
std::copy(start, last, data);
}
template<typename InputIterator>
byte_array(InputIterator start) {
std::copy(start, n, data);
}
uint8_t &operator[](size_t i) {
return data[i];
}
uint8_t operator[](size_t i) const{
return data[i];
}
iterator begin() {
return data;
}
iterator end() {
return data + n;
}
const_iterator begin() const {
return data;
}
const_iterator end() const {
return data + n;
}
size_t size() const {
return n;
}
private:
uint8_t data[n];
};
void skip_line(std::istream &input);
bool from_hex(const std::string &str, uint32_t &result);
template<bool, typename T = void>
struct enable_if {
typedef T type;
};
template<typename T>
struct enable_if<false, T> {
};
PDU *pdu_from_flag(Constants::Ethernet::e flag, const uint8_t *buffer,
uint32_t size, bool rawpdu_on_no_match = true);
PDU *pdu_from_flag(Constants::IP::e flag, const uint8_t *buffer,
uint32_t size, bool rawpdu_on_no_match = true);
PDU *pdu_from_flag(PDU::PDUType type, const uint8_t *buffer, uint32_t size);
Constants::Ethernet::e pdu_flag_to_ether_type(PDU::PDUType flag);
Constants::IP::e pdu_flag_to_ip_type(PDU::PDUType flag);
template<typename T>
bool increment_buffer(T &addr) {
typename T::iterator it = addr.end() - 1;
while(it >= addr.begin() && *it == 0xff) {
*it = 0;
--it;
}
// reached end
if(it < addr.begin())
return true;
(*it)++;
return false;
}
template<typename T>
bool decrement_buffer(T &addr) {
typename T::iterator it = addr.end() - 1;
while(it >= addr.begin() && *it == 0) {
*it = 0xff;
--it;
}
// reached end
if(it < addr.begin())
return true;
(*it)--;
return false;
}
bool increment(IPv4Address &addr);
bool increment(IPv6Address &addr);
bool decrement(IPv4Address &addr);
bool decrement(IPv6Address &addr);
template<size_t n>
bool increment(HWAddress<n> &addr) {
return increment_buffer(addr);
}
template<size_t n>
bool decrement(HWAddress<n> &addr) {
return decrement_buffer(addr);
}
IPv4Address last_address_from_mask(IPv4Address addr, IPv4Address mask);
IPv6Address last_address_from_mask(IPv6Address addr, const IPv6Address &mask);
template<size_t n>
HWAddress<n> last_address_from_mask(HWAddress<n> addr, const HWAddress<n> &mask) {
typename HWAddress<n>::iterator addr_iter = addr.begin();
for(typename HWAddress<n>::const_iterator it = mask.begin(); it != mask.end(); ++it, ++addr_iter) {
*addr_iter = *addr_iter | ~*it;
}
return addr;
}
inline bool is_dot3(const uint8_t *ptr, size_t sz) {
return (sz >= 13 && ptr[12] < 8);
}
template<typename T>
struct is_unsigned_integral {
static const bool value = false;
};
template<>
struct is_unsigned_integral<uint8_t> {
static const bool value = true;
};
template<>
struct is_unsigned_integral<uint16_t> {
static const bool value = true;
};
template<>
struct is_unsigned_integral<uint32_t> {
static const bool value = true;
};
template<>
struct is_unsigned_integral<uint64_t> {
static const bool value = true;
};
} // namespace Internals
} // namespace Tins
/**
* \endcond
*/
#endif

663
include/tins/ip.h Normal file
View File

@@ -0,0 +1,663 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_IP_H
#define TINS_IP_H
#include <list>
#include "pdu.h"
#include "small_uint.h"
#include "endianness.h"
#include "ip_address.h"
#include "pdu_option.h"
#include "macros.h"
#include "cxxstd.h"
namespace Tins {
/**
* \class IP
* \brief Class that represents an IP PDU.
*
* By default, IP PDUs are initialized, setting TTL to IP::DEFAULT_TTL,
* id field to 1 and version to 4. Taking this into account, users
* should set destination and source port and would be enough to send one.
*/
class IP : public PDU {
public:
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::IP;
/**
* The type used to store addresses.
*/
typedef IPv4Address address_type;
/**
* \brief Enum indicating the option's class.
*
* Enum OptionClass represents the different classes of
* IP Options.
*/
enum OptionClass {
CONTROL = 0,
MEASUREMENT = 2
};
/**
* \brief Enum indicating the option's id number.
*
* Enum Option indicates the possible IP Options.
*/
enum OptionNumber {
END = 0,
NOOP = 1,
SEC = 2,
LSSR = 3,
TIMESTAMP = 4,
EXTSEC = 5,
RR = 7,
SID = 8,
SSRR = 9,
MTUPROBE = 11,
MTUREPLY = 12,
EIP = 17,
TR = 18,
ADDEXT = 19,
RTRALT = 20,
SDB = 21,
DPS = 23,
UMP = 24,
QS = 25
};
/**
* \brief The type used to represent an option's type.
*/
TINS_BEGIN_PACK
struct option_identifier {
#if TINS_IS_LITTLE_ENDIAN
uint8_t number:5,
op_class:2,
copied:1;
#elif TINS_IS_BIG_ENDIAN
uint8_t copied:1,
op_class:2,
number:5;
#endif
/**
* \brief Default constructor.
*
* Initializes every field to 0.
*/
option_identifier()
#if TINS_IS_LITTLE_ENDIAN
: number(0), op_class(0), copied(0) {}
#else
: copied(0), op_class(0), number(0) {}
#endif
/**
* \brief Constructs this option from a single uint8_t value.
*
* This parses the value and initializes each field with the
* appropriate value.
*
* \param value The value to be parsed and used for
* initialization
*/
option_identifier(uint8_t value)
#if TINS_IS_LITTLE_ENDIAN
: number(value & 0x1f),
op_class((value >> 5) & 0x03),
copied((value >> 7) & 0x01) {}
#elif TINS_IS_BIG_ENDIAN
: copied((value >> 7) & 0x01),
op_class((value >> 5) & 0x03),
number(value & 0x1f) {}
#endif
/**
* Constructor using user provided values for each field.
* \param number The number field value.
* \param op_class The option class field value.
* \param copied The copied field value.
*/
option_identifier(OptionNumber number, OptionClass op_class,
small_uint<1> copied)
#if TINS_IS_LITTLE_ENDIAN
: number(number), op_class(op_class), copied(copied) {}
#else
: copied(copied), op_class(op_class), number(number) {}
#endif
/**
* \brief Equality operator.
*/
bool operator==(const option_identifier &rhs) const {
return number == rhs.number && op_class == rhs.op_class && copied == rhs.copied;
}
} TINS_END_PACK;
/**
* The IP options type.
*/
typedef PDUOption<option_identifier, IP> option;
/**
* The type of the security option.
*/
struct security_type {
uint16_t security, compartments;
uint16_t handling_restrictions;
small_uint<24> transmission_control;
security_type(uint16_t sec = 0, uint16_t comp = 0,
uint16_t hand_res = 0, small_uint<24> tcc = 0)
: security(sec), compartments(comp),
handling_restrictions(hand_res), transmission_control(tcc)
{}
static security_type from_option(const option &opt);
};
/**
* The type of the Loose Source and Record Route
*/
struct generic_route_option_type {
typedef std::vector<address_type> routes_type;
uint8_t pointer;
routes_type routes;
generic_route_option_type(uint8_t ptr = 0,
routes_type rts = routes_type())
: pointer(ptr), routes(rts) {}
static generic_route_option_type from_option(const option &opt);
};
/**
* The type of the Loose Source and Record Route
*/
typedef generic_route_option_type lsrr_type;
/**
* The type of the Strict Source and Record Route
*/
typedef generic_route_option_type ssrr_type;
/**
* The type of the Record Route
*/
typedef generic_route_option_type record_route_type;
/**
* The type used to store IP options.
*/
typedef std::list<option> options_type;
/**
* \brief Constructor for building the IP PDU.
*
* Both the destination and source IP address can be supplied.
* By default, those fields are initialized using the IP
* address 0.0.0.0.
*
* \param ip_dst The destination ip address(optional).
* \param ip_src The source ip address(optional).
*/
IP(address_type ip_dst = address_type(),
address_type ip_src = address_type());
/**
* \brief Constructs an IP object from a buffer and adds all
* identifiable PDUs found in the buffer as children of this
* one.
*
* If there is not enough size for an IP header, a
* malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
IP(const uint8_t *buffer, uint32_t total_sz);
/* Getters */
/**
* \brief Getter for the header length field.
*
* \return The number of dwords the header occupies in an uin8_t.
*/
small_uint<4> head_len() const { return this->_ip.ihl; }
/**
* \brief Getter for the type of service field.
*
* \return The this IP PDU's type of service.
*/
uint8_t tos() const { return _ip.tos; }
/**
* \brief Getter for the total length field.
*
* \return The total length of this IP PDU.
*/
uint16_t tot_len() const {
return Endian::be_to_host(_ip.tot_len);
}
/**
* \brief Getter for the id field.
*
* \return The id for this IP PDU.
*/
uint16_t id() const { return Endian::be_to_host(_ip.id); }
/**
* \brief Getter for the fragment offset field.
*
* \return The fragment offset for this IP PDU.
*/
uint16_t frag_off() const { return Endian::be_to_host(_ip.frag_off); }
/**
* \brief Getter for the time to live field.
*
* \return The time to live for this IP PDU.
*/
uint8_t ttl() const { return _ip.ttl; }
/**
* \brief Getter for the protocol field.
*
* \return The protocol for this IP PDU.
*/
uint8_t protocol() const { return _ip.protocol; }
/**
* \brief Getter for the checksum field.
*
* \return The checksum for this IP PDU.
*/
uint16_t checksum() const { return Endian::be_to_host(_ip.check); }
/**
* \brief Getter for the source address field.
*
* \return The source address for this IP PDU.
*/
address_type src_addr() const { return address_type(_ip.saddr); }
/**
* \brief Getter for the destination address field.
* \return The destination address for this IP PDU.
*/
address_type dst_addr() const { return address_type(_ip.daddr); }
/**
* \brief Getter for the version field.
* \return The version for this IP PDU.
*/
small_uint<4> version() const { return _ip.version; }
/**
* \brief Getter for the IP options.
* \return The stored options.
*/
const options_type &options() const { return _ip_options; }
/* Setters */
/**
* \brief Setter for the type of service field.
*
* \param new_tos The new type of service.
*/
void tos(uint8_t new_tos);
/**
* \brief Setter for the id field.
*
* \param new_id The new id.
*/
void id(uint16_t new_id);
/**
* \brief Setter for the fragment offset field.
*
* \param new_frag_off The new fragment offset.
*/
void frag_off(uint16_t new_frag_off);
/**
* \brief Setter for the time to live field.
*
* \param new_ttl The new time to live.
*/
void ttl(uint8_t new_ttl);
/**
* \brief Setter for the protocol field.
*
* Note that this protocol will be overwritten using the
* inner_pdu's protocol type during serialization unless the IP
* datagram is fragmented.
*
* If the packet is fragmented and was originally sniffed, the
* original protocol type will be kept when serialized.
*
* If this packet has been crafted manually and the inner_pdu
* is, for example, a RawPDU, then setting the protocol yourself
* is necessary.
*
* \param new_protocol The new protocol.
*/
void protocol(uint8_t new_protocol);
/**
* \brief Setter for the source address field.
*
* \param ip The source address to be set.
*/
void src_addr(address_type ip);
/**
* \brief Setter for the destination address field.
*
* \param ip The destination address to be set.
*/
void dst_addr(address_type ip);
/**
* \brief Setter for the version field.
*
* \param ver The version field to be set.
*/
void version(small_uint<4> ver);
/**
* \brief Adds an IP option.
*
* The option is added after the last option in the option
* fields.
*
* \param opt The option to be added
*/
void add_option(const option &opt);
#if TINS_IS_CXX11
/**
* \brief Adds an IP option.
*
* The option is move-constructed.
*
* \param opt The option to be added.
*/
void add_option(option &&opt) {
internal_add_option(opt);
_ip_options.push_back(std::move(opt));
}
/**
* \brief Adds an IP option.
*
* The option is constructed from the provided parameters.
*
* \param args The arguments to be used in the option's
* constructor.
*/
template<typename... Args>
void add_option(Args&&... args) {
_ip_options.emplace_back(std::forward<Args>(args)...);
internal_add_option(_ip_options.back());
}
#endif
/**
* \brief Searchs for an option that matchs the given flag.
*
* If the option is not found, a null pointer is returned.
* Deleting the returned pointer will result in <b>undefined
* behaviour</b>.
*
* \param id The option identifier to be searched.
*/
const option *search_option(option_identifier id) const;
// Option setters
/**
* \brief Adds an End Of List option.
*/
void eol();
/**
* \brief Adds a NOP option.
*/
void noop();
/**
* \brief Adds a security option.
*
* \param data The data to be stored in this option.
*/
void security(const security_type &data);
/**
* \brief Adds a Loose Source and Record Route option.
*
* \param data The data to be stored in this option.
*/
void lsrr(const lsrr_type &data) {
add_route_option(131, data);
}
/**
* \brief Adds a Strict Source and Record Route option.
*
* \param data The data to be stored in this option.
*/
void ssrr(const ssrr_type &data) {
add_route_option(137, data);
}
/**
* \brief Adds a Record Route option.
*
* \param data The data to be stored in this option.
*/
void record_route(const record_route_type &data) {
add_route_option(7, data);
}
/**
* \brief Adds a Stream Identifier option.
*
* \param stream_id The stream id to be stored in this option.
*/
void stream_identifier(uint16_t stream_id);
// Option getters
/**
* \brief Searchs and returns a security option.
*
* If no such option exists, an option_not_found exception
* is thrown.
*
* \return security_type containing the option found.
*/
security_type security() const;
/**
* \brief Searchs and returns a Loose Source and Record Route
* option.
*
* If no such option exists, an option_not_found exception
* is thrown.
*
* \return lsrr_type containing the option found.
*/
lsrr_type lsrr() const {
return search_route_option(131);
}
/**
* \brief Searchs and returns a Strict Source and Record Route
* option.
*
* If no such option exists, an option_not_found exception
* is thrown.
*
* \return ssrr_type containing the option found.
*/
ssrr_type ssrr() const {
return search_route_option(137);
}
/**
* \brief Searchs and returns a Record Route option.
*
* If no such option exists, an option_not_found exception
* is thrown.
*
* \return record_route_type containing the option found.
*/
record_route_type record_route() const {
return search_route_option(7);
}
/**
* \brief Searchs and returns a Stream Identifier option.
*
* If no such option exists, an option_not_found exception
* is thrown.
*
* \return uint16_t containing the option found.
*/
uint16_t stream_identifier() const;
/* Virtual methods */
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \sa PDU::send()
*/
void send(PacketSender &sender, const NetworkInterface &);
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Receives a matching response for this packet.
*
* \sa PDU::recv_response
* \param sender The packet sender which will receive the packet.
*/
PDU *recv_response(PacketSender &sender, const NetworkInterface &);
/**
* Indicates whether this PDU is fragmented.
*
* \return true if this PDU is fragmented, false otherwise.
*/
bool is_fragmented() const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::IP; }
/**
* \sa PDU::clone
*/
IP *clone() const {
return new IP(*this);
}
private:
static const uint8_t DEFAULT_TTL;
TINS_BEGIN_PACK
struct iphdr {
#if TINS_IS_LITTLE_ENDIAN
uint8_t ihl:4,
version:4;
#else
uint8_t version:4,
ihl:4;
#endif
uint8_t tos;
uint16_t tot_len;
uint16_t id;
uint16_t frag_off;
uint8_t ttl;
uint8_t protocol;
uint16_t check;
uint32_t saddr;
uint32_t daddr;
/*The options start here. */
} TINS_END_PACK;
void head_len(small_uint<4> new_head_len);
void tot_len(uint16_t new_tot_len);
void prepare_for_serialize(const PDU *parent);
void internal_add_option(const option &option);
void init_ip_fields();
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
uint8_t* write_option(const option &opt, uint8_t* buffer);
void add_route_option(option_identifier id, const generic_route_option_type &data);
generic_route_option_type search_route_option(option_identifier id) const;
void checksum(uint16_t new_check);
iphdr _ip;
uint16_t _options_size, _padded_options_size;
options_type _ip_options;
};
}
#endif // TINS_IP_H

199
include/tins/ip_address.h Normal file
View File

@@ -0,0 +1,199 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_IPADDRESS_H
#define TINS_IPADDRESS_H
#include <string>
#include <iostream>
#include <stdint.h>
#include "cxxstd.h"
namespace Tins {
/**
* \class IPv4Address
* \brief Abstraction of an IPv4 address.
*/
class IPv4Address {
public:
/**
* The address size.
*/
static const size_t address_size = sizeof(uint32_t);
/**
* The broadcast address.
*/
static const IPv4Address broadcast;
/**
* \brief Constructor taking a const char*.
*
* Constructs an IPv4Address from a dotted-notation address
* cstring. If the pointer provided is null, then a default
* IPv4Address object is constructed, which corresponds to
* the 0.0.0.0 address.
*
* \param ip const char* containing the dotted-notation address.
*/
IPv4Address(const char *ip = 0);
/**
* \brief Constructor taking a std::string.
*
* Constructs an IPv4Address from a dotted-notation std::strings
*
* \param ip std::string containing the dotted-notation address.
*/
IPv4Address(const std::string &ip);
/**
* \brief Constructor taking a IP address represented as a
* big endian integer.
*
* This constructor should be used internally by PDUs that
* handle IP addresses. The provided integer <b>must</b> be
* be in big endian.
*/
explicit IPv4Address(uint32_t ip);
/**
* \brief User defined conversion to big endian integral value.
*/
operator uint32_t() const;
/**
* \brief Retrieve the string representation of this address.
*
* \return std::string containing the representation of this address.
*/
std::string to_string() const;
/**
* \brief Compare this IPv4Address for equality.
*
* \param rhs The address to be compared.
* \return bool indicating whether this address equals rhs.
*/
bool operator==(const IPv4Address &rhs) const {
return ip_addr == rhs.ip_addr;
}
/**
* \brief Compare this IPv4Address for inequality.
*
* \param rhs The address to be compared.
* \return bool indicating whether this address is distinct
* from rhs.
*/
bool operator!=(const IPv4Address &rhs) const {
return !(*this == rhs);
}
/**
* \brief Compare this IPv4Address for less-than inequality.
*
* \param rhs The address to be compared.
* \return bool indicating whether this address is less-than rhs.
*/
bool operator< (const IPv4Address &rhs) const {
return ip_addr < rhs.ip_addr;
}
/**
* \brief Returns true if this is a private IPv4 address.
*
* This takes into account the private network ranges defined in
* RFC 1918. Therefore, this method returns true if this address
* is in any of the following network ranges, false otherwise:
*
* - 192.168.0.0/16
* - 10.0.0.0/8
* - 172.16.0.0/12
*/
bool is_private() const;
/**
* \brief Returns true if this is a loopback IPv4 address.
*
* This method returns true if this address is in the address range
* 127.0.0.0/8, false otherwise.
*/
bool is_loopback() const;
/**
* \brief Returns true if this is a multicast IPv4 address.
*
* This method returns true if this address is in the address range
* 224.0.0.0/4, false otherwise.
*/
bool is_multicast() const;
/**
* \brief Returns true if this is an unicast IPv4 address.
*/
bool is_unicast() const;
/**
* \brief Returns true if this is a broadcast IPv4 address.
*/
bool is_broadcast() const;
/**
* \brief Writes this address to a std::ostream.
*
* This method writes addr in a dotted-string notation address
* to the std::ostream argument.
*
* \param output The std::ostream in which to write the address.
* \param addr The IPv4Address to be written.
* \return std::stream& pointing to output.
*/
friend std::ostream &operator<<(std::ostream &output, const IPv4Address &addr);
private:
uint32_t ip_to_int(const char* ip);
uint32_t ip_addr;
};
} //namespace Tins
#if TINS_IS_CXX11
namespace std
{
template<>
struct hash<Tins::IPv4Address> {
size_t operator()(const Tins::IPv4Address &addr) const {
return std::hash<uint32_t>()(addr);
}
};
} // namespace std
#endif
#endif // TINS_IPADDRESS_H

View File

@@ -0,0 +1,216 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_IP_REASSEMBLER_H
#define TINS_IP_REASSEMBLER_H
#include <vector>
#include <map>
#include "pdu.h"
#include "ip_address.h"
namespace Tins {
/**
* \cond
*/
class IP;
namespace Internals {
class IPv4Fragment {
public:
typedef PDU::serialization_type payload_type;
IPv4Fragment() : offset_() { }
template<typename T>
IPv4Fragment(T *pdu, uint16_t offset)
: payload_(pdu->serialize()), offset_(offset)
{
}
const payload_type &payload() const {
return payload_;
}
uint16_t offset() const {
return offset_;
}
private:
payload_type payload_;
uint16_t offset_;
};
class IPv4Stream {
public:
IPv4Stream();
void add_fragment(IP *ip);
bool is_complete() const;
PDU *allocate_pdu() const;
private:
typedef std::vector<IPv4Fragment> fragments_type;
uint16_t extract_offset(const IP *ip);
bool extract_more_frag(const IP *ip);
fragments_type fragments;
bool received_end;
uint8_t transport_proto;
size_t received_size, total_size;
};
} // namespace Internals
/**
* \endcond
*/
/**
* \brief Reassembles fragmented IP packets.
*/
class IPv4Reassembler {
public:
/**
* The status of each processed packet.
*/
enum packet_status {
NOT_FRAGMENTED,
FRAGMENTED,
REASSEMBLED
};
/**
* The type used to represent the overlapped segment
* reassembly technique to be used.
*/
enum overlapping_technique {
NONE
};
/**
* Constructs an IPV4Reassembler.
* \param technique The technique to be used for reassembling
* overlapped fragments.
*/
IPv4Reassembler(overlapping_technique technique = NONE);
/**
* \brief Processes a PDU and tries to reassemble it.
*
* This method tries to reassemble the provided packet. If
* the packet is successfully reassembled using previously
* processed packets, its contents will be modified so that
* it contains the whole payload and not just a fragment.
*
* \param pdu The PDU to process.
* \return NOT_FRAGMENTED if the PDU does not contain an IP
* layer or is not fragmented, FRAGMENTED if the packet is
* fragmented or REASSEMBLED if the packet was fragmented
* but has now been reassembled.
*/
packet_status process(PDU &pdu);
/**
* Removes all of the packets and data stored.
*/
void clear_streams();
/**
* \brief Removes all of the packets and data stored that
* belongs to IP headers whose identifier, source and destination
* addresses are equal to the provided parameters.
*
* \param id The idenfier to search.
* \param addr1 The source address to search.
* \param addr2 The destinatin address to search.
* \sa IP::id
*/
void remove_stream(uint16_t id, IPv4Address addr1, IPv4Address addr2);
private:
typedef std::pair<IPv4Address, IPv4Address> address_pair;
typedef std::pair<uint16_t, address_pair> key_type;
typedef std::map<key_type, Internals::IPv4Stream> streams_type;
key_type make_key(const IP *ip) const;
address_pair make_address_pair(IPv4Address addr1, IPv4Address addr2) const;
streams_type streams;
overlapping_technique technique;
};
/**
* Proxy functor class that reassembles PDUs.
*/
template<typename Functor>
class IPv4ReassemblerProxy {
public:
/**
* Constructs the proxy from a functor object.
*
* \param func The functor object.
*/
IPv4ReassemblerProxy(Functor func)
: functor_(func)
{
}
/**
* \brief Tries to reassemble the packet and forwards it to
* the functor.
*
* \param pdu The packet to process
* \return true if the packet wasn't forwarded, otherwise
* the value returned by the functor.
*/
bool operator()(PDU &pdu) {
// Forward it unless it's fragmented.
if(reassembler.process(pdu) != IPv4Reassembler::FRAGMENTED)
return functor_(pdu);
else
return true;
}
private:
IPv4Reassembler reassembler;
Functor functor_;
};
/**
* Helper function that creates an IPv4ReassemblerProxy.
*
* \param func The functor object to use in the IPv4ReassemblerProxy.
* \return An IPv4ReassemblerProxy.
*/
template<typename Functor>
IPv4ReassemblerProxy<Functor> make_ipv4_reassembler_proxy(Functor func) {
return IPv4ReassemblerProxy<Functor>(func);
}
}
#endif // TINS_IP_REASSEMBLER_H

265
include/tins/ipsec.h Normal file
View File

@@ -0,0 +1,265 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_IPSEC_H
#define TINS_IPSEC_H
#include "pdu.h"
#include "endianness.h"
#include "small_uint.h"
namespace Tins {
/**
* \class IPSecAH
* \brief Represents an IPSec Authentication Header.
*/
class IPSecAH : public PDU {
public:
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::IPSEC_AH;
/**
* \brief Default constructor.
*
* The ICV field is initialized with four 0 bytes. The length
* field is initialized appropriately.
*/
IPSecAH();
/**
* \brief Constructs an IPSecAH object from a buffer and adds all
* identifiable PDUs found in the buffer as children of this
* one.
*
* If there is not enough size for an IPSecAH header, a
* malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
IPSecAH(const uint8_t *buffer, uint32_t total_sz);
// Getters
/**
* \brief Getter for the Next header field.
* \return The stored Next header field value.
*/
uint8_t next_header() const {
return _header.next_header;
}
/**
* \brief Getter for the Length field.
* \return The stored Length field value.
*/
uint8_t length() const {
return _header.length;
}
/**
* \brief Getter for the Security Parameters Index field.
* \return The stored Security Parameters Index field value.
*/
uint32_t spi() const {
return Endian::be_to_host(_header.spi);
}
/**
* \brief Getter for the Sequence number field.
* \return The stored Sequence number field value.
*/
uint32_t seq_number() const {
return Endian::be_to_host(_header.seq_number);
}
/**
* \brief Getter for the ICV field.
* \return The stored ICV field value.
*/
const byte_array &icv() const {
return _icv;
}
// Setters
/**
* \brief Setter for the Next header field.
* \param new_next_header The new Next header field value.
*/
void next_header(uint8_t new_next_header);
/**
* \brief Setter for the Length field.
* \param new_length The new Length field value.
*/
void length(uint8_t new_length);
/**
* \brief Setter for the Security Parameters Index field.
* \param new_spi The new Security Parameters Index field value.
*/
void spi(uint32_t new_spi);
/**
* \brief Setter for the Sequence number field.
* \param new_seq_number The new Sequence number field value.
*/
void seq_number(uint32_t new_seq_number);
/**
* \brief Setter for the ICV field.
* \param new_icv The new ICV field value.
*/
void icv(const byte_array &new_icv);
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_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_flag; }
/**
* \sa PDU::clone
*/
IPSecAH *clone() const {
return new IPSecAH(*this);
}
private:
struct header {
uint8_t next_header, length;
uint32_t spi, seq_number;
};
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *);
header _header;
byte_array _icv;
};
/**
* \brief Represents an IPSec Authentication Header.
*/
class IPSecESP : public PDU {
public:
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::IPSEC_ESP;
/**
* \brief Default constructor.
*/
IPSecESP();
/**
* \brief Constructs an IPSecESP object from a buffer and adds all
* identifiable PDUs found in the buffer as children of this
* one.
*
* If there is not enough size for an IPSecESP header, a
* malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
IPSecESP(const uint8_t *buffer, uint32_t total_sz);
// Getters
/**
* \brief Getter for the Security Parameters Index field.
* \return The stored Security Parameters Index field value.
*/
uint32_t spi() const {
return Endian::be_to_host(_header.spi);
}
/**
* \brief Getter for the Sequence number field.
* \return The stored Sequence number field value.
*/
uint32_t seq_number() const {
return Endian::be_to_host(_header.seq_number);
}
// Setters
/**
* \brief Setter for the Security Parameters Index field.
* \param new_spi The new Security Parameters Index field value.
*/
void spi(uint32_t new_spi);
/**
* \brief Setter for the Sequence number field.
* \param new_seq_number The new Sequence number field value.
*/
void seq_number(uint32_t new_seq_number);
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_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_flag; }
/**
* \sa PDU::clone
*/
IPSecESP *clone() const {
return new IPSecESP(*this);
}
private:
struct header {
uint32_t spi, seq_number;
};
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *);
header _header;
};
}
#endif // TINS_IPSEC_H

331
include/tins/ipv6.h Normal file
View File

@@ -0,0 +1,331 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_IPV6_h
#define TINS_IPV6_h
#include <list>
#include <stdexcept>
#include "macros.h"
#include "pdu.h"
#include "endianness.h"
#include "small_uint.h"
#include "pdu_option.h"
#include "ipv6_address.h"
namespace Tins {
class PacketSender;
/**
* \class IPv6
* Represents an IPv6 PDU.
*/
class IPv6 : public PDU {
public:
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::IPv6;
/**
* The type used to store addresses.
*/
typedef IPv6Address address_type;
/**
* The type used to represent IPv6 extension headers.
*/
typedef PDUOption<uint8_t, IPv6> ext_header;
/**
* The type used to store the extension headers.
*/
typedef std::list<ext_header> headers_type;
/**
* The values used to identify extension headers.
*/
enum ExtensionHeader {
HOP_BY_HOP = 0,
DESTINATION_ROUTING_OPTIONS = 60,
ROUTING = 43,
FRAGMENT = 44,
AUTHENTICATION = 51,
SECURITY_ENCAPSULATION = 50,
DESTINATION_OPTIONS = 60,
MOBILITY = 135,
NO_NEXT_HEADER = 59
};
/**
* \brief Constructs an IPv6 object.
*
* \param ip_dst The destination ip address(optional).
* \param ip_src The source ip address(optional).
* \param child pointer to a PDU which will be set as the inner_pdu
* for the packet being constructed(optional).
*/
IPv6(address_type ip_dst = address_type(),
address_type ip_src = address_type(),
PDU *child = 0);
/**
* \brief Constructs an IPv6 object from a buffer and adds all
* identifiable PDUs found in the buffer as children of this one.
*
* If there is not enough size for an IPv6 header, a malformed_packet
* exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
IPv6(const uint8_t *buffer, uint32_t total_sz);
// Getters
/**
* \brief Getter for the version field.
* \return The stored version field value.
*/
small_uint<4> version() const {
return _header.version;
}
/**
* \brief Getter for the traffic_class field.
* \return The stored traffic_class field value.
*/
uint8_t traffic_class() const {
#if TINS_IS_LITTLE_ENDIAN
return ((_header.traffic_class << 4) & 0xf0) |
((_header.flow_label[0] >> 4) & 0x0f);
#else
return _header.traffic_class;
#endif
}
/**
* \brief Getter for the flow_label field.
* \return The stored flow_label field value.
*/
small_uint<20> flow_label() const {
#if TINS_IS_LITTLE_ENDIAN
return ((_header.flow_label[0] & 0x0f) << 16)
| (_header.flow_label[1] << 8)
| (_header.flow_label[2]);
#else
return _header.flow_label;
#endif
}
/**
* \brief Getter for the payload_length field.
* \return The stored payload_length field value.
*/
uint16_t payload_length() const {
return Endian::be_to_host(_header.payload_length);
}
/**
* \brief Getter for the next_header field.
* \return The stored next_header field value.
*/
uint8_t next_header() const {
return _header.next_header;
}
/**
* \brief Getter for the hop_limit field.
* \return The stored hop_limit field value.
*/
uint8_t hop_limit() const {
return _header.hop_limit;
}
/**
* \brief Getter for the src_addr field.
* \return The stored src_addr field value.
*/
address_type src_addr() const {
return _header.src_addr;
}
/**
* \brief Getter for the dst_addr field.
* \return The stored dst_addr field value.
*/
address_type dst_addr() const {
return _header.dst_addr;
}
/**
* \brief Getter for the IPv6 extension headers.
* \return The stored headers.
*/
const headers_type& headers() const {
return ext_headers;
}
// Setters
/**
* \brief Setter for the version field.
* \param new_version The new version field value.
*/
void version(small_uint<4> new_version);
/**
* \brief Setter for the traffic_class field.
* \param new_traffic_class The new traffic_class field value.
*/
void traffic_class(uint8_t new_traffic_class);
/**
* \brief Setter for the flow_label field.
* \param new_flow_label The new flow_label field value.
*/
void flow_label(small_uint<20> new_flow_label);
/**
* \brief Setter for the payload_length field.
* \param new_payload_length The new payload_length field value.
*/
void payload_length(uint16_t new_payload_length);
/**
* \brief Setter for the next_header field.
* \param new_next_header The new next_header field value.
*/
void next_header(uint8_t new_next_header);
/**
* \brief Setter for the hop_limit field.
* \param new_hop_limit The new hop_limit field value.
*/
void hop_limit(uint8_t new_hop_limit);
/**
* \brief Setter for the src_addr field.
* \param new_src_addr The new src_addr field value.
*/
void src_addr(const address_type &new_src_addr);
/**
* \brief Setter for the dst_addr field.
* \param new_dst_addr The new dst_addr field value.
*/
void dst_addr(const address_type &new_dst_addr);
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \sa PDU::clone
*/
IPv6 *clone() const {
return new IPv6(*this);
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
#ifndef BSD
/**
* \sa PDU::send()
*/
void send(PacketSender &sender, const NetworkInterface &);
#endif
/**
* Adds an extension header.
*
* \param header The extension header to be added.
*/
void add_ext_header(const ext_header &header);
/**
* \brief Searchs for an extension header that matchs the given
* flag.
*
* If the header is not found, a null pointer is returned.
* Deleting the returned pointer will result in <b>undefined
* behaviour</b>.
*
* \param id The header identifier to be searched.
*/
const ext_header *search_header(ExtensionHeader id) const;
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
void set_last_next_header(uint8_t value);
static uint8_t *write_header(const ext_header &header, uint8_t *buffer);
static bool is_extension_header(uint8_t header_id);
TINS_BEGIN_PACK
struct ipv6_header {
#if TINS_IS_BIG_ENDIAN
uint32_t version:4,
traffic_class:8,
flow_label:20;
uint32_t payload_length:16,
next_header:8,
hop_limit:8;
#else
uint8_t traffic_class:4,
version:4;
uint8_t flow_label[3];
uint16_t payload_length;
uint8_t next_header;
uint8_t hop_limit;
#endif
uint8_t src_addr[16], dst_addr[16];
} TINS_END_PACK;
ipv6_header _header;
headers_type ext_headers;
uint32_t headers_size;
};
}
#endif // TINS_IPV6_h

230
include/tins/ipv6_address.h Normal file
View File

@@ -0,0 +1,230 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_IPV6_ADDRESS
#define TINS_IPV6_ADDRESS
#include <string>
#include <stdexcept>
#include <stdint.h>
#include "cxxstd.h"
namespace Tins {
/**
* Represents an IPv6 address.
*/
class IPv6Address {
public:
/**
* The exception thrown when a malformed address is parsed.
*/
class malformed_address : public std::exception {
public:
const char *what() const throw() {
return "Malformed address";
}
};
static const size_t address_size = 16;
/**
* The iterator type.
*/
typedef uint8_t* iterator;
/**
* The const iterator type.
*/
typedef const uint8_t* const_iterator;
/**
* \brief Default constructor.
* Initializes this IPv6 address to "::"
*/
IPv6Address();
/**
* \brief Constructor from a text representation char*.
* \param addr The text representation from which to construct this
* object.
*/
IPv6Address(const char *addr);
/**
* \brief Constructor from a text representation std::string.
* \param addr The text representation from which to construct this
* object.
*/
IPv6Address(const std::string &addr);
/**
* \brief Constructor from a buffer.
*
* The ptr parameter must be at least address_size bytes long.
*
* \param ptr The buffer from which to construct this object.
*/
IPv6Address(const_iterator ptr);
/**
* \brief Retrieve the string representation of this address.
*
* \return std::string containing the representation of this address.
*/
std::string to_string() const;
/**
* Returns an iterator to the beginning of this address.
*/
iterator begin() {
return address;
}
/**
* Returns a const iterator to the beginning of this address.
*/
const_iterator begin() const {
return address;
}
/**
* Returns an iterator to the one-past-the-end element of this address.
*/
iterator end() {
return address + address_size;
}
/**
* Returns a const iterator to the one-past-the-end element of this
* address.
*/
const_iterator end() const {
return address + address_size;
}
/**
* \brief Compares this address for equality.
*
* \param rhs The address to be compared to.
*
* \return bool indicating whether addresses are equal.
*/
bool operator==(const IPv6Address &rhs) const {
return std::equal(begin(), end(), rhs.begin());
}
/**
* \brief Compares this address for inequality.
*
* \param rhs The address to be compared to.
*
* \return bool indicating whether addresses are distinct.
*/
bool operator!=(const IPv6Address &rhs) const {
return !(*this == rhs);
}
/**
* \brief Compares this address for less-than inequality.
*
* \param rhs The address to be compared to.
*
* \return bool indicating whether this address is less-than rhs.
*/
bool operator<(const IPv6Address &rhs) const {
return std::lexicographical_compare(begin(), end(), rhs.begin(), rhs.end());
}
/**
* \brief Helper function which copies the address into an output
* iterator.
*
* This is the same as:
*
* std::copy(begin(), end(), iter);
*
* But since some PDUs return a IPv6Address by value, this function
* can be used to avoid temporaries.
*
* \param iter The output iterator in which to store this address.
* \return OutputIterator pointing to one-past the last position
* written.
*/
template<typename OutputIterator>
OutputIterator copy(OutputIterator iter) const {
return std::copy(begin(), end(), iter);
}
/**
* \brief Returns true if this is a loopback IPv6 address.
*
* This method returns true if this address is the ::1/128 address,
* false otherwise.
*/
bool is_loopback() const;
/**
* \brief Returns true if this is a multicast IPv6 address.
*
* This method returns true if this address is in the address range
* ff00::/8, false otherwise.
*/
bool is_multicast() const;
/**
* \brief Writes this address in hex-notation to a std::ostream.
*
* \param os The stream in which to write the address.
* \param addr The parameter to be written.
* \return std::ostream& pointing to the os parameter.
*/
friend std::ostream &operator<<(std::ostream &os, const IPv6Address &addr) {
return os << addr.to_string();
}
private:
void init(const char *addr);
uint8_t address[address_size];
};
} //namespace Tins
#if TINS_IS_CXX11
namespace std
{
template<>
struct hash<Tins::IPv6Address> {
size_t operator()(const Tins::IPv6Address &addr) const {
return std::hash<std::string>()(addr.to_string());
}
};
} // namespace std
#endif
#endif // TINS_IPV6_ADDRESS

403
include/tins/llc.h Normal file
View File

@@ -0,0 +1,403 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_IEEE8022_H
#define TINS_IEEE8022_H
#include <list>
#include <vector>
#include <stdint.h>
#include "macros.h"
#include "pdu.h"
#include "endianness.h"
namespace Tins {
/**
* \class LLC
* \brief Representing a LLC frame.
*
* This PDU follows the standard LLC frame described in the IEEE 802.2 specs.
*/
class LLC : public PDU {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::LLC;
/**
* \brief Represents the LLC global DSAP address.
*/
static const uint8_t GLOBAL_DSAP_ADDR;
/**
* \brief Represents the LLC NULL address.
*/
static const uint8_t NULL_ADDR;
/**
* \brief LLC Format flags.
*/
enum Format {
INFORMATION = 0,
SUPERVISORY = 1,
UNNUMBERED = 3
};
/**
* \brief LLC Modifier functions.
*/
enum ModifierFunctions {
UI = 0x00,
XID = 0x1D,
TEST = 0x07,
SABME = 0x1E,
DISC = 0x02,
UA = 0x06,
DM = 0x18,
FRMR = 0x11
};
/**
* \brief LLC Supervisory functions
*/
enum SupervisoryFunctions {
RECEIVE_READY = 0,
REJECT = 2,
RECEIVE_NOT_READY = 1
};
/**
* \brief Default constructor.
*/
LLC();
/**
* \brief Constructs an instance of LLC, setting the dsap and ssap.
* The control field is set to 0.
* \param dsap The dsap value to be set.
* \param ssap The ssap value to be set.
*/
LLC(uint8_t dsap, uint8_t ssap);
/**
* \brief Constructs a LLC object from a buffer and adds all
* identifiable PDUs found in the buffer as children of this one.
*
* If there is not enough size for a LLC header, a malformed_packet
* exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
LLC(const uint8_t *buffer, uint32_t total_sz);
/* Setters */
/**
* \brief Setter for the group destination bit.
* \param value The value to be set.
*/
void group(bool value);
/**
* \brief Setter for the dsap field.
* \param new_dsap The new dsap field.
*/
void dsap(uint8_t new_dsap);
/**
* \brief Setter for the response bit.
* \param value The value to be set.
*/
void response(bool value);
/**
* \brief Setter for the ssap field.
* \param new_ssap The new ssap field.
*/
void ssap(uint8_t new_ssap);
/**
* \brief Setter for the LLC frame format type.
* \param type The LLC frame format to set.
*/
void type(Format type);
/**
* \brief Setter for sender send sequence number.
* Only applied if format is INFORMATION.
* \param seq_number New sender send sequence number to be set.
*/
void send_seq_number(uint8_t seq_number);
/**
* \brief Setter for sender receive sequence number.
* Only applied if format is INFORMATION or SUPERVISORY.
* \param seq_number New sender receive sequence number to be set.
*/
void receive_seq_number(uint8_t seq_number);
/**
* \brief Setter for the poll/final flag.
* \param value Bool indicating the value of the flag.
*/
void poll_final(bool value);
/**
* \brief Setter for the supervisory function.
* Only applied if format is SUPERVISORY.
* \param new_func Value to set on the supervisory function field.
*/
void supervisory_function(SupervisoryFunctions new_func);
/**
* \brief Setter for the modifier function field.
* Only applied if format is UNNUMBERED.
* \param modifier_func Value to set on the modifier function field.
*/
void modifier_function(ModifierFunctions mod_func);
/**
* \brief Add a xid information field.
* Only applied if format is UNNUMBERED and function is XID.
* \param xid_id XID information of the MAC sublayer.
* \param llc_type_class Value to set the llc_type_class field.
* \param receive_window XID sender's receive window size.
*/
void add_xid_information(uint8_t xid_id, uint8_t llc_type_class, uint8_t receive_window);
//TODO: Add Acknowledged connectionless information
/* Getters */
/**
* \brief Getter for the group destination bit.
* \return Whether the group bit is set or not.
*/
bool group() {return _header.dsap & 0x01; }
/**
* \brief Getter for the dsap field.
* \return The dsap field value
*/
uint8_t dsap() {return _header.dsap; }
/**
* \brief Getter for the response bit.
* \return Whether the response bit is set or not.
*/
bool response() {return (_header.ssap & 0x01); }
/**
* \brief Getter for the ssap field.
* \return The ssap field.
*/
uint8_t ssap() {return _header.ssap; }
/**
* \brief Getter for the LLC frame format type.
* \return The LLC frame format.
*/
uint8_t type() {return _type; }
/**
* \brief Getter for sender send sequence number.
*
* \return The sender send sequence number if format is INFORMATION else 0.
*/
uint8_t send_seq_number() {
return (type() == INFORMATION) ? (control_field.info.send_seq_num) : 0;
}
/**
* \brief Getter for sender receive sequence number.
*
* \return The sender receive sequence number if format is
* INFORMATION or SUPERVISORY else 0.
*/
uint8_t receive_seq_number() {
switch (type()) {
case INFORMATION:
return control_field.info.recv_seq_num;
case SUPERVISORY:
return control_field.super.recv_seq_num;
case UNNUMBERED:
return 0;
default:
return 0;
}
}
/**
* \brief Getter for the poll/final flag.
* \return Whether the poll/final flag is set.
*/
bool poll_final() {
switch (type()) {
case UNNUMBERED:
return control_field.unnumbered.poll_final_bit;
case INFORMATION:
return control_field.info.poll_final_bit;
case SUPERVISORY:
return control_field.super.poll_final_bit;
default:
return false;
}
}
/**
* \brief Getter for the supervisory function.
*
* \return The supervisory function if format is SUPERVISORY else 0.
*/
uint8_t supervisory_function() {
if (type() == SUPERVISORY)
return control_field.super.supervisory_func;
return 0;
}
/**
* \brief Getter for the modifier function field.
*
* \return The modifier function if format is UNNUMBERED else 0.
*/
uint8_t modifier_function() {
if (type() == UNNUMBERED)
return (control_field.unnumbered.mod_func1 << 3) + control_field.unnumbered.mod_func2;
return 0;
}
/**
* \brief Returns the LLC frame's header length.
*
* \return 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_flag; }
/**
* \brief Delete all the information fields added.
*/
void clear_information_fields();
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
LLC *clone() const {
return new LLC(*this);
}
private:
TINS_BEGIN_PACK
struct llchdr {
uint8_t dsap;
uint8_t ssap;
} TINS_END_PACK;
#if TINS_IS_LITTLE_ENDIAN
TINS_BEGIN_PACK
struct info_control_field {
uint16_t
type_bit:1,
send_seq_num:7,
poll_final_bit:1,
recv_seq_num:7;
} TINS_END_PACK;
TINS_BEGIN_PACK
struct super_control_field {
uint16_t type_bit:2,
supervisory_func:2,
unused:4,
poll_final_bit:1,
recv_seq_num:7;
} TINS_END_PACK;
TINS_BEGIN_PACK
struct un_control_field {
uint8_t type_bits:2,
mod_func1:2,
poll_final_bit:1,
mod_func2:3;
} TINS_END_PACK;
#elif TINS_IS_BIG_ENDIAN
TINS_BEGIN_PACK
struct info_control_field {
uint16_t send_seq_num:7,
type_bit:1,
recv_seq_num:7,
poll_final_bit:1;
} TINS_END_PACK;
TINS_BEGIN_PACK
struct super_control_field {
uint16_t unused:4,
supervisory_func:2,
type_bit:2,
recv_seq_num:7,
poll_final_bit:1;
} TINS_END_PACK;
TINS_BEGIN_PACK
struct un_control_field {
uint8_t mod_func2:3,
poll_final_bit:1,
mod_func1:2,
type_bits:2;
} TINS_END_PACK;
#endif
typedef std::vector<uint8_t> field_type;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
llchdr _header;
uint8_t control_field_length;
union {
info_control_field info;
super_control_field super;
un_control_field unnumbered;
} control_field;
Format _type;
uint8_t information_field_length;
std::list<field_type> information_fields;
};
}
#endif // TINS_IEEE8022_H

109
include/tins/loopback.h Normal file
View File

@@ -0,0 +1,109 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_LOOPBACK_H
#define TINS_LOOPBACK_H
#include "pdu.h"
#include "macros.h"
namespace Tins {
class Loopback : public PDU {
public:
/**
* This PDU's type.
*/
static const PDU::PDUType pdu_flag = PDU::LOOPBACK;
/**
* \brief Default constructs a Loopback PDU.
*
* The family identifier is left as zero.
*/
Loopback();
/**
* \brief Construct a Loopback object from a buffer and adds
* all identifiable PDUs found in the buffer as children of
* this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for a Loopback header, a
* malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Loopback(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Getter for the family identifier.
* \return The stored family identifier.
*/
uint32_t family() const { return _family; }
/**
* \brief Setter for the family identifier.
* \param family_id The family identifier to be set.
*/
void family(uint32_t family_id);
/**
* \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_flag; }
/**
* \sa PDU::clone
*/
Loopback *clone() const {
return new Loopback(*this);
}
// Null/Loopback can only be sent in *BSD
#ifdef BSD
/**
* \sa PDU::send()
*/
void send(PacketSender &sender, const NetworkInterface &iface);
#endif // BSD
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
uint32_t _family;
};
}
#endif // TINS_LOOPBACK_H

52
include/tins/macros.h Normal file
View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_MACROS_H
#define TINS_MACROS_H
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#include <sys/param.h>
#endif
// Packing directives....
#ifdef _MSC_VER
#define TINS_BEGIN_PACK __pragma( pack(push, 1) )
#define TINS_END_PACK __pragma( pack(pop) )
#define TINS_PACKED(DECLARATION) __pragma( pack(push, 1) ) DECLARATION __pragma( pack(pop) )
#define TINS_DEPRECATED(func) __declspec(deprecated) func
#define TINS_NOEXCEPT
#else
#define TINS_BEGIN_PACK
#define TINS_END_PACK __attribute__((packed))
#define TINS_PACKED(DECLARATION) DECLARATION __attribute__((packed))
#define TINS_DEPRECATED(func) func __attribute__ ((deprecated))
#define TINS_NOEXCEPT noexcept
#endif
#endif

View File

@@ -0,0 +1,171 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_NETWORK_INTERFACE_H
#define TINS_NETWORK_INTERFACE_H
#include <string>
#include <vector>
#include <stdint.h>
#include "hw_address.h"
#include "ip_address.h"
namespace Tins {
/**
* \class NetworkInterface
* \brief Abstraction of a network interface
*/
class NetworkInterface {
public:
/**
* \brief The type used to store the interface's identifier.
*/
typedef uint32_t id_type;
/**
* \brief The type of this interface's address.
*/
typedef HWAddress<6> address_type;
/**
* \brief Struct that holds an interface's addresses.
*/
struct Info {
IPv4Address ip_addr, netmask, bcast_addr;
address_type hw_addr;
};
/**
* Returns a NetworkInterface object associated with the default
* interface.
*/
static NetworkInterface default_interface();
/**
* Returns all available network interfaces.
*/
static std::vector<NetworkInterface> all();
/**
* Returns a network interface for the given index.
*/
static NetworkInterface from_index(id_type identifier);
/**
* Default constructor.
*/
NetworkInterface();
/**
* \brief Constructor from std::string.
*
* \param name The name of the interface this object will abstract.
*/
NetworkInterface(const std::string &name);
/**
* \brief Constructor from const char*.
*
* \param name The name of the interface this object will abstract.
*/
NetworkInterface(const char *name);
/**
* \brief Constructs a NetworkInterface from an ip address.
*
* This abstracted interface will be the one that would be the gateway
* when sending a packet to the given ip.
*
* \param ip The ip address being looked up.
*/
NetworkInterface(IPv4Address ip);
/**
* \brief Getter for this interface's identifier.
*
* \return id_type containing the identifier.
*/
id_type id() const {
return iface_id;
}
/**
* \brief Retrieves this interface's name.
*
* This name can be used as the interface name provided to the
* Sniffer class when starting a sniffing session.
*
* \sa Sniffer
* \return std::string containing this interface's name.
*/
std::string name() const;
/**
* \brief Retrieve this interface's addresses.
*
* This method iterates through all the interface's until the
* correct one is found. Therefore it's O(N), being N the amount
* of interfaces in the system.
*/
Info addresses() const;
/**
* \brief Tests whether this is a valid interface;
*
* An interface will not be valid iff it was created using the
* default constructor.
*/
operator bool() const {
return iface_id != 0;
}
/**
* \brief Compares this interface for equality.
*
* \param rhs The interface being compared.
*/
bool operator==(const NetworkInterface &rhs) const {
return iface_id == rhs.iface_id;
}
/**
* \brief Compares this interface for inequality.
*
* \param rhs The interface being compared.
*/
bool operator!=(const NetworkInterface &rhs) const {
return !(*this == rhs);
}
private:
id_type resolve_index(const char *name);
id_type iface_id;
};
}
#endif // TINS_NETWORK_INTERFACE_H

View File

@@ -0,0 +1,157 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_OFFLINE_PACKET_FILTER_H
#define TINS_OFFLINE_PACKET_FILTER_H
#include <string>
#include <stdint.h>
#include "data_link_type.h"
namespace Tins {
class PDU;
/**
* \class OfflinePacketFilter
*
* \brief Wraps a pcap filter and matches it against a packet or buffer.
*
* This is a thin wrapper over <i>pcap_offline_filter</i>. You can use
* it to perform packet filtering outside of Sniffer instances.
*
* A potential use case would be if you are capturing packets that are
* sent from another host over UDP. You would recieve UDP packets, then
* parse their content, and apply the OfflinePacketFilter over the
* wrapped packet. For example:
*
* \code
* // Assume we get an UDP packet from somewhere.
* // Inside the payload, there will be a complete packet
* // including its link layer protocol.
* UDP udp = get_packet();
*
* // Create the filter. We'll be expecting Ethernet packets.
* OfflinePacketFilter filter("ip and port 80", DataLinkLayer<EthernetII>());
*
* // We can use this directly over the inner PDU (assuming it has one)
* // See the notes on the efficiency of doing it this way.
* if(filter.matches_filter(*udp.inner_pdu())) {
* // Matches!
* }
*
* // We can also use the payload. This version it faster and should
* // be preferred over the one above
* const RawPDU& raw = udp.rfind_pdu<RawPDU>();
* const auto& payload = raw.payload();
* if(filter.matches_filter(payload.data(), payload.size())) {
* // Matches!
* }
* \endcode
*/
class OfflinePacketFilter {
public:
/**
* Constructs an OfflinePacketFilter object.
*
* \param filter The pcap filter to use.
* \param lt The link layer type to use.
* \param snap_len The snapshot length to use.
*/
template<typename T>
OfflinePacketFilter(const std::string& filter, const DataLinkType<T>& lt,
unsigned int snap_len = 65535)
: string_filter(filter)
{
init(filter, lt.get_type(), snap_len);
}
/**
* \brief Copy constructor.
*
* Note that during copy construction the pcap filter is
* recompiled. Therefore, it might be somehow expensive to
* copy OfflinePacketFilters.
*
* \param other The filter to be copied.
*/
OfflinePacketFilter(const OfflinePacketFilter& other);
/**
* \brief Copy assignment operator.
*
* \param other The filter to be copied.
*
* \sa OfflinePacketFilter
*/
OfflinePacketFilter& operator=(const OfflinePacketFilter& other);
/**
* Releases the compiled pcap filter and handle.
*/
~OfflinePacketFilter();
/**
* \brief Applies the compiled filter on the provided buffer.
*
* This method uses <i>pcap_offline_filter</i> on the provided buffer
* and returns a bool indicating if the packet pointed by the buffer
* matches the filter.
*
* \param buffer A pointer to a buffer which holds a raw packet.
* \param total_sz The length of the buffer pointed by buffer.
* \return true iff the packet matches the filter.
*/
bool matches_filter(const uint8_t* buffer, uint32_t total_sz) const;
/**
* \brief Applies the compiled filter on the provided packet.
*
* This method checks whether the provided packet matches the filter.
* Since this uses pcap filters and they work over a raw data buffer,
* this method serialices the packet and then applies the filter.
* Therefore, this can be quite expensive to use. If you have access
* to the packet before constructing a PDU from it, it is recommended
* to use the other overload over the raw buffer.
*
* \param pdu The packet to be matched against the filter.
* \return true iff the packet matches the filter.
*/
bool matches_filter(PDU& pdu) const;
private:
void init(const std::string& pcap_filter, int link_type,
unsigned int snap_len);
pcap_t* handle;
mutable bpf_program filter;
std::string string_filter;
};
} // Tins
#endif // TINS_OFFLINE_PACKET_FILTER_H

311
include/tins/packet.h Normal file
View File

@@ -0,0 +1,311 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_PACKET_H
#define TINS_PACKET_H
#include <algorithm>
#include "cxxstd.h"
#include "pdu.h"
#include "timestamp.h"
/**
* \namespace Tins
*/
namespace Tins {
template<typename WrappedType, typename TimestampType>
class PacketWrapper;
/**
* \brief Thin wrapper over a PDU and Timestamp reference.
*/
typedef PacketWrapper<PDU&, const Timestamp&> RefPacket;
/**
* \brief Thin wrapper over a PDU pointer and a Timestamp.
*/
typedef PacketWrapper<PDU*, Timestamp> PtrPacket;
/**
* \brief Represents a sniffed packet.
*
* RefPackets contain a PDU reference and a timestamp. The difference between
* this class and the Packet class is that this one contains a reference
* to a PDU, and not a pointer to one.
*
* This class is only used in some BaseSniffer methods as a thin wrapper
* to a PDU pointer/reference. Only BaseSniffer and derived objects can
* create instances of it.
*/
template<typename PDUType, typename TimestampType>
class PacketWrapper {
public:
typedef PDUType pdu_type;
typedef TimestampType timestamp_type;
/**
* \brief User defined conversion to wrapped_type.
*
* This conversion is defined so that BaseSniffer::sniff_loop callback
* or code that calls BaseSniffer::next_packet can still receive a
* PDU pointer/reference without modifying the code at all.
*/
operator pdu_type() {
return pdu_;
}
/**
* \brief Returns the wrapped_type.
*/
pdu_type pdu() {
return pdu_;
}
/**
* \brief Returns the PDU const reference.
*/
const pdu_type pdu() const {
return pdu_;
}
/**
* \brief Returns the packet timestamp.
*
* This is the timestamp in which the packet was taken out of the
* network interface/pcap file.
*/
const Timestamp &timestamp() const {
return ts_;
}
private:
friend class BaseSniffer;
friend class SnifferIterator;
PacketWrapper(pdu_type pdu, const Timestamp &ts)
: pdu_(pdu), ts_(ts) {}
PacketWrapper(const PacketWrapper&);
PacketWrapper& operator=(const PacketWrapper&);
void* operator new (size_t size);
void operator delete (void *p);
pdu_type pdu_;
timestamp_type ts_;
};
/**
* \class Represents a sniffed packet.
*
* A Packet contains a PDU pointer and a Timestamp object. Packets
* <b>will delete</b> the stored PDU* unless you call release_pdu at
* some point before destruction.
*/
class Packet {
public:
/**
* Tag used to specify that a Packet should own a PDU pointer.
*/
struct own_pdu {
};
/**
* \brief Default constructs a Packet.
*
* The PDU* will be set to a null pointer.
*/
Packet()
: pdu_(0) { }
/**
* \brief Constructs a Packet from a PDU* and a Timestamp.
*
* The PDU* is cloned using PDU::clone.
*/
Packet(const PDU *apdu, const Timestamp &tstamp)
: pdu_(apdu->clone()), ts(tstamp) { }
/**
* \brief Constructs a Packet from a PDU* and a Timestamp.
*
* The PDU* will be owned by the Packet. This means you
* <b>do not</b> have to explicitly delete the pointer, that
* will be done automatically by the Packet when it goes out
* of scope.
*/
Packet(PDU *apdu, const Timestamp &tstamp, own_pdu)
: pdu_(apdu), ts(tstamp) { }
/**
* \brief Constructs a Packet from a const PDU&.
*
* The timestamp will be set to the current time.
*
* This calls PDU::clone on the PDU parameter.
*
*/
Packet(const PDU &rhs)
: pdu_(rhs.clone()), ts(Timestamp::current_time()) { }
/**
* \brief Constructs a Packet from a RefPacket.
*
* This calls PDU::clone on the RefPacket's PDU.
*
*/
Packet(const RefPacket &pck)
: pdu_(pck.pdu().clone()), ts(pck.timestamp()) { }
/**
* \brief Constructs a Packet from a PtrPacket object.
*/
Packet(const PtrPacket &pck)
: pdu_(pck.pdu()), ts(pck.timestamp()) { }
/**
* \brief Copy constructor.
*
* This calls PDU::clone on the rhs's PDU* member.
*/
Packet(const Packet &rhs) : ts(rhs.timestamp()) {
pdu_ = rhs.pdu() ? rhs.pdu()->clone() : 0;
}
/**
* \brief Copy assignment operator.
*
* This calls PDU::clone on the rhs's PDU* member.
*/
Packet& operator=(const Packet &rhs) {
if(this != &rhs) {
delete pdu_;
ts = rhs.timestamp();
pdu_ = rhs.pdu() ? rhs.pdu()->clone() : 0;
}
return *this;
}
#if TINS_IS_CXX11
/**
* Move constructor.
*/
Packet(Packet &&rhs) TINS_NOEXCEPT : pdu_(rhs.pdu()), ts(rhs.timestamp()) {
rhs.pdu_ = nullptr;
}
/**
* Move assignment operator.
*/
Packet& operator=(Packet &&rhs) TINS_NOEXCEPT {
if(this != &rhs) {
std::swap(pdu_, rhs.pdu_);
ts = rhs.timestamp();
}
return *this;
}
#endif
/**
* \brief Packet destructor.
*
* This calls operator delete on the stored PDU*.
*/
~Packet() {
delete pdu_;
}
/**
* Returns this Packet's timestamp.
*/
const Timestamp &timestamp() const {
return ts;
}
/**
* \brief Returns the stored PDU*.
*
* Caller <b>must not</b> delete the pointer. \sa Packet::release_pdu
*/
PDU *pdu() {
return pdu_;
}
/**
* \brief Returns the stored PDU*.
*
* Caller <b>must not</b> delete the pointer. \sa Packet::release_pdu
*/
const PDU *pdu() const {
return pdu_;
}
/**
* \brief Releases ownership of the stored PDU*.
*
* This method returns the stored PDU* and sets the stored PDU* to
* a null pointer, so the destructor will be well behaved. Use this
* method if you want to keep the internal PDU* somewhere. Otherwise,
* when Packet's destructor is called, the stored pointer will be
* deleted.
*/
PDU *release_pdu() {
PDU *some_pdu = pdu_;
pdu_ = 0;
return some_pdu;
}
/**
* \brief Tests whether this is Packet contains a valid PDU.
*
* \return true if pdu() == nullptr, false otherwise.
*/
operator bool() const {
return pdu_ ? true : false;
}
/**
*
* \brief Concatenation operator.
*
* Adds the PDU at the end of the PDU stack.
*
* \param rhs The PDU to be appended.
*/
Packet &operator/=(const PDU &rhs) {
pdu_ /= rhs;
return *this;
}
private:
PDU *pdu_;
Timestamp ts;
};
}
#endif // TINS_PACKET_H

View File

@@ -0,0 +1,404 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_PACKET_SENDER_H
#define TINS_PACKET_SENDER_H
#include <string>
#include <stdexcept>
#include <vector>
#include <stdint.h>
#include <map>
#include "network_interface.h"
#include "macros.h"
#include "cxxstd.h"
struct timeval;
struct sockaddr;
namespace Tins {
class PDU;
/**
* \class PacketSender
* \brief Sends packets through a network interface.
*
* This class allows sending packets through a network interface.
* It can send basically two types of packets:
*
* - Those that contain a link layer PDU (EthernetII, SLL, etc). These
* will be serialized and sent through an interface that has to be
* specified. This can be done by providing it when you call
* PacketSender::send, or set a default one using
* PacketSender::default_interface.
* - Those that don't contain a link layer PDU. In this case, the
* kernel will be responsible for picking the appropriate network interface
* based on the destination address.
*
* Sending packets can be done via PacketSender::send:
*
* \code
* // Construct a packet which uses an EthernetII link layer.
* EthernetII pkt1 = ...;
*
* // Construct a packet sender, which we'll use to send packets.
* PacketSender sender;
*
* // Send it through interface eth0
* sender.send(pkt1, "eth0");
*
* // Set the default interface to eth0
* sender.default_interface("eth0");
*
* // This is now equivalent to the previous send.
* sender.send(pkt1);
*
* // Construct a packet which has no link layer protocol.
* IP ip = IP("192.168.0.1") / TCP(22, 928);
*
* // Here the kernel will figure out which interface to use and it will
* // append the appropriate link layer protocol PDU. It will also perform
* // the necessary ARP lookups in order to use the destination host's
* // hardware address.
* //
* // libtins will find which is the appropriate source IP address to use.
* // This will be done by the kernel as well, but it's required when
* // calculating checksums.
* sender.send(ip);
* \endcode
*
* PacketSender also supports sending a packet and waiting for a response.
* This can be done by using PacketSender::send_recv.
*
* This class opens sockets as it needs to, and closes them when the object
* is destructed.
*
* \sa PacketSender::send
* \sa PacketSender::send_recv
*/
class PacketSender {
public:
/**
* The default timeout for receive actions.
*/
static const uint32_t DEFAULT_TIMEOUT;
/**
* Flags to indicate the socket type.
*/
enum SocketType {
ETHER_SOCKET,
IP_TCP_SOCKET,
IP_UDP_SOCKET,
IP_RAW_SOCKET,
ARP_SOCKET,
ICMP_SOCKET,
IPV6_SOCKET,
SOCKETS_END
};
/**
* \brief Constructor for PacketSender objects.
*
* \param iface The default interface in which to send the packets.
* \param recv_timeout The timeout which will be used when receiving responses.
*/
PacketSender(const NetworkInterface &iface = NetworkInterface(),
uint32_t recv_timeout = DEFAULT_TIMEOUT, uint32_t usec = 0);
#if TINS_IS_CXX11
/**
* \brief Move constructor.
* \param rhs The sender to be moved.
*/
PacketSender(PacketSender &&rhs) TINS_NOEXCEPT {
*this = std::move(rhs);
}
/**
* \brief Move assignment operator.
* \param rhs The sender to be moved.
*/
PacketSender& operator=(PacketSender &&rhs) TINS_NOEXCEPT {
_sockets = std::move(rhs._sockets);
rhs._sockets = std::vector<int>(SOCKETS_END, INVALID_RAW_SOCKET);
#ifndef WIN32
#if defined(BSD) || defined(__FreeBSD_kernel__)
_ether_socket = std::move(rhs._ether_socket);
#else
_ether_socket = rhs._ether_socket;
rhs._ether_socket = INVALID_RAW_SOCKET;
#endif
#endif
_types = rhs._types; // no move
_timeout = rhs._timeout;
_timeout_usec = rhs._timeout_usec;
default_iface = rhs.default_iface;
return *this;
}
#endif
/**
* \brief PacketSender destructor.
*
* This gracefully closes all open sockets.
*/
~PacketSender();
#ifndef WIN32
/**
* \brief Opens a layer 2 socket.
*
* If this operation fails, then a socket_open_error will be thrown.
*/
void open_l2_socket(const NetworkInterface& iface = NetworkInterface());
#endif // WIN32
/**
* \brief Opens a layer 3 socket, using the corresponding protocol
* for the given flag.
*
* If this operation fails, then a socket_open_error will be thrown.
* If the provided socket type is not valid, an invalid_socket_type
* exception will be throw.
*
* \param type The type of socket which will be used to pick the protocol flag
* for this socket.
*/
void open_l3_socket(SocketType type);
/**
* \brief Closes the socket associated with the given flag.
*
* If the provided type is invalid, meaning no such open socket
* exists, an invalid_socket_type exception is thrown.
*
* If any socket close errors are encountered, a socket_close_error
* is thrown.
*
* \param type The type of the socket to be closed.
*/
void close_socket(SocketType type, const NetworkInterface &iface = NetworkInterface());
/**
* \brief Sets the default interface.
*
* The interface will be used whenever PacketSender::send(PDU&)
* is called.
*/
void default_interface(const NetworkInterface &iface);
/**
* \brief Gets the default interface.
*
* \sa PacketSender::default_interface
*/
const NetworkInterface& default_interface() const;
/**
* \brief Sends a PDU.
*
* This method opens the appropriate socket, if it's not open yet,
* and sends the PDU on the open socket.
*
* If any send error occurs, then a socket_write_error is thrown.
*
* If the PDU contains a link layer protocol, then default_interface
* is used.
*
* \sa PacketSender::default_interface
*
* \param pdu The PDU to be sent.
*/
void send(PDU &pdu);
/**
* \brief Sends a PDU.
*
* \sa PacketSender::send
*
* This overload takes a NetworkInterface. The packet is sent
* through that interface if a link-layer PDU is present,
* otherwise this call is equivalent to send(PDU&).
*
* The interface stored in the link layer PDU(if any), is restored
* after this method ends.
*
* \param pdu The PDU to be sent.
* \param iface The network interface to use.
*/
void send(PDU &pdu, const NetworkInterface &iface);
/**
* \brief Sends a PDU and waits for its response.
*
* This method is used to send PDUs and receive their response.
* The packet is sent, and then a response is awaited.
* PDU::matches_pdu is called on the packet sent in order to
* check whether a packet received is a response.
*
* This will match every response to a packet. For example,
* if you send a TCP packet, any response matching the same
* IP addresses and ports will be taken as a response to it.
* This also happens for other protocols, such as ARP, ICMP,
* DHCP, DNS, IP, etc.
*
* If you send a packet and get an ICMP response indicating
* an error (such as host unreachable, ttl exceeded, etc),
* that packet will be considered a response.
*
* \param pdu The PDU to send.
* \return Returns the response PDU, 0 if not response was received.
*/
PDU *send_recv(PDU &pdu);
/**
* \brief Sends a PDU and waits for its response.
*
* Sends a packet and receives a response. This overload takes
* a NetworkInterface.
*
* \sa PacketSender::send_recv(PDU&);
* \param pdu The PDU to send.
* \param iface The network interface in which to send and receive.
* \return Returns the response PDU, 0 if not response was received.
*/
PDU *send_recv(PDU &pdu, const NetworkInterface &iface);
#ifndef WIN32
/**
* \brief Receives a layer 2 PDU response to a previously sent PDU.
*
* This method is used internally. You should just use PacketSender::send_recv.
*
* This PacketSender will receive data from a raw socket, open using
* the corresponding flag, according to the given type of protocol, until
* a match for the given PDU is received.
*
* \param pdu The PDU which will try to match the responses.
* \param link_addr The sockaddr struct which will be used to receive the PDU.
* \param len_addr The sockaddr struct length.
* \return Returns the response PDU. If no response is received, then 0 is returned.
*/
PDU *recv_l2(PDU &pdu, struct sockaddr *link_addr, uint32_t len_addr,
const NetworkInterface &iface = NetworkInterface());
/**
* \brief Sends a level 2 PDU.
*
* This method is used internally. You should just use PacketSender::send.
*
* This method sends a layer 2 PDU, using a raw socket, open
* using the corresponding flag, according to the given type of
* protocol.
*
* If any socket write error occurs, a socket_write_error is thrown.
*
* \param pdu The PDU to send.
* \param link_addr The sockaddr struct which will be used to send the PDU.
* \param len_addr The sockaddr struct length.
*/
void send_l2(PDU &pdu, struct sockaddr* link_addr, uint32_t len_addr,
const NetworkInterface &iface = NetworkInterface());
#endif // WIN32
/**
* \brief Receives a layer 3 PDU response to a previously sent PDU.
*
* This method is used internally. You should just use PacketSender::send_recv.
*
* This PacketSender will receive data from a raw socket, open using the corresponding flag,
* according to the given type of protocol, until a match for the given PDU is received.
*
* \param pdu The PDU which will try to match the responses.
* \param link_addr The sockaddr struct which will be used to receive the PDU.
* \param len_addr The sockaddr struct length.
* \param type The socket protocol type.
* \return Returns the response PDU. If no response is received, then 0 is returned.
*/
PDU *recv_l3(PDU &pdu, struct sockaddr *link_addr, uint32_t len_addr, SocketType type);
/**
* \brief Sends a level 3 PDU.
*
* This method is used internally. You should just use PacketSender::send.
*
* This method sends a layer 3 PDU, using a raw socket, open using the corresponding flag,
* according to the given type of protocol.
*
* If any socket write error occurs, a socket_write_error is thrown.
*
* \param pdu The PDU to send.
* \param link_addr The sockaddr struct which will be used to send the PDU.
* \param len_addr The sockaddr struct length.
* \param type The socket protocol type.
*/
void send_l3(PDU &pdu, struct sockaddr *link_addr, uint32_t len_addr, SocketType type);
private:
static const int INVALID_RAW_SOCKET;
typedef std::map<SocketType, int> SocketTypeMap;
PacketSender(const PacketSender&);
PacketSender& operator=(const PacketSender&);
int find_type(SocketType type);
int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y);
#ifndef WIN32
bool ether_socket_initialized(const NetworkInterface& iface = NetworkInterface()) const;
int get_ether_socket(const NetworkInterface& iface = NetworkInterface());
#endif
template<typename T>
void send(PDU &pdu, const NetworkInterface &iface) {
static_cast<T&>(pdu).send(*this, iface);
}
PDU *recv_match_loop(const std::vector<int>& sockets, PDU &pdu, struct sockaddr* link_addr,
uint32_t addrlen);
std::vector<int> _sockets;
#ifndef WIN32
#if defined(BSD) || defined(__FreeBSD_kernel__)
typedef std::map<uint32_t, int> BSDEtherSockets;
BSDEtherSockets _ether_socket;
#else
int _ether_socket;
#endif
#endif
SocketTypeMap _types;
uint32_t _timeout, _timeout_usec;
NetworkInterface default_iface;
// In BSD we need to store the buffer size, retrieved using BIOCGBLEN
#if defined(BSD) || defined(__FreeBSD_kernel__)
int buffer_size;
#endif
};
}
#endif // TINS_PACKET_SENDER_H

View File

@@ -0,0 +1,209 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_PACKET_WRITER_H
#define TINS_PACKET_WRITER_H
#include <string>
#include <iterator>
#include <pcap.h>
#include "data_link_type.h"
#include "utils.h"
#include "cxxstd.h"
namespace Tins {
class PDU;
/**
* \class PacketWriter
* \brief Writes PDUs to a pcap format file.
*
* This class can be used to write packets into a <i>pcap</i> format
* file. It supports both writing packets one by one, or writing all
* packets in a range (provided by iterators), so you can use it
* to dump all packets in a vector.
*
* Since you might use both PDU objects and pointers to them,
* both the PacketWriter::write overload that takes a single object
* or the one that takes an iterator range accept a PDU reference type
* as well as any type that can be dereferenced until a PDU type is found.
* This means you can use both raw and smart pointers.
*
* For example:
*
* \code
* // Differents types holding PDUs
* EthernetII object;
* std::shared_ptr<PDU> smart_ptr = ...;
* std::vector<std::shared_ptr<PDU>> vt = ....;
*
* // The writer we'll use
* PacketWriter writer("/tmp/file.pcap", DataLinkType<EthernetII>());
*
* // Now write all of them
* writer.write(object);
* writer.write(smart_ptr);
* writer.write(vt.begin(), vt.end());
* \endcode
*/
class PacketWriter {
public:
/**
* \brief The type of PDUs that will be written to this file (deprecated).
* \deprecated Use DataLinkType instead of this enum.
*
* This flag should match the type of the lowest layer PDU to be
* written.
*/
enum LinkType {
RADIOTAP = DLT_IEEE802_11_RADIO,
DOT11 = DLT_IEEE802_11,
ETH2 = DLT_EN10MB,
DOT3 = DLT_EN10MB,
SLL = DLT_LINUX_SLL
};
/**
* \brief Constructs a PacketWriter.
*
* This method takes a DataLinkType, which indicates the link
* layer protocol that will be used on the packets to write.
*
* For example, you can write packets that contain an
* EthernetII link layer type by doing:
*
* \code
* // Construct a PacketWriter
* PacketWriter writer("/tmp/test.pcap", DataLinkType<EthernetII>());
* // Write some packet
* writer.write(packet);
* \endcode
*
* \param file_name The file in which to store the written PDUs.
* \param lt A DataLinkType that represents the link layer
* protocol to use.
* \sa PcapIdentifier.
*/
template<typename T>
PacketWriter(const std::string &file_name, const DataLinkType<T>& lt)
{
init(file_name, lt.get_type());
}
/**
* \brief Constructs a PacketWriter.
*
* \deprecated Use the PacketWriter(const std::string&, const DataLinkType<T>&)
* constructor.
*
* \param file_name The file in which to store the written PDUs.
* \param lt The link type which will be written to this file.
* \sa LinkType.
*/
PacketWriter(const std::string &file_name, LinkType lt);
#if TINS_IS_CXX11
/**
* \brief Move constructor.
*
* Note that calling PacketWriter::write on an previously moved
* object will lead to undefined behaviour.
*
* \param rhs The PacketWriter to be moved.
*/
PacketWriter(PacketWriter &&rhs) TINS_NOEXCEPT {
*this = std::move(rhs);
}
/**
* \brief Move assignment operator.
*
* Note that calling PacketWriter::write on an previously moved
* object will lead to undefined behaviour.
*
* \param rhs The PacketWriter to be moved.
*/
PacketWriter& operator=(PacketWriter &&rhs) TINS_NOEXCEPT {
handle = 0;
dumper = 0;
std::swap(handle, rhs.handle);
std::swap(dumper, rhs.dumper);
return *this;
}
#endif
/**
* \brief Destructor.
*
* Gracefully closes the output file.
*/
~PacketWriter();
/**
* \brief Writes a PDU to this file.
*/
void write(PDU &pdu);
/**
* \brief Writes a PDU to this file.
*
* The template parameter T must at some point yield a PDU& after
* applying operator* one or more than one time. This accepts both
* raw and smart pointers.
*/
template<typename T>
void write(T &pdu) {
write(Utils::dereference_until_pdu(pdu));
}
/**
* \brief Writes all the PDUs in the range [start, end)
* \param start A forward iterator pointing to the first PDU
* to be written.
* \param end A forward iterator pointing to one past the last
* PDU in the range.
*/
template<typename ForwardIterator>
void write(ForwardIterator start, ForwardIterator end) {
while(start != end)
write(Utils::dereference_until_pdu(*start++));
}
private:
// You shall not copy
PacketWriter(const PacketWriter&);
PacketWriter& operator=(const PacketWriter&);
void init(const std::string& file_name, int link_type);
pcap_t *handle;
pcap_dumper_t *dumper;
};
}
#endif // TINS_PACKET_WRITER_H

551
include/tins/pdu.h Normal file
View File

@@ -0,0 +1,551 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_PDU_H
#define TINS_PDU_H
#include <stdint.h>
#include <vector>
#include "macros.h"
#include "cxxstd.h"
#include "exceptions.h"
/** \brief The Tins namespace.
*/
namespace Tins {
class PacketSender;
class NetworkInterface;
/**
* The type used to store several PDU option values.
*/
typedef std::vector<uint8_t> byte_array;
/**
* \class PDU
* \brief Base class for protocol data units.
*
* Every PDU implementation inherits from this class.
*
* PDUs can contain 0 or 1 inner PDU. By stacking several PDUs together,
* you can construct packets. These are created upwards: upper layers
* will be children of the lower ones.
*
* If you want to find a specific protocol within a PDU chain, you can use
* PDU::find_pdu and PDU::rfind_pdu. Both of them take a template parameter
* that indicates the PDU type you are looking for. The first one returns a
* pointer to the first object of that type, and the second one returns a
* reference (and throws if it is not found).
*
* For example:
*
* \code
* // Take a whole packet from somewhere.
* EthernetII packet = ...;
*
* // Find the IP layer
* const IP* ip = packet.find_pdu<IP>();
* if(ip) {
* // If the pointer is not null, then it will point to the IP layer
* }
*
* // Find the TCP layer. This will throw a pdu_not_found exception
* // if there is no TCP layer in this packet.
* const TCP& tcp = packet.rfind_pdu<TCP>();
* \endcode
*
* PDU objects can be serialized. Serialization converts the entire PDU
* stack into a vector of bytes. This process might modify some parameters
* on packets depending on which protocols are used in it. For example:
*
* - If the lowest protocol layer is IP (this means that there is no
* link layer protocol in the packet), then it calculates the source address
* that should be used in that IP PDU. \sa IP
* - If a protocol contains a checksum field, its value will be calculated
* and included in its serialized contents.
* - If a protocol contains a "next protocol" field, it is also set based
* on the type of the next PDU in the packet.
*
* If you want to serialize a packet, just use PDU::serialize:
*
* \code
* // Construct a packet
* EthernetII packet = EthernetII() / IP() / TCP() / RawPDU("hello");
*
* // Now serialize it. This is a std::vector<uint8_t>.
* PDU::serialization_type buffer = packet.serialize();
* \endcode
*/
class PDU {
public:
/**
* The type that will be returned when serializing PDUs.
*/
typedef byte_array serialization_type;
/**
* The typep used to identify the endianness of every PDU.
*/
enum endian_type {
BE,
LE
};
/**
* \brief Enum which identifies each type of PDU.
*
* This enum is used to identify the PDU type.
*/
enum PDUType {
RAW,
ETHERNET_II,
IEEE802_3,
RADIOTAP,
DOT11,
DOT11_ACK,
DOT11_ASSOC_REQ,
DOT11_ASSOC_RESP,
DOT11_AUTH,
DOT11_BEACON,
DOT11_BLOCK_ACK,
DOT11_BLOCK_ACK_REQ,
DOT11_CF_END,
DOT11_DATA,
DOT11_CONTROL,
DOT11_DEAUTH,
DOT11_DIASSOC,
DOT11_END_CF_ACK,
DOT11_MANAGEMENT,
DOT11_PROBE_REQ,
DOT11_PROBE_RESP,
DOT11_PS_POLL,
DOT11_REASSOC_REQ,
DOT11_REASSOC_RESP,
DOT11_RTS,
DOT11_QOS_DATA,
LLC,
SNAP,
IP,
ARP,
TCP,
UDP,
ICMP,
BOOTP,
DHCP,
EAPOL,
RC4EAPOL,
RSNEAPOL,
DNS,
LOOPBACK,
IPv6,
ICMPv6,
SLL,
DHCPv6,
DOT1Q,
PPPOE,
STP,
PPI,
IPSEC_AH,
IPSEC_ESP,
USER_DEFINED_PDU = 1000
};
/**
* The endianness used by this PDU. This can be overriden
* by subclasses.
*/
static const endian_type endianness = BE;
/**
* \brief Default constructor.
*/
PDU();
#if TINS_IS_CXX11
/**
* \brief Move constructor.
*
* \param rhs The PDU to be moved.
*/
PDU(PDU &&rhs) TINS_NOEXCEPT
: _inner_pdu(0)
{
std::swap(_inner_pdu, rhs._inner_pdu);
}
/**
* \brief Move assignment operator.
*
* \param rhs The PDU to be moved.
*/
PDU& operator=(PDU &&rhs) TINS_NOEXCEPT {
std::swap(_inner_pdu, rhs._inner_pdu);
return *this;
}
#endif
/**
* \brief PDU destructor.
*
* Deletes the inner pdu, as a consequence every child pdu is
* deleted.
*/
virtual ~PDU();
/** \brief The header's size
*/
virtual uint32_t header_size() const = 0;
/** \brief Trailer's size.
*
* Some protocols require a trailer(like Ethernet). This defaults to 0.
*/
virtual uint32_t trailer_size() const { return 0; }
/** \brief The whole chain of PDU's size, including this one.
*
* Returns the sum of this and all children PDUs' size.
*/
uint32_t size() const;
/**
* \brief Getter for the inner PDU.
* \return The current inner PDU. Might be 0.
*/
PDU *inner_pdu() const { return _inner_pdu; }
/**
* \brief Releases the inner PDU.
*
* This method makes this PDU to <b>no longer own</b> the inner
* PDU. The current inner PDU is returned, and is <b>not</b>
* destroyed. That means after calling this function, you are
* responsible for using operator delete on the returned pointer.
*
* Use this method if you want to somehow re-use a PDU that
* is already owned by another PDU.
*
* \return The current inner PDU. Might be 0.
*/
PDU *release_inner_pdu();
/**
* \brief Sets the child PDU.
*
* When setting a new inner_pdu, the instance takesownership of
* the object, therefore deleting it when it's no longer required.
*
* \param next_pdu The new child PDU.
*/
void inner_pdu(PDU *next_pdu);
/**
* \brief Sets the child PDU.
*
* The PDU parameter is cloned using PDU::clone.
*
* \param next_pdu The new child PDU.
*/
void inner_pdu(const PDU &next_pdu);
/**
* \brief Serializes the whole chain of PDU's, including this one.
*
* This allocates a std::vector of size size(), and fills it
* with the serialization this PDU, and all of the inner ones'.
*
* \return serialization_type containing the serialization
* of the whole stack of PDUs.
*/
serialization_type serialize();
/**
* \brief Finds and returns the first PDU that matches the given flag.
*
* This method searches for the first PDU which has the same type flag as
* the given one. If the first PDU matches that flag, it is returned.
* If no PDU matches, 0 is returned.
* \param flag The flag which being searched.
*/
template<typename T>
T *find_pdu(PDUType type = T::pdu_flag) {
PDU *pdu = this;
while(pdu) {
if(pdu->matches_flag(type))
return static_cast<T*>(pdu);
pdu = pdu->inner_pdu();
}
return 0;
}
/**
* \brief Finds and returns the first PDU that matches the given flag.
*
* \param flag The flag which being searched.
*/
template<typename T>
const T *find_pdu(PDUType type = T::pdu_flag) const {
return const_cast<PDU*>(this)->find_pdu<T>();
}
/**
* \brief Finds and returns the first PDU that matches the given flag.
*
* If the PDU is not found, a pdu_not_found exception is thrown.
*
* \sa PDU::find_pdu
*
* \param flag The flag which being searched.
*/
template<typename T>
T &rfind_pdu(PDUType type = T::pdu_flag) {
T *ptr = find_pdu<T>(type);
if(!ptr)
throw pdu_not_found();
return *ptr;
}
/**
* \brief Finds and returns the first PDU that matches the given flag.
*
* \param flag The flag which being searched.
*/
template<typename T>
const T &rfind_pdu(PDUType type = T::pdu_flag) const {
return const_cast<PDU*>(this)->rfind_pdu<T>();
}
/**
* \brief Clones this packet.
*
* This method clones this PDU and clones every inner PDU,
* therefore obtaining a clone of the whole inner PDU chain.
* The pointer returned must be deleted by the user.
* \return A pointer to a clone of this packet.
*/
virtual PDU *clone() const = 0;
/**
* \brief Send the stack of PDUs through a PacketSender.
*
* This method will be called only for the PDU on the bottom of the stack,
* therefore it should only implement this method if it can be sent.
*
* PacketSender implements specific methods to send packets which start
* on every valid TCP/IP stack layer; this should only be a proxy for
* those methods.
*
* If this PDU does not represent a link layer protocol, then
* the interface argument will be ignored.
*
* \param sender The PacketSender which will send the packet.
* \param iface The network interface in which this packet will
* be sent.
*/
virtual void send(PacketSender &sender, const NetworkInterface &iface);
/**
* \brief Receives a matching response for this packet.
*
* This method should act as a proxy for PacketSender::recv_lX methods.
*
* \param sender The packet sender which will receive the packet.
* \param iface The interface in which to expect the response.
*/
virtual PDU *recv_response(PacketSender &sender, const NetworkInterface &iface);
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* This method must check wether the buffer pointed by ptr is a valid
* response for this PDU. If it is valid, then it might want to propagate
* the call to the next PDU. Note that in some cases, such as ICMP
* Host Unreachable, there is no need to ask the next layer for matching.
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
virtual bool matches_response(const uint8_t *ptr, uint32_t total_sz) const {
return false;
}
/**
* \brief Check wether this PDU matches the specified flag.
*
* This method should be reimplemented in PDU classes which have
* subclasses, and try to match the given PDU to each of its parent
* classes' flag.
* \param flag The flag to match.
*/
virtual bool matches_flag(PDUType flag) const {
return flag == pdu_type();
}
/**
* \brief Getter for the PDU's type.
*
* \return Returns the PDUType corresponding to the PDU.
*/
virtual PDUType pdu_type() const = 0;
protected:
/**
* \brief Copy constructor.
*/
PDU(const PDU &other);
/**
* \brief Copy assignment operator.
*/
PDU &operator=(const PDU &other);
/**
* \brief Copy other PDU's inner PDU(if any).
* \param pdu The PDU from which to copy the inner PDU.
*/
void copy_inner_pdu(const PDU &pdu);
/**
* \brief Prepares this PDU for serialization.
*
* This method is called before the inner PDUs are serialized.
* It's useful in situations such as when serializing IP PDUs,
* which don't contain any link layer encapsulation, and therefore
* require to set the source IP address before the TCP/UDP checksum
* is calculated.
*
* By default, this method does nothing
*
* \param parent The parent PDU.
*/
virtual void prepare_for_serialize(const PDU *parent) { }
/**
* \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 Serializes this TCP PDU.
*
* Each PDU must override this method and implement it's own
* serialization.
* \param buffer The buffer in which the PDU will be serialized.
* \param total_sz The size available in the buffer.
* \param parent The PDU that's one level below this one on the stack. Might be 0.
*/
virtual void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) = 0;
private:
PDU *_inner_pdu;
};
/**
* \brief Concatenation operator.
*
* This operator concatenates several PDUs. A copy of the right
* operand is set at the end of the left one's inner PDU chain.
* This means that:
*
* IP some_ip = IP("127.0.0.1") / TCP(12, 13) / RawPDU("bleh");
*
* Works as expected, meaning the output PDU will look like the
* following:
*
* IP - TCP - RawPDU
*
* \param lop The left operand, which will be the one modified.
* \param rop The right operand, the one which will be appended
* to lop.
*/
template<typename T>
T &operator/= (T &lop, const PDU &rop) {
PDU *last = &lop;
while(last->inner_pdu())
last = last->inner_pdu();
last->inner_pdu(rop.clone());
return lop;
}
/**
* \brief Concatenation operator.
*
* \sa operator/=
*/
template<typename T>
T operator/ (T lop, const PDU &rop) {
lop /= rop;
return lop;
}
/**
* \brief Concatenation operator on PDU pointers.
*
* \sa operator/=
*/
template<typename T>
T *operator/= (T* lop, const PDU &rop) {
*lop /= rop;
return lop;
}
namespace Internals {
template<typename T>
struct remove_pointer {
typedef T type;
};
template<typename T>
struct remove_pointer<T*> {
typedef T type;
};
}
template<typename T, typename U>
T tins_cast(U *pdu) {
typedef typename Internals::remove_pointer<T>::type TrueT;
return pdu && (TrueT::pdu_flag == pdu->pdu_type()) ?
static_cast<T>(pdu) :
0;
}
template<typename T, typename U>
T &tins_cast(U &pdu) {
T *ptr = tins_cast<T*>(&pdu);
if(!ptr)
throw bad_tins_cast();
return *ptr;
}
}
#endif // TINS_PDU_H

View File

@@ -0,0 +1,182 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_PDU_ALLOCATOR_H
#define TINS_PDU_ALLOCATOR_H
#include <map>
#include "pdu.h"
namespace Tins {
/**
* \cond
*/
class EthernetII;
class SNAP;
class Dot1Q;
class SLL;
class IP;
class IPv6;
namespace Internals {
template<typename PDUType>
PDU *default_allocator(const uint8_t *buffer, uint32_t size)
{
return new PDUType(buffer, size);
}
template<typename Tag>
class PDUAllocator {
public:
typedef typename Tag::identifier_type id_type;
typedef PDU *(*allocator_type)(const uint8_t *, uint32_t);
template<typename PDUType>
static void register_allocator(id_type identifier)
{
allocators[identifier] = &default_allocator<PDUType>;
pdu_types[PDUType::pdu_flag] = identifier;
}
static PDU *allocate(id_type identifier, const uint8_t *buffer, uint32_t size)
{
typename allocators_type::const_iterator it = allocators.find(identifier);
return (it == allocators.end()) ? 0 : (*it->second)(buffer, size);
}
static bool pdu_type_registered(PDU::PDUType type)
{
return pdu_types.count(type) != 0;
}
static id_type pdu_type_to_id(PDU::PDUType type)
{
typename pdu_map_types::const_iterator it = pdu_types.find(type);
return it->second;
}
private:
typedef std::map<id_type, allocator_type> allocators_type;
typedef std::map<PDU::PDUType, id_type> pdu_map_types;
static allocators_type allocators;
static pdu_map_types pdu_types;
};
template<typename Tag>
typename PDUAllocator<Tag>::allocators_type PDUAllocator<Tag>::allocators;
template<typename Tag>
typename PDUAllocator<Tag>::pdu_map_types PDUAllocator<Tag>::pdu_types;
template<typename IDType>
struct pdu_tag {
typedef IDType identifier_type;
};
template<typename PDUType>
struct pdu_tag_mapper;
#define TINS_GENERATE_TAG_MAPPER(pdu, id_type) \
template<> \
struct pdu_tag_mapper<pdu> { \
typedef pdu_tag<id_type> type; \
};
TINS_GENERATE_TAG_MAPPER(EthernetII, uint16_t)
TINS_GENERATE_TAG_MAPPER(SNAP, uint16_t)
TINS_GENERATE_TAG_MAPPER(SLL, uint16_t)
TINS_GENERATE_TAG_MAPPER(Dot1Q, uint16_t)
TINS_GENERATE_TAG_MAPPER(IP, uint8_t)
TINS_GENERATE_TAG_MAPPER(IPv6, uint8_t)
#undef TINS_GENERATE_TAG_MAPPER
template<typename PDUType>
PDU* allocate(
typename pdu_tag_mapper<PDUType>::type::identifier_type id,
const uint8_t *buffer,
uint32_t size)
{
return PDUAllocator<typename pdu_tag_mapper<PDUType>::type>::allocate(id, buffer, size);
}
template<typename PDUType>
bool pdu_type_registered(PDU::PDUType type)
{
return PDUAllocator<typename pdu_tag_mapper<PDUType>::type>::pdu_type_registered(type);
}
template<typename PDUType>
typename pdu_tag_mapper<PDUType>::type::identifier_type pdu_type_to_id(PDU::PDUType type)
{
return PDUAllocator<typename pdu_tag_mapper<PDUType>::type>::pdu_type_to_id(type);
}
} // namespace Interals
/**
* \endcond
*/
/**
* \brief Defines inner PDU allocators.
*/
namespace Allocators {
/**
* \brief Registers an allocator for the provided PDU type.
*
* Registering a certain allocator for a PDU type is useful for
* extending the library. Once an allocator is registered, it will
* be taken into account while constructing a PDU from a buffer.
*
* If PDU finds that it cannot define which is the protocol
* that should be allocated based on its protocol identifier, it
* will try using the registered allocators if any.
*
* \code
* // Register the 0x666 identifer. Now if EthernetII finds a
* // network layer identifier field whose value is 0x666, it will
* // use SomePDUType as its inner PDU type.
* Allocators::register_allocator<EthernetII, SomePDUType>(0x666);
* \endcode
*
* Note that some PDU types are grouped together. For example,
* registering an allocator for EthernetII will make it work for
* the rest of the link layer protocols, sine they should all work
* the same way.
*/
template<typename PDUType, typename AllocatedType>
void register_allocator(typename Internals::pdu_tag_mapper<PDUType>::type::identifier_type id)
{
Internals::PDUAllocator<
typename Internals::pdu_tag_mapper<PDUType>::type
>::template register_allocator<AllocatedType>(id);
}
} // namespace Allocators
} // namespace Tins
#endif // TINS_PDU_ALLOCATOR_H

158
include/tins/pdu_cacher.h Normal file
View File

@@ -0,0 +1,158 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_PDU_CACHER_H
#define TINS_PDU_CACHER_H
#include <algorithm>
#include "pdu.h"
#include "macros.h"
namespace Tins {
/**
* \class PDUCacher
* \brief PDU wrapper that caches the result of the wrapped PDU's
* serialization.
*
* This wrapper class holds a PDU of the template parameter type, and
* forwards every PDU virtual call to the stored object. Whenever a
* call to write_serialization is performed on this wrapper, the result
* is cached in a PDU::serialization_type. On subsequent calls to
* PDUCacher::write_serialization, the contents of that cache will be
* written to the output buffer.
*
* This class should provide a nice performance boost if you're sending
* over and over a packet that requires some computation while being
* serialized, such as performing checksums, iterate and copy options,
* etc.
*/
template<typename T>
class PDUCacher : public PDU {
public:
/**
* The cached PDU type.
*/
typedef T cached_type;
/**
*
*/
static const PDU::PDUType pdu_flag = cached_type::pdu_flag;
/**
* Default constructs the cached PDU.
*/
PDUCacher() : cached_size() {}
/**
* Constructor from a cached_type.
* \param pdu The PDU to be copy constructed.
*/
PDUCacher(const cached_type &pdu) : cached(pdu),
cached_size() {}
/**
* Forwards the call to the cached PDU.
*
* \sa PDU::header_size.
*/
uint32_t header_size() const {
if(cached_serialization.empty())
cached_size = cached.size();
return cached_size;
}
/**
* Forwards the call to the cached PDU.
*
* \sa PDU::clone.
*/
PDUCacher *clone() const {
return new PDUCacher<T>(*this);
}
/**
* Forwards the call to the cached PDU.
*
* \sa PDU::send.
*/
void send(PacketSender &sender, const NetworkInterface &iface) {
cached.send(sender, iface);
}
/**
* Forwards the call to the cached PDU.
*
* \sa PDU::recv_responde.
*/
PDU *recv_response(PacketSender &sender, const NetworkInterface &iface) {
return cached.recv_response(sender, iface);
}
/**
* Forwards the call to the cached PDU.
*
* \sa PDU::matches_response.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const {
return cached.matches_response(ptr, total_sz);
}
/**
* Forwards the call to the cached PDU.
*
* \sa PDU::matches_flag.
*/
bool matches_flag(PDUType flag) const {
return cached.matches_flag(flag);
}
/**
* Forwards the call to the cached PDU.
*
* \sa PDU::pdu_type.
*/
PDUType pdu_type() const {
return cached.pdu_type();
}
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
if(cached_serialization.size() != total_sz) {
cached_serialization = cached.serialize();
}
std::copy(cached_serialization.begin(), cached_serialization.end(), buffer);
}
cached_type cached;
PDU::serialization_type cached_serialization;
mutable uint32_t cached_size;
};
}
#endif // TINS_PDU_CACHER_H

521
include/tins/pdu_option.h Normal file
View File

@@ -0,0 +1,521 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_PDU_OPTION_H
#define TINS_PDU_OPTION_H
#include <vector>
#include <iterator>
#include <cstring>
#include <algorithm>
#include <string>
#include <stdint.h>
#include "exceptions.h"
#include "endianness.h"
#include "internals.h"
#include "ip_address.h"
#include "ipv6_address.h"
#include "hw_address.h"
namespace Tins {
/**
* \cond
*/
template<typename OptionType, class PDUType>
class PDUOption;
namespace Internals {
template<typename T, typename X, typename PDUType>
T convert_to_integral(const PDUOption<X, PDUType> & opt) {
if(opt.data_size() != sizeof(T))
throw malformed_option();
T data = *(T*)opt.data_ptr();
if(PDUType::endianness == PDUType::BE)
data = Endian::be_to_host(data);
else
data = Endian::le_to_host(data);
return data;
}
template<typename T, typename = void>
struct converter {
template<typename X, typename PDUType>
static T convert(const PDUOption<X, PDUType>& opt) {
return T::from_option(opt);
}
};
template<>
struct converter<uint8_t> {
template<typename X, typename PDUType>
static uint8_t convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() != 1)
throw malformed_option();
return *opt.data_ptr();
}
};
template<>
struct converter<uint16_t> {
template<typename X, typename PDUType>
static uint16_t convert(const PDUOption<X, PDUType>& opt) {
return convert_to_integral<uint16_t>(opt);
}
};
template<>
struct converter<uint32_t> {
template<typename X, typename PDUType>
static uint32_t convert(const PDUOption<X, PDUType>& opt) {
return convert_to_integral<uint32_t>(opt);
}
};
template<>
struct converter<uint64_t> {
template<typename X, typename PDUType>
static uint64_t convert(const PDUOption<X, PDUType>& opt) {
return convert_to_integral<uint64_t>(opt);
}
};
template<size_t n>
struct converter<HWAddress<n> > {
template<typename X, typename PDUType>
static HWAddress<n> convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() != n)
throw malformed_option();
return HWAddress<n>(opt.data_ptr());
}
};
template<>
struct converter<IPv4Address> {
template<typename X, typename PDUType>
static IPv4Address convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() != sizeof(uint32_t))
throw malformed_option();
const uint32_t *ptr = (const uint32_t*)opt.data_ptr();
if(PDUType::endianness == PDUType::BE)
return IPv4Address(*ptr);
else
return IPv4Address(Endian::change_endian(*ptr));
}
};
template<>
struct converter<IPv6Address> {
template<typename X, typename PDUType>
static IPv6Address convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() != IPv6Address::address_size)
throw malformed_option();
return IPv6Address(opt.data_ptr());
}
};
template<>
struct converter<std::string> {
template<typename X, typename PDUType>
static std::string convert(const PDUOption<X, PDUType>& opt) {
return std::string(
opt.data_ptr(),
opt.data_ptr() + opt.data_size()
);
}
};
template<>
struct converter<std::vector<float> > {
template<typename X, typename PDUType>
static std::vector<float> convert(const PDUOption<X, PDUType>& opt) {
std::vector<float> output;
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
while(ptr != end) {
output.push_back(float(*(ptr++) & 0x7f) / 2);
}
return output;
}
};
template<typename T>
struct converter<std::vector<T>, typename enable_if<is_unsigned_integral<T>::value>::type> {
template<typename X, typename PDUType>
static std::vector<T> convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() % sizeof(T) != 0)
throw malformed_option();
const T *ptr = (const T*)opt.data_ptr();
const T *end = (const T*)(opt.data_ptr() + opt.data_size());
std::vector<T> output(std::distance(ptr, end));
typename std::vector<T>::iterator it = output.begin();
while(ptr < end) {
if(PDUType::endianness == PDUType::BE)
*it++ = Endian::be_to_host(*ptr++);
else
*it++ = Endian::le_to_host(*ptr++);
}
return output;
}
};
template<typename T, typename U>
struct converter<
std::vector<std::pair<T, U> >,
typename enable_if<
is_unsigned_integral<T>::value && is_unsigned_integral<U>::value
>::type
> {
template<typename X, typename PDUType>
static std::vector<std::pair<T, U> > convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() % (sizeof(T) + sizeof(U)) != 0)
throw malformed_option();
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
std::vector<std::pair<T, U> > output;
while(ptr < end) {
std::pair<T, U> data;
data.first = *(const T*)ptr;
ptr += sizeof(T);
data.second = *(const U*)ptr;
ptr += sizeof(U);
if(PDUType::endianness == PDUType::BE) {
data.first = Endian::be_to_host(data.first);
data.second = Endian::be_to_host(data.second);
}
else {
data.first = Endian::le_to_host(data.first);
data.second = Endian::le_to_host(data.second);
}
output.push_back(data);
}
return output;
}
};
template<>
struct converter<std::vector<IPv4Address> > {
template<typename X, typename PDUType>
static std::vector<IPv4Address> convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() % 4 != 0)
throw malformed_option();
const uint32_t *ptr = (const uint32_t*)opt.data_ptr();
const uint32_t *end = (const uint32_t*)(opt.data_ptr() + opt.data_size());
std::vector<IPv4Address> output(std::distance(ptr, end));
std::vector<IPv4Address>::iterator it = output.begin();
while(ptr < end) {
if(PDUType::endianness == PDUType::BE)
*it++ = IPv4Address(*ptr++);
else
*it++ = IPv4Address(Endian::change_endian(*ptr++));
}
return output;
}
};
template<>
struct converter<std::vector<IPv6Address> > {
template<typename X, typename PDUType>
static std::vector<IPv6Address> convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() % IPv6Address::address_size != 0)
throw malformed_option();
const uint8_t *ptr = opt.data_ptr(), *end = opt.data_ptr() + opt.data_size();
std::vector<IPv6Address> output;
while(ptr < end) {
output.push_back(IPv6Address(ptr));
ptr += IPv6Address::address_size;
}
return output;
}
};
template<typename T, typename U>
struct converter<
std::pair<T, U>,
typename enable_if<
is_unsigned_integral<T>::value && is_unsigned_integral<U>::value
>::type
> {
template<typename X, typename PDUType>
static std::pair<T, U> convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() != sizeof(T) + sizeof(U))
throw malformed_option();
std::pair<T, U> output;
std::memcpy(&output.first, opt.data_ptr(), sizeof(T));
std::memcpy(&output.second, opt.data_ptr() + sizeof(T), sizeof(U));
if(PDUType::endianness == PDUType::BE) {
output.first = Endian::be_to_host(output.first);
output.second = Endian::be_to_host(output.second);
}
else {
output.first = Endian::le_to_host(output.first);
output.second = Endian::le_to_host(output.second);
}
return output;
}
};
}
/**
* \endcond
*/
/**
* \class PDUOption
* \brief Represents a PDU option field.
*
* Several PDUs, such as TCP, IP, Dot11 or DHCP contain options. All
* of them behave exactly the same way. This class represents those
* options.
*
* The OptionType template parameter indicates the type that will be
* used to store this option's identifier.
*/
template<typename OptionType, class PDUType>
class PDUOption {
private:
static const int small_buffer_size = 8;
public:
typedef uint8_t data_type;
typedef OptionType option_type;
/**
* \brief Constructs a PDUOption.
* \param opt The option type.
* \param length The option's data length.
* \param data The option's data(if any).
*/
PDUOption(option_type opt = option_type(), size_t length = 0, const data_type *data = 0)
: option_(opt), size_(length) {
set_payload_contents(data, data + (data ? length : 0));
}
/**
* \brief Copy constructor.
* \param rhs The PDUOption to be copied.
*/
PDUOption(const PDUOption& rhs) {
real_size_ = 0;
*this = rhs;
}
#if TINS_IS_CXX11
/**
* \brief Move constructor.
* \param rhs The PDUOption to be moved.
*/
PDUOption(PDUOption&& rhs) {
real_size_ = 0;
*this = std::move(rhs);
}
/**
* \brief Move assignment operator.
* \param rhs The PDUOption to be moved.
*/
PDUOption& operator=(PDUOption&& rhs) {
option_ = rhs.option_;
size_ = rhs.size_;
if(real_size_ > small_buffer_size) {
delete[] payload_.big_buffer_ptr;
}
real_size_ = rhs.real_size_;
if(real_size_ > small_buffer_size) {
payload_.big_buffer_ptr = nullptr;
std::swap(payload_.big_buffer_ptr, rhs.payload_.big_buffer_ptr);
rhs.real_size_ = 0;
}
else {
std::copy(
rhs.data_ptr(),
rhs.data_ptr() + rhs.data_size(),
payload_.small_buffer
);
}
return *this;
}
#endif // TINS_IS_CXX11
/**
* \brief Copy assignment operator.
* \param rhs The PDUOption to be copied.
*/
PDUOption& operator=(const PDUOption& rhs) {
option_ = rhs.option_;
size_ = rhs.size_;
if(real_size_ > small_buffer_size) {
delete[] payload_.big_buffer_ptr;
}
real_size_ = rhs.real_size_;
set_payload_contents(rhs.data_ptr(), rhs.data_ptr() + rhs.data_size());
return *this;
}
/**
* \brief Destructor.
*/
~PDUOption() {
if(real_size_ > small_buffer_size) {
delete[] payload_.big_buffer_ptr;
}
}
/**
* \brief Constructs a PDUOption from iterators, which
* indicate the data to be stored in it.
*
* \param opt The option type.
* \param start The beginning of the option data.
* \param end The end of the option data.
*/
template<typename ForwardIterator>
PDUOption(option_type opt, ForwardIterator start, ForwardIterator end)
: option_(opt), size_(std::distance(start, end)) {
set_payload_contents(start, end);
}
/**
* \brief Constructs a PDUOption from iterators, which
* indicate the data to be stored in it.
*
* The length parameter indicates the contents of the length field
* when this option is serialized. Note that this can be different
* to std::distance(start, end).
*
* \sa length_field
*
* \param opt The option type.
* \param length The length of this option.
* \param start The beginning of the option data.
* \param end The end of the option data.
*/
template<typename ForwardIterator>
PDUOption(option_type opt, size_t length, ForwardIterator start, ForwardIterator end)
: option_(opt), size_(length) {
set_payload_contents(start, end);
}
/**
* Retrieves this option's type.
* \return uint8_t containing this option's size.
*/
option_type option() const {
return option_;
}
/**
* Sets this option's type
* \param opt The option type to be set.
*/
void option(option_type opt) {
option_ = opt;
}
/**
* Retrieves this option's data.
*
* If this method is called when data_size() == 0,
* dereferencing the returned pointer will result in undefined
* behaviour.
*
* \return const data_type& containing this option's value.
*/
const data_type *data_ptr() const {
return real_size_ <= small_buffer_size ?
payload_.small_buffer :
payload_.big_buffer_ptr;
}
/**
* \brief Retrieves the length of this option's data.
*
* This is the actual size of the data.
*/
size_t data_size() const {
return real_size_;
}
/**
* \brief Retrieves the data length field.
*
* This is what the size field will contain when this option is
* serialized. It can differ from the actual data size.
*
* This will be equal to data_size unless the constructor that takes
* both a data length and two iterators is used.
*
* \sa data_size.
*/
size_t length_field() const {
return size_;
}
/**
* \brief Constructs a T from this PDUOption.
*
* Use this method to convert a PDUOption to the specific type that
* represents it. For example, if you know an option is of type
* PDU::SACK, you could use option.to<TCP::sack_type>().
*/
template<typename T>
T to() const {
return Internals::converter<T>::convert(*this);
}
private:
template<typename ForwardIterator>
void set_payload_contents(ForwardIterator start, ForwardIterator end) {
real_size_ = std::distance(start, end);
if(real_size_ <= small_buffer_size) {
std::copy(
start,
end,
payload_.small_buffer
);
}
else {
payload_.big_buffer_ptr = new data_type[real_size_];
std::copy(
start,
end,
payload_.big_buffer_ptr
);
}
}
option_type option_;
uint16_t size_, real_size_;
union {
data_type small_buffer[small_buffer_size];
data_type* big_buffer_ptr;
} payload_;
};
} // namespace Tins
#endif // TINS_PDU_OPTION_H

135
include/tins/ppi.h Normal file
View File

@@ -0,0 +1,135 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_PPI_H
#define TINS_PPI_H
#include "pdu.h"
#include "endianness.h"
#include "small_uint.h"
namespace Tins {
/**
* \class PPI
* \brief Represents a Per-Packet Information PDU.
*
* This PDU can only be constructed from a buffer, and
* cannot be serialized. Therefore, it is only useful while
* sniffing packets.
*/
class PPI : public PDU {
public:
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::PPI;
/**
* \brief Constructs an PPI object from a buffer and adds all
* identifiable PDUs found in the buffer as children of this
* one.
*
* If there is not enough size for an PPI header, a
* malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
PPI(const uint8_t *buffer, uint32_t total_sz);
// Getters
/**
* \brief Getter for the version field.
* \return The stored version field value.
*/
uint8_t version() const {
return _header.version;
}
/**
* \brief Getter for the flags field.
* \return The stored flags field value.
*/
uint8_t flags() const {
return _header.flags;
}
/**
* \brief Getter for the length field.
* \return The stored length field value.
*/
uint16_t length() const {
return Endian::le_to_host(_header.length);
}
/**
* \brief Getter for the Data Link Type field.
* \return The stored Data Link Type field value.
*/
uint32_t dlt() const {
return Endian::le_to_host(_header.dlt);
}
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_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_flag; }
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
PPI *clone() const {
return new PPI(*this);
}
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *);
struct header {
uint8_t version, flags;
uint16_t length;
uint32_t dlt;
};
header _header;
byte_array _data;
};
}
#endif // TINS_PPI_H

434
include/tins/pppoe.h Normal file
View File

@@ -0,0 +1,434 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_PPPoE_H
#define TINS_PPPoE_H
#include <list>
#include <string>
#include <vector>
#include "pdu.h"
#include "endianness.h"
#include "small_uint.h"
#include "pdu_option.h"
#include "cxxstd.h"
namespace Tins {
/**
* \class PPPoE
* \brief Represents a Point-to-point protocol over Ethernet PDU.
*/
class PPPoE : public PDU {
public:
/**
* The tag types enum.
*/
enum TagTypes {
END_OF_LIST = 0,
SERVICE_NAME = 0x101,
#if TINS_IS_LITTLE_ENDIAN
AC_NAME = 0x201,
HOST_UNIQ = 0x301,
AC_COOKIE = 0x401,
VENDOR_SPECIFIC = 0x501,
RELAY_SESSION_ID = 0x101,
SERVICE_NAME_ERROR = 0x201,
AC_SYSTEM_ERROR = 0x202,
GENERIC_ERROR = 0x302
#else
AC_NAME = 0x102,
HOST_UNIQ = 0x103,
AC_COOKIE = 0x104,
VENDOR_SPECIFIC = 0x105,
RELAY_SESSION_ID = 0x110,
SERVICE_NAME_ERROR = 0x201,
AC_SYSTEM_ERROR = 0x202,
GENERIC_ERROR = 0x203
#endif
};
/**
* The type used to store a TLV option.
*/
typedef PDUOption<TagTypes, PPPoE> tag;
/**
* The type used to store the options.
*/
typedef std::list<tag> tags_type;
/**
* The type used to store the Vendor-Specific tag's value.
*/
struct vendor_spec_type {
typedef std::vector<uint8_t> data_type;
uint32_t vendor_id;
data_type data;
vendor_spec_type(uint32_t vendor_id = 0, const data_type &data = data_type())
: vendor_id(vendor_id), data(data) { }
static vendor_spec_type from_option(const tag &opt);
};
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::PPPOE;
/**
* \brief Default constructor.
*
* This sets the version and type fields to 0x1.
*/
PPPoE();
/**
* \brief Constructor which creates an PPPoE object from a buffer.
*
* If there is not enough size for a PPPoE header, a malformed_packet
* exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
PPPoE(const uint8_t *buffer, uint32_t total_sz);
// Getters
/**
* \brief Getter for the version field.
* \return The stored version field value.
*/
small_uint<4> version() const {
return _header.version;
}
/**
* \brief Getter for the type field.
* \return The stored type field value.
*/
small_uint<4> type() const {
return _header.type;
}
/**
* \brief Getter for the code field.
* \return The stored code field value.
*/
uint8_t code() const {
return _header.code;
}
/**
* \brief Getter for the session_id field.
* \return The stored session_id field value.
*/
uint16_t session_id() const {
return Endian::be_to_host(_header.session_id);
}
/**
* \brief Getter for the payload_length field.
* \return The stored payload_length field value.
*/
uint16_t payload_length() const {
return Endian::be_to_host(_header.payload_length);
}
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Returns the list of tags.
*/
const tags_type &tags() const {
return _tags;
}
/**
* \sa PDU::clone
*/
PPPoE *clone() const {
return new PPPoE(*this);
}
const tag *search_tag(TagTypes identifier) const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
// Setters
/**
* \brief Setter for the version field.
* \param new_version The new version field value.
*/
void version(small_uint<4> new_version);
/**
* \brief Setter for the type field.
* \param new_type The new type field value.
*/
void type(small_uint<4> new_type);
/**
* \brief Setter for the code field.
* \param new_code The new code field value.
*/
void code(uint8_t new_code);
/**
* \brief Setter for the session_id field.
* \param new_session_id The new session_id field value.
*/
void session_id(uint16_t new_session_id);
/**
* \brief Setter for the payload_length field.
* \param new_payload_length The new payload_length field value.
*/
void payload_length(uint16_t new_payload_length);
/**
* \brief Adds a PPPoE tag.
*
* \param option The option to be added.
*/
void add_tag(const tag &option);
#if TINS_IS_CXX11
/**
* \brief Adds a PPPoE tag.
*
* This move-constructs the option.
*
* \param option The option to be added.
*/
void add_tag(tag &&option) {
_tags_size += option.data_size() + sizeof(uint16_t) * 2;
_tags.push_back(std::move(option));
}
#endif
// Option setters
/**
* \brief Adds an end-of-list tag.
*/
void end_of_list();
/**
* \brief Adds a service-name tag.
*
* \param value The service name.
*/
void service_name(const std::string &value);
/**
* \brief Adds a AC-name tag.
*
* \param value The AC name.
*/
void ac_name(const std::string &value);
/**
* \brief Adds a host-uniq tag.
*
* \param value The tag's value.
*/
void host_uniq(const byte_array &value);
/**
* \brief Adds a AC-Cookie tag.
*
* \param value The tag's value.
*/
void ac_cookie(const byte_array &value);
/**
* \brief Adds a Vendor-Specific tag.
*
* \param value The tag's value.
*/
void vendor_specific(const vendor_spec_type &value);
/**
* \brief Adds a Relay-Session-Id tag.
*
* \param value The tag's value.
*/
void relay_session_id(const byte_array &value);
/**
* \brief Adds a Service-Name-Error tag.
*
* \param value The tag's value.
*/
void service_name_error(const std::string &value);
/**
* \brief Adds a AC-System-Error tag.
*
* \param value The tag's value.
*/
void ac_system_error(const std::string &value);
/**
* \brief Adds a Generic-Error tag.
*
* \param value The tag's value.
*/
void generic_error(const std::string &value);
// Option getters
/**
* \brief Getter for the service-name tag.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
std::string service_name() const;
/**
* \brief Getter for the AC-name tag.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
std::string ac_name() const;
/**
* \brief Getter for the host-uniq tag.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
byte_array host_uniq() const;
/**
* \brief Getter for the AC-Cookie tag.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
byte_array ac_cookie() const;
/**
* \brief Getter for the Vendor-Specific tag.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
vendor_spec_type vendor_specific() const;
/**
* \brief Getter for the Vendor-Specific tag.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
byte_array relay_session_id() const;
/**
* \brief Getter for the Service-Name-Error tag.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
std::string service_name_error() const;
/**
* \brief Getter for the AC-System-Error tag.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
std::string ac_system_error() const;
/**
* \brief Getter for the Generic-Error tag.
*
* This method will throw an option_not_found exception if the
* option is not found.
*/
std::string generic_error() const;
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *);
template<typename T>
void add_tag_iterable(TagTypes id, const T &data) {
add_tag(
tag(
id,
data.begin(),
data.end()
)
);
}
template<typename T>
T search_and_convert(TagTypes id) const {
const tag *t = search_tag(id);
if(!t)
throw option_not_found();
return t->to<T>();
}
TINS_BEGIN_PACK
struct pppoe_hdr {
#if TINS_IS_LITTLE_ENDIAN
uint8_t version:4,
type:4;
uint8_t code;
#else
uint16_t version:4,
type:4,
code:8;
#endif
uint16_t session_id;
uint16_t payload_length;
} TINS_END_PACK;
pppoe_hdr _header;
tags_type _tags;
uint16_t _tags_size;
};
}
#endif // TINS_PPPoE_H

433
include/tins/radiotap.h Normal file
View File

@@ -0,0 +1,433 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "config.h"
#if !defined(TINS_RADIOTAP_H) && defined(HAVE_DOT11)
#define TINS_RADIOTAP_H
#include "macros.h"
#include "pdu.h"
#include "endianness.h"
namespace Tins {
class PacketSender;
/**
* \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:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::RADIOTAP;
/**
* \brief Enumeration of the different channel type flags.
*
* These channel type flags can be OR'd and set using the
* RadioTap::channel() method.
*/
enum ChannelType {
TURBO = 0x10,
CCK = 0x20,
OFDM = 0x40,
TWO_GZ = 0x80,
FIVE_GZ = 0x100,
PASSIVE = 0x200,
DYN_CCK_OFDM = 0x400,
GFSK = 0x800
};
/**
* \brief Flags used in the present field.
*
* \sa RadioTap::present()
*/
enum PresentFlags {
TSTF = 1,
FLAGS = 2,
RATE = 4,
CHANNEL = 8,
FHSS = 16,
DBM_SIGNAL = 32,
DBM_NOISE = 64,
LOCK_QUALITY = 128,
TX_ATTENUATION = 256,
DB_TX_ATTENUATION = 512,
DBM_TX_ATTENUATION = 1024,
ANTENNA = 2048,
DB_SIGNAL = 4096,
DB_NOISE = 8192,
RX_FLAGS = 16382,
CHANNEL_PLUS = 262144
};
/**
* \brief Flags used in the RadioTap::flags() method.
*/
enum FrameFlags {
CFP = 1,
PREAMBLE = 2,
WEP = 4,
FRAGMENTATION = 8,
FCS = 16,
PADDING = 32,
FAILED_FCS = 64,
SHORT_GI = 128
};
/**
* \brief Default constructor.
*/
RadioTap();
/**
* \brief Constructs a RadioTap object from a buffer and adds all
* identifiable PDUs found in the buffer as children of this one.
*
* If there is not enough size for a RadioTap header, a
* malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
RadioTap(const uint8_t *buffer, uint32_t total_sz);
/* Setters */
#ifndef WIN32
/**
* \sa PDU::send()
*/
void send(PacketSender &sender, const NetworkInterface &iface);
#endif
/**
* \brief Setter for the version field.
* \param new_version The new version.
*/
void version(uint8_t new_version);
/**
* \brief Setter for the padding field.
* \param new_padding The new padding.
*/
void padding(uint8_t new_padding);
/**
* \brief Setter for the length field.
* \param new_length The new length.
*/
void length(uint16_t new_length);
/**
* \brief Setter for the TSFT field.
* \param new_tsft The new TSFT
*/
void tsft(uint64_t new_tsft);
/**
* \brief Setter for the flags field.
* \param new_flags The new flags.
*/
void flags(FrameFlags new_flags);
/**
* \brief Setter for the rate field.
* \param new_rate The new rate.
*/
void rate(uint8_t new_rate);
/**
* \brief Setter for the channel frequency and type field.
* \param new_freq The new channel frequency.
* \param new_type The new channel type.
*/
void channel(uint16_t new_freq, uint16_t new_type);
/**
* \brief Setter for the dbm signal field.
* \param new_dbm_signal The new dbm signal.
*/
void dbm_signal(uint8_t new_dbm_signal);
/**
* \brief Setter for the dbm noise field.
* \param new_dbm_noise The new dbm noise.
*/
void dbm_noise(uint8_t new_dbm_noise);
/**
* \brief Setter for the signal quality field.
* \param new_antenna The signal quality signal.
*/
void signal_quality(uint8_t new_signal_quality);
/**
* \brief Setter for the antenna field.
* \param new_antenna The antenna signal.
*/
void antenna(uint8_t new_antenna);
/**
* \brief Setter for the db signal field.
* \param new_antenna The db signal signal.
*/
void db_signal(uint8_t new_db_signal);
/**
* \brief Setter for the rx flag field.
* \param new_rx_flag The antenna signal.
*/
void rx_flags(uint16_t new_rx_flag);
/* Getters */
/**
* \brief Getter for the version field.
* \return The version field.
*/
uint8_t version() const { return _radio.it_version; }
/**
* \brief Getter for the padding field.
* \return The padding field.
*/
uint8_t padding() const { return _radio.it_pad; }
/**
* \brief Getter for the length field.
* \return The length field.
*/
uint16_t length() const { return Endian::le_to_host(_radio.it_len); }
/**
* \brief Getter for the tsft field.
* \return The tsft field.
*/
uint64_t tsft() const { return Endian::le_to_host(_tsft); }
/**
* \brief Getter for the flags field.
* \return The flags field.
*/
FrameFlags flags() const { return (FrameFlags)_flags; }
/**
* \brief Getter for the rate field.
* \return The rate field.
*/
uint8_t rate() const { return _rate; }
/**
* \brief Getter for the channel frequency field.
* \return The channel frequency field.
*/
uint16_t channel_freq() const { return Endian::le_to_host(_channel_freq); }
/**
* \brief Getter for the channel type field.
* \return The channel type field.
*/
uint16_t channel_type() const { return Endian::le_to_host(_channel_type); }
/**
* \brief Getter for the dbm signal field.
* \return The dbm signal field.
*/
uint8_t dbm_signal() const { return _dbm_signal; }
/**
* \brief Getter for the dbm noise field.
* \return The dbm noise field.
*/
uint8_t dbm_noise() const { return _dbm_noise; }
/**
* \brief Getter for the signal quality field.
* \return The signal quality field.
*/
uint16_t signal_quality() const { return _signal_quality; }
/**
* \brief Getter for the antenna field.
* \return The antenna field.
*/
uint8_t antenna() const { return _antenna; }
/**
* \brief Getter for the db signal field.
* \return The db signal field.
*/
uint8_t db_signal() const { return _db_signal; }
/**
* \brief Getter for the channel+ field.
* \return The channel+ field.
*/
uint32_t channel_plus() const { return Endian::le_to_host<uint32_t>(_channel_type); }
/**
* \brief Getter for the rx flags field.
* \return The rx flags field.
*/
uint16_t rx_flags() const { return Endian::le_to_host(_rx_flags); }
/**
* \brief Getter for the present bit fields.
*
* Use this method and masks created from the values taken from
* the PresentFlags enum to find out which fields are set.
* Accessing non-initialized fields, the behaviour is undefined
* will be undefined. It is only safe to use the getter of a field
* if its corresponding bit flag is set in the present field.
*/
PresentFlags present() const {
//return (PresentFlags)*(uint32_t*)(&_radio.it_len + 1);
return (PresentFlags)Endian::le_to_host(_radio.flags_32);
}
/** \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Returns the RadioTap frame's header length.
*
* \return An uint32_t with the header's size.
* \sa PDU::header_size()
*/
uint32_t header_size() const;
/**
* \brief Returns the frame's trailer size.
* \return The trailer's size.
*/
uint32_t trailer_size() const;
/**
* \sa PDU::clone
*/
RadioTap *clone() const {
return new RadioTap(*this);
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::RADIOTAP; }
private:
TINS_BEGIN_PACK
struct radiotap_hdr {
#if TINS_IS_LITTLE_ENDIAN
uint8_t it_version;
uint8_t it_pad;
uint16_t it_len;
union {
struct {
uint32_t tsft:1,
flags:1,
rate:1,
channel:1,
fhss:1,
dbm_signal:1,
dbm_noise:1,
lock_quality:1,
tx_attenuation:1,
db_tx_attenuation:1,
dbm_tx_attenuation:1,
antenna:1,
db_signal:1,
db_noise:1,
rx_flags:1,
reserved1:3,
channel_plus:1,
reserved2:12,
ext:1;
} flags;
uint32_t flags_32;
};
#else
uint8_t it_pad;
uint8_t it_version;
uint16_t it_len;
union {
struct {
uint32_t lock_quality:1,
dbm_noise:1,
dbm_signal:1,
fhss:1,
channel:1,
rate:1,
flags:1,
tsft:1,
reserved3:1,
rx_flags:1,
db_tx_attenuation:1,
dbm_tx_attenuation:1,
antenna:1,
db_signal:1,
db_noise:1,
tx_attenuation:1,
reserved2:5,
channel_plus:1,
reserved1:2,
reserved4:7,
ext:1;
} flags;
uint32_t flags_32;
};
#endif
} TINS_END_PACK;
void init();
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
radiotap_hdr _radio;
// present fields...
uint64_t _tsft;
uint16_t _channel_type, _channel_freq, _rx_flags, _signal_quality;
uint8_t _antenna, _flags, _rate, _dbm_signal, _dbm_noise, _channel, _max_power, _db_signal;
};
}
#endif // TINS_RADIOTAP_H

204
include/tins/rawpdu.h Normal file
View File

@@ -0,0 +1,204 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_RAWPDU_H
#define TINS_RAWPDU_H
#include <vector>
#include <string>
#include "pdu.h"
#include "cxxstd.h"
namespace Tins {
/**
* \class PDU
* \brief Represents a PDU which holds raw data.
*
* This class is a wrapper over a byte array. It can be used to hold
* the payload sent over transport layer protocols (such as TCP or UDP).
*
* While sniffing, this class is the one that will hold transport layer
* protocols' payload. You can simply convert a RawPDU into a specific
* application layer protocol using the RawPDU::to method:
*
* \code
* // Get a RawPDU from somewhere
* RawPDU raw = get_raw_pdu();
*
* // Parse it as a DHCP PDU.
* DHCP dhcp = raw.to<DHCP>();
*
* // Or parse it as DNS. Of course this will fail if the contents
* // don't look like DNS
* DNS dns = raw.to<DNS>();
* \endcode
*/
class RawPDU : public PDU {
public:
/**
* The type used to store the payload.
*/
typedef std::vector<uint8_t> payload_type;
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::RAW;
/**
* \brief Creates an instance of RawPDU.
*
* The payload is copied, therefore the original payload's memory
* must be freed by the user.
* \param pload The payload which the RawPDU will contain.
* \param size The size of the payload.
*/
RawPDU(const uint8_t *pload, uint32_t size);
/**
* \brief Constructs a RawPDU from an iterator range.
*
* The data in the iterator range is copied into the RawPDU
* internal buffer.
*
* \param start The beginning of the iterator range.
* \param end The end of the iterator range.
*/
template<typename ForwardIterator>
RawPDU(ForwardIterator start, ForwardIterator end)
: _payload(start, end) { }
#if TINS_IS_CXX11
/**
* \brief Creates an instance of RawPDU from a payload_type.
*
* The payload is moved into the RawPDU's internal buffer.
*
* \param data The payload to use.
*/
RawPDU(payload_type&& data)
: _payload(move(data)) { }
#endif // TINS_IS_CXX11
/**
* \brief Creates an instance of RawPDU from an input string.
*
* \param data The content of the payload.
*/
RawPDU(const std::string &data);
/**
* \brief Setter for the payload field
* \param pload The payload to be set.
*/
void payload(const payload_type &pload);
/**
* \brief Setter for the payload field
* \param start The start of the new payload.
* \param end The end of the new payload.
*/
template<typename ForwardIterator>
void payload(ForwardIterator start, ForwardIterator end) {
_payload.assign(start, end);
}
/**
* \brief Const getter for the payload.
* \return The RawPDU's payload.
*/
const payload_type &payload() const { return _payload; }
/**
* \brief Non-const getter for the payload.
* \return The RawPDU's payload.
*/
payload_type &payload() { return _payload; }
/**
* \brief Returns the header size.
*
* This returns the same as RawPDU::payload_size().
*
* This metod overrides PDU::header_size. \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Returns the payload size.
*
* \return uint32_t containing the payload size.
*/
uint32_t payload_size() const {
return _payload.size();
}
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* This always returns true, since we don't know what this
* RawPDU is holding.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::RAW; }
/**
* \brief Constructs the given PDU type from the raw data stored
* in this RawPDU.
*/
template<typename T>
T to() const {
return T(&_payload[0], _payload.size());
}
/**
* \sa PDU::clone
*/
RawPDU *clone() const {
return new RawPDU(*this);
}
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
payload_type _payload;
};
}
#endif // TINS_RAWPDU_H

View File

@@ -0,0 +1,196 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "config.h"
#if !defined(TINS_RSN_INFORMATION) && defined(HAVE_DOT11)
#define TINS_RSN_INFORMATION
#include <stdint.h>
#include <vector>
#include "endianness.h"
namespace Tins{
class Dot11;
template<typename T, typename U>
class PDUOption;
/**
* \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
};
/**
* The type used to store the cypher suites.
*/
typedef std::vector<CypherSuites> cyphers_type;
/**
* The type used to store the AKM suites.
*/
typedef std::vector<AKMSuites> akm_type;
/**
* The type returned on serialization.
*/
typedef std::vector<uint8_t> serialization_type;
/**
* \brief Constructs an RSNInformation object.
*
* By default, the version is set to 1.
*/
RSNInformation();
/**
* \brief Constructs an RSNInformation object from a
* serialization_type object.
*
* \param buffer The buffer from which to construct this object.
*/
RSNInformation(const serialization_type &buffer);
/**
* \brief Constructs a RSNInformation from a buffer.
*
* If the input is malformed, a malformed_packet exception is
* thrown.
*
* \param buffer The buffer from which this object will be constructed.
* \param total_sz The total size of the buffer.
*/
RSNInformation(const uint8_t *buffer, uint32_t total_sz);
/**
* \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 an 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.
*/
CypherSuites group_suite() const { return _group_suite; }
/**
* \brief Getter for the version field.
* \return The version field.
*/
uint16_t version() const { return Endian::le_to_host(_version); }
/**
* \brief Getter for the capabilities field.
* \return The version field.
*/
uint16_t capabilities() const { return Endian::le_to_host(_capabilities); }
/**
* \brief Getter for the pairwise cypher suite list.
* \return A list of pairwise cypher suites.
*/
const cyphers_type &pairwise_cyphers() const { return _pairwise_cyphers; }
/**
* \brief Getter for the akm suite list.
* \return A list of akm suites.
*/
const akm_type &akm_cyphers() const { return _akm_cyphers; }
/**
* \brief Serializes this object.
* \return The result of the serialization.
*/
serialization_type serialize() const;
/**
* Constructs an RSNInformation object from a Dot11 tagged option.
*/
static RSNInformation from_option(const PDUOption<uint8_t, Dot11> &opt);
private:
void init(const uint8_t *buffer, uint32_t total_sz);
uint16_t _version, _capabilities;
CypherSuites _group_suite;
akm_type _akm_cyphers;
cyphers_type _pairwise_cyphers;
};
} // namespace Tins
#endif // TINS_RSN_INFORMATION

181
include/tins/sll.h Normal file
View File

@@ -0,0 +1,181 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_SLL_H
#define TINS_SLL_H
#include <vector>
#include "pdu.h"
#include "endianness.h"
#include "hw_address.h"
namespace Tins {
/**
* \class SLL
* \brief Represents a Linux cooked-mode capture (SLL) PDU.
*/
class SLL : public PDU {
public:
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::SLL;
/**
* The type of the address type
*/
typedef HWAddress<8> address_type;
/**
* Default constructor
*/
SLL();
/**
* \brief Constructs a SLL object from a buffer and adds all
* identifiable PDUs found in the buffer as children of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for a SLL header in the
* buffer, a malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
SLL(const uint8_t *buffer, uint32_t total_sz);
// Getters
/**
* \brief Getter for the Packet Type field.
* \return The stored Packet Type field value.
*/
uint16_t packet_type() const {
return Endian::be_to_host(_header.packet_type);
}
/**
* \brief Getter for the LLADDR Type field.
* \return The stored LLADDR Type field value.
*/
uint16_t lladdr_type() const {
return Endian::be_to_host(_header.lladdr_type);
}
/**
* \brief Getter for the LLADDR Length field.
* \return The stored LLADDR Length field value.
*/
uint16_t lladdr_len() const {
return Endian::be_to_host(_header.lladdr_len);
}
/**
* \brief Getter for the Address field.
* \return The stored Address field value.
*/
address_type address() const {
return _header.address;
}
/**
* \brief Getter for the Protocol field.
* \return The stored Protocol field value.
*/
uint16_t protocol() const {
return Endian::be_to_host(_header.protocol);
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
// Setters
/**
* \brief Setter for the Packet Type field.
* \param new_packet_type The new Packet Type field value.
*/
void packet_type(uint16_t new_packet_type);
/**
* \brief Setter for the LLADDR Type field.
* \param new_lladdr_type The new LLADDR Type field value.
*/
void lladdr_type(uint16_t new_lladdr_type);
/**
* \brief Setter for the LLADDR Length field.
* \param new_lladdr_len The new LLADDR Length field value.
*/
void lladdr_len(uint16_t new_lladdr_len);
/**
* \brief Setter for the Address field.
* \param new_address The new Address field value.
*/
void address(const address_type &new_address);
/**
* \brief Setter for the Protocol field.
* \param new_protocol The new Protocol field value.
*/
void protocol(uint16_t new_protocol);
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \sa PDU::clone
*/
SLL *clone() const {
return new SLL(*this);
}
private:
TINS_BEGIN_PACK
struct sllhdr {
uint16_t packet_type, lladdr_type, lladdr_len;
uint8_t address[8];
uint16_t protocol;
} TINS_END_PACK;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *);
sllhdr _header;
};
}
#endif // TINS_SLL_H

131
include/tins/small_uint.h Normal file
View File

@@ -0,0 +1,131 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_SMALL_UINT_H
#define TINS_SMALL_UINT_H
#include <stdint.h>
#include <stdexcept>
namespace Tins {
class value_too_large : public std::exception {
public:
const char *what() const throw() {
return "Value is too large";
}
};
/**
* \class small_uint
* \brief Represents a field of <i>n</i> bits.
*
* This finds the best integral type of at least <i>n</i> bits and
* uses it to store the wrapped value.
*/
template<size_t n>
class small_uint {
private:
template<bool cond, typename OnTrue, typename OnFalse>
struct if_then_else {
typedef OnTrue type;
};
template<typename OnTrue, typename OnFalse>
struct if_then_else<false, OnTrue, OnFalse> {
typedef OnFalse type;
};
template<size_t i>
struct best_type {
typedef typename if_then_else<
(i <= 8),
uint8_t,
typename if_then_else<
(i <= 16),
uint16_t,
typename if_then_else<
(i <= 32),
uint32_t,
uint64_t
>::type
>::type
>::type type;
};
template<uint64_t base, uint64_t pow>
struct power {
static const uint64_t value = base * power<base, pow - 1>::value;
};
template<uint64_t base>
struct power<base, 0> {
static const uint64_t value = 1;
};
public:
/**
* The type used to store the value.
*/
typedef typename best_type<n>::type repr_type;
/**
* The maximum value this class can hold.
*/
static const repr_type max_value = power<2, n>::value - 1;
/**
* Value initializes the value.
*/
small_uint() : value() {}
/**
* \brief Copy constructs the stored value.
*
* This throws a value_too_large exception if the value provided
* is larger than max_value.
*
* \param val The parameter from which to copy construct.
*/
small_uint(repr_type val) {
if(val > max_value)
throw value_too_large();
value = val;
}
/**
* User defined conversion to repr_type.
*/
operator repr_type() const {
return value;
}
private:
repr_type value;
};
} // namespace Tins
#endif // TINS_SMALL_UINT_H

178
include/tins/snap.h Normal file
View File

@@ -0,0 +1,178 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_SNAP_H
#define TINS_SNAP_H
#include <stdint.h>
#include "pdu.h"
#include "macros.h"
#include "endianness.h"
#include "small_uint.h"
namespace Tins {
/**
* \class SNAP
* \brief Represents a SNAP frame.
*
* Note that this PDU contains the 802.3 LLC structure + SNAP frame.
* So far only unnumbered information structure is supported.
*/
class SNAP : public PDU {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::SNAP;
/**
* \brief Creates an instance of SNAP
* This constructor sets the dsap and ssap fields to 0xaa, and
* the id field to 3.
*/
SNAP();
/**
* \brief Constructs a SNAP object from a buffer and adds all
* identifiable PDUs found in the buffer as children of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for a SNAP header in the
* buffer, a malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
SNAP(const uint8_t *buffer, uint32_t total_sz);
/* Setters */
/**
* \brief Setter for the Control field.
* \param new_id The new Control to be set.
*/
void control(uint8_t new_control);
/**
* \brief Setter for the Organization Code field.
* \param new_org The new Organization Code to be set.
*/
void org_code(small_uint<24> new_org);
/**
* \brief Setter for the Ethernet Type field.
* \param new_eth The new Ethernet Type to be set.
*/
void eth_type(uint16_t new_eth);
/* Getters */
/**
* \brief Getter for the DSAP field.
* \return The DSAP field.
*/
uint8_t dsap() const { return _snap.dsap; }
/**
* \brief Getter for the SSAP field.
* \return The SSAP field.
*/
uint8_t ssap() const { return _snap.ssap; }
/**
* \brief Getter for the Control field.
* \return The Control field.
*/
uint8_t control() const {
#if TINS_IS_LITTLE_ENDIAN
return (_snap.control_org) & 0xff;
#else
return (_snap.control_org >> 24) & 0xff;
#endif
}
/**
* \brief Getter for the Organization Code field.
* \return The Organization Code field.
*/
small_uint<24> org_code() const {
#if TINS_IS_LITTLE_ENDIAN
return Endian::be_to_host<uint32_t>(_snap.control_org & 0xffffff00);
#else
return _snap.control_org & 0xffffff;
#endif
}
/**
* \brief Getter for the Ethernet Type field.
* \return The Ethernet Type field.
*/
uint16_t eth_type() const { return Endian::be_to_host(_snap.eth_type); }
/**
* \brief Returns the SNAP frame's header length.
*
* \return 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_flag; }
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
SNAP *clone() const {
return new SNAP(*this);
}
private:
TINS_BEGIN_PACK
struct snaphdr {
uint8_t dsap;
uint8_t ssap;
uint32_t control_org;
uint16_t eth_type;
} TINS_END_PACK;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
snaphdr _snap;
};
}
#endif // TINS_SNAP_H

592
include/tins/sniffer.h Normal file
View File

@@ -0,0 +1,592 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_SNIFFER_H
#define TINS_SNIFFER_H
#include <pcap.h>
#include <string>
#include <memory>
#include <stdexcept>
#include <iterator>
#include "pdu.h"
#include "packet.h"
#include "cxxstd.h"
#include "exceptions.h"
#include "internals.h"
namespace Tins {
class SnifferIterator;
class SnifferConfiguration;
/**
* \class BaseSniffer
* \brief Base class for sniffers.
*
* This class implements the basic sniffing operations. Subclasses
* should only initialize this object using a pcap_t pointer, which
* will be used to extract packets.
*
* Initialization must be done using the BaseSniffer::init method.
*/
class BaseSniffer {
public:
/**
* The iterator type.
*/
typedef SnifferIterator iterator;
#if TINS_IS_CXX11
/**
* \brief Move constructor.
* This constructor is available only in C++11.
*/
BaseSniffer(BaseSniffer &&rhs) TINS_NOEXCEPT
: handle(nullptr), mask()
{
*this = std::move(rhs);
}
/**
* \brief Move assignment operator.
* This operator is available only in C++11.
*/
BaseSniffer& operator=(BaseSniffer &&rhs) TINS_NOEXCEPT
{
using std::swap;
swap(handle, rhs.handle);
swap(mask, rhs.mask);
return *this;
}
#endif
/**
* \brief Sniffer destructor.
* This frees all memory used by the pcap handle.
*/
virtual ~BaseSniffer();
/**
* \brief Compiles a filter and uses it to capture one packet.
*
* This method returns the first valid sniffed packet that matches the
* sniffer's filter, or the first sniffed packet if no filter has
* been set.
*
* The return type is a thin wrapper over a PDU* and a Timestamp
* object. This wrapper can be both implicitly converted to a
* PDU* and a Packet object. So doing this:
*
* \code
* Sniffer s(...);
* std::unique_ptr<PDU> pdu(s.next_packet());
* // Packet takes care of the PDU*.
* Packet packet(s.next_packet());
* \endcode
*
* Is fine, but this:
*
* \code
* // bad!!
* PtrPacket p = s.next_packet();
* \endcode
*
* Is not, since PtrPacket can't be copy constructed.
*
* \sa Packet::release_pdu
*
* \return A captured packet. If an error occured, PtrPacket::pdu
* will return 0. Caller takes ownership of the PDU pointer stored in
* the PtrPacket.
*/
PtrPacket next_packet();
/**
* \brief Starts a sniffing loop, using a callback functor for every
* sniffed packet.
*
* The functor must implement an operator with one of the
* following signatures:
*
* \code
* bool(PDU&);
* bool(const PDU&);
* \endcode
*
* This functor will be called using the each of the sniffed packets
* as its argument. Using PDU member functions that modify the PDU,
* such as PDU::release_inner_pdu, is perfectly valid.
*
* Note that if you're using a functor object, it will be copied using
* its copy constructor, so it should be some kind of proxy to
* another object which will process the packets(e.g. std::bind).
*
* Sniffing will stop when either max_packets are sniffed(if it is != 0),
* or when the functor returns false.
*
* This method catches both malformed_packet and pdu_not_found exceptions,
* which allows writing much cleaner code, since you can call PDU::rfind_pdu
* without worrying about catching the exception that can be thrown. This
* allows writing code such as the following:
*
* \code
* bool callback(const PDU& pdu) {
* // If either RawPDU is not found, or construction of the DNS
* // object fails, the BaseSniffer object will trap the exceptions,
* // so we don't need to worry about it.
* DNS dns = pdu.rfind_pdu<RawPDU>().to<DNS>();
* return true;
* }
* \endcode
*
* \param function The callback handler object which should process packets.
* \param max_packets The maximum amount of packets to sniff. 0 == infinite.
*/
template<class Functor>
void sniff_loop(Functor function, uint32_t max_packets = 0);
/**
* \brief Sets a filter on this sniffer.
* \param filter The filter to be set.
* \return True iif it was possible to apply the filter.
*/
bool set_filter(const std::string &filter);
/**
* \brief Stops sniffing loops.
*
* This method must be called from the same thread from which
* BaseSniffer::sniff_loop was called.
*/
void stop_sniff();
/**
* \brief Gets the file descriptor associated with the sniffer.
*/
int get_fd();
/**
* \brief Sets the read timeout for this sniffer.
*
* This calls pcap_set_timeout using the provided parameter.
* \param ms The amount of milliseconds.
*/
void set_timeout(int ms);
/**
* \brief Sets whether to extract RawPDUs or fully parsed packets.
*
* By default, packets will be parsed starting from link layer.
* However, if you're parsing a lot of traffic, then you might
* want to extract packets and push them into a queue,
* so a consumer can parse them when they're popped.
*
* This method allows doing that. If the parameter is true,
* then packets taken from this BaseSniffer will only contain
* a RawPDU which will have to entire contents of the packet.
*
* \param value Whether to extract RawPDUs or not.
*/
void set_extract_raw_pdus(bool value);
/**
* \brief Retrieves this sniffer's link type.
*
* This calls pcap_datalink on the stored pcap handle and
* returns its result.
*/
int link_type() const;
/**
* Retrieves an iterator to the next packet in this sniffer.
*/
iterator begin();
/**
* Retrieves an end iterator.
*/
iterator end();
/**
* Retrieves the pcap handle used by this sniffer.
*/
pcap_t* get_pcap_handle();
/**
* Retrieves the pcap handle used by this sniffer.
*/
const pcap_t* get_pcap_handle() const;
protected:
/**
* Default constructor.
*/
BaseSniffer();
void set_pcap_handle(pcap_t* const pcap_handle);
void set_if_mask(bpf_u_int32 if_mask);
bpf_u_int32 get_if_mask() const;
private:
BaseSniffer(const BaseSniffer&);
BaseSniffer &operator=(const BaseSniffer&);
pcap_t *handle;
bpf_u_int32 mask;
bool extract_raw;
};
/**
* \class Sniffer
* \brief Sniffs packets from a network interface.
*/
class Sniffer : public BaseSniffer {
public:
/**
* \deprecated This enum is no longer necessary. You should use the
* Sniffer(const std::string&, const SnifferConfiguration&) constructor.
*/
enum promisc_type {
NON_PROMISC,
PROMISC
};
/**
* \brief Constructs an instance of Sniffer using the provided configuration.
*
* This constructor was added as a way to improve the parameter bloat
* introduced by the other ones available. You should create an instance
* of SnifferConfiguration, set the desired parameters, and then use it
* when constructing a Sniffer object.
*
* \sa SnifferConfiguration
*
* \param device The device which will be sniffed.
* \param configuration The configuration object to use to setup the sniffer.
*/
Sniffer(const std::string &device, const SnifferConfiguration& configuration);
/**
* \brief Constructs an instance of Sniffer.
*
* By default the interface won't be put into promiscuous mode, and won't
* be put into monitor mode.
*
* \deprecated Use the Sniffer(const std::string&, const SnifferConfiguration&)
* constructor.
* \param device The device which will be sniffed.
* \param max_packet_size The maximum packet size to be read.
* \param promisc bool indicating wether to put the interface in promiscuous mode.(optional)
* \param filter A capture filter to be used on the sniffing session.(optional);
* \param rfmon Indicates if the interface should be put in monitor mode.(optional);
*/
Sniffer(const std::string &device, unsigned max_packet_size,
bool promisc = false, const std::string &filter = "", bool rfmon = false);
/**
* \brief Constructs an instance of Sniffer.
*
* The maximum capture size is set to 65535. By default the interface won't
* be put into promiscuous mode, and won't be put into monitor mode.
*
* \deprecated Use the Sniffer(const std::string&, const SnifferConfiguration&)
* constructor.
* \param device The device which will be sniffed.
* \param promisc Indicates if the interface should be put in promiscuous mode.
* \param filter A capture filter to be used on the sniffing session.(optional);
* \param rfmon Indicates if the interface should be put in monitor mode.(optional);
*/
Sniffer(const std::string &device, promisc_type promisc = NON_PROMISC,
const std::string &filter = "", bool rfmon = false);
private:
friend class SnifferConfiguration;
void set_snap_len(unsigned snap_len);
void set_buffer_size(unsigned buffer_size);
void set_promisc_mode(bool promisc_enabled);
void set_rfmon(bool rfmon_enabled);
};
/**
* \class FileSniffer
* \brief Reads pcap files and interprets the packets in it.
*
* This class acts exactly in the same way that Sniffer, but reads
* packets from a pcap file instead of an interface.
*/
class FileSniffer : public BaseSniffer {
public:
/**
* \brief Constructs an instance of FileSniffer.
* \param file_name The pcap file which will be parsed.
* \param filter A capture filter to be used on the file.(optional);
*/
FileSniffer(const std::string &file_name, const SnifferConfiguration& configuration);
/**
* \deprecated Use the constructor that takes a SnifferConfiguration instead.
*
* \brief Constructs an instance of FileSniffer.
* \param file_name The pcap file which will be parsed.
* \param filter A capture filter to be used on the file.(optional);
*/
FileSniffer(const std::string &file_name, const std::string &filter = "");
};
template<class T>
class HandlerProxy {
public:
typedef T* ptr_type;
typedef bool (T::*fun_type)(PDU&) ;
HandlerProxy(ptr_type ptr, fun_type function)
: object(ptr), fun(function) {}
bool operator()(PDU &pdu) {
return (object->*fun)(pdu);
}
private:
ptr_type object;
fun_type fun;
};
template<class T>
HandlerProxy<T> make_sniffer_handler(T *ptr, typename HandlerProxy<T>::fun_type function)
{
return HandlerProxy<T>(ptr, function);
}
/**
* \brief Iterates over packets sniffed by a BaseSniffer.
*/
class SnifferIterator : public std::iterator<std::forward_iterator_tag, PDU> {
public:
/**
* Constructs a SnifferIterator.
* \param sniffer The sniffer to iterate.
*/
SnifferIterator(BaseSniffer *sniffer = 0)
: sniffer(sniffer)
{
if(sniffer)
advance();
}
/**
* Advances the iterator.
*/
SnifferIterator& operator++() {
advance();
return *this;
}
/**
* Advances the iterator.
*/
SnifferIterator operator++(int) {
SnifferIterator other(*this);
advance();
return other;
}
/**
* Dereferences the iterator.
* \return reference to the current packet.
*/
PDU &operator*() {
return *pkt.pdu();
}
/**
* Dereferences the iterator.
* \return pointer to the current packet.
*/
PDU *operator->() {
return &(**this);
}
/**
* Compares this iterator for equality.
* \param rhs The iterator to be compared to.
*/
bool operator==(const SnifferIterator &rhs) const {
return sniffer == rhs.sniffer;
}
/**
* Compares this iterator for in-equality.
* \param rhs The iterator to be compared to.
*/
bool operator!=(const SnifferIterator &rhs) const {
return !(*this == rhs);
}
private:
void advance() {
pkt = sniffer->next_packet();
if(!pkt)
sniffer = 0;
}
BaseSniffer *sniffer;
Packet pkt;
};
/**
* \class SnifferConfiguration
* \brief Represents the configuration of a BaseSniffer object.
*
* This class can be used as an easy way to configure a Sniffer
* or FileSniffer object.
*
* It can be used by constructing an object of this type,
* setting the desired values and then passing it to the
* Sniffer or FileSniffer object's constructor. This sets
* default values for some attributes:
*
* - Snapshot length: 65535 bytes (64 KB).
* - Timeout: 1000 milliseconds.
* - Promiscuous mode: false.
*
* For any of the attributes not listed above, the associated
* pcap function which is used to set them on a pcap handle
* won't be called at all.
*
* This class can be used to configure a Sniffer object,
* like this:
*
* \code
* // Initialize the configuration.
* SnifferConfiguration config;
* config.set_filter("ip and port 80");
* config.set_promisc_mode(true);
*
* // Use it on a Sniffer object.
* Sniffer sniffer("eth0", config);
* \endcode
*/
class SnifferConfiguration {
public:
/**
* \brief The default snapshot length.
*
* This is 65535 by default.
*/
static const unsigned DEFAULT_SNAP_LEN;
/**
* \brief The default timeout.
*
* This is 1000 by default.
*/
static const unsigned DEFAULT_TIMEOUT;
/**
* Default constructs a SnifferConfiguration.
*/
SnifferConfiguration();
/**
* Sets the snapshot length option.
* \param snap_len The snapshot length to be set.
*/
void set_snap_len(unsigned snap_len);
/**
* Sets the buffer size option.
* \param buffer_size The buffer size to be set.
*/
void set_buffer_size(unsigned buffer_size);
/**
* Sets the promiscuous mode option.
* \param enabled The promiscuous mode value.
*/
void set_promisc_mode(bool enabled);
/**
* Sets a pcap filter to use on the sniffer.
* \param filter The pcap filter to be used.
*/
void set_filter(const std::string& filter);
/**
* Sets the rfmon option.
* \param enabled The rfmon option value.
*/
void set_rfmon(bool enabled);
/**
* Sets the timeout option.
* \param timeout The timeout to be set.
*/
void set_timeout(unsigned timeout);
protected:
friend class Sniffer;
friend class FileSniffer;
void configure_sniffer_pre_activation(Sniffer& sniffer) const;
void configure_sniffer_pre_activation(FileSniffer& sniffer) const;
void configure_sniffer_post_activation(Sniffer& sniffer) const;
unsigned _snap_len;
bool _has_buffer_size;
unsigned _buffer_size;
bool _has_promisc;
bool _promisc;
bool _has_rfmon;
bool _rfmon;
bool _has_filter;
std::string _filter;
unsigned _timeout;
};
template<class Functor>
void Tins::BaseSniffer::sniff_loop(Functor function, uint32_t max_packets) {
for(iterator it = begin(); it != end(); ++it) {
try {
// If the functor returns false, we're done
if(!function(*it))
return;
}
catch(malformed_packet&) { }
catch(pdu_not_found&) { }
if(max_packets && --max_packets == 0)
return;
}
}
}
#endif // TINS_SNIFFER_H

311
include/tins/stp.h Normal file
View File

@@ -0,0 +1,311 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_STP_H
#define TINS_STP_H
#include "pdu.h"
#include "endianness.h"
#include "hw_address.h"
#include "small_uint.h"
namespace Tins {
/**
* \class STP
* \brief Represents a Spanning Tree Protocol PDU.
*/
class STP : public PDU {
public:
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::STP;
/**
* The type used to store BPDU identifier addresses.
*/
typedef HWAddress<6> address_type;
/**
* The type used to store the BPDU identifiers.
*/
struct bpdu_id_type {
small_uint<4> priority;
small_uint<12> ext_id;
address_type id;
bpdu_id_type(small_uint<4> priority=0, small_uint<12> ext_id=0,
const address_type& id=address_type())
: priority(priority), ext_id(ext_id), id(id) { }
};
/**
* \brief Default constructor.
*/
STP();
/**
* \brief Constructs a STP object from a buffer.
*
* If there is not enough size for a STP header, a malformed_packet
* exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
STP(const uint8_t *buffer, uint32_t total_sz);
// Getters
/**
* \brief Getter for the Protocol ID field.
* \return The stored Protocol ID field value.
*/
uint16_t proto_id() const {
return Endian::be_to_host(_header.proto_id);
}
/**
* \brief Getter for the Protocol Version field.
* \return The stored Protocol Version field value.
*/
uint8_t proto_version() const {
return _header.proto_version;
}
/**
* \brief Getter for the BDU Type field.
* \return The stored BDU Type field value.
*/
uint8_t bpdu_type() const {
return _header.bpdu_type;
}
/**
* \brief Getter for the BDU Flags field.
* \return The stored BDU Flags field value.
*/
uint8_t bpdu_flags() const {
return _header.bpdu_flags;
}
/**
* \brief Getter for the Root Path Cost field.
* \return The stored Root Path Cost field value.
*/
uint32_t root_path_cost() const {
return Endian::be_to_host(_header.root_path_cost);
}
/**
* \brief Getter for the Port ID field.
* \return The stored Port ID field value.
*/
uint16_t port_id() const {
return Endian::be_to_host(_header.port_id);
}
/**
* \brief Getter for the Message Age field.
* \return The stored Message Age field value.
*/
uint16_t msg_age() const {
return Endian::be_to_host(_header.msg_age) / 256;
}
/**
* \brief Getter for the Maximum Age field.
* \return The stored Maximum Age field value.
*/
uint16_t max_age() const {
return Endian::be_to_host(_header.max_age) / 256;
}
/**
* \brief Getter for the Hello Time field.
* \return The stored Hello Time field value.
*/
uint16_t hello_time() const {
return Endian::be_to_host(_header.hello_time) / 256;
}
/**
* \brief Getter for the Forward Delay field.
* \return The stored Forward Delay field value.
*/
uint16_t fwd_delay() const {
return Endian::be_to_host(_header.fwd_delay) / 256;
}
/**
* \brief Getter for the Root ID field.
* \return The stored Root ID field value.
*/
bpdu_id_type root_id() const;
/**
* \brief Getter for the Bridge ID field.
* \return The stored Bridge ID field value.
*/
bpdu_id_type bridge_id() const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \sa PDU::clone
*/
STP *clone() const {
return new STP(*this);
}
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. \sa PDU::header_size
*/
uint32_t header_size() const;
// Setters
/**
* \brief Setter for the Protocol ID field.
* \param new_proto_id The new Protocol ID field value.
*/
void proto_id(uint16_t new_proto_id);
/**
* \brief Setter for the Protocol Version field.
* \param new_proto_version The new Protocol Version field value.
*/
void proto_version(uint8_t new_proto_version);
/**
* \brief Setter for the BPDU Type field.
* \param new_bpdu_type The new BPDU Type field value.
*/
void bpdu_type(uint8_t new_bpdu_type);
/**
* \brief Setter for the BPDU Flags field.
* \param new_bpdu_flags The new BPDU Flags field value.
*/
void bpdu_flags(uint8_t new_bpdu_flags);
/**
* \brief Setter for the Root Path Cost field.
* \param new_root_path_cost The new Root Path Cost field value.
*/
void root_path_cost(uint32_t new_root_path_cost);
/**
* \brief Setter for the Port ID field.
* \param new_port_id The new Port ID field value.
*/
void port_id(uint16_t new_port_id);
/**
* \brief Setter for the Message Age field.
* \param new_msg_age The new Message Age field value.
*/
void msg_age(uint16_t new_msg_age);
/**
* \brief Setter for the Maximum Age field.
* \param new_max_age The new Maximum Age field value.
*/
void max_age(uint16_t new_max_age);
/**
* \brief Setter for the Hello Time field.
* \param new_hello_time The new Hello Time field value.
*/
void hello_time(uint16_t new_hello_time);
/**
* \brief Setter for the Forward Delay field.
* \param new_fwd_delay The new Forward Delay field value.
*/
void fwd_delay(uint16_t new_fwd_delay);
/**
* \brief Setter for the Root ID field.
* \param new_fwd_delay The new Root ID field value.
*/
void root_id(const bpdu_id_type &id);
/**
* \brief Setter for the Bridge ID field.
* \param new_fwd_delay The new Bridge ID field value.
*/
void bridge_id(const bpdu_id_type &id);
private:
TINS_BEGIN_PACK
struct pvt_bpdu_id {
#if TINS_IS_LITTLE_ENDIAN
// fixme
uint16_t ext_id:4,
priority:4,
ext_idL:8;
#else
uint16_t priority:4,
ext_id:12;
#endif
uint8_t id[6];
} TINS_END_PACK;
TINS_BEGIN_PACK
struct stphdr {
uint16_t proto_id;
uint8_t proto_version;
uint8_t bpdu_type;
uint8_t bpdu_flags;
pvt_bpdu_id root_id;
uint32_t root_path_cost;
pvt_bpdu_id bridge_id;
uint16_t port_id;
uint16_t msg_age;
uint16_t max_age;
uint16_t hello_time;
uint16_t fwd_delay;
} TINS_END_PACK;
static bpdu_id_type convert(const pvt_bpdu_id &id);
static pvt_bpdu_id convert(const bpdu_id_type &id);
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
stphdr _header;
};
}
#endif // TINS_STP_H

568
include/tins/tcp.h Normal file
View File

@@ -0,0 +1,568 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_TCP_H
#define TINS_TCP_H
#include <list>
#include <vector>
#include <stdint.h>
#include <stdexcept>
#include <utility>
#include "pdu.h"
#include "macros.h"
#include "endianness.h"
#include "small_uint.h"
#include "pdu_option.h"
#include "cxxstd.h"
namespace Tins {
/**
* \class TCP
* \brief Represents a TCP PDU.
*
* This class represents a TCP PDU.
*
* When sending TCP PDUs, the checksum is calculated automatically
* every time you send the packet.
*
* While sniffing, the payload sent in each packet will be wrapped
* in a RawPDU, which is set as the TCP object's inner_pdu. Therefore,
* if you are sniffing and want to see the TCP packet's payload,
* you need to do the following:
*
* \code
* // Get a packet from somewhere.
* TCP tcp = ...;
*
* // Extract the RawPDU object.
* const RawPDU& raw = tcp.rfind_pdu<RawPDU>();
*
* // Finally, take the payload (this is a vector<uint8_t>)
* const RawPDU::payload_type& payload = raw.payload();
* \endcode
*
* \sa RawPDU
*/
class TCP : public PDU {
public:
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::TCP;
/**
* \brief TCP flags enum.
*
* These flags identify those supported by the TCP PDU.
*/
enum Flags {
FIN = 1,
SYN = 2,
RST = 4,
PSH = 8,
ACK = 16,
URG = 32,
ECE = 64,
CWR = 128
};
/**
* \brief TCP options enum.
*
* This enum defines option types supported by TCP PDU.
*/
enum OptionTypes {
EOL = 0,
NOP = 1,
MSS = 2,
WSCALE = 3,
SACK_OK = 4,
SACK = 5,
TSOPT = 8,
ALTCHK = 14
};
/**
* \brief Alternate checksum enum.
*/
enum AltChecksums {
CHK_TCP,
CHK_8FLETCHER,
CHK_16FLETCHER
};
/**
* The type used to store TCP options.
*/
typedef PDUOption<uint8_t, TCP> option;
/**
* The type used to store the options.
*/
typedef std::list<option> options_type;
/**
* The type used to store the sack option.
*/
typedef std::vector<uint32_t> sack_type;
/**
* \brief TCP constructor.
*
* Creates an instance of TCP. Destination and source port can
* be provided, otherwise both will be 0.
*
* \param dport Destination port.
* \param sport Source port.
* */
TCP(uint16_t dport = 0, uint16_t sport = 0);
/**
* \brief Constructs TCP object from a buffer.
*
* If there is not enough size for a TCP header, or any of the
* TLV options are malformed, a malformed_packet exception is
* thrown.
*
* Any extra data will be stored in a RawPDU.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
TCP(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Getter for the destination port field.
*
* \return The destination port field value.
*/
uint16_t dport() const { return Endian::be_to_host(_tcp.dport); }
/**
* \brief Getter for the source port field.
*
* \return The source port field value.
*/
uint16_t sport() const { return Endian::be_to_host(_tcp.sport); }
/**
* \brief Getter for the sequence number field.
*
* \return The sequence number field value.
*/
uint32_t seq() const { return Endian::be_to_host(_tcp.seq); }
/**
* \brief Getter for the acknowledge number field.
*
* \return The acknowledge number field value.
*/
uint32_t ack_seq() const { return Endian::be_to_host(_tcp.ack_seq); }
/**
* \brief Getter for the window size field.
*
* \return The window size field value.
*/
uint16_t window() const { return Endian::be_to_host(_tcp.window); }
/**
* \brief Getter for the checksum field.
*
* \return The checksum field value.
*/
uint16_t checksum() const { return Endian::be_to_host(_tcp.check); }
/**
* \brief Getter for the urgent pointer field.
*
* \return The urgent pointer field value.
*/
uint16_t urg_ptr() const { return Endian::be_to_host(_tcp.urg_ptr); }
/**
* \brief Getter for the data offset field.
*
* \return The data offset field value.
*/
small_uint<4> data_offset() const { return this->_tcp.doff; }
/**
* \brief Getter for the option list.
*
* \return The options list.
*/
const options_type &options() const { return _options; }
/**
* \brief Gets the value of a flag.
*
* This method gets the value of a specific flag. If you
* want to check for multiple flags at the same time,
* use TCP::flags.
*
* If you want to check if this PDU has the SYN flag on,
* you can do it like this:
*
* \code
* // Get a TCP packet from somewhere.
* TCP tcp = ...;
*
* if(tcp.get_flag(TCP::SYN)) {
* // The SYN flag is on!
* }
* \endcode
*
* \sa TCP::flags
* \param tcp_flag The polled flag.
* \return The value of the flag.
*/
small_uint<1> get_flag(Flags tcp_flag) const;
/**
*
* \brief Gets the flags' values.
*
* All of the set flags will be joined together into
* a 12 bit value. This way, you can check for multiple
* flags at the same time:
*
* \code
* TCP tcp = ...;
* if(tcp.flags() == (TCP::SYN | TCP::ACK)) {
* // It's a SYN+ACK!
* }
* \endcode
*
* \return The value of the flags field.
*/
small_uint<12> flags() const;
/* Setters */
/**
* \brief Setter for the destination port field.
*
* \param new_dport The new destination port.
*/
void dport(uint16_t new_dport);
/**
* \brief Setter for the source port field.
*
* \param new_sport The new source port.
*/
void sport(uint16_t new_sport);
/**
* \brief Setter for the sequence number.
*
* \param new_seq The new sequence number.
*/
void seq(uint32_t new_seq);
/**
* \brief Setter for the acknowledge number.
*
* \param new_ack_seq The new acknowledge number.
*/
void ack_seq(uint32_t new_ack_seq);
/**
* \brief Setter for the window size.
*
* \param new_window The new window size.
*/
void window(uint16_t new_window);
/**
* \brief Setter for the urgent pointer field.
*
* \param new_urg_ptr The new urgent pointer.
*/
void urg_ptr(uint16_t new_urg_ptr);
/**
* \brief Setter for the data offset pointer field.
*
* \param new_doff The new data offset pointer.
*/
void data_offset(small_uint<4> new_doff);
// Options
/**
* \brief Add a maximum segment size option.
*
* \param value The new maximum segment size.
*/
void mss(uint16_t value);
/**
* \brief Searchs for a maximum segment size option.
* \param value A pointer in which the option's value will be stored.
* \return True if the option was found, false otherwise.
*/
uint16_t mss() const;
/**
* \brief Add a window scale option.
*
* \param value The new window scale.
*/
void winscale(uint8_t value);
/**
* \brief Searchs for a window scale option.
* \param value A pointer in which the option's value will be stored.
* \return True if the option was found, false otherwise.
*/
uint8_t winscale() const;
/**
* \brief Add a sack permitted option.
*/
void sack_permitted();
/**
* \brief Searchs for a sack permitted option.
* \return True if the option was found, false otherwise.
*/
bool has_sack_permitted() const;
/**
* \brief Add a sack option.
*
* \param value The new window scale.
*/
void sack(const sack_type &edges);
/**
* \brief Searchs for a sack option.
* \param value A pointer in which the option's value will be stored.
* \return True if the option was found, false otherwise.
*/
sack_type sack() const;
/**
* \brief Add a timestamp option.
*
* \param value The current value of the timestamp clock.
* \param reply The echo reply field.
*/
void timestamp(uint32_t value, uint32_t reply);
/**
* \brief Searchs for a timestamp option.
* \param value A pointer in which the option's value will be stored.
* \param reply A pointer in which the option's reply value will be stored.
* \return True if the option was found, false otherwise.
*/
std::pair<uint32_t, uint32_t> timestamp() const;
/**
* \brief Add a alternate checksum option.
*
* \param value The new alternate checksum scale.
*/
void altchecksum(AltChecksums value);
/**
* \brief Searchs for a alternate checksum option.
* \param value A pointer in which the option's value will be stored.
* \return True if the option was found, false otherwise.
*/
AltChecksums altchecksum() const;
/**
* \brief Set a TCP flag value.
*
* \param tcp_flag The flag to be set.
* \param value The new value for this flag. Must be 0 or 1.
*/
void set_flag(Flags tcp_flag, small_uint<1> value);
/**
* \brief Sets the value of the flag fields.
*
* This method can be used to set several flags at the
* same time.
*
* \code
* // Get a TCP packet from somewhere and set the flags to SYN && ACK
* TCP tcp = ...;
* tcp.flags(TCP::SYN | TCP::ACK);
*
* // Now also set the PSH flag, without modifying
* // the rest of the flags.
* tcp.flags(tcp.flags() | TCP::PSH);
* \endcode
*
* \param value The new value of the flags.
*/
void flags(small_uint<12> value);
/**
* \brief Adds a TCP option.
*
* \param option The option to be added.
*/
void add_option(const option &opt);
#if TINS_IS_CXX11
/**
* \brief Adds a TCP option.
*
* This move-constructs the option.
*
* \param option The option to be added.
*/
void add_option(option &&opt) {
internal_add_option(opt);
_options.push_back(std::move(opt));
}
/**
* \brief Adds a TCP option using the provided arguments.
*
* The option is constructed from the provided parameters.
*
* \param args The arguments to be used in the option's
* constructor.
*/
template<typename... Args>
void add_option(Args&&... args) {
_options.emplace_back(std::forward<Args>(args)...);
internal_add_option(_options.back());
}
#endif
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. This size includes the
* payload and options size.
*
* \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Getter for the PDU's type.
*
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::TCP; }
/**
* \brief Searchs for an option that matchs the given flag.
* \param opt_flag The flag to be searched.
* \return A pointer to the option, or 0 if it was not found.
*/
const option *search_option(OptionTypes opt) const;
/**
* \sa PDU::clone
*/
TCP *clone() const {
return new TCP(*this);
}
private:
TINS_BEGIN_PACK
struct tcphdr {
uint16_t sport;
uint16_t dport;
uint32_t seq;
uint32_t ack_seq;
#if TINS_IS_LITTLE_ENDIAN
uint16_t res1:4,
doff:4,
fin:1,
syn:1,
rst:1,
psh:1,
ack:1,
urg:1,
ece:1,
cwr:1;
#elif TINS_IS_BIG_ENDIAN
uint16_t doff:4,
res1:4,
cwr:1,
ece:1,
urg:1,
ack:1,
psh:1,
rst:1,
syn:1,
fin:1;
#else
#error "Endian is not LE nor BE..."
#endif
uint16_t window;
uint16_t check;
uint16_t urg_ptr;
} TINS_END_PACK;
static const uint16_t DEFAULT_WINDOW;
template<class T>
T generic_search(OptionTypes opt_type) const {
const option *opt = search_option(opt_type);
if(!opt)
throw option_not_found();
return opt->to<T>();
}
void internal_add_option(const option &option);
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
void checksum(uint16_t new_check);
uint8_t *write_option(const option &opt, uint8_t *buffer);
tcphdr _tcp;
uint16_t _options_size, _total_options_size;
options_type _options;
};
}
#endif // TINS_TCP_H

376
include/tins/tcp_stream.h Normal file
View File

@@ -0,0 +1,376 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_TCP_STREAM_H
#define TINS_TCP_STREAM_H
#include <map>
#include <utility>
#include <iterator>
#include <vector>
#include <algorithm>
#include <stdint.h>
#include "sniffer.h"
#include "tcp.h"
#include "utils.h"
#include "ip.h"
#include "ip_address.h"
namespace Tins {
class Sniffer;
class RawPDU;
/**
* \class TCPStream
* \brief Represents a TCP stream.
*/
class TCPStream {
public:
/**
* The stream information.
*/
struct StreamInfo {
IPv4Address client_addr, server_addr;
uint16_t client_port, server_port;
StreamInfo() {}
StreamInfo(IPv4Address client, IPv4Address server,
uint16_t cport, uint16_t sport);
bool operator<(const StreamInfo &rhs) const;
};
/**
* The type used to store the payload.
*/
typedef std::vector<uint8_t> payload_type;
/**
* \brief TCPStream constructor.
* \param ip The IP PDU from which to take the initial parameters.
* \param tcp The TCP PDU from which to take the initial parameters.
* \param identifier This stream's identifier number
*/
TCPStream(IP *ip, TCP *tcp, uint64_t identifier);
/**
* Copy constructor.
*/
TCPStream(const TCPStream &rhs);
/**
* Copy assignment operator.
*/
TCPStream& operator=(const TCPStream &rhs);
/**
* Destructor.
*/
~TCPStream();
/**
* \brief Retrieves the client payload.
*
* This is the payload that the connection's client has sent so far.
*
* \return const payload_type& containing the payload.
*/
const payload_type &client_payload() const {
return client_payload_;
}
/**
* \brief Retrieves the client payload.
*
* This is the payload that the connection's client has sent so far.
*
* \return payload_type& containing the payload.
*/
payload_type &client_payload() {
return client_payload_;
}
/**
* \brief Retrieves the server payload.
*
* This is the payload that the connection's server has sent so far.
*
* \return const payload_type& containing the payload.
*/
const payload_type &server_payload() const {
return server_payload_;
}
/**
* \brief Retrieves the server payload.
*
* This is the payload that the connection's server has sent so far.
*
* \return payload_type& containing the payload.
*/
payload_type &server_payload() {
return server_payload_;
}
/**
* \brief Retrieves this stream's identification number.
* \return uint64_t containing the identification number.
*/
uint64_t id() const {
return identifier;
}
/**
* \brief Retrieves the stream information.
* \return const StreamInfo& containing the stream information.
*/
const StreamInfo &stream_info() const {
return info;
}
/**
* \brief Checks whether this stream is finished.
*
* A stream is considered to be finished, if at least one of the
* peers sends a TCP segment containing the FIN bit on.
*
* \return bool indicating whether the stream is finished.
*/
bool is_finished() const {
return fin_sent;
}
/**
* \brief Updates the stream data.
*
* This may update both the payload and the expected sequence numbers.
*
* \param ip The IP PDU from which to take information.
* \param tcp The TCP PDU from which to take information.
* \return bool indicating whether any changes have been done to
* any of the stored payloads.
*/
bool update(IP *ip, TCP *tcp);
private:
typedef std::map<uint32_t, RawPDU*> fragments_type;
static void free_fragments(fragments_type &frags);
static fragments_type clone_fragments(const fragments_type &frags);
bool generic_process(uint32_t &my_seq, uint32_t &other_seq,
payload_type &pload, fragments_type &frags, TCP *tcp);
void safe_insert(fragments_type &frags, uint32_t seq, RawPDU *raw);
uint32_t client_seq, server_seq;
StreamInfo info;
uint64_t identifier;
payload_type client_payload_, server_payload_;
fragments_type client_frags, server_frags;
bool syn_ack_sent, fin_sent;
};
/**
* \class TCPStreamFollower
* \brief Follows TCP streams and notifies the user when data is available.
*/
class TCPStreamFollower {
public:
/**
* \brief Default constructor.
*/
TCPStreamFollower();
/**
* \brief Starts following TCP streams.
*
* The template functors must accept a TCPStream& as argument, which
* will point to the stream which has been modified.
*
* \param sniffer The sniffer which will be used to sniff PDUs.
* \param data_fun The function which will be called whenever one of
* the peers in a connection sends data.
* \param end_fun This function will be called when a stream is
* closed.
*/
template<typename DataFunctor, typename EndFunctor>
void follow_streams(BaseSniffer &sniffer, DataFunctor data_fun, EndFunctor end_fun);
/**
* \brief Starts following TCP streams.
*
* This overload takes a range of iterators containing the PDUs
* in which TCP streams will be looked up and followed. The iterators
* will be dereferenced until a PDU& is found, so iterators can hold
* not only PDUs, but also smart pointers, etc.
*
* The template functors must accept a TCPStream& as argument, which
* will point to the stream which has been modified.
*
* The state of the PDUs stored in the iterator range provided might
* be modified internally.
*
* \param start The start of the range of PDUs.
* \param end The start of the range of PDUs.
* \param data_fun The function which will be called whenever one of
* the peers in a connection sends data.
* \param end_fun This function will be called when a stream is
* closed.
*/
template<typename ForwardIterator, typename DataFunctor, typename EndFunctor>
void follow_streams(ForwardIterator start, ForwardIterator end,
DataFunctor data_fun, EndFunctor end_fun);
/**
* \brief Starts following TCP streams.
*
* The template functor must accept a TCPStream& as argument, which
* will point to the stream which has been modified.
*
* \param sniffer The sniffer which will be used to sniff PDUs.
* \param data_fun The function which will be called whenever one of
* the peers in a connection sends data.
* closed.
*/
template<typename DataFunctor>
void follow_streams(BaseSniffer &sniffer, DataFunctor data_fun);
/**
* \brief Starts following TCP streams.
*
* This overload takes a range of iterators containing the PDUs
* in which TCP streams will be looked up and followed. The iterators
* will be dereferenced until a PDU& is found, so iterators can hold
* not only PDUs, but also smart pointers, etc.
*
* The template functors must accept a TCPStream& as argument, which
* will point to the stream which has been modified.
*
* The state of the PDUs stored in the iterator range provided might
* be modified internally.
*
* \param start The start of the range of PDUs.
* \param end The start of the range of PDUs.
* \param data_fun The function which will be called whenever one of
* the peers in a connection sends data.
*/
template<typename ForwardIterator, typename DataFunctor>
void follow_streams(ForwardIterator start, ForwardIterator end,
DataFunctor data_fun);
private:
typedef std::map<TCPStream::StreamInfo, TCPStream> sessions_type;
template<typename DataFunctor, typename EndFunctor>
struct proxy_caller {
bool callback(PDU &pdu) {
return stream->callback(pdu, data_fun, end_fun);
}
TCPStreamFollower *stream;
DataFunctor data_fun;
EndFunctor end_fun;
};
template<typename DataFunctor, typename EndFunctor>
bool callback(PDU &pdu, const DataFunctor &fun, const EndFunctor &end_fun);
static void dummy_function(TCPStream&) { }
sessions_type sessions;
uint64_t last_identifier;
};
template<typename DataFunctor, typename EndFunctor>
void TCPStreamFollower::follow_streams(BaseSniffer &sniffer, DataFunctor data_fun, EndFunctor end_fun) {
typedef proxy_caller<DataFunctor, EndFunctor> proxy_type;
proxy_type proxy = { this, data_fun, end_fun };
sniffer.sniff_loop(make_sniffer_handler(&proxy, &proxy_type::callback));
}
template<typename ForwardIterator, typename DataFunctor, typename EndFunctor>
void TCPStreamFollower::follow_streams(ForwardIterator start, ForwardIterator end,
DataFunctor data_fun, EndFunctor end_fun)
{
while(start != end) {
if(!callback(Utils::dereference_until_pdu(start), data_fun, end_fun))
return;
start++;
}
}
template<typename DataFunctor>
void TCPStreamFollower::follow_streams(BaseSniffer &sniffer, DataFunctor data_fun) {
return follow_streams(sniffer, data_fun, dummy_function);
}
template<typename ForwardIterator, typename DataFunctor>
void TCPStreamFollower::follow_streams(ForwardIterator start, ForwardIterator end,
DataFunctor data_fun)
{
follow_streams(start, end, data_fun, dummy_function);
}
template<typename DataFunctor, typename EndFunctor>
bool TCPStreamFollower::callback(PDU &pdu, const DataFunctor &data_fun, const EndFunctor &end_fun) {
IP &ip = pdu.rfind_pdu<IP>();
TCP &tcp = pdu.rfind_pdu<TCP>();
TCPStream::StreamInfo info(
ip.src_addr(), ip.dst_addr(),
tcp.sport(), tcp.dport()
);
sessions_type::iterator it = sessions.find(info);
if(it == sessions.end()) {
std::swap(info.client_addr, info.server_addr);
std::swap(info.client_port, info.server_port);
if((it = sessions.find(info)) == sessions.end()) {
if(tcp.get_flag(TCP::SYN) && !tcp.get_flag(TCP::ACK)) {
sessions.insert(
std::make_pair(
info,
TCPStream(&ip, &tcp, last_identifier++)
)
);
}
return true;
}
}
if(it->second.update(&ip, &tcp))
data_fun(it->second);
// We're done with this stream
if(it->second.is_finished()) {
end_fun(it->second);
sessions.erase(it);
}
return true;
}
}
#endif // TINS_TCP_STREAM_H

126
include/tins/timestamp.h Normal file
View File

@@ -0,0 +1,126 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_TIMESTAMP_H
#define TINS_TIMESTAMP_H
#ifdef WIN32
#include <winsock2.h>
#else
#include <sys/time.h>
#endif
#include "cxxstd.h"
#if TINS_IS_CXX11
#include <chrono>
#endif
namespace Tins {
/**
* \brief Represents a packet timestamp.
*/
class Timestamp {
public:
#ifdef WIN32
typedef long seconds_type;
typedef long microseconds_type;
#else
typedef time_t seconds_type;
typedef suseconds_t microseconds_type;
#endif
/**
* \brief Constructs a Timestamp which will hold the current time.
*/
static Timestamp current_time() {
#ifdef WIN32
//fixme
return Timestamp();
#else
timeval tv;
gettimeofday(&tv, 0);
return tv;
#endif
}
/**
* Default constructs the timestamp.
*/
Timestamp() : tv() {}
#if TINS_IS_CXX11
/**
* Constructs a Timestamp from a std::chrono::duration.
*/
template<typename Rep, typename Period>
Timestamp(const std::chrono::duration<Rep, Period>& ts) {
using std::chrono::duration_cast;
using std::chrono::microseconds;
using std::chrono::seconds;
tv.tv_sec = duration_cast<seconds>(ts).count();
tv.tv_usec = duration_cast<microseconds>(
ts - seconds(tv.tv_sec)).count();
}
#endif
/**
* Constructs a timestamp from a timeval object.
* \param time_val The timeval object.
*/
Timestamp(const timeval &time_val) : tv(time_val) {}
/**
* Returns the amount of seconds in this timestamp.
*/
seconds_type seconds() const {
return tv.tv_sec;
}
/**
* Returns the amount of microseconds in this timestamp.
*/
microseconds_type microseconds() const {
return tv.tv_usec;
}
#if TINS_IS_CXX11
/**
* Converts this Timestamp to a std::chrono::microseconds
*/
operator std::chrono::microseconds() const {
return std::chrono::seconds(seconds()) +
std::chrono::microseconds(microseconds());
}
#endif
private:
timeval tv;
};
}
#endif // TINS_TIMESTAMP_H

77
include/tins/tins.h Normal file
View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_TINS_H
#define TINS_TINS_H
#include "dns.h"
#include "arp.h"
#include "bootp.h"
#include "dhcp.h"
#include "eapol.h"
#include "ethernetII.h"
#include "ieee802_3.h"
#include "llc.h"
#include "icmp.h"
#include "icmpv6.h"
#include "dot11.h"
#include "dot1q.h"
#include "dot3.h"
#include "ip.h"
#include "ipv6.h"
#include "packet_sender.h"
#include "packet_writer.h"
#include "pdu.h"
#include "radiotap.h"
#include "rawpdu.h"
#include "snap.h"
#include "sniffer.h"
#include "tcp.h"
#include "udp.h"
#include "utils.h"
#include "tcp_stream.h"
#include "crypto.h"
#include "pdu_cacher.h"
#include "rsn_information.h"
#include "ipv6_address.h"
#include "ip_address.h"
#include "packet.h"
#include "timestamp.h"
#include "sll.h"
#include "dhcpv6.h"
#include "pppoe.h"
#include "stp.h"
#include "handshake_capturer.h"
#include "address_range.h"
#include "pdu_allocator.h"
#include "ipsec.h"
#include "ip_reassembler.h"
#include "ppi.h"
#endif // TINS_TINS_H

185
include/tins/udp.h Normal file
View File

@@ -0,0 +1,185 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_UDP_H
#define TINS_UDP_H
#include "macros.h"
#include "pdu.h"
#include "endianness.h"
namespace Tins {
/**
* \class UDP
* \brief Represents an UDP PDU.
*
* This class represents an UDP PDU.
*
* While sniffing, the payload sent in each packet will be wrapped
* in a RawPDU, which is set as the UDP object's inner_pdu. Therefore,
* if you are sniffing and want to see the UDP packet's payload,
* you need to do the following:
*
* \code
* // Get a packet from somewhere.
* UDP udp = ...;
*
* // Extract the RawPDU object.
* const RawPDU& raw = udp.rfind_pdu<RawPDU>();
*
* // Finally, take the payload (this is a vector<uint8_t>)
* const RawPDU::payload_type& payload = raw.payload();
* \endcode
*
* \sa RawPDU
*/
class UDP : public PDU {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::UDP;
/**
* \brief UDP constructor.
*
* Constructs an instance of UDP. The destination and source
* port can be provided, otherwise both of them will be 0.
*
* \param dport Destination port.
* \param sport Source port.
* */
UDP(uint16_t dport = 0, uint16_t sport = 0);
/**
* \brief Constructs an UDP object from a buffer.
*
* If there is not enough size for a UDP header a malformed_packet
* exception is thrown.
*
* Any extra data will be stored in a RawPDU.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
UDP(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Getter for the destination port.
* \return The datagram's destination port.
*/
uint16_t dport() const { return Endian::be_to_host(_udp.dport); }
/**
* \brief Getter for the source port.
* \return The datagram's source port.
*/
uint16_t sport() const { return Endian::be_to_host(_udp.sport); }
/**
* \brief Getter for the length of the datagram.
* \return The length of the datagram.
*/
uint16_t length() const { return Endian::be_to_host(_udp.len); }
/**
* \brief Getter for the checksum of the datagram.
* \return The datagram's checksum.
*/
uint16_t checksum() const { return Endian::be_to_host(_udp.check); }
/**
* \brief Set the destination port.
* \param new_dport The new destination port.
*/
void dport(uint16_t new_dport);
/**
* \brief Set the source port.
*
* \param new_sport The new source port.
*/
void sport(uint16_t new_sport);
/**
* \brief Getter for the length field.
* \param new_len The new length field.
* \return The length field.
*/
void length(uint16_t new_len);
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* This compares the source and destination ports in the provided
* response with those stored in this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. This size includes the
* payload and options 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::UDP; }
/**
* \sa PDU::clone
*/
UDP *clone() const {
return new UDP(*this);
}
private:
TINS_BEGIN_PACK
struct udphdr {
uint16_t sport;
uint16_t dport;
uint16_t len;
uint16_t check;
} TINS_END_PACK;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
udphdr _udp;
};
}
#endif // TINS_UDP_H

427
include/tins/utils.h Normal file
View File

@@ -0,0 +1,427 @@
/*
* Copyright (c) 2014, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TINS_UTILS_H
#define TINS_UTILS_H
#ifndef WIN32
#include <ifaddrs.h>
#else
#include <winsock2.h>
#include <iphlpapi.h>
#undef interface
#include "network_interface.h"
#endif
#include "macros.h"
#if defined(BSD) || defined(__FreeBSD_kernel__)
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#endif
#include <string>
#include <set>
#include <fstream>
#include <vector>
#include <stdint.h>
#include "ip_address.h"
#include "ipv6_address.h"
#include "hw_address.h"
#include "internals.h"
namespace Tins {
class NetworkInterface;
class PacketSender;
class PDU;
/**
* \brief Network utils namespace.
*
* This namespace provides utils to convert between integer IP addresses
* and dotted notation strings, "net to host" integer conversions,
* interface listing, etc.
*/
namespace Utils {
/**
* Struct that represents an entry in /proc/net/route
*/
struct RouteEntry {
/**
* This interface's name.
*/
std::string interface;
/**
* This route entry's destination.
*/
IPv4Address destination;
/**
* This route entry's gateway.
*/
IPv4Address gateway;
/**
* This route entry's subnet mask.
*/
IPv4Address mask;
};
/**
* \brief Resolves a domain name and returns its corresponding ip address.
*
* If an ip address is given, its integer representation is returned.
* Otherwise, the domain name is resolved and its ip address is returned.
*
* \param to_resolve The domain name/ip address to resolve.
*/
IPv4Address resolve_domain(const std::string &to_resolve);
/**
* \brief Resolves a domain name and returns its corresponding ip address.
*
* If an ip address is given, its integer representation is returned.
* Otherwise, the domain name is resolved and its ip address is returned.
*
* \param to_resolve The domain name/ip address to resolve.
*/
IPv6Address resolve_domain6(const std::string &to_resolve);
/**
* \brief Resolves the hardware address for a given ip.
*
* If the address can't be resolved, a std::runtime_error
* exception is thrown.
*
* \param iface The interface in which the packet will be sent.
* \param ip The ip to resolve, in integer format.
* \param sender The sender to use to send and receive the ARP requests.
* \return HWAddress<6> containing the resolved hardware address.
*/
HWAddress<6> resolve_hwaddr(const NetworkInterface &iface,
IPv4Address ip, PacketSender &sender);
/**
* \brief Resolves the hardware address for a given ip.
*
* If the address can't be resolved, a std::runtime_error
* exception is thrown.
*
* This method sends and receives the packet through
* PacketSender::default_interface.
*
* \param ip The ip to resolve, in integer format.
* \param sender The sender to use to send and receive the ARP requests.
* \return HWAddress<6> containing the resolved hardware address.
*/
HWAddress<6> resolve_hwaddr(IPv4Address ip, PacketSender &sender);
/** \brief List all network interfaces.
*
* Returns a set of strings, each of them representing the name
* of a network interface. These names can be used as the input
* interface for Utils::interface_ip, Utils::interface_hwaddr, etc.
*/
std::set<std::string> network_interfaces();
/**
* \brief Finds the gateway's IP address for the given IP
* address.
*
* \param ip The IP address for which the default gateway will
* be searched.
* \param gw_addr This parameter will contain the gateway's IP
* address in case it is found.
*
* \return bool indicating wether the lookup was successfull.
*/
bool gateway_from_ip(IPv4Address ip, IPv4Address &gw_addr);
/**
* \brief Retrieves entries in the routing table.
*
* \brief output ForwardIterator in which entries will be stored.
*/
template<class ForwardIterator>
void route_entries(ForwardIterator output);
/**
* \brief Retrieves entries in the routing table.
*
* \return a vector which contains all of the route entries.
*/
std::vector<RouteEntry> route_entries();
/** \brief Returns the 32 bit crc of the given buffer.
*
* \param data The input buffer.
* \param data_size The size of the input buffer.
*/
uint32_t crc32(const uint8_t* data, uint32_t data_size);
/**
* \brief Converts a channel number to its mhz representation.
* \param channel The channel number.
* \return The channel's mhz representation.
*/
uint16_t channel_to_mhz(uint16_t channel);
/**
* \brief Converts mhz units to the appropriate channel number.
* \param mhz The mhz units to be converted.
* \return The channel number.
*/
uint16_t mhz_to_channel(uint16_t mhz);
/**
* \brief Converts a PDUType to a string.
* \param pduType The PDUType to be converted.
* \return A string representation, for example "DOT11_QOS_DATA".
*/
std::string to_string(PDU::PDUType pduType);
/** \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(const uint8_t *start, const 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(IPv4Address source_ip, IPv4Address dest_ip, uint32_t len, uint32_t flag);
/** \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(IPv6Address source_ip, IPv6Address dest_ip, uint32_t len, uint32_t flag);
/** \brief Generic function to iterate through interface and collect
* data.
*
* The parameter is applied to every interface found, allowing
* the object to collect data from them.
* \param functor An instance of an class which implements operator(struct ifaddrs*).
*/
#ifndef WIN32
template<class Functor>
void generic_iface_loop(Functor &functor) {
struct ifaddrs *ifaddrs = 0;
struct ifaddrs *if_it = 0;
getifaddrs(&ifaddrs);
for(if_it = ifaddrs; if_it; if_it = if_it->ifa_next) {
if(functor(if_it))
break;
}
if(ifaddrs)
freeifaddrs(ifaddrs);
}
#else // WIN32
template<class Functor>
void generic_iface_loop(Functor &functor) {
ULONG size;
::GetAdaptersAddresses(AF_INET, 0, 0, 0, &size);
std::vector<uint8_t> buffer(size);
if (::GetAdaptersAddresses(AF_INET, 0, 0, (IP_ADAPTER_ADDRESSES *)&buffer[0], &size) == ERROR_SUCCESS) {
PIP_ADAPTER_ADDRESSES iface = (IP_ADAPTER_ADDRESSES *)&buffer[0];
while(iface) {
if(functor(iface))
break;
iface = iface->Next;
}
}
}
#endif // WIN32
template <typename T>
struct is_pdu {
template <typename U>
static char test(typename U::PDUType*);
template <typename U>
static long test(...);
static const bool value = sizeof(test<T>(0)) == 1;
};
/**
* Returns the argument.
*/
inline PDU& dereference_until_pdu(PDU &pdu) {
return pdu;
}
/**
* \brief Dereferences the parameter until a PDU is found.
*
* This function dereferences the parameter until a PDU object
* is found. When it's found, it is returned.
*
* \param value The parameter to be dereferenced.
*/
template<typename T>
inline typename Internals::enable_if<!is_pdu<T>::value, PDU&>::type
dereference_until_pdu(T &value) {
return dereference_until_pdu(*value);
}
#if defined(BSD) || defined(__FreeBSD_kernel__)
inline std::vector<char> query_route_table() {
int mib[6];
std::vector<char> buf;
size_t len;
mib[0] = CTL_NET;
mib[1] = AF_ROUTE;
mib[2] = 0;
mib[3] = AF_INET;
mib[4] = NET_RT_DUMP;
mib[5] = 0;
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
throw std::runtime_error("sysctl failed");
buf.resize(len);
if (sysctl(mib, 6, &buf[0], &len, NULL, 0) < 0) {
throw std::runtime_error("sysctl failed");
}
return buf;
}
template<typename ForwardIterator>
void parse_header(struct rt_msghdr *rtm, ForwardIterator iter)
{
char *ptr = (char *)(rtm + 1);
sockaddr *sa = 0;
for (int i = 0; i < RTAX_MAX; i++) {
if (rtm->rtm_addrs & (1 << i)) {
sa = (struct sockaddr *)ptr;
ptr += sa->sa_len;
if (sa->sa_family == 0)
sa = 0;
}
*iter++ = sa;
}
}
#endif
}
}
#if defined(BSD) || defined(__FreeBSD_kernel__)
template<class ForwardIterator>
void Tins::Utils::route_entries(ForwardIterator output) {
std::vector<char> buffer = query_route_table();
char *next = &buffer[0], *end = &buffer[buffer.size()];
rt_msghdr *rtm;
std::vector<sockaddr*> sa(RTAX_MAX);
char iface_name[IF_NAMESIZE];
while(next < end) {
rtm = (rt_msghdr*)next;
parse_header(rtm, sa.begin());
if (sa[RTAX_DST] && sa[RTAX_GATEWAY] && if_indextoname(rtm->rtm_index, iface_name)) {
RouteEntry entry;
entry.destination = IPv4Address(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr.s_addr);
entry.gateway = IPv4Address(((struct sockaddr_in *)sa[RTAX_GATEWAY])->sin_addr.s_addr);
if(sa[RTAX_GENMASK])
entry.mask = IPv4Address(((struct sockaddr_in *)sa[RTAX_GENMASK])->sin_addr.s_addr);
else
entry.mask = IPv4Address(uint32_t());
entry.interface = iface_name;
*output++ = entry;
}
next += rtm->rtm_msglen;
}
}
#elif defined(WIN32)
template<class ForwardIterator>
void Tins::Utils::route_entries(ForwardIterator output) {
MIB_IPFORWARDTABLE *table;
ULONG size = 0;
char iface_name[256];
GetIpForwardTable(0, &size, 0);
std::vector<uint8_t> buffer(size);
table = (MIB_IPFORWARDTABLE*)&buffer[0];
GetIpForwardTable(table, &size, 0);
for (DWORD i = 0; i < table->dwNumEntries; i++) {
MIB_IPFORWARDROW *row = &table->table[i];
if(row->dwForwardType == MIB_IPROUTE_TYPE_INDIRECT) {
RouteEntry entry;
entry.interface = NetworkInterface::from_index(row->dwForwardIfIndex).name();
entry.destination = IPv4Address(row->dwForwardDest);
entry.mask = IPv4Address(row->dwForwardMask);
entry.gateway = IPv4Address(row->dwForwardNextHop);
*output++ = entry;
}
}
}
#else
template<class ForwardIterator>
void Tins::Utils::route_entries(ForwardIterator output) {
using namespace Tins::Internals;
std::ifstream input("/proc/net/route");
std::string destination, mask, gw;
uint32_t dummy;
skip_line(input);
RouteEntry entry;
while(input >> entry.interface >> destination >> gw) {
for(unsigned i(0); i < 5; ++i)
input >> mask;
from_hex(destination, dummy);
entry.destination = IPv4Address(dummy);
from_hex(mask, dummy);
entry.mask = IPv4Address(dummy);
from_hex(gw, dummy);
entry.gateway = IPv4Address(dummy);
skip_line(input);
*output = entry;
++output;
}
}
#endif
#endif // TINS_UTILS_H