mirror of
https://github.com/mfontanini/libtins
synced 2026-01-29 13:04:28 +01:00
Code cleanup and use same syntax on the entire project
Initial code cleanup More code cleanup Cleanup more code Cleanup Dot11 code Fix OSX build issue Cleanup examples Fix ref and pointer declaration syntax Fix braces
This commit is contained in:
@@ -31,22 +31,27 @@
|
||||
#include "ip_address.h"
|
||||
#include "ipv6_address.h"
|
||||
|
||||
using std::logic_error;
|
||||
|
||||
namespace Tins {
|
||||
IPv4Range operator/(const IPv4Address &addr, int mask) {
|
||||
if(mask > 32)
|
||||
throw std::logic_error("Prefix length cannot exceed 32");
|
||||
|
||||
IPv4Range operator/(const IPv4Address& addr, int mask) {
|
||||
if (mask > 32) {
|
||||
throw logic_error("Prefix length cannot exceed 32");
|
||||
}
|
||||
return IPv4Range::from_mask(
|
||||
addr,
|
||||
IPv4Address(Endian::host_to_be(0xffffffff << (32 - mask)))
|
||||
);
|
||||
}
|
||||
|
||||
IPv6Range operator/(const IPv6Address &addr, int mask) {
|
||||
if(mask > 128)
|
||||
IPv6Range operator/(const IPv6Address& addr, int mask) {
|
||||
if (mask > 128) {
|
||||
throw std::logic_error("Prefix length cannot exceed 128");
|
||||
}
|
||||
IPv6Address last_addr;
|
||||
IPv6Address::iterator it = last_addr.begin();
|
||||
while(mask > 8) {
|
||||
while (mask > 8) {
|
||||
*it = 0xff;
|
||||
++it;
|
||||
mask -= 8;
|
||||
@@ -54,4 +59,5 @@ IPv6Range operator/(const IPv6Address &addr, int mask) {
|
||||
*it = 0xff << (8 - mask);
|
||||
return IPv6Range::from_mask(addr, last_addr);
|
||||
}
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
92
src/arp.cpp
92
src/arp.cpp
@@ -38,17 +38,16 @@
|
||||
#include "exceptions.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::runtime_error;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
ARP::ARP(ipaddress_type target_ip, ipaddress_type sender_ip,
|
||||
const hwaddress_type &target_hw, const hwaddress_type &sender_hw)
|
||||
: _arp()
|
||||
{
|
||||
ARP::ARP(ipaddress_type target_ip,
|
||||
ipaddress_type sender_ip,
|
||||
const hwaddress_type& target_hw,
|
||||
const hwaddress_type& sender_hw)
|
||||
: header_() {
|
||||
hw_addr_format((uint16_t)Constants::ARP::ETHER);
|
||||
prot_addr_format((uint16_t)Constants::Ethernet::IP);
|
||||
hw_addr_length(Tins::EthernetII::address_type::address_size);
|
||||
@@ -59,89 +58,92 @@ const hwaddress_type &target_hw, const hwaddress_type &sender_hw)
|
||||
target_hw_addr(target_hw);
|
||||
}
|
||||
|
||||
ARP::ARP(const uint8_t *buffer, uint32_t total_sz)
|
||||
{
|
||||
ARP::ARP(const uint8_t* buffer, uint32_t total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_arp);
|
||||
stream.read(header_);
|
||||
if (stream) {
|
||||
inner_pdu(new RawPDU(stream.pointer(), stream.size()));
|
||||
}
|
||||
}
|
||||
|
||||
void ARP::sender_hw_addr(const hwaddress_type &new_snd_hw_addr) {
|
||||
std::copy(new_snd_hw_addr.begin(), new_snd_hw_addr.end(), _arp.ar_sha);
|
||||
void ARP::sender_hw_addr(const hwaddress_type& address) {
|
||||
address.copy(header_.sender_hw_address);
|
||||
}
|
||||
|
||||
void ARP::sender_ip_addr(ipaddress_type new_snd_ip_addr) {
|
||||
this->_arp.ar_sip = new_snd_ip_addr;
|
||||
void ARP::sender_ip_addr(ipaddress_type address) {
|
||||
header_.sender_ip_address = address;
|
||||
}
|
||||
|
||||
void ARP::target_hw_addr(const hwaddress_type &new_tgt_hw_addr) {
|
||||
std::copy(new_tgt_hw_addr.begin(), new_tgt_hw_addr.end(), _arp.ar_tha);
|
||||
void ARP::target_hw_addr(const hwaddress_type& address) {
|
||||
address.copy(header_.target_hw_address);
|
||||
}
|
||||
|
||||
void ARP::target_ip_addr(ipaddress_type new_tgt_ip_addr) {
|
||||
this->_arp.ar_tip = new_tgt_ip_addr;
|
||||
void ARP::target_ip_addr(ipaddress_type address) {
|
||||
header_.target_ip_address = address;
|
||||
}
|
||||
|
||||
void ARP::hw_addr_format(uint16_t new_hw_addr_fmt) {
|
||||
this->_arp.ar_hrd = Endian::host_to_be(new_hw_addr_fmt);
|
||||
void ARP::hw_addr_format(uint16_t format) {
|
||||
header_.hw_address_format = Endian::host_to_be(format);
|
||||
}
|
||||
|
||||
void ARP::prot_addr_format(uint16_t new_prot_addr_fmt) {
|
||||
this->_arp.ar_pro = Endian::host_to_be(new_prot_addr_fmt);
|
||||
void ARP::prot_addr_format(uint16_t format) {
|
||||
header_.proto_address_format = Endian::host_to_be(format);
|
||||
}
|
||||
|
||||
void ARP::hw_addr_length(uint8_t new_hw_addr_len) {
|
||||
this->_arp.ar_hln = new_hw_addr_len;
|
||||
void ARP::hw_addr_length(uint8_t length) {
|
||||
header_.hw_address_length = length;
|
||||
}
|
||||
|
||||
void ARP::prot_addr_length(uint8_t new_prot_addr_len) {
|
||||
this->_arp.ar_pln = new_prot_addr_len;
|
||||
void ARP::prot_addr_length(uint8_t length) {
|
||||
header_.proto_address_length = length;
|
||||
}
|
||||
|
||||
void ARP::opcode(Flags new_opcode) {
|
||||
this->_arp.ar_op = Endian::host_to_be<uint16_t>(new_opcode);
|
||||
void ARP::opcode(Flags code) {
|
||||
header_.opcode = Endian::host_to_be<uint16_t>(code);
|
||||
}
|
||||
|
||||
uint32_t ARP::header_size() const {
|
||||
return sizeof(arphdr);
|
||||
return sizeof(header_);
|
||||
}
|
||||
|
||||
void ARP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
|
||||
void ARP::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
stream.write(_arp);
|
||||
stream.write(header_);
|
||||
}
|
||||
|
||||
bool ARP::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
if(total_sz < sizeof(arphdr))
|
||||
bool ARP::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
if (total_sz < sizeof(header_)) {
|
||||
return false;
|
||||
const arphdr *arp_ptr = (const arphdr*)ptr;
|
||||
return arp_ptr->ar_sip == _arp.ar_tip && arp_ptr->ar_tip == _arp.ar_sip;
|
||||
}
|
||||
const arp_header* arp_ptr = (const arp_header*)ptr;
|
||||
return arp_ptr->sender_ip_address == header_.target_ip_address &&
|
||||
arp_ptr->target_ip_address == header_.sender_ip_address;
|
||||
}
|
||||
|
||||
EthernetII ARP::make_arp_request(ipaddress_type target, ipaddress_type sender,
|
||||
const hwaddress_type &hw_snd)
|
||||
{
|
||||
/* Create ARP packet and set its attributes */
|
||||
EthernetII ARP::make_arp_request(ipaddress_type target,
|
||||
ipaddress_type sender,
|
||||
const hwaddress_type& hw_snd) {
|
||||
// Create ARP packet and set its attributes
|
||||
ARP arp;
|
||||
arp.target_ip_addr(target);
|
||||
arp.sender_ip_addr(sender);
|
||||
arp.sender_hw_addr(hw_snd);
|
||||
arp.opcode(REQUEST);
|
||||
|
||||
/* Create the EthernetII PDU with the ARP PDU as its inner PDU */
|
||||
// Create the EthernetII PDU with the ARP PDU as its inner PDU
|
||||
return EthernetII(EthernetII::BROADCAST, hw_snd) / arp;
|
||||
}
|
||||
|
||||
EthernetII ARP::make_arp_reply(ipaddress_type target, ipaddress_type sender,
|
||||
const hwaddress_type &hw_tgt, const hwaddress_type &hw_snd)
|
||||
{
|
||||
/* Create ARP packet and set its attributes */
|
||||
EthernetII ARP::make_arp_reply(ipaddress_type target,
|
||||
ipaddress_type sender,
|
||||
const hwaddress_type& hw_tgt,
|
||||
const hwaddress_type& hw_snd) {
|
||||
// Create ARP packet and set its attributes
|
||||
ARP arp(target, sender, hw_tgt, hw_snd);
|
||||
arp.opcode(REPLY);
|
||||
|
||||
/* Create the EthernetII PDU with the ARP PDU as its inner PDU */
|
||||
// Create the EthernetII PDU with the ARP PDU as its inner PDU
|
||||
return EthernetII(hw_tgt, hw_snd) / arp;
|
||||
}
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
@@ -33,98 +33,100 @@
|
||||
#include "exceptions.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::copy;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins{
|
||||
|
||||
BootP::BootP()
|
||||
: _bootp(), _vend(64) {
|
||||
: bootp_(), vend_(64) {
|
||||
|
||||
}
|
||||
|
||||
BootP::BootP(const uint8_t *buffer, uint32_t total_sz, uint32_t vend_field_size)
|
||||
: _vend(vend_field_size)
|
||||
{
|
||||
BootP::BootP(const uint8_t* buffer, uint32_t total_sz, uint32_t vend_field_size)
|
||||
: vend_(vend_field_size) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_bootp);
|
||||
buffer += sizeof(bootphdr);
|
||||
total_sz -= sizeof(bootphdr);
|
||||
_vend.assign(stream.pointer(), stream.pointer() + vend_field_size);
|
||||
stream.read(bootp_);
|
||||
if (!stream.can_read(vend_field_size)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
stream.read(vend_, vend_field_size);
|
||||
}
|
||||
|
||||
uint32_t BootP::header_size() const {
|
||||
return static_cast<uint32_t>(sizeof(bootphdr) + _vend.size());
|
||||
return static_cast<uint32_t>(sizeof(bootp_) + vend_.size());
|
||||
}
|
||||
|
||||
void BootP::opcode(uint8_t new_opcode) {
|
||||
_bootp.opcode = new_opcode;
|
||||
void BootP::opcode(uint8_t code) {
|
||||
bootp_.opcode = code;
|
||||
}
|
||||
|
||||
void BootP::htype(uint8_t new_htype) {
|
||||
_bootp.htype = new_htype;
|
||||
void BootP::htype(uint8_t type) {
|
||||
bootp_.htype = type;
|
||||
}
|
||||
|
||||
void BootP::hlen(uint8_t new_hlen) {
|
||||
_bootp.hlen = new_hlen;
|
||||
void BootP::hlen(uint8_t length) {
|
||||
bootp_.hlen = length;
|
||||
}
|
||||
|
||||
void BootP::hops(uint8_t new_hops) {
|
||||
_bootp.hops = new_hops;
|
||||
void BootP::hops(uint8_t count) {
|
||||
bootp_.hops = count;
|
||||
}
|
||||
|
||||
void BootP::xid(uint32_t new_xid) {
|
||||
_bootp.xid = Endian::host_to_be(new_xid);
|
||||
void BootP::xid(uint32_t identifier) {
|
||||
bootp_.xid = Endian::host_to_be(identifier);
|
||||
}
|
||||
|
||||
void BootP::secs(uint16_t new_secs) {
|
||||
_bootp.secs = Endian::host_to_be(new_secs);
|
||||
void BootP::secs(uint16_t value) {
|
||||
bootp_.secs = Endian::host_to_be(value);
|
||||
}
|
||||
|
||||
void BootP::padding(uint16_t new_padding) {
|
||||
_bootp.padding = Endian::host_to_be(new_padding);
|
||||
void BootP::padding(uint16_t value) {
|
||||
bootp_.padding = Endian::host_to_be(value);
|
||||
}
|
||||
|
||||
void BootP::ciaddr(ipaddress_type new_ciaddr) {
|
||||
_bootp.ciaddr = new_ciaddr;
|
||||
void BootP::ciaddr(ipaddress_type address) {
|
||||
bootp_.ciaddr = address;
|
||||
}
|
||||
|
||||
void BootP::yiaddr(ipaddress_type new_yiaddr) {
|
||||
_bootp.yiaddr = new_yiaddr;
|
||||
void BootP::yiaddr(ipaddress_type address) {
|
||||
bootp_.yiaddr = address;
|
||||
}
|
||||
|
||||
void BootP::siaddr(ipaddress_type new_siaddr) {
|
||||
_bootp.siaddr = new_siaddr;
|
||||
void BootP::siaddr(ipaddress_type address) {
|
||||
bootp_.siaddr = address;
|
||||
}
|
||||
|
||||
void BootP::giaddr(ipaddress_type new_giaddr) {
|
||||
_bootp.giaddr = new_giaddr;
|
||||
void BootP::giaddr(ipaddress_type address) {
|
||||
bootp_.giaddr = address;
|
||||
}
|
||||
|
||||
void BootP::sname(const uint8_t *new_sname) {
|
||||
//std::memcpy(_bootp.sname, new_sname, sizeof(_bootp.sname));
|
||||
std::copy(new_sname, new_sname + sizeof(_bootp.sname), _bootp.sname);
|
||||
void BootP::sname(const uint8_t* new_sname) {
|
||||
copy(new_sname, new_sname + sizeof(bootp_.sname), bootp_.sname);
|
||||
}
|
||||
|
||||
void BootP::file(const uint8_t *new_file) {
|
||||
//std::memcpy(_bootp.file, new_file, sizeof(_bootp.file));
|
||||
std::copy(new_file, new_file + sizeof(_bootp.file), _bootp.file);
|
||||
void BootP::file(const uint8_t* new_file) {
|
||||
copy(new_file, new_file + sizeof(bootp_.file), bootp_.file);
|
||||
}
|
||||
|
||||
void BootP::vend(const vend_type &new_vend) {
|
||||
_vend = new_vend;
|
||||
void BootP::vend(const vend_type& newvend_) {
|
||||
vend_ = newvend_;
|
||||
}
|
||||
|
||||
void BootP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
|
||||
void BootP::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
stream.write(_bootp);
|
||||
stream.write(_vend.begin(), _vend.end());
|
||||
stream.write(bootp_);
|
||||
stream.write(vend_.begin(), vend_.end());
|
||||
}
|
||||
|
||||
bool BootP::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
if(total_sz < sizeof(bootphdr))
|
||||
bool BootP::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
if (total_sz < sizeof(bootp_)) {
|
||||
return false;
|
||||
const bootphdr *bootp_ptr = (const bootphdr *)ptr;
|
||||
return bootp_ptr->xid == _bootp.xid;
|
||||
}
|
||||
}
|
||||
const bootp_header* bootp_ptr = (const bootp_header *)ptr;
|
||||
return bootp_ptr->xid == bootp_.xid;
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
340
src/crypto.cpp
340
src/crypto.cpp
@@ -40,42 +40,57 @@
|
||||
#include "dot11/dot11_beacon.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
using std::string;
|
||||
using std::make_pair;
|
||||
using std::equal;
|
||||
using std::copy;
|
||||
using std::min;
|
||||
using std::max;
|
||||
using std::lexicographical_compare;
|
||||
using std::fill;
|
||||
using std::runtime_error;
|
||||
|
||||
namespace Tins {
|
||||
namespace Crypto {
|
||||
|
||||
WEPDecrypter::WEPDecrypter()
|
||||
: key_buffer(4) {
|
||||
: key_buffer_(4) {
|
||||
|
||||
}
|
||||
|
||||
void WEPDecrypter::add_password(const address_type &addr, const std::string &password) {
|
||||
passwords[addr] = password;
|
||||
key_buffer.resize(std::max(3 + password.size(), key_buffer.size()));
|
||||
void WEPDecrypter::add_password(const address_type& addr, const string& password) {
|
||||
passwords_[addr] = password;
|
||||
key_buffer_.resize(max(3 + password.size(), key_buffer_.size()));
|
||||
}
|
||||
|
||||
void WEPDecrypter::remove_password(const address_type &addr) {
|
||||
passwords.erase(addr);
|
||||
void WEPDecrypter::remove_password(const address_type& addr) {
|
||||
passwords_.erase(addr);
|
||||
}
|
||||
|
||||
bool WEPDecrypter::decrypt(PDU &pdu) {
|
||||
Dot11Data *dot11 = pdu.find_pdu<Dot11Data>();
|
||||
if(dot11) {
|
||||
RawPDU *raw = dot11->find_pdu<RawPDU>();
|
||||
if(raw) {
|
||||
bool WEPDecrypter::decrypt(PDU& pdu) {
|
||||
Dot11Data* dot11 = pdu.find_pdu<Dot11Data>();
|
||||
if (dot11) {
|
||||
RawPDU* raw = dot11->find_pdu<RawPDU>();
|
||||
if (raw) {
|
||||
address_type addr;
|
||||
if(!dot11->from_ds() && !dot11->to_ds())
|
||||
if (!dot11->from_ds() && !dot11->to_ds()) {
|
||||
addr = dot11->addr3();
|
||||
else if(!dot11->from_ds() && dot11->to_ds())
|
||||
}
|
||||
else if (!dot11->from_ds() && dot11->to_ds()) {
|
||||
addr = dot11->addr1();
|
||||
else if(dot11->from_ds() && !dot11->to_ds())
|
||||
}
|
||||
else if (dot11->from_ds() && !dot11->to_ds()) {
|
||||
addr = dot11->addr2();
|
||||
else
|
||||
}
|
||||
else {
|
||||
// ????
|
||||
addr = dot11->addr3();
|
||||
passwords_type::iterator it = passwords.find(addr);
|
||||
if(it != passwords.end()) {
|
||||
}
|
||||
passwords_type::iterator it = passwords_.find(addr);
|
||||
if (it != passwords_.end()) {
|
||||
dot11->inner_pdu(decrypt(*raw, it->second));
|
||||
// If its valid, then return true
|
||||
if(dot11->inner_pdu()) {
|
||||
if (dot11->inner_pdu()) {
|
||||
// it's no longer encrypted.
|
||||
dot11->wep(0);
|
||||
return true;
|
||||
@@ -86,29 +101,31 @@ bool WEPDecrypter::decrypt(PDU &pdu) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PDU *WEPDecrypter::decrypt(RawPDU &raw, const std::string &password) {
|
||||
RawPDU::payload_type &pload = raw.payload();
|
||||
PDU* WEPDecrypter::decrypt(RawPDU& raw, const string& password) {
|
||||
RawPDU::payload_type& pload = raw.payload();
|
||||
// We require at least the IV, the encrypted checksum and something to decrypt
|
||||
if(pload.size() <= 8)
|
||||
if (pload.size() <= 8) {
|
||||
return 0;
|
||||
std::copy(pload.begin(), pload.begin() + 3, key_buffer.begin());
|
||||
std::copy(password.begin(), password.end(), key_buffer.begin() + 3);
|
||||
}
|
||||
copy(pload.begin(), pload.begin() + 3, key_buffer_.begin());
|
||||
copy(password.begin(), password.end(), key_buffer_.begin() + 3);
|
||||
|
||||
// Generate the key
|
||||
RC4Key key(key_buffer.begin(), key_buffer.begin() + password.size() + 3);
|
||||
RC4Key key(key_buffer_.begin(), key_buffer_.begin() + password.size() + 3);
|
||||
rc4(pload.begin() + 4, pload.end(), key, pload.begin());
|
||||
uint32_t payload_size = static_cast<uint32_t>(pload.size() - 8);
|
||||
uint32_t crc = Utils::crc32(&pload[0], payload_size);
|
||||
if(pload[pload.size() - 8] != (crc & 0xff) ||
|
||||
if (pload[pload.size() - 8] != (crc & 0xff) ||
|
||||
pload[pload.size() - 7] != ((crc >> 8) & 0xff) ||
|
||||
pload[pload.size() - 6] != ((crc >> 16) & 0xff) ||
|
||||
pload[pload.size() - 5] != ((crc >> 24) & 0xff))
|
||||
pload[pload.size() - 5] != ((crc >> 24) & 0xff)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
return new SNAP(&pload[0], payload_size);
|
||||
}
|
||||
catch(std::runtime_error&) {
|
||||
catch (exception_base&) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -118,17 +135,17 @@ PDU *WEPDecrypter::decrypt(RawPDU &raw, const std::string &password) {
|
||||
|
||||
using WPA2::SessionKeys;
|
||||
|
||||
const HWAddress<6> &min(const HWAddress<6>& lhs, const HWAddress<6>& rhs) {
|
||||
const HWAddress<6>& min(const HWAddress<6>& lhs, const HWAddress<6>& rhs) {
|
||||
return lhs < rhs ? lhs : rhs;
|
||||
}
|
||||
|
||||
const HWAddress<6> &max(const HWAddress<6>& lhs, const HWAddress<6>& rhs) {
|
||||
const HWAddress<6>& max(const HWAddress<6>& lhs, const HWAddress<6>& rhs) {
|
||||
return lhs < rhs ? rhs : lhs;
|
||||
}
|
||||
|
||||
template<typename InputIterator1, typename InputIterator2, typename OutputIterator>
|
||||
void xor_range(InputIterator1 src1, InputIterator2 src2, OutputIterator dst, size_t sz) {
|
||||
for(size_t i = 0; i < sz; ++i) {
|
||||
for (size_t i = 0; i < sz; ++i) {
|
||||
*dst++ = *src1++ ^ *src2++;
|
||||
}
|
||||
}
|
||||
@@ -224,13 +241,16 @@ uint16_t lower_byte(uint16_t value) {
|
||||
return value & 0xff;
|
||||
}
|
||||
|
||||
HWAddress<6> get_bssid(const Dot11Data &dot11) {
|
||||
if(dot11.from_ds() && !dot11.to_ds())
|
||||
HWAddress<6> get_bssid(const Dot11Data& dot11) {
|
||||
if (dot11.from_ds() && !dot11.to_ds()) {
|
||||
return dot11.addr3();
|
||||
else if(!dot11.from_ds() && dot11.to_ds())
|
||||
}
|
||||
else if (!dot11.from_ds() && dot11.to_ds()) {
|
||||
return dot11.addr2();
|
||||
else
|
||||
}
|
||||
else {
|
||||
return dot11.addr2();
|
||||
}
|
||||
}
|
||||
|
||||
namespace WPA2 {
|
||||
@@ -243,51 +263,55 @@ SessionKeys::SessionKeys() {
|
||||
}
|
||||
|
||||
SessionKeys::SessionKeys(const ptk_type& ptk, bool is_ccmp)
|
||||
: ptk(ptk), is_ccmp(is_ccmp) {
|
||||
if (ptk.size() != PTK_SIZE) {
|
||||
: ptk_(ptk), is_ccmp_(is_ccmp) {
|
||||
if (ptk_.size() != PTK_SIZE) {
|
||||
throw invalid_handshake();
|
||||
}
|
||||
}
|
||||
|
||||
SessionKeys::SessionKeys(const RSNHandshake &hs, const pmk_type &pmk)
|
||||
: ptk(PTK_SIZE) {
|
||||
SessionKeys::SessionKeys(const RSNHandshake& hs, const pmk_type& pmk)
|
||||
: ptk_(PTK_SIZE) {
|
||||
if (pmk.size() != PMK_SIZE) {
|
||||
throw invalid_handshake();
|
||||
}
|
||||
|
||||
uint8_t PKE[100] = "Pairwise key expansion";
|
||||
uint8_t MIC[20];
|
||||
is_ccmp = (hs.handshake()[3].key_descriptor() == 2);
|
||||
is_ccmp_ = (hs.handshake()[3].key_descriptor() == 2);
|
||||
|
||||
min(hs.client_address(), hs.supplicant_address()).copy(PKE + 23);
|
||||
max(hs.client_address(), hs.supplicant_address()).copy(PKE + 29);
|
||||
const uint8_t *nonce1 = hs.handshake()[1].nonce(),
|
||||
const uint8_t* nonce1 = hs.handshake()[1].nonce(),
|
||||
*nonce2 = hs.handshake()[2].nonce();
|
||||
if(std::lexicographical_compare(nonce1, nonce1 + 32, nonce2, nonce2 + 32)) {
|
||||
std::copy(nonce1, nonce1 + 32, PKE + 35);
|
||||
std::copy(nonce2, nonce2 + 32, PKE + 67);
|
||||
if (lexicographical_compare(nonce1, nonce1 + 32, nonce2, nonce2 + 32)) {
|
||||
copy(nonce1, nonce1 + 32, PKE + 35);
|
||||
copy(nonce2, nonce2 + 32, PKE + 67);
|
||||
}
|
||||
else {
|
||||
std::copy(nonce2, nonce2 + 32, PKE + 35);
|
||||
std::copy(nonce1, nonce1 + 32, PKE + 67);
|
||||
copy(nonce2, nonce2 + 32, PKE + 35);
|
||||
copy(nonce1, nonce1 + 32, PKE + 67);
|
||||
}
|
||||
for(int i(0); i < 4; ++i) {
|
||||
for (int i(0); i < 4; ++i) {
|
||||
PKE[99] = i;
|
||||
HMAC(EVP_sha1(), &pmk[0], pmk.size(), PKE, 100, &ptk[0] + i * 20, 0);
|
||||
HMAC(EVP_sha1(), &pmk[0], pmk.size(), PKE, 100, &ptk_[0] + i * 20, 0);
|
||||
}
|
||||
RSNEAPOL& last_hs = const_cast<RSNEAPOL&>(hs.handshake()[3]);
|
||||
PDU::serialization_type buffer = last_hs.serialize();
|
||||
fill(buffer.begin() + 81, buffer.begin() + 81 + 16, 0);
|
||||
if (is_ccmp_) {
|
||||
HMAC(EVP_sha1(), &ptk_[0], 16, &buffer[0], buffer.size(), MIC, 0);
|
||||
}
|
||||
else {
|
||||
HMAC(EVP_md5(), &ptk_[0], 16, &buffer[0], buffer.size(), MIC, 0);
|
||||
}
|
||||
PDU::serialization_type buffer = const_cast<RSNEAPOL&>(hs.handshake()[3]).serialize();
|
||||
std::fill(buffer.begin() + 81, buffer.begin() + 81 + 16, 0);
|
||||
if(is_ccmp)
|
||||
HMAC(EVP_sha1(), &ptk[0], 16, &buffer[0], buffer.size(), MIC, 0);
|
||||
else
|
||||
HMAC(EVP_md5(), &ptk[0], 16, &buffer[0], buffer.size(), MIC, 0);
|
||||
|
||||
if(!std::equal(MIC, MIC + RSNEAPOL::mic_size, hs.handshake()[3].mic()))
|
||||
if (!equal(MIC, MIC + RSNEAPOL::mic_size, last_hs.mic())) {
|
||||
throw invalid_handshake();
|
||||
}
|
||||
}
|
||||
|
||||
SNAP *SessionKeys::ccmp_decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) const {
|
||||
RawPDU::payload_type &pload = raw.payload();
|
||||
SNAP* SessionKeys::ccmp_decrypt_unicast(const Dot11Data& dot11, RawPDU& raw) const {
|
||||
RawPDU::payload_type& pload = raw.payload();
|
||||
uint8_t MIC[16] = {0};
|
||||
uint8_t PN[6] = {
|
||||
pload[7],
|
||||
@@ -301,8 +325,9 @@ SNAP *SessionKeys::ccmp_decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) con
|
||||
uint8_t AAD[32] = {0};
|
||||
AAD[0] = 0;
|
||||
AAD[1] = 22 + 6 * int(dot11.from_ds() && dot11.to_ds());
|
||||
if(dot11.subtype() == Dot11::QOS_DATA_DATA)
|
||||
if (dot11.subtype() == Dot11::QOS_DATA_DATA) {
|
||||
AAD[1] += 2;
|
||||
}
|
||||
AAD[2] = dot11.protocol() | (dot11.type() << 2) | ((dot11.subtype() << 4) & 0x80);
|
||||
AAD[3] = 0x40 | dot11.to_ds() | (dot11.from_ds() << 1) |
|
||||
(dot11.more_frag() << 2) | (dot11.order() << 7);
|
||||
@@ -313,11 +338,12 @@ SNAP *SessionKeys::ccmp_decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) con
|
||||
AAD[22] = dot11.frag_num();
|
||||
AAD[23] = 0;
|
||||
|
||||
if(dot11.from_ds() && dot11.to_ds())
|
||||
if (dot11.from_ds() && dot11.to_ds()) {
|
||||
dot11.addr4().copy(AAD + 24);
|
||||
}
|
||||
|
||||
AES_KEY ctx;
|
||||
AES_set_encrypt_key(&ptk[0] + 32, 128, &ctx);
|
||||
AES_set_encrypt_key(&ptk_[0] + 32, 128, &ctx);
|
||||
uint8_t crypted_block[16];
|
||||
size_t total_sz = raw.payload_size() - 16, offset = 8, blocks = (total_sz + 15) / 16;
|
||||
|
||||
@@ -325,7 +351,7 @@ SNAP *SessionKeys::ccmp_decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) con
|
||||
counter[0] = 0x59;
|
||||
counter[1] = 0;
|
||||
dot11.addr2().copy(counter + 2);
|
||||
std::copy(PN, PN + 6, counter + 8);
|
||||
copy(PN, PN + 6, counter + 8);
|
||||
counter[14] = (total_sz >> 8) & 0xff;
|
||||
counter[15] = total_sz & 0xff;
|
||||
|
||||
@@ -339,12 +365,13 @@ SNAP *SessionKeys::ccmp_decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) con
|
||||
counter[14] = counter[15] = 0;
|
||||
AES_encrypt(counter, crypted_block, &ctx);
|
||||
uint8_t nice_MIC[8];
|
||||
std::copy(pload.begin() + pload.size() - 8, pload.end(), nice_MIC);
|
||||
copy(pload.begin() + pload.size() - 8, pload.end(), nice_MIC);
|
||||
xor_range(crypted_block, nice_MIC, nice_MIC, 8);
|
||||
for(size_t i = 1; i <= blocks; ++i) {
|
||||
for (size_t i = 1; i <= blocks; ++i) {
|
||||
size_t block_sz = (i == blocks) ? (total_sz % 16) : 16;
|
||||
if(block_sz == 0)
|
||||
if (block_sz == 0) {
|
||||
block_sz = 16;
|
||||
}
|
||||
counter[14] = (i >> 8) & 0xff;
|
||||
counter[15] = i & 0xff;
|
||||
AES_encrypt(counter, crypted_block, &ctx );
|
||||
@@ -355,14 +382,17 @@ SNAP *SessionKeys::ccmp_decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) con
|
||||
AES_encrypt(MIC, MIC, &ctx);
|
||||
offset += block_sz;
|
||||
}
|
||||
return (std::equal(nice_MIC, nice_MIC + sizeof(nice_MIC), MIC)) ?
|
||||
new SNAP(&pload[0], total_sz) :
|
||||
0;
|
||||
if (equal(nice_MIC, nice_MIC + sizeof(nice_MIC), MIC)) {
|
||||
return new SNAP(&pload[0], total_sz);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
RC4Key SessionKeys::generate_rc4_key(const Dot11Data &dot11, const RawPDU &raw) const {
|
||||
const RawPDU::payload_type &pload = raw.payload();
|
||||
const uint8_t *tk = &ptk[0] + 32;
|
||||
RC4Key SessionKeys::generate_rc4_key(const Dot11Data& dot11, const RawPDU& raw) const {
|
||||
const RawPDU::payload_type& pload = raw.payload();
|
||||
const uint8_t* tk = &ptk_[0] + 32;
|
||||
Internals::byte_array<16> rc4_key;
|
||||
uint16_t ppk[6];
|
||||
const Dot11::address_type addr = dot11.addr2();
|
||||
@@ -373,7 +403,7 @@ RC4Key SessionKeys::generate_rc4_key(const Dot11Data &dot11, const RawPDU &raw)
|
||||
ppk[3] = join_bytes(addr[3], addr[2]);
|
||||
ppk[4] = join_bytes(addr[5], addr[4]);
|
||||
|
||||
for(size_t i = 0; i < 4; ++i) {
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
ppk[0] += sbox(ppk[4] ^ join_bytes(tk[1], tk[0]));
|
||||
ppk[1] += sbox(ppk[0] ^ join_bytes(tk[5], tk[4]));
|
||||
ppk[2] += sbox(ppk[1] ^ join_bytes(tk[9], tk[8]));
|
||||
@@ -424,41 +454,43 @@ RC4Key SessionKeys::generate_rc4_key(const Dot11Data &dot11, const RawPDU &raw)
|
||||
return RC4Key(rc4_key.begin(), rc4_key.end());
|
||||
}
|
||||
|
||||
SNAP *SessionKeys::tkip_decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) const {
|
||||
SNAP* SessionKeys::tkip_decrypt_unicast(const Dot11Data& dot11, RawPDU& raw) const {
|
||||
// at least 20 bytes for IV + crc + stuff
|
||||
if(raw.payload_size() <= 20)
|
||||
if (raw.payload_size() <= 20) {
|
||||
return 0;
|
||||
}
|
||||
Crypto::RC4Key key = generate_rc4_key(dot11, raw);
|
||||
RawPDU::payload_type &pload = raw.payload();
|
||||
RawPDU::payload_type& pload = raw.payload();
|
||||
rc4(pload.begin() + 8, pload.end(), key, pload.begin());
|
||||
|
||||
uint32_t crc = Utils::crc32(&pload[0], pload.size() - 12);
|
||||
if(pload[pload.size() - 12] != (crc & 0xff) ||
|
||||
if (pload[pload.size() - 12] != (crc & 0xff) ||
|
||||
pload[pload.size() - 11] != ((crc >> 8) & 0xff) ||
|
||||
pload[pload.size() - 10] != ((crc >> 16) & 0xff) ||
|
||||
pload[pload.size() - 9] != ((crc >> 24) & 0xff))
|
||||
pload[pload.size() - 9] != ((crc >> 24) & 0xff)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return new SNAP(&pload[0], pload.size() - 20);
|
||||
}
|
||||
|
||||
SNAP *SessionKeys::decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) const {
|
||||
return is_ccmp ?
|
||||
ccmp_decrypt_unicast(dot11, raw) :
|
||||
tkip_decrypt_unicast(dot11, raw);
|
||||
SNAP* SessionKeys::decrypt_unicast(const Dot11Data& dot11, RawPDU& raw) const {
|
||||
return is_ccmp_ ?
|
||||
ccmp_decrypt_unicast(dot11, raw) :
|
||||
tkip_decrypt_unicast(dot11, raw);
|
||||
}
|
||||
|
||||
const SessionKeys::ptk_type& SessionKeys::get_ptk() const {
|
||||
return ptk;
|
||||
return ptk_;
|
||||
}
|
||||
|
||||
bool SessionKeys::uses_ccmp() const {
|
||||
return is_ccmp;
|
||||
return is_ccmp_;
|
||||
}
|
||||
|
||||
// supplicant_data
|
||||
|
||||
SupplicantData::SupplicantData(const std::string &psk, const std::string &ssid)
|
||||
SupplicantData::SupplicantData(const string& psk, const string& ssid)
|
||||
: pmk_(SessionKeys::PMK_SIZE) {
|
||||
PKCS5_PBKDF2_HMAC_SHA1(
|
||||
psk.c_str(),
|
||||
@@ -471,106 +503,122 @@ SupplicantData::SupplicantData(const std::string &psk, const std::string &ssid)
|
||||
);
|
||||
}
|
||||
|
||||
const SupplicantData::pmk_type &SupplicantData::pmk() const {
|
||||
const SupplicantData::pmk_type& SupplicantData::pmk() const {
|
||||
return pmk_;
|
||||
}
|
||||
} // namespace WPA2
|
||||
|
||||
void WPA2Decrypter::add_ap_data(const std::string &psk, const std::string &ssid) {
|
||||
pmks.insert(std::make_pair(ssid, WPA2::SupplicantData(psk, ssid)));
|
||||
void WPA2Decrypter::add_ap_data(const string& psk, const string& ssid) {
|
||||
pmks_.insert(make_pair(ssid, WPA2::SupplicantData(psk, ssid)));
|
||||
}
|
||||
|
||||
void WPA2Decrypter::add_ap_data(const std::string &psk, const std::string &ssid,
|
||||
const address_type &addr)
|
||||
{
|
||||
void WPA2Decrypter::add_ap_data(const string& psk,
|
||||
const string& ssid,
|
||||
const address_type& addr) {
|
||||
add_ap_data(psk, ssid);
|
||||
add_access_point(ssid, addr);
|
||||
}
|
||||
|
||||
void WPA2Decrypter::add_access_point(const std::string &ssid, const address_type &addr) {
|
||||
pmks_map::const_iterator it = pmks.find(ssid);
|
||||
if(it == pmks.end())
|
||||
throw std::runtime_error("supplicant data not registered");
|
||||
aps.insert(std::make_pair(addr, it->second));
|
||||
void WPA2Decrypter::add_access_point(const string& ssid, const address_type& addr) {
|
||||
pmks_map::const_iterator it = pmks_.find(ssid);
|
||||
if (it == pmks_.end()) {
|
||||
throw runtime_error("Supplicant data not registered");
|
||||
}
|
||||
aps_.insert(make_pair(addr, it->second));
|
||||
}
|
||||
|
||||
void WPA2Decrypter::add_decryption_keys(const addr_pair& addresses, const SessionKeys& session_keys) {
|
||||
void WPA2Decrypter::add_decryption_keys(const addr_pair& addresses,
|
||||
const SessionKeys& session_keys) {
|
||||
addr_pair sorted_pair = make_addr_pair(addresses.first, addresses.second);
|
||||
keys[sorted_pair] = session_keys;
|
||||
keys_[sorted_pair] = session_keys;
|
||||
}
|
||||
|
||||
void WPA2Decrypter::try_add_keys(const Dot11Data &dot11, const RSNHandshake &hs) {
|
||||
void WPA2Decrypter::try_add_keys(const Dot11Data& dot11, const RSNHandshake& hs) {
|
||||
bssids_map::const_iterator it = find_ap(dot11);
|
||||
if(it != aps.end()) {
|
||||
if (it != aps_.end()) {
|
||||
addr_pair addr_p = extract_addr_pair(dot11);
|
||||
try {
|
||||
SessionKeys session(hs, it->second.pmk());
|
||||
keys[addr_p] = session;
|
||||
keys_[addr_p] = session;
|
||||
}
|
||||
catch(WPA2::invalid_handshake&) {
|
||||
|
||||
}
|
||||
catch(WPA2::invalid_handshake&) { }
|
||||
}
|
||||
}
|
||||
|
||||
const WPA2Decrypter::keys_map& WPA2Decrypter::get_keys() const {
|
||||
return keys;
|
||||
return keys_;
|
||||
}
|
||||
|
||||
WPA2Decrypter::addr_pair WPA2Decrypter::extract_addr_pair(const Dot11Data &dot11) {
|
||||
if(dot11.from_ds() && !dot11.to_ds())
|
||||
WPA2Decrypter::addr_pair WPA2Decrypter::extract_addr_pair(const Dot11Data& dot11) {
|
||||
if (dot11.from_ds() && !dot11.to_ds()) {
|
||||
return make_addr_pair(dot11.addr2(), dot11.addr3());
|
||||
else if(!dot11.from_ds() && dot11.to_ds())
|
||||
return make_addr_pair(dot11.addr1(), dot11.addr2());
|
||||
else
|
||||
return make_addr_pair(dot11.addr2(), dot11.addr3());
|
||||
}
|
||||
|
||||
WPA2Decrypter::addr_pair WPA2Decrypter::extract_addr_pair_dst(const Dot11Data &dot11) {
|
||||
if(dot11.from_ds() && !dot11.to_ds())
|
||||
return make_addr_pair(dot11.addr1(), dot11.addr2());
|
||||
else if(!dot11.from_ds() && dot11.to_ds())
|
||||
return make_addr_pair(dot11.addr1(), dot11.addr3());
|
||||
else
|
||||
return make_addr_pair(dot11.addr1(), dot11.addr3());
|
||||
}
|
||||
|
||||
WPA2Decrypter::bssids_map::const_iterator WPA2Decrypter::find_ap(const Dot11Data &dot11) {
|
||||
if(dot11.from_ds() && !dot11.to_ds())
|
||||
return aps.find(dot11.addr2());
|
||||
else if(!dot11.from_ds() && dot11.to_ds())
|
||||
return aps.find(dot11.addr1());
|
||||
else
|
||||
return aps.find(dot11.addr3());
|
||||
}
|
||||
|
||||
bool WPA2Decrypter::decrypt(PDU &pdu) {
|
||||
if(capturer.process_packet(pdu)) {
|
||||
try_add_keys(pdu.rfind_pdu<Dot11Data>(), capturer.handshakes().front());
|
||||
capturer.clear_handshakes();
|
||||
}
|
||||
else if(const Dot11Beacon *beacon = pdu.find_pdu<Dot11Beacon>()) {
|
||||
if(aps.count(beacon->addr3()) == 0) {
|
||||
else if (!dot11.from_ds() && dot11.to_ds()) {
|
||||
return make_addr_pair(dot11.addr1(), dot11.addr2());
|
||||
}
|
||||
else {
|
||||
return make_addr_pair(dot11.addr2(), dot11.addr3());
|
||||
}
|
||||
}
|
||||
|
||||
WPA2Decrypter::addr_pair WPA2Decrypter::extract_addr_pair_dst(const Dot11Data& dot11) {
|
||||
if (dot11.from_ds() && !dot11.to_ds()) {
|
||||
return make_addr_pair(dot11.addr1(), dot11.addr2());
|
||||
}
|
||||
else if (!dot11.from_ds() && dot11.to_ds()) {
|
||||
return make_addr_pair(dot11.addr1(), dot11.addr3());
|
||||
}
|
||||
else {
|
||||
return make_addr_pair(dot11.addr1(), dot11.addr3());
|
||||
}
|
||||
}
|
||||
|
||||
WPA2Decrypter::bssids_map::const_iterator WPA2Decrypter::find_ap(const Dot11Data& dot11) {
|
||||
if (dot11.from_ds() && !dot11.to_ds()) {
|
||||
return aps_.find(dot11.addr2());
|
||||
}
|
||||
else if (!dot11.from_ds() && dot11.to_ds()) {
|
||||
return aps_.find(dot11.addr1());
|
||||
}
|
||||
else {
|
||||
return aps_.find(dot11.addr3());
|
||||
}
|
||||
}
|
||||
|
||||
bool WPA2Decrypter::decrypt(PDU& pdu) {
|
||||
if (capturer_.process_packet(pdu)) {
|
||||
try_add_keys(pdu.rfind_pdu<Dot11Data>(), capturer_.handshakes().front());
|
||||
capturer_.clear_handshakes();
|
||||
}
|
||||
else if (const Dot11Beacon* beacon = pdu.find_pdu<Dot11Beacon>()) {
|
||||
if (aps_.count(beacon->addr3()) == 0) {
|
||||
try {
|
||||
std::string ssid = beacon->ssid();
|
||||
if(pmks.count(ssid)) {
|
||||
string ssid = beacon->ssid();
|
||||
if (pmks_.count(ssid)) {
|
||||
add_access_point(ssid, beacon->addr3());
|
||||
}
|
||||
}
|
||||
catch(option_not_found&) { }
|
||||
catch(option_not_found&) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Dot11Data *data = pdu.find_pdu<Dot11Data>();
|
||||
RawPDU *raw = pdu.find_pdu<RawPDU>();
|
||||
if(data && raw && data->wep()) {
|
||||
Dot11Data* data = pdu.find_pdu<Dot11Data>();
|
||||
RawPDU* raw = pdu.find_pdu<RawPDU>();
|
||||
if (data && raw && data->wep()) {
|
||||
// search for the tuple (bssid, src_addr)
|
||||
keys_map::const_iterator it = keys.find(extract_addr_pair(*data));
|
||||
keys_map::const_iterator it = keys_.find(extract_addr_pair(*data));
|
||||
|
||||
// search for the tuple (bssid, dst_addr) if the above didn't work
|
||||
if(it == keys.end())
|
||||
it = keys.find(extract_addr_pair_dst(*data));
|
||||
if(it != keys.end()) {
|
||||
SNAP *snap = it->second.decrypt_unicast(*data, *raw);
|
||||
if(snap) {
|
||||
if (it == keys_.end()) {
|
||||
it = keys_.find(extract_addr_pair_dst(*data));
|
||||
}
|
||||
if (it != keys_.end()) {
|
||||
SNAP* snap = it->second.decrypt_unicast(*data, *raw);
|
||||
if (snap) {
|
||||
data->inner_pdu(snap);
|
||||
data->wep(0);
|
||||
return true;
|
||||
@@ -579,8 +627,10 @@ bool WPA2Decrypter::decrypt(PDU &pdu) {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} // namespace WPA2
|
||||
}
|
||||
|
||||
#endif // HAVE_WPA2_DECRYPTION
|
||||
|
||||
} // namespace Crypto
|
||||
} // namespace Tins
|
||||
|
||||
|
||||
78
src/dhcp.cpp
78
src/dhcp.cpp
@@ -37,6 +37,7 @@
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::list;
|
||||
using std::runtime_error;
|
||||
using std::find_if;
|
||||
@@ -48,20 +49,20 @@ namespace Tins {
|
||||
|
||||
// Magic cookie: uint32_t.
|
||||
DHCP::DHCP()
|
||||
: _size(sizeof(uint32_t)) {
|
||||
: size_(sizeof(uint32_t)) {
|
||||
opcode(BOOTREQUEST);
|
||||
htype(1); //ethernet
|
||||
hlen(EthernetII::address_type::address_size);
|
||||
}
|
||||
|
||||
DHCP::DHCP(const uint8_t *buffer, uint32_t total_sz)
|
||||
: BootP(buffer, total_sz, 0), _size(sizeof(uint32_t))
|
||||
{
|
||||
DHCP::DHCP(const uint8_t* buffer, uint32_t total_sz)
|
||||
: BootP(buffer, total_sz, 0), size_(sizeof(uint32_t)) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(BootP::header_size() - vend().size());
|
||||
const uint32_t magic_number = stream.read<uint32_t>();
|
||||
if (magic_number != Endian::host_to_be<uint32_t>(0x63825363))
|
||||
if (magic_number != Endian::host_to_be<uint32_t>(0x63825363)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
// While there's data left
|
||||
while (stream) {
|
||||
OptionTypes option_type;
|
||||
@@ -80,39 +81,39 @@ DHCP::DHCP(const uint8_t *buffer, uint32_t total_sz)
|
||||
}
|
||||
}
|
||||
|
||||
void DHCP::add_option(const option &opt) {
|
||||
void DHCP::add_option(const option& opt) {
|
||||
internal_add_option(opt);
|
||||
_options.push_back(opt);
|
||||
options_.push_back(opt);
|
||||
}
|
||||
|
||||
void DHCP::internal_add_option(const option &opt) {
|
||||
_size += static_cast<uint32_t>(opt.data_size() + (sizeof(uint8_t) << 1));
|
||||
void DHCP::internal_add_option(const option& opt) {
|
||||
size_ += static_cast<uint32_t>(opt.data_size() + (sizeof(uint8_t) << 1));
|
||||
}
|
||||
|
||||
bool DHCP::remove_option(OptionTypes type) {
|
||||
options_type::iterator iter = search_option_iterator(type);
|
||||
if (iter == _options.end()) {
|
||||
if (iter == options_.end()) {
|
||||
return false;
|
||||
}
|
||||
_size -= static_cast<uint32_t>(iter->data_size() + (sizeof(uint8_t) << 1));
|
||||
_options.erase(iter);
|
||||
size_ -= static_cast<uint32_t>(iter->data_size() + (sizeof(uint8_t) << 1));
|
||||
options_.erase(iter);
|
||||
return true;
|
||||
}
|
||||
|
||||
const DHCP::option *DHCP::search_option(OptionTypes opt) const {
|
||||
const DHCP::option* DHCP::search_option(OptionTypes opt) const {
|
||||
// Search for the iterator. If we found something, return it, otherwise return nullptr.
|
||||
options_type::const_iterator iter = search_option_iterator(opt);
|
||||
return (iter != _options.end()) ? &*iter : 0;
|
||||
return (iter != options_.end()) ? &*iter : 0;
|
||||
}
|
||||
|
||||
DHCP::options_type::const_iterator DHCP::search_option_iterator(OptionTypes opt) const {
|
||||
Internals::option_type_equality_comparator<option> comparator(opt);
|
||||
return find_if(_options.begin(), _options.end(), comparator);
|
||||
return find_if(options_.begin(), options_.end(), comparator);
|
||||
}
|
||||
|
||||
DHCP::options_type::iterator DHCP::search_option_iterator(OptionTypes opt) {
|
||||
Internals::option_type_equality_comparator<option> comparator(opt);
|
||||
return find_if(_options.begin(), _options.end(), comparator);
|
||||
return find_if(options_.begin(), options_.end(), comparator);
|
||||
}
|
||||
|
||||
void DHCP::type(Flags type) {
|
||||
@@ -164,22 +165,22 @@ DHCP::ipaddress_type DHCP::subnet_mask() const {
|
||||
return search_and_convert<ipaddress_type>(SUBNET_MASK);
|
||||
}
|
||||
|
||||
void DHCP::routers(const std::vector<ipaddress_type> &routers) {
|
||||
void DHCP::routers(const vector<ipaddress_type>& routers) {
|
||||
serialization_type buffer = serialize_list(routers);
|
||||
add_option(option(ROUTERS, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
std::vector<DHCP::ipaddress_type> DHCP::routers() const {
|
||||
return search_and_convert<std::vector<DHCP::ipaddress_type> >(ROUTERS);
|
||||
vector<DHCP::ipaddress_type> DHCP::routers() const {
|
||||
return search_and_convert<vector<DHCP::ipaddress_type> >(ROUTERS);
|
||||
}
|
||||
|
||||
void DHCP::domain_name_servers(const std::vector<ipaddress_type> &dns) {
|
||||
void DHCP::domain_name_servers(const vector<ipaddress_type>& dns) {
|
||||
serialization_type buffer = serialize_list(dns);
|
||||
add_option(option(DOMAIN_NAME_SERVERS, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
std::vector<DHCP::ipaddress_type> DHCP::domain_name_servers() const {
|
||||
return search_and_convert<std::vector<DHCP::ipaddress_type> >(DOMAIN_NAME_SERVERS);
|
||||
vector<DHCP::ipaddress_type> DHCP::domain_name_servers() const {
|
||||
return search_and_convert<vector<DHCP::ipaddress_type> >(DOMAIN_NAME_SERVERS);
|
||||
}
|
||||
|
||||
void DHCP::broadcast(ipaddress_type addr) {
|
||||
@@ -200,20 +201,20 @@ DHCP::ipaddress_type DHCP::requested_ip() const {
|
||||
return search_and_convert<ipaddress_type>(DHCP_REQUESTED_ADDRESS);
|
||||
}
|
||||
|
||||
void DHCP::domain_name(const string &name) {
|
||||
void DHCP::domain_name(const string& name) {
|
||||
add_option(option(DOMAIN_NAME, name.size(), (const uint8_t*)name.c_str()));
|
||||
}
|
||||
|
||||
std::string DHCP::domain_name() const {
|
||||
return search_and_convert<std::string>(DOMAIN_NAME);
|
||||
string DHCP::domain_name() const {
|
||||
return search_and_convert<string>(DOMAIN_NAME);
|
||||
}
|
||||
|
||||
void DHCP::hostname(const std::string &name) {
|
||||
void DHCP::hostname(const string& name) {
|
||||
add_option(option(HOST_NAME, name.size(), (const uint8_t*)name.c_str()));
|
||||
}
|
||||
|
||||
std::string DHCP::hostname() const {
|
||||
return search_and_convert<std::string>(HOST_NAME);
|
||||
string DHCP::hostname() const {
|
||||
return search_and_convert<string>(HOST_NAME);
|
||||
}
|
||||
|
||||
void DHCP::rebind_time(uint32_t time) {
|
||||
@@ -225,27 +226,29 @@ uint32_t DHCP::rebind_time() const {
|
||||
return search_and_convert<uint32_t>(DHCP_REBINDING_TIME);
|
||||
}
|
||||
|
||||
PDU::serialization_type DHCP::serialize_list(const std::vector<ipaddress_type> &ip_list) {
|
||||
PDU::serialization_type DHCP::serialize_list(const vector<ipaddress_type>& ip_list) {
|
||||
serialization_type buffer(ip_list.size() * sizeof(uint32_t));
|
||||
uint32_t *ptr = (uint32_t*)&buffer[0];
|
||||
for(std::vector<ipaddress_type>::const_iterator it = ip_list.begin(); it != ip_list.end(); ++it)
|
||||
uint32_t* ptr = (uint32_t*)&buffer[0];
|
||||
typedef vector<ipaddress_type>::const_iterator iterator;
|
||||
for (iterator it = ip_list.begin(); it != ip_list.end(); ++it) {
|
||||
*(ptr++) = *it;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
uint32_t DHCP::header_size() const {
|
||||
return static_cast<uint32_t>(BootP::header_size() - vend().size() + _size);
|
||||
return static_cast<uint32_t>(BootP::header_size() - vend().size() + size_);
|
||||
}
|
||||
|
||||
void DHCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
|
||||
if (_size) {
|
||||
vend_type &result = BootP::vend();
|
||||
result.resize(_size);
|
||||
void DHCP::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
if (size_) {
|
||||
vend_type& result = BootP::vend();
|
||||
result.resize(size_);
|
||||
// Build a stream over the vend vector
|
||||
OutputMemoryStream stream(&result[0], result.size());
|
||||
// Magic cookie
|
||||
stream.write(Endian::host_to_be<uint32_t>(0x63825363));
|
||||
for (options_type::const_iterator it = _options.begin(); it != _options.end(); ++it) {
|
||||
for (options_type::const_iterator it = options_.begin(); it != options_.end(); ++it) {
|
||||
stream.write(it->option());
|
||||
stream.write<uint8_t>(it->length_field());
|
||||
stream.write(it->data_ptr(), it->data_size());
|
||||
@@ -253,4 +256,5 @@ void DHCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *pa
|
||||
}
|
||||
BootP::write_serialization(buffer, total_sz, parent);
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
538
src/dhcpv6.cpp
538
src/dhcpv6.cpp
@@ -34,6 +34,11 @@
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::find_if;
|
||||
using std::copy;
|
||||
using std::vector;
|
||||
using std::runtime_error;
|
||||
using std::memcpy;
|
||||
using std::equal;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
@@ -41,13 +46,12 @@ using Tins::Memory::OutputMemoryStream;
|
||||
namespace Tins {
|
||||
|
||||
DHCPv6::DHCPv6()
|
||||
: header_data(), options_size() {
|
||||
: header_data_(), options_size_() {
|
||||
|
||||
}
|
||||
|
||||
DHCPv6::DHCPv6(const uint8_t *buffer, uint32_t total_sz)
|
||||
: options_size()
|
||||
{
|
||||
DHCPv6::DHCPv6(const uint8_t* buffer, uint32_t total_sz)
|
||||
: options_size_() {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
if (!stream) {
|
||||
throw malformed_packet();
|
||||
@@ -56,32 +60,25 @@ DHCPv6::DHCPv6(const uint8_t *buffer, uint32_t total_sz)
|
||||
const MessageType message_type = (MessageType)*stream.pointer();
|
||||
bool is_relay_msg = (message_type == RELAY_FORWARD || message_type == RELAY_REPLY);
|
||||
uint32_t required_size = is_relay_msg ? 2 : 4;
|
||||
stream.read(&header_data, required_size);
|
||||
stream.read(&header_data_, required_size);
|
||||
if (is_relay_message()) {
|
||||
if (!stream.can_read(ipaddress_type::address_size * 2)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
// Read both addresses
|
||||
link_addr = stream.pointer();
|
||||
peer_addr = stream.pointer() + ipaddress_type::address_size;
|
||||
stream.skip(ipaddress_type::address_size * 2);
|
||||
stream.read(link_addr_);
|
||||
stream.read(peer_addr_);
|
||||
}
|
||||
while (stream) {
|
||||
uint16_t opt = Endian::be_to_host(stream.read<uint16_t>());
|
||||
uint16_t data_size = Endian::be_to_host(stream.read<uint16_t>());
|
||||
if(!stream.can_read(data_size)) {
|
||||
uint16_t opt = stream.read_be<uint16_t>();
|
||||
uint16_t data_size = stream.read_be<uint16_t>();
|
||||
if (!stream.can_read(data_size)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
add_option(
|
||||
option(opt, stream.pointer(), stream.pointer() + data_size)
|
||||
);
|
||||
add_option(option(opt, stream.pointer(), stream.pointer() + data_size));
|
||||
stream.skip(data_size);
|
||||
}
|
||||
}
|
||||
|
||||
void DHCPv6::add_option(const option &opt) {
|
||||
void DHCPv6::add_option(const option& opt) {
|
||||
options_.push_back(opt);
|
||||
options_size += opt.data_size() + sizeof(uint16_t) * 2;
|
||||
options_size_ += opt.data_size() + sizeof(uint16_t) * 2;
|
||||
}
|
||||
|
||||
bool DHCPv6::remove_option(OptionTypes type) {
|
||||
@@ -89,12 +86,12 @@ bool DHCPv6::remove_option(OptionTypes type) {
|
||||
if (iter == options_.end()) {
|
||||
return false;
|
||||
}
|
||||
options_size -= iter->data_size() + sizeof(uint16_t) * 2;
|
||||
options_size_ -= iter->data_size() + sizeof(uint16_t) * 2;
|
||||
options_.erase(iter);
|
||||
return true;
|
||||
}
|
||||
|
||||
const DHCPv6::option *DHCPv6::search_option(OptionTypes type) const {
|
||||
const DHCPv6::option* DHCPv6::search_option(OptionTypes type) const {
|
||||
// Search for the iterator. If we found something, return it, otherwise return nullptr.
|
||||
options_type::const_iterator iter = search_option_iterator(type);
|
||||
return (iter != options_.end()) ? &*iter : 0;
|
||||
@@ -110,33 +107,33 @@ DHCPv6::options_type::iterator DHCPv6::search_option_iterator(OptionTypes type)
|
||||
return find_if(options_.begin(), options_.end(), comparator);
|
||||
}
|
||||
|
||||
void DHCPv6::write_option(const option &opt, OutputMemoryStream& stream) const {
|
||||
stream.write(Endian::host_to_be<uint16_t>(opt.option()));
|
||||
stream.write(Endian::host_to_be<uint16_t>(opt.length_field()));
|
||||
void DHCPv6::write_option(const option& opt, OutputMemoryStream& stream) const {
|
||||
stream.write_be<uint16_t>(opt.option());
|
||||
stream.write_be<uint16_t>(opt.length_field());
|
||||
stream.write(opt.data_ptr(), opt.data_size());
|
||||
}
|
||||
|
||||
void DHCPv6::msg_type(MessageType type) {
|
||||
header_data[0] = static_cast<uint8_t>(type);
|
||||
header_data_[0] = static_cast<uint8_t>(type);
|
||||
}
|
||||
|
||||
void DHCPv6::hop_count(uint8_t count) {
|
||||
header_data[1] = count;
|
||||
header_data_[1] = count;
|
||||
}
|
||||
|
||||
void DHCPv6::transaction_id(small_uint<24> id) {
|
||||
uint32_t id_32 = id;
|
||||
header_data[1] = id_32 >> 16;
|
||||
header_data[2] = id_32 >> 8;
|
||||
header_data[3] = id_32 & 0xff;
|
||||
header_data_[1] = id_32 >> 16;
|
||||
header_data_[2] = id_32 >> 8;
|
||||
header_data_[3] = id_32 & 0xff;
|
||||
}
|
||||
|
||||
void DHCPv6::peer_address(const ipaddress_type &addr) {
|
||||
peer_addr = addr;
|
||||
void DHCPv6::peer_address(const ipaddress_type& addr) {
|
||||
peer_addr_ = addr;
|
||||
}
|
||||
|
||||
void DHCPv6::link_address(const ipaddress_type &addr) {
|
||||
link_addr = addr;
|
||||
void DHCPv6::link_address(const ipaddress_type& addr) {
|
||||
link_addr_ = addr;
|
||||
}
|
||||
|
||||
bool DHCPv6::is_relay_message() const {
|
||||
@@ -144,25 +141,26 @@ bool DHCPv6::is_relay_message() const {
|
||||
}
|
||||
|
||||
uint32_t DHCPv6::header_size() const {
|
||||
return (is_relay_message() ? (2 + ipaddress_type::address_size * 2) : 4) + options_size;
|
||||
return (is_relay_message() ? (2 + ipaddress_type::address_size * 2) : 4) + options_size_;
|
||||
}
|
||||
|
||||
bool DHCPv6::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
if(!is_relay_message()) {
|
||||
if(total_sz < 4 || (ptr[0] == 12 || ptr[0] == 13))
|
||||
bool DHCPv6::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
if (!is_relay_message()) {
|
||||
if (total_sz < 4 || (ptr[0] == 12 || ptr[0] == 13)) {
|
||||
return false;
|
||||
return std::equal(header_data + 1, header_data + 4, ptr + 1);
|
||||
}
|
||||
return equal(header_data_ + 1, header_data_ + 4, ptr + 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DHCPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
|
||||
void DHCPv6::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *) {
|
||||
const uint32_t required_size = is_relay_message() ? 2 : 4;
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
stream.write(header_data, required_size);
|
||||
stream.write(header_data_, required_size);
|
||||
if (is_relay_message()) {
|
||||
stream.write(link_addr);
|
||||
stream.write(peer_addr);
|
||||
stream.write(link_addr_);
|
||||
stream.write(peer_addr_);
|
||||
}
|
||||
for (options_type::const_iterator it = options_.begin(); it != options_.end(); ++it) {
|
||||
write_option(*it, stream);
|
||||
@@ -254,147 +252,99 @@ DHCPv6::duid_type DHCPv6::server_id() const {
|
||||
// Option setters
|
||||
// ********************************************************************
|
||||
|
||||
void DHCPv6::ia_na(const ia_na_type &value) {
|
||||
std::vector<uint8_t> buffer(sizeof(uint32_t) * 3 + value.options.size());
|
||||
uint32_t *ptr = (uint32_t*)&buffer[0];
|
||||
*ptr++ = Endian::host_to_be(value.id);
|
||||
*ptr++ = Endian::host_to_be(value.t1);
|
||||
*ptr++ = Endian::host_to_be(value.t2);
|
||||
std::copy(
|
||||
value.options.begin(),
|
||||
value.options.end(),
|
||||
buffer.begin() + sizeof(uint32_t) * 3
|
||||
);
|
||||
add_option(
|
||||
option(IA_NA, buffer.begin(), buffer.end())
|
||||
);
|
||||
void DHCPv6::ia_na(const ia_na_type& value) {
|
||||
vector<uint8_t> buffer(sizeof(uint32_t) * 3 + value.options.size());
|
||||
OutputMemoryStream stream(buffer);
|
||||
stream.write_be(value.id);
|
||||
stream.write_be(value.t1);
|
||||
stream.write_be(value.t2);
|
||||
stream.write(value.options.begin(), value.options.end());
|
||||
add_option(option(IA_NA, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
void DHCPv6::ia_ta(const ia_ta_type &value) {
|
||||
std::vector<uint8_t> buffer(sizeof(uint32_t) + value.options.size());
|
||||
uint32_t *ptr = (uint32_t*)&buffer[0];
|
||||
*ptr++ = Endian::host_to_be(value.id);
|
||||
std::copy(
|
||||
value.options.begin(),
|
||||
value.options.end(),
|
||||
buffer.begin() + sizeof(uint32_t)
|
||||
);
|
||||
add_option(
|
||||
option(IA_TA, buffer.begin(), buffer.end())
|
||||
);
|
||||
void DHCPv6::ia_ta(const ia_ta_type& value) {
|
||||
vector<uint8_t> buffer(sizeof(uint32_t) + value.options.size());
|
||||
OutputMemoryStream stream(buffer);
|
||||
stream.write_be(value.id);
|
||||
stream.write(value.options.begin(), value.options.end());
|
||||
add_option(option(IA_TA, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
void DHCPv6::ia_address(const ia_address_type &value) {
|
||||
std::vector<uint8_t> buffer(
|
||||
void DHCPv6::ia_address(const ia_address_type& value) {
|
||||
vector<uint8_t> buffer(
|
||||
sizeof(uint32_t) * 2 + ipaddress_type::address_size + value.options.size()
|
||||
);
|
||||
uint32_t *ptr = (uint32_t*)&buffer[ipaddress_type::address_size];
|
||||
value.address.copy(&buffer[0]);
|
||||
*ptr++ = Endian::host_to_be(value.preferred_lifetime);
|
||||
*ptr++ = Endian::host_to_be(value.valid_lifetime);
|
||||
std::copy(
|
||||
value.options.begin(),
|
||||
value.options.end(),
|
||||
buffer.begin() + sizeof(uint32_t) * 2 + ipaddress_type::address_size
|
||||
);
|
||||
add_option(
|
||||
option(IA_ADDR, buffer.begin(), buffer.end())
|
||||
);
|
||||
OutputMemoryStream stream(buffer);
|
||||
stream.write(value.address);
|
||||
stream.write_be(value.preferred_lifetime);
|
||||
stream.write_be(value.valid_lifetime);
|
||||
stream.write(value.options.begin(), value.options.end());
|
||||
add_option(option(IA_ADDR, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
void DHCPv6::option_request(const option_request_type &value) {
|
||||
void DHCPv6::option_request(const option_request_type& value) {
|
||||
typedef option_request_type::const_iterator iterator;
|
||||
|
||||
std::vector<uint8_t> buffer(value.size() * sizeof(uint16_t));
|
||||
size_t index = 0;
|
||||
uint16_t uint16_t_buffer;
|
||||
for(iterator it = value.begin(); it != value.end(); ++it, index += 2) {
|
||||
uint16_t_buffer = Endian::host_to_be<uint16_t>(*it);
|
||||
std::memcpy(&buffer[index], &uint16_t_buffer, sizeof(uint16_t));
|
||||
vector<uint8_t> buffer(value.size() * sizeof(uint16_t));
|
||||
OutputMemoryStream stream(buffer);
|
||||
for (iterator it = value.begin(); it != value.end(); ++it) {
|
||||
stream.write_be(*it);
|
||||
}
|
||||
add_option(
|
||||
option(OPTION_REQUEST, buffer.begin(), buffer.end())
|
||||
);
|
||||
add_option(option(OPTION_REQUEST, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
void DHCPv6::preference(uint8_t value) {
|
||||
add_option(
|
||||
option(PREFERENCE, 1, &value)
|
||||
);
|
||||
add_option(option(PREFERENCE, 1, &value));
|
||||
}
|
||||
|
||||
void DHCPv6::elapsed_time(uint16_t value) {
|
||||
value = Endian::host_to_be(value);
|
||||
add_option(
|
||||
option(ELAPSED_TIME, 2, (const uint8_t*)&value)
|
||||
);
|
||||
add_option(option(ELAPSED_TIME, 2, (const uint8_t*)&value));
|
||||
}
|
||||
|
||||
void DHCPv6::relay_message(const relay_msg_type &value) {
|
||||
add_option(
|
||||
option(RELAY_MSG, value.begin(), value.end())
|
||||
);
|
||||
void DHCPv6::relay_message(const relay_msg_type& value) {
|
||||
add_option(option(RELAY_MSG, value.begin(), value.end()));
|
||||
}
|
||||
|
||||
void DHCPv6::authentication(const authentication_type &value) {
|
||||
std::vector<uint8_t> buffer(
|
||||
void DHCPv6::authentication(const authentication_type& value) {
|
||||
vector<uint8_t> buffer(
|
||||
sizeof(uint8_t) * 3 + sizeof(uint64_t) + value.auth_info.size()
|
||||
);
|
||||
buffer[0] = value.protocol;
|
||||
buffer[1] = value.algorithm;
|
||||
buffer[2] = value.rdm;
|
||||
uint64_t uint64_t_buffer = Endian::host_to_be(value.replay_detection);
|
||||
std::memcpy(&buffer[3], &uint64_t_buffer, sizeof(uint64_t));
|
||||
std::copy(
|
||||
value.auth_info.begin(),
|
||||
value.auth_info.end(),
|
||||
buffer.begin() + sizeof(uint8_t) * 3 + sizeof(uint64_t)
|
||||
);
|
||||
add_option(
|
||||
option(AUTH, buffer.begin(), buffer.end())
|
||||
);
|
||||
OutputMemoryStream stream(buffer);
|
||||
stream.write(value.protocol);
|
||||
stream.write(value.algorithm);
|
||||
stream.write(value.rdm);
|
||||
stream.write_be(value.replay_detection);
|
||||
stream.write(value.auth_info.begin(), value.auth_info.end());
|
||||
add_option(option(AUTH, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
void DHCPv6::server_unicast(const ipaddress_type &value) {
|
||||
add_option(
|
||||
option(UNICAST, value.begin(), value.end())
|
||||
);
|
||||
void DHCPv6::server_unicast(const ipaddress_type& value) {
|
||||
add_option(option(UNICAST, value.begin(), value.end()));
|
||||
}
|
||||
|
||||
void DHCPv6::status_code(const status_code_type &value) {
|
||||
std::vector<uint8_t> buffer(sizeof(uint16_t) + value.message.size());
|
||||
uint16_t uint16_t_buffer = Endian::host_to_be(value.code);
|
||||
std::memcpy(&buffer[0], &uint16_t_buffer, sizeof(uint16_t));
|
||||
std::copy(
|
||||
value.message.begin(),
|
||||
value.message.end(),
|
||||
buffer.begin() + sizeof(uint16_t)
|
||||
);
|
||||
add_option(
|
||||
option(STATUS_CODE, buffer.begin(), buffer.end())
|
||||
);
|
||||
void DHCPv6::status_code(const status_code_type& value) {
|
||||
vector<uint8_t> buffer(sizeof(uint16_t) + value.message.size());
|
||||
OutputMemoryStream stream(buffer);
|
||||
stream.write_be(value.code);
|
||||
stream.write(value.message.begin(), value.message.end());
|
||||
add_option(option(STATUS_CODE, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
void DHCPv6::rapid_commit() {
|
||||
add_option(
|
||||
RAPID_COMMIT
|
||||
);
|
||||
add_option(RAPID_COMMIT);
|
||||
}
|
||||
|
||||
void DHCPv6::user_class(const user_class_type &value) {
|
||||
std::vector<uint8_t> buffer;
|
||||
void DHCPv6::user_class(const user_class_type& value) {
|
||||
vector<uint8_t> buffer;
|
||||
Internals::class_option_data2option(value.data.begin(), value.data.end(), buffer);
|
||||
add_option(
|
||||
option(USER_CLASS, buffer.begin(), buffer.end())
|
||||
);
|
||||
add_option(option(USER_CLASS, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
void DHCPv6::vendor_class(const vendor_class_type &value) {
|
||||
std::vector<uint8_t> buffer(
|
||||
sizeof(uint32_t)
|
||||
);
|
||||
uint32_t enterprise_number = Endian::host_to_be(value.enterprise_number);
|
||||
std::memcpy(&buffer[0], &enterprise_number, sizeof(uint32_t));
|
||||
void DHCPv6::vendor_class(const vendor_class_type& value) {
|
||||
vector<uint8_t> buffer(sizeof(uint32_t));
|
||||
OutputMemoryStream stream(buffer);
|
||||
stream.write_be(value.enterprise_number);
|
||||
Internals::class_option_data2option(
|
||||
value.vendor_class_data.begin(),
|
||||
value.vendor_class_data.end(),
|
||||
@@ -406,276 +356,218 @@ void DHCPv6::vendor_class(const vendor_class_type &value) {
|
||||
);
|
||||
}
|
||||
|
||||
void DHCPv6::vendor_info(const vendor_info_type &value) {
|
||||
std::vector<uint8_t> buffer(sizeof(uint32_t) + value.data.size());
|
||||
uint32_t enterprise_number = Endian::host_to_be(value.enterprise_number);
|
||||
std::memcpy(&buffer[0], &enterprise_number, sizeof(uint32_t));
|
||||
std::copy(
|
||||
value.data.begin(),
|
||||
value.data.end(),
|
||||
buffer.begin() + sizeof(uint32_t)
|
||||
);
|
||||
add_option(
|
||||
option(VENDOR_OPTS, buffer.begin(), buffer.end())
|
||||
);
|
||||
void DHCPv6::vendor_info(const vendor_info_type& value) {
|
||||
vector<uint8_t> buffer(sizeof(uint32_t) + value.data.size());
|
||||
OutputMemoryStream stream(buffer);
|
||||
stream.write_be(value.enterprise_number);
|
||||
stream.write(value.data.begin(), value.data.end());
|
||||
add_option(option(VENDOR_OPTS, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
void DHCPv6::interface_id(const interface_id_type &value) {
|
||||
add_option(
|
||||
option(INTERFACE_ID, value.begin(), value.end())
|
||||
);
|
||||
void DHCPv6::interface_id(const interface_id_type& value) {
|
||||
add_option(option(INTERFACE_ID, value.begin(), value.end()));
|
||||
}
|
||||
|
||||
void DHCPv6::reconfigure_msg(uint8_t value) {
|
||||
add_option(
|
||||
option(RECONF_MSG, 1, &value)
|
||||
);
|
||||
add_option(option(RECONF_MSG, 1, &value));
|
||||
}
|
||||
|
||||
void DHCPv6::reconfigure_accept() {
|
||||
add_option(RECONF_ACCEPT);
|
||||
}
|
||||
|
||||
void DHCPv6::client_id(const duid_type& value) {
|
||||
serialization_type buffer(sizeof(uint16_t) + value.data.size());
|
||||
OutputMemoryStream stream(buffer);
|
||||
stream.write_be(value.id);
|
||||
stream.write(value.data.begin(), value.data.end());
|
||||
add_option(option(CLIENTID, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
void DHCPv6::server_id(const duid_type& value) {
|
||||
serialization_type buffer(sizeof(uint16_t) + value.data.size());
|
||||
OutputMemoryStream stream(buffer);
|
||||
stream.write_be(value.id);
|
||||
stream.write(value.data.begin(), value.data.end());
|
||||
add_option(option(SERVERID, buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
// DUIDs
|
||||
|
||||
DHCPv6::duid_llt DHCPv6::duid_llt::from_bytes(const uint8_t *buffer, uint32_t total_sz)
|
||||
{
|
||||
DHCPv6::duid_llt DHCPv6::duid_llt::from_bytes(const uint8_t* buffer, uint32_t total_sz) {
|
||||
// at least one byte for lladdress
|
||||
if(total_sz < sizeof(uint16_t) + sizeof(uint32_t) + 1)
|
||||
throw std::runtime_error("Not enough size for a DUID_LLT identifier");
|
||||
if (total_sz < sizeof(uint16_t) + sizeof(uint32_t) + 1) {
|
||||
throw runtime_error("Not enough size for a DUID_LLT identifier");
|
||||
}
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
duid_llt output;
|
||||
std::memcpy(&output.hw_type, buffer, sizeof(uint16_t));
|
||||
output.hw_type = Endian::be_to_host(output.hw_type);
|
||||
buffer += sizeof(uint16_t);
|
||||
std::memcpy(&output.time, buffer, sizeof(uint32_t));
|
||||
output.time = Endian::be_to_host(output.time);
|
||||
buffer += sizeof(uint32_t);
|
||||
total_sz -= sizeof(uint16_t) + sizeof(uint32_t);
|
||||
output.lladdress.assign(buffer, buffer + total_sz);
|
||||
output.hw_type = stream.read_be<uint16_t>();
|
||||
output.time = stream.read_be<uint32_t>();
|
||||
stream.read(output.lladdress, stream.size());
|
||||
return output;
|
||||
}
|
||||
|
||||
PDU::serialization_type DHCPv6::duid_llt::serialize() const {
|
||||
serialization_type output(sizeof(uint16_t) + sizeof(uint32_t) + lladdress.size());
|
||||
uint16_t tmp_hw_type = Endian::host_to_be(hw_type);
|
||||
uint32_t tmp_time = Endian::host_to_be(time);
|
||||
std::memcpy(&output[0], &tmp_hw_type, sizeof(uint16_t));
|
||||
std::memcpy(&output[sizeof(uint16_t)], &tmp_time, sizeof(uint32_t));
|
||||
std::copy(
|
||||
lladdress.begin(),
|
||||
lladdress.end(),
|
||||
output.begin() + sizeof(uint16_t) + sizeof(uint32_t)
|
||||
);
|
||||
OutputMemoryStream stream(output);
|
||||
stream.write_be(hw_type);
|
||||
stream.write_be(time);
|
||||
stream.write(lladdress.begin(), lladdress.end());
|
||||
return output;
|
||||
}
|
||||
|
||||
DHCPv6::duid_en DHCPv6::duid_en::from_bytes(const uint8_t *buffer, uint32_t total_sz)
|
||||
{
|
||||
DHCPv6::duid_en DHCPv6::duid_en::from_bytes(const uint8_t* buffer, uint32_t total_sz) {
|
||||
// at least one byte for identifier
|
||||
if(total_sz < sizeof(uint32_t) + 1)
|
||||
throw std::runtime_error("Not enough size for a DUID_en identifier");
|
||||
if (total_sz < sizeof(uint32_t) + 1) {
|
||||
throw runtime_error("Not enough size for a DUID_en identifier");
|
||||
}
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
duid_en output;
|
||||
std::memcpy(&output.enterprise_number, buffer, sizeof(uint32_t));
|
||||
output.enterprise_number = Endian::be_to_host(output.enterprise_number);
|
||||
buffer += sizeof(uint32_t);
|
||||
total_sz -= sizeof(uint32_t);
|
||||
output.identifier.assign(buffer, buffer + total_sz);
|
||||
output.enterprise_number = stream.read_be<uint32_t>();
|
||||
stream.read(output.identifier, stream.size());
|
||||
return output;
|
||||
}
|
||||
|
||||
PDU::serialization_type DHCPv6::duid_en::serialize() const {
|
||||
serialization_type output(sizeof(uint32_t) + identifier.size());
|
||||
uint32_t tmp_enterprise_number = Endian::host_to_be(enterprise_number);
|
||||
std::memcpy(&output[0], &tmp_enterprise_number, sizeof(uint32_t));
|
||||
std::copy(
|
||||
identifier.begin(),
|
||||
identifier.end(),
|
||||
output.begin() + sizeof(uint32_t)
|
||||
);
|
||||
OutputMemoryStream stream(output);
|
||||
stream.write_be(enterprise_number);
|
||||
stream.write(identifier.begin(), identifier.end());
|
||||
return output;
|
||||
}
|
||||
|
||||
DHCPv6::duid_ll DHCPv6::duid_ll::from_bytes(const uint8_t *buffer, uint32_t total_sz)
|
||||
{
|
||||
DHCPv6::duid_ll DHCPv6::duid_ll::from_bytes(const uint8_t* buffer, uint32_t total_sz) {
|
||||
// at least one byte for lladdress
|
||||
if(total_sz < sizeof(uint16_t) + 1)
|
||||
throw std::runtime_error("Not enough size for a DUID_en identifier");
|
||||
if (total_sz < sizeof(uint16_t) + 1) {
|
||||
throw runtime_error("Not enough size for a DUID_en identifier");
|
||||
}
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
duid_ll output;
|
||||
std::memcpy(&output.hw_type, buffer, sizeof(uint16_t));
|
||||
output.hw_type = Endian::be_to_host(output.hw_type);
|
||||
buffer += sizeof(uint16_t);
|
||||
total_sz -= sizeof(uint16_t);
|
||||
output.lladdress.assign(buffer, buffer + total_sz);
|
||||
output.hw_type = stream.read_be<uint16_t>();
|
||||
stream.read(output.lladdress, stream.size());
|
||||
return output;
|
||||
}
|
||||
|
||||
PDU::serialization_type DHCPv6::duid_ll::serialize() const {
|
||||
serialization_type output(sizeof(uint16_t) + lladdress.size());
|
||||
uint16_t tmp_hw_type = Endian::host_to_be(hw_type);
|
||||
std::memcpy(&output[0], &tmp_hw_type, sizeof(uint16_t));
|
||||
std::copy(
|
||||
lladdress.begin(),
|
||||
lladdress.end(),
|
||||
output.begin() + sizeof(uint16_t)
|
||||
);
|
||||
OutputMemoryStream stream(output);
|
||||
stream.write_be(hw_type);
|
||||
stream.write(lladdress.begin(), lladdress.end());
|
||||
return output;
|
||||
}
|
||||
|
||||
void DHCPv6::client_id(const duid_type &value) {
|
||||
serialization_type buffer(sizeof(uint16_t) + value.data.size());
|
||||
uint16_t tmp_id = Endian::host_to_be(value.id);
|
||||
std::memcpy(&buffer[0], &tmp_id, sizeof(uint16_t));
|
||||
std::copy(
|
||||
value.data.begin(),
|
||||
value.data.end(),
|
||||
buffer.begin() + sizeof(uint16_t)
|
||||
);
|
||||
add_option(
|
||||
option(CLIENTID, buffer.begin(), buffer.end())
|
||||
);
|
||||
}
|
||||
|
||||
void DHCPv6::server_id(const duid_type &value) {
|
||||
serialization_type buffer(sizeof(uint16_t) + value.data.size());
|
||||
uint16_t tmp_id = Endian::host_to_be(value.id);
|
||||
std::memcpy(&buffer[0], &tmp_id, sizeof(uint16_t));
|
||||
std::copy(
|
||||
value.data.begin(),
|
||||
value.data.end(),
|
||||
buffer.begin() + sizeof(uint16_t)
|
||||
);
|
||||
add_option(
|
||||
option(SERVERID, buffer.begin(), buffer.end())
|
||||
);
|
||||
}
|
||||
|
||||
// Options
|
||||
|
||||
DHCPv6::ia_na_type DHCPv6::ia_na_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < sizeof(uint32_t) * 3)
|
||||
DHCPv6::ia_na_type DHCPv6::ia_na_type::from_option(const option& opt) {
|
||||
if (opt.data_size() < sizeof(uint32_t) * 3) {
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr() + sizeof(uint32_t) * 3;
|
||||
const uint32_t *ptr_32 = (const uint32_t*)opt.data_ptr();
|
||||
}
|
||||
InputMemoryStream stream(opt.data_ptr(), opt.data_size());
|
||||
DHCPv6::ia_na_type output;
|
||||
output.id = Endian::be_to_host(*ptr_32++);
|
||||
output.t1 = Endian::be_to_host(*ptr_32++);
|
||||
output.t2 = Endian::be_to_host(*ptr_32++);
|
||||
output.options.assign(ptr, opt.data_ptr() + opt.data_size());
|
||||
output.id = stream.read_be<uint32_t>();
|
||||
output.t1 = stream.read_be<uint32_t>();
|
||||
output.t2 = stream.read_be<uint32_t>();
|
||||
stream.read(output.options, stream.size());
|
||||
return output;
|
||||
}
|
||||
|
||||
DHCPv6::ia_ta_type DHCPv6::ia_ta_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < sizeof(uint32_t))
|
||||
DHCPv6::ia_ta_type DHCPv6::ia_ta_type::from_option(const option& opt) {
|
||||
if (opt.data_size() < sizeof(uint32_t)) {
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr() + sizeof(uint32_t);
|
||||
const uint32_t *ptr_32 = (const uint32_t*)opt.data_ptr();
|
||||
}
|
||||
InputMemoryStream stream(opt.data_ptr(), opt.data_size());
|
||||
DHCPv6::ia_ta_type output;
|
||||
output.id = Endian::be_to_host(*ptr_32++);
|
||||
output.options.assign(ptr, opt.data_ptr() + opt.data_size());
|
||||
output.id = stream.read_be<uint32_t>();
|
||||
stream.read(output.options, stream.size());
|
||||
return output;
|
||||
}
|
||||
|
||||
DHCPv6::ia_address_type DHCPv6::ia_address_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < sizeof(uint32_t) * 2 + DHCPv6::ipaddress_type::address_size)
|
||||
DHCPv6::ia_address_type DHCPv6::ia_address_type::from_option(const option& opt) {
|
||||
if (opt.data_size() < sizeof(uint32_t) * 2 + DHCPv6::ipaddress_type::address_size) {
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr() + sizeof(uint32_t) * 2 + ipaddress_type::address_size;
|
||||
const uint32_t *ptr_32 = (const uint32_t*)(opt.data_ptr() + ipaddress_type::address_size);
|
||||
}
|
||||
InputMemoryStream stream(opt.data_ptr(), opt.data_size());
|
||||
DHCPv6::ia_address_type output;
|
||||
output.address = opt.data_ptr();
|
||||
output.preferred_lifetime = Endian::be_to_host(*ptr_32++);
|
||||
output.valid_lifetime = Endian::be_to_host(*ptr_32++);
|
||||
output.options.assign(ptr, opt.data_ptr() + opt.data_size());
|
||||
stream.read(output.address);
|
||||
output.preferred_lifetime = stream.read_be<uint32_t>();
|
||||
output.valid_lifetime = stream.read_be<uint32_t>();
|
||||
stream.read(output.options, stream.size());
|
||||
return output;
|
||||
}
|
||||
|
||||
DHCPv6::authentication_type DHCPv6::authentication_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < sizeof(uint8_t) * 3 + sizeof(uint64_t))
|
||||
DHCPv6::authentication_type DHCPv6::authentication_type::from_option(const option& opt) {
|
||||
if (opt.data_size() < sizeof(uint8_t) * 3 + sizeof(uint64_t)) {
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr();
|
||||
}
|
||||
InputMemoryStream stream(opt.data_ptr(), opt.data_size());
|
||||
authentication_type output;
|
||||
output.protocol = *ptr++;
|
||||
output.algorithm = *ptr++;
|
||||
output.rdm = *ptr++;
|
||||
std::memcpy(&output.replay_detection, ptr, sizeof(uint64_t));
|
||||
output.replay_detection = Endian::be_to_host(output.replay_detection);
|
||||
ptr += sizeof(uint64_t);
|
||||
output.auth_info.assign(ptr, opt.data_ptr() + opt.data_size());
|
||||
output.protocol = stream.read<uint8_t>();
|
||||
output.algorithm = stream.read<uint8_t>();
|
||||
output.rdm = stream.read<uint8_t>();
|
||||
output.replay_detection = stream.read_be<uint64_t>();
|
||||
stream.read(output.auth_info, stream.size());
|
||||
return output;
|
||||
}
|
||||
|
||||
DHCPv6::status_code_type DHCPv6::status_code_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < sizeof(uint16_t))
|
||||
DHCPv6::status_code_type DHCPv6::status_code_type::from_option(const option& opt) {
|
||||
if (opt.data_size() < sizeof(uint16_t)) {
|
||||
throw malformed_option();
|
||||
}
|
||||
InputMemoryStream stream(opt.data_ptr(), opt.data_size());
|
||||
status_code_type output;
|
||||
std::memcpy(&output.code, opt.data_ptr(), sizeof(uint16_t));
|
||||
output.code = Endian::be_to_host(output.code);
|
||||
output.message.assign(
|
||||
opt.data_ptr() + sizeof(uint16_t),
|
||||
opt.data_ptr() + opt.data_size()
|
||||
);
|
||||
output.code = stream.read_be<uint16_t>();
|
||||
output.message.assign(stream.pointer(), stream.pointer() + stream.size());
|
||||
return output;
|
||||
}
|
||||
|
||||
DHCPv6::vendor_info_type DHCPv6::vendor_info_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < sizeof(uint32_t))
|
||||
DHCPv6::vendor_info_type DHCPv6::vendor_info_type::from_option(const option& opt) {
|
||||
if (opt.data_size() < sizeof(uint32_t)) {
|
||||
throw malformed_option();
|
||||
}
|
||||
InputMemoryStream stream(opt.data_ptr(), opt.data_size());
|
||||
vendor_info_type output;
|
||||
std::memcpy(&output.enterprise_number, opt.data_ptr(), sizeof(uint32_t));
|
||||
output.enterprise_number = Endian::be_to_host(output.enterprise_number);
|
||||
output.data.assign(
|
||||
opt.data_ptr() + sizeof(uint32_t),
|
||||
opt.data_ptr() + opt.data_size()
|
||||
);
|
||||
output.enterprise_number = stream.read_be<uint32_t>();
|
||||
stream.read(output.data, stream.size());
|
||||
return output;
|
||||
}
|
||||
|
||||
DHCPv6::vendor_class_type DHCPv6::vendor_class_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < sizeof(uint32_t))
|
||||
DHCPv6::vendor_class_type DHCPv6::vendor_class_type::from_option(const option& opt) {
|
||||
if (opt.data_size() < sizeof(uint32_t)) {
|
||||
throw malformed_option();
|
||||
}
|
||||
typedef vendor_class_type::class_data_type data_type;
|
||||
InputMemoryStream stream(opt.data_ptr(), opt.data_size());
|
||||
vendor_class_type output;
|
||||
std::memcpy(&output.enterprise_number, opt.data_ptr(), sizeof(uint32_t));
|
||||
output.enterprise_number = Endian::be_to_host(output.enterprise_number);
|
||||
output.enterprise_number = stream.read_be<uint32_t>();
|
||||
output.vendor_class_data = Internals::option2class_option_data<data_type>(
|
||||
opt.data_ptr() + sizeof(uint32_t),
|
||||
static_cast<uint32_t>(opt.data_size() - sizeof(uint32_t))
|
||||
stream.pointer(),
|
||||
stream.size()
|
||||
);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
DHCPv6::duid_type DHCPv6::duid_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < sizeof(uint16_t) + 1)
|
||||
DHCPv6::duid_type DHCPv6::duid_type::from_option(const option& opt) {
|
||||
if (opt.data_size() < sizeof(uint16_t) + 1) {
|
||||
throw malformed_option();
|
||||
|
||||
uint16_t uint16_t_buffer;
|
||||
std::memcpy(&uint16_t_buffer, opt.data_ptr(), sizeof(uint16_t));
|
||||
}
|
||||
InputMemoryStream stream(opt.data_ptr(), opt.data_size());
|
||||
uint16_t id = stream.read_be<uint16_t>();
|
||||
return duid_type(
|
||||
Endian::be_to_host(uint16_t_buffer),
|
||||
serialization_type(
|
||||
opt.data_ptr() + sizeof(uint16_t),
|
||||
opt.data_ptr() + opt.data_size()
|
||||
)
|
||||
id,
|
||||
serialization_type(stream.pointer(), stream.pointer() + stream.size())
|
||||
);
|
||||
}
|
||||
|
||||
DHCPv6::user_class_type DHCPv6::user_class_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < sizeof(uint16_t))
|
||||
DHCPv6::user_class_type DHCPv6::user_class_type::from_option(const option& opt) {
|
||||
if (opt.data_size() < sizeof(uint16_t)) {
|
||||
throw malformed_option();
|
||||
}
|
||||
user_class_type output;
|
||||
output.data = Internals::option2class_option_data<data_type>(
|
||||
opt.data_ptr(), static_cast<uint32_t>(opt.data_size())
|
||||
);
|
||||
return output;
|
||||
}
|
||||
|
||||
} // namespace Tins
|
||||
|
||||
448
src/dns.cpp
448
src/dns.cpp
@@ -41,7 +41,10 @@
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::string;
|
||||
using std::copy;
|
||||
using std::memcpy;
|
||||
using std::list;
|
||||
using std::make_pair;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
@@ -49,259 +52,232 @@ using Tins::Memory::OutputMemoryStream;
|
||||
namespace Tins {
|
||||
|
||||
DNS::DNS()
|
||||
: dns(), answers_idx(), authority_idx(), additional_idx()
|
||||
{
|
||||
: header_(), answers_idx_(), authority_idx_(), additional_idx_() {
|
||||
}
|
||||
|
||||
DNS::DNS(const uint8_t *buffer, uint32_t total_sz)
|
||||
: answers_idx(), authority_idx(), additional_idx()
|
||||
{
|
||||
DNS::DNS(const uint8_t* buffer, uint32_t total_sz)
|
||||
: answers_idx_(), authority_idx_(), additional_idx_() {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(dns);
|
||||
records_data.assign(stream.pointer(), stream.pointer() + stream.size());
|
||||
stream.read(header_);
|
||||
stream.read(records_data_, stream.size());
|
||||
// Avoid doing this if there's no data. Otherwise VS's asserts fail.
|
||||
if (!records_data.empty()) {
|
||||
buffer = &records_data[0];
|
||||
const uint8_t *end = &records_data[0] + records_data.size(), *prev_start = buffer;
|
||||
if (!records_data_.empty()) {
|
||||
InputMemoryStream stream(records_data_);
|
||||
uint16_t nquestions = questions_count();
|
||||
for(uint16_t i(0); i < nquestions; ++i) {
|
||||
buffer = find_dname_end(buffer);
|
||||
if((buffer + (sizeof(uint16_t) * 2)) > end)
|
||||
throw malformed_packet();
|
||||
buffer += sizeof(uint16_t) * 2;
|
||||
for (uint16_t i(0); i < nquestions; ++i) {
|
||||
skip_to_dname_end(stream);
|
||||
stream.skip(sizeof(uint16_t) * 2);
|
||||
}
|
||||
answers_idx = static_cast<uint32_t>(buffer - prev_start);
|
||||
authority_idx = static_cast<uint32_t>(
|
||||
find_section_end(&records_data[0] + answers_idx, answers_count()) - &records_data[0]
|
||||
);
|
||||
additional_idx = static_cast<uint32_t>(
|
||||
find_section_end(&records_data[0] + authority_idx, authority_count()) - &records_data[0]
|
||||
);
|
||||
const uint8_t* base_offset = &records_data_[0];
|
||||
answers_idx_ = static_cast<uint32_t>(stream.pointer() - base_offset);
|
||||
skip_to_section_end(stream, answers_count());
|
||||
authority_idx_ = static_cast<uint32_t>(stream.pointer() - base_offset);
|
||||
skip_to_section_end(stream, authority_count());
|
||||
additional_idx_ = static_cast<uint32_t>(stream.pointer() - base_offset);
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t* DNS::find_dname_end(const uint8_t *ptr) const {
|
||||
const uint8_t *end = &records_data[0] + records_data.size();
|
||||
while(ptr < end) {
|
||||
if(*ptr == 0) {
|
||||
++ptr;
|
||||
void DNS::skip_to_dname_end(InputMemoryStream& stream) const {
|
||||
while (stream) {
|
||||
uint8_t value = stream.read<uint8_t>();
|
||||
if (value == 0) {
|
||||
// Found the ending null byte, we're done
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if((*ptr & 0xc0)) {
|
||||
ptr += sizeof(uint16_t);
|
||||
if ((value & 0xc0)) {
|
||||
// This is an offset label, skip the second byte and we're done
|
||||
stream.skip(1);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
uint8_t size = *ptr;
|
||||
ptr += size + 1;
|
||||
// This is an actual label, skip its contents
|
||||
stream.skip(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
const uint8_t *DNS::find_section_end(const uint8_t *ptr, const uint32_t num_records) const {
|
||||
const uint8_t *end = &records_data[0] + records_data.size();
|
||||
uint16_t uint16_t_buffer;
|
||||
for(uint32_t i = 0; i < num_records; ++i) {
|
||||
ptr = find_dname_end(ptr);
|
||||
if(ptr + sizeof(uint16_t) * 3 + sizeof(uint32_t) > end)
|
||||
void DNS::skip_to_section_end(InputMemoryStream& stream,
|
||||
const uint32_t num_records) const {
|
||||
for (uint32_t i = 0; i < num_records; ++i) {
|
||||
skip_to_dname_end(stream);
|
||||
stream.skip(sizeof(uint16_t) * 2 + sizeof(uint32_t));
|
||||
uint16_t data_size = stream.read_be<uint16_t>();
|
||||
if (!stream.can_read(data_size)) {
|
||||
throw malformed_packet();
|
||||
ptr += sizeof(uint16_t) * 2 + sizeof(uint32_t);
|
||||
std::memcpy(&uint16_t_buffer, ptr, sizeof(uint16_t));
|
||||
uint16_t data_size = Endian::be_to_host(uint16_t_buffer); // Data size
|
||||
ptr += sizeof(uint16_t);
|
||||
if(ptr + data_size > end)
|
||||
throw malformed_packet();
|
||||
ptr += data_size;
|
||||
}
|
||||
stream.skip(data_size);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint32_t DNS::header_size() const {
|
||||
return static_cast<uint32_t>(sizeof(dns) + records_data.size());
|
||||
return static_cast<uint32_t>(sizeof(header_) + records_data_.size());
|
||||
}
|
||||
|
||||
void DNS::id(uint16_t new_id) {
|
||||
dns.id = Endian::host_to_be(new_id);
|
||||
header_.id = Endian::host_to_be(new_id);
|
||||
}
|
||||
|
||||
void DNS::type(QRType new_qr) {
|
||||
dns.qr = new_qr;
|
||||
header_.qr = new_qr;
|
||||
}
|
||||
|
||||
void DNS::opcode(uint8_t new_opcode) {
|
||||
dns.opcode = new_opcode;
|
||||
header_.opcode = new_opcode;
|
||||
}
|
||||
|
||||
void DNS::authoritative_answer(uint8_t new_aa) {
|
||||
dns.aa = new_aa;
|
||||
header_.aa = new_aa;
|
||||
}
|
||||
|
||||
void DNS::truncated(uint8_t new_tc) {
|
||||
dns.tc = new_tc;
|
||||
header_.tc = new_tc;
|
||||
}
|
||||
|
||||
void DNS::recursion_desired(uint8_t new_rd) {
|
||||
dns.rd = new_rd;
|
||||
header_.rd = new_rd;
|
||||
}
|
||||
|
||||
void DNS::recursion_available(uint8_t new_ra) {
|
||||
dns.ra = new_ra;
|
||||
header_.ra = new_ra;
|
||||
}
|
||||
|
||||
void DNS::z(uint8_t new_z) {
|
||||
dns.z = new_z;
|
||||
header_.z = new_z;
|
||||
}
|
||||
|
||||
void DNS::authenticated_data(uint8_t new_ad) {
|
||||
dns.ad = new_ad;
|
||||
header_.ad = new_ad;
|
||||
}
|
||||
|
||||
void DNS::checking_disabled(uint8_t new_cd) {
|
||||
dns.cd = new_cd;
|
||||
header_.cd = new_cd;
|
||||
}
|
||||
|
||||
void DNS::rcode(uint8_t new_rcode) {
|
||||
dns.rcode = new_rcode;
|
||||
header_.rcode = new_rcode;
|
||||
}
|
||||
|
||||
bool DNS::contains_dname(uint16_t type) {
|
||||
return type == MX || type == CNAME ||
|
||||
type == PTR || type == NS;
|
||||
return type == MX || type == CNAME || type == PTR || type == NS;
|
||||
}
|
||||
|
||||
void DNS::add_query(const Query &query) {
|
||||
void DNS::add_query(const Query& query) {
|
||||
string new_str = encode_domain_name(query.dname());
|
||||
// Type (2 bytes) + Class (2 Bytes)
|
||||
size_t previous_length = new_str.size();
|
||||
// Epand the string to hold: Type (2 bytes) + Class (2 Bytes)
|
||||
new_str.insert(new_str.end(), sizeof(uint16_t) * 2, ' ');
|
||||
uint16_t uint16_t_buffer;
|
||||
uint16_t_buffer = Endian::host_to_be<uint16_t>(query.type());
|
||||
std::memcpy(&new_str[new_str.size() - 4], &uint16_t_buffer, sizeof(uint16_t));
|
||||
uint16_t_buffer = Endian::host_to_be<uint16_t>(query.query_class());
|
||||
std::memcpy(&new_str[new_str.size() - 2], &uint16_t_buffer, sizeof(uint16_t));
|
||||
// Build a stream at the end
|
||||
OutputMemoryStream stream(
|
||||
(uint8_t*)&new_str[0] + previous_length,
|
||||
sizeof(uint16_t) * 2
|
||||
);
|
||||
stream.write_be<uint16_t>(query.type());
|
||||
stream.write_be<uint16_t>(query.query_class());
|
||||
|
||||
uint32_t offset = static_cast<uint32_t>(new_str.size()), threshold = answers_idx;
|
||||
update_records(answers_idx, answers_count(), threshold, offset);
|
||||
update_records(authority_idx, authority_count(), threshold, offset);
|
||||
update_records(additional_idx, additional_count(), threshold, offset);
|
||||
records_data.insert(
|
||||
records_data.begin() + threshold,
|
||||
uint32_t offset = static_cast<uint32_t>(new_str.size()), threshold = answers_idx_;
|
||||
update_records(answers_idx_, answers_count(), threshold, offset);
|
||||
update_records(authority_idx_, authority_count(), threshold, offset);
|
||||
update_records(additional_idx_, additional_count(), threshold, offset);
|
||||
records_data_.insert(
|
||||
records_data_.begin() + threshold,
|
||||
new_str.begin(),
|
||||
new_str.end()
|
||||
);
|
||||
dns.questions = Endian::host_to_be(static_cast<uint16_t>(questions_count() + 1));
|
||||
header_.questions = Endian::host_to_be(static_cast<uint16_t>(questions_count() + 1));
|
||||
}
|
||||
|
||||
void DNS::add_answer(const Resource &resource) {
|
||||
void DNS::add_answer(const Resource& resource) {
|
||||
sections_type sections;
|
||||
sections.push_back(std::make_pair(&authority_idx, authority_count()));
|
||||
sections.push_back(std::make_pair(&additional_idx, additional_count()));
|
||||
sections.push_back(make_pair(&authority_idx_, authority_count()));
|
||||
sections.push_back(make_pair(&additional_idx_, additional_count()));
|
||||
add_record(resource, sections);
|
||||
dns.answers = Endian::host_to_be<uint16_t>(
|
||||
header_.answers = Endian::host_to_be<uint16_t>(
|
||||
answers_count() + 1
|
||||
);
|
||||
}
|
||||
|
||||
void DNS::add_record(const Resource &resource, const sections_type §ions) {
|
||||
void DNS::add_record(const Resource& resource, const sections_type& sections) {
|
||||
// We need to check that the data provided is correct. Otherwise, the sections
|
||||
// will end up being inconsistent.
|
||||
IPv4Address v4_addr;
|
||||
IPv6Address v6_addr;
|
||||
std::string buffer = encode_domain_name(resource.dname()), encoded_data;
|
||||
string buffer = encode_domain_name(resource.dname()), encoded_data;
|
||||
// By default the data size is the length of the data field.
|
||||
size_t data_size = resource.data().size();
|
||||
if(resource.type() == A) {
|
||||
if (resource.type() == A) {
|
||||
v4_addr = resource.data();
|
||||
data_size = 4;
|
||||
}
|
||||
else if(resource.type() == AAAA) {
|
||||
else if (resource.type() == AAAA) {
|
||||
v6_addr = resource.data();
|
||||
data_size = IPv6Address::address_size;
|
||||
}
|
||||
else if(contains_dname(resource.type())) {
|
||||
else if (contains_dname(resource.type())) {
|
||||
encoded_data = encode_domain_name(resource.data());
|
||||
data_size = encoded_data.size();
|
||||
}
|
||||
size_t offset = buffer.size() + sizeof(uint16_t) * 3 + sizeof(uint32_t) + data_size,
|
||||
threshold = sections.empty() ? records_data.size() : *sections.front().first;
|
||||
threshold = sections.empty() ? records_data_.size() :* sections.front().first;
|
||||
// Skip the preference field
|
||||
if(resource.type() == MX) {
|
||||
if (resource.type() == MX) {
|
||||
offset += sizeof(uint16_t);
|
||||
}
|
||||
for(size_t i = 0; i < sections.size(); ++i) {
|
||||
for (size_t i = 0; i < sections.size(); ++i) {
|
||||
update_records(*sections[i].first, sections[i].second,
|
||||
static_cast<uint32_t>(threshold), static_cast<uint32_t>(offset));
|
||||
}
|
||||
|
||||
records_data.insert(
|
||||
records_data.begin() + threshold,
|
||||
records_data_.insert(
|
||||
records_data_.begin() + threshold,
|
||||
offset,
|
||||
0
|
||||
);
|
||||
uint8_t *ptr = std::copy(
|
||||
buffer.begin(),
|
||||
buffer.end(),
|
||||
&records_data[0] + threshold
|
||||
);
|
||||
|
||||
uint16_t uint16_t_buffer;
|
||||
uint32_t uint32_t_buffer;
|
||||
|
||||
uint16_t_buffer = Endian::host_to_be(resource.type());
|
||||
std::memcpy(ptr, &uint16_t_buffer, sizeof(uint16_t));
|
||||
ptr += sizeof(uint16_t);
|
||||
uint16_t_buffer = Endian::host_to_be(resource.query_class());
|
||||
std::memcpy(ptr, &uint16_t_buffer, sizeof(uint16_t));
|
||||
ptr += sizeof(uint16_t);
|
||||
uint32_t_buffer = Endian::host_to_be(resource.ttl());
|
||||
std::memcpy(ptr, &uint32_t_buffer, sizeof(uint32_t));
|
||||
ptr += sizeof(uint32_t);
|
||||
uint16_t_buffer = Endian::host_to_be(
|
||||
static_cast<uint16_t>(data_size + (resource.type() == MX ? 2 : 0))
|
||||
);
|
||||
std::memcpy(ptr, &uint16_t_buffer, sizeof(uint16_t));
|
||||
ptr += sizeof(uint16_t);
|
||||
if(resource.type() == MX) {
|
||||
ptr += sizeof(uint16_t);
|
||||
OutputMemoryStream stream(&records_data_[0] + threshold, offset);
|
||||
stream.write(buffer.begin(), buffer.end());
|
||||
stream.write_be(resource.type());
|
||||
stream.write_be(resource.query_class());
|
||||
stream.write_be(resource.ttl());
|
||||
stream.write_be<uint16_t>(data_size + (resource.type() == MX ? 2 : 0));
|
||||
if (resource.type() == MX) {
|
||||
stream.skip(sizeof(uint16_t));
|
||||
}
|
||||
if(resource.type() == A) {
|
||||
uint32_t ip_int = v4_addr;
|
||||
std::memcpy(ptr, &ip_int, sizeof(ip_int));
|
||||
if (resource.type() == A) {
|
||||
stream.write(v4_addr);
|
||||
}
|
||||
else if(resource.type() == AAAA) {
|
||||
std::copy(v6_addr.begin(), v6_addr.end(), ptr);
|
||||
else if (resource.type() == AAAA) {
|
||||
stream.write(v6_addr);
|
||||
}
|
||||
else if(!encoded_data.empty()) {
|
||||
std::copy(encoded_data.begin(), encoded_data.end(), ptr);
|
||||
else if (!encoded_data.empty()) {
|
||||
stream.write(encoded_data.begin(), encoded_data.end());
|
||||
}
|
||||
else {
|
||||
std::copy(resource.data().begin(), resource.data().end(), ptr);
|
||||
stream.write(resource.data().begin(), resource.data().end());
|
||||
}
|
||||
}
|
||||
|
||||
void DNS::add_authority(const Resource &resource) {
|
||||
void DNS::add_authority(const Resource& resource) {
|
||||
sections_type sections;
|
||||
sections.push_back(std::make_pair(&additional_idx, additional_count()));
|
||||
sections.push_back(make_pair(&additional_idx_, additional_count()));
|
||||
add_record(resource, sections);
|
||||
dns.authority = Endian::host_to_be<uint16_t>(
|
||||
header_.authority = Endian::host_to_be<uint16_t>(
|
||||
authority_count() + 1
|
||||
);
|
||||
}
|
||||
|
||||
void DNS::add_additional(const Resource &resource){
|
||||
void DNS::add_additional(const Resource& resource){
|
||||
add_record(resource, sections_type());
|
||||
dns.additional = Endian::host_to_be<uint16_t>(
|
||||
header_.additional = Endian::host_to_be<uint16_t>(
|
||||
additional_count() + 1
|
||||
);
|
||||
}
|
||||
|
||||
std::string DNS::encode_domain_name(const std::string &dn) {
|
||||
std::string output;
|
||||
string DNS::encode_domain_name(const string& dn) {
|
||||
string output;
|
||||
size_t last_index(0), index;
|
||||
if(!dn.empty()) {
|
||||
while((index = dn.find('.', last_index+1)) != string::npos) {
|
||||
if (!dn.empty()) {
|
||||
while ((index = dn.find('.', last_index+1)) != string::npos) {
|
||||
output.push_back(static_cast<char>(index - last_index));
|
||||
output.append(dn.begin() + last_index, dn.begin() + index);
|
||||
last_index = index + 1; //skip dot
|
||||
@@ -316,59 +292,64 @@ std::string DNS::encode_domain_name(const std::string &dn) {
|
||||
// The output buffer should be at least 256 bytes long. This used to use
|
||||
// a std::string but it worked about 50% slower, so this is somehow
|
||||
// unsafe but a lot faster.
|
||||
const uint8_t* DNS::compose_name(const uint8_t *ptr, char *out_ptr) const {
|
||||
const uint8_t *end = &records_data[0] + records_data.size();
|
||||
const uint8_t *end_ptr = 0;
|
||||
char *current_out_ptr = out_ptr;
|
||||
while(*ptr) {
|
||||
uint32_t DNS::compose_name(const uint8_t* ptr, char* out_ptr) const {
|
||||
const uint8_t* start_ptr = ptr;
|
||||
const uint8_t* end = &records_data_[0] + records_data_.size();
|
||||
const uint8_t* end_ptr = 0;
|
||||
char* current_out_ptr = out_ptr;
|
||||
while (*ptr) {
|
||||
// It's an offset
|
||||
if((*ptr & 0xc0)) {
|
||||
if(ptr + sizeof(uint16_t) > end)
|
||||
if ((*ptr & 0xc0)) {
|
||||
if (ptr + sizeof(uint16_t) > end) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
uint16_t index;
|
||||
std::memcpy(&index, ptr, sizeof(uint16_t));
|
||||
memcpy(&index, ptr, sizeof(uint16_t));
|
||||
index = Endian::be_to_host(index) & 0x3fff;
|
||||
// Check that the offset is neither too low or too high
|
||||
if(index < 0x0c || (&records_data[0] + (index - 0x0c)) >= end)
|
||||
if (index < 0x0c || (&records_data_[0] + (index - 0x0c)) >= end) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
// We've probably found the end of the original domain name. Save it.
|
||||
if(end_ptr == 0)
|
||||
if (end_ptr == 0) {
|
||||
end_ptr = ptr + sizeof(uint16_t);
|
||||
}
|
||||
// Now this is our pointer
|
||||
ptr = &records_data[index - 0x0c];
|
||||
ptr = &records_data_[index - 0x0c];
|
||||
}
|
||||
else {
|
||||
// It's a label, grab its size.
|
||||
uint8_t size = *ptr;
|
||||
ptr++;
|
||||
if(ptr + size > end || current_out_ptr - out_ptr + size + 1 > 255)
|
||||
if (ptr + size > end || current_out_ptr - out_ptr + size + 1 > 255) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
// Append a dot if it's not the first one.
|
||||
if(current_out_ptr != out_ptr)
|
||||
if (current_out_ptr != out_ptr) {
|
||||
*current_out_ptr++ = '.';
|
||||
std::copy(
|
||||
ptr,
|
||||
ptr + size,
|
||||
current_out_ptr
|
||||
);
|
||||
}
|
||||
copy(ptr, ptr + size, current_out_ptr);
|
||||
current_out_ptr += size;
|
||||
ptr += size;
|
||||
}
|
||||
}
|
||||
// Add the null terminator.
|
||||
*current_out_ptr = 0;
|
||||
return end_ptr ? end_ptr : (ptr + 1);
|
||||
if (!end_ptr) {
|
||||
end_ptr = ptr + 1;
|
||||
}
|
||||
return end_ptr - start_ptr;
|
||||
}
|
||||
|
||||
void DNS::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
|
||||
void DNS::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
stream.write(dns);
|
||||
stream.write(records_data.begin(), records_data.end());
|
||||
stream.write(header_);
|
||||
stream.write(records_data_.begin(), records_data_.end());
|
||||
}
|
||||
|
||||
// Optimization. Creating an IPv4Address and then using IPv4Address::to_string
|
||||
// was quite slow. The output buffer should be able to hold an IPv4 address.
|
||||
void DNS::inline_convert_v4(uint32_t value, char *output) {
|
||||
void DNS::inline_convert_v4(uint32_t value, char* output) {
|
||||
output += sprintf(
|
||||
output,
|
||||
"%d.%d.%d.%d",
|
||||
@@ -388,82 +369,62 @@ void DNS::inline_convert_v4(uint32_t value, char *output) {
|
||||
}
|
||||
|
||||
// Parses records in some section.
|
||||
void DNS::convert_records(const uint8_t *ptr, const uint8_t *end, resources_type &res) const {
|
||||
void DNS::convert_records(const uint8_t* ptr,
|
||||
const uint8_t* end,
|
||||
resources_type& res) const {
|
||||
InputMemoryStream stream(ptr, end - ptr);
|
||||
char dname[256], small_addr_buf[256];
|
||||
while(ptr < end) {
|
||||
std::string addr;
|
||||
while (stream) {
|
||||
string addr;
|
||||
bool used_small_buffer = false;
|
||||
// Retrieve the record's domain name.
|
||||
ptr = compose_name(ptr, dname);
|
||||
// 3 uint16_t fields: Type + Class + Data size
|
||||
// 1 uint32_t field: TTL
|
||||
if(ptr + sizeof(uint16_t) * 3 + sizeof(uint32_t) > end)
|
||||
throw malformed_packet();
|
||||
stream.skip(compose_name(stream.pointer(), dname));
|
||||
// Retrieve the following fields.
|
||||
uint16_t type, qclass, data_size;
|
||||
uint32_t ttl;
|
||||
std::memcpy(&type, ptr, sizeof(uint16_t)); // Type
|
||||
type = Endian::be_to_host(type);
|
||||
ptr += sizeof(uint16_t);
|
||||
std::memcpy(&qclass, ptr, sizeof(uint16_t)); // Class
|
||||
qclass = Endian::be_to_host(qclass);
|
||||
ptr += sizeof(uint16_t);
|
||||
std::memcpy(&ttl, ptr, sizeof(uint32_t)); // TTL
|
||||
ttl = Endian::be_to_host(ttl);
|
||||
ptr += sizeof(uint32_t);
|
||||
std::memcpy(&data_size, ptr, sizeof(uint16_t)); // Data size
|
||||
data_size = Endian::be_to_host(data_size);
|
||||
ptr += sizeof(uint16_t);
|
||||
type = stream.read_be<uint16_t>();
|
||||
qclass = stream.read_be<uint16_t>();
|
||||
ttl = stream.read_be<uint32_t>();
|
||||
data_size = stream.read_be<uint16_t>();
|
||||
// Skip the preference field if it's MX
|
||||
if(type == MX) {
|
||||
if(data_size < 2)
|
||||
throw malformed_packet();
|
||||
ptr += 2;
|
||||
data_size -= 2;
|
||||
if (type == MX) {
|
||||
stream.skip(sizeof(uint16_t));
|
||||
data_size -= sizeof(uint16_t);
|
||||
}
|
||||
if(ptr + data_size > end)
|
||||
if (!stream.can_read(data_size)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
switch (type) {
|
||||
case AAAA:
|
||||
if(data_size != 16)
|
||||
throw malformed_packet();
|
||||
addr = IPv6Address(ptr).to_string();
|
||||
addr = stream.read<IPv6Address>().to_string();
|
||||
break;
|
||||
case A:
|
||||
if(data_size == 4) {
|
||||
uint32_t uint32_t_buffer;
|
||||
std::memcpy(&uint32_t_buffer, ptr, sizeof(uint32_t));
|
||||
inline_convert_v4(uint32_t_buffer, small_addr_buf);
|
||||
used_small_buffer = true;
|
||||
}
|
||||
else
|
||||
throw malformed_packet();
|
||||
inline_convert_v4(stream.read<uint32_t>(), small_addr_buf);
|
||||
used_small_buffer = true;
|
||||
break;
|
||||
case NS:
|
||||
case CNAME:
|
||||
case DNAM:
|
||||
case PTR:
|
||||
case MX:
|
||||
compose_name(ptr, small_addr_buf);
|
||||
compose_name(stream.pointer(), small_addr_buf);
|
||||
stream.skip(data_size);
|
||||
used_small_buffer = true;
|
||||
break;
|
||||
default:
|
||||
if(data_size < sizeof(small_addr_buf) - 1) {
|
||||
std::copy(
|
||||
ptr,
|
||||
ptr + data_size,
|
||||
small_addr_buf
|
||||
);
|
||||
if (data_size < sizeof(small_addr_buf) - 1) {
|
||||
stream.read(small_addr_buf, data_size);
|
||||
// null terminator
|
||||
small_addr_buf[data_size] = 0;
|
||||
used_small_buffer = true;
|
||||
}
|
||||
else
|
||||
addr.assign(ptr, ptr + data_size);
|
||||
else {
|
||||
addr.assign(stream.pointer(), stream.pointer() + data_size);
|
||||
stream.skip(data_size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
ptr += data_size;
|
||||
res.push_back(
|
||||
Resource(
|
||||
dname,
|
||||
@@ -477,15 +438,15 @@ void DNS::convert_records(const uint8_t *ptr, const uint8_t *end, resources_type
|
||||
}
|
||||
|
||||
// no length checks, records should already be valid
|
||||
uint8_t *DNS::update_dname(uint8_t *ptr, uint32_t threshold, uint32_t offset) {
|
||||
while(*ptr != 0) {
|
||||
if((*ptr & 0xc0)) {
|
||||
uint8_t* DNS::update_dname(uint8_t* ptr, uint32_t threshold, uint32_t offset) {
|
||||
while (*ptr != 0) {
|
||||
if ((*ptr & 0xc0)) {
|
||||
uint16_t index;
|
||||
std::memcpy(&index, ptr, sizeof(uint16_t));
|
||||
memcpy(&index, ptr, sizeof(uint16_t));
|
||||
index = Endian::be_to_host(index) & 0x3fff;
|
||||
if(index > threshold) {
|
||||
if (index > threshold) {
|
||||
index = Endian::host_to_be<uint16_t>((index + offset) | 0xc000);
|
||||
std::memcpy(ptr, &index, sizeof(uint16_t));
|
||||
memcpy(ptr, &index, sizeof(uint16_t));
|
||||
}
|
||||
ptr += sizeof(uint16_t);
|
||||
break;
|
||||
@@ -499,24 +460,27 @@ uint8_t *DNS::update_dname(uint8_t *ptr, uint32_t threshold, uint32_t offset) {
|
||||
|
||||
// Updates offsets in domain names inside records.
|
||||
// No length checks, records are already valid.
|
||||
void DNS::update_records(uint32_t §ion_start, uint32_t num_records, uint32_t threshold, uint32_t offset) {
|
||||
if(section_start < records_data.size()) {
|
||||
uint8_t *ptr = &records_data[section_start];
|
||||
for(uint32_t i = 0; i < num_records; ++i) {
|
||||
void DNS::update_records(uint32_t& section_start,
|
||||
uint32_t num_records,
|
||||
uint32_t threshold,
|
||||
uint32_t offset) {
|
||||
if (section_start < records_data_.size()) {
|
||||
uint8_t* ptr = &records_data_[section_start];
|
||||
for (uint32_t i = 0; i < num_records; ++i) {
|
||||
ptr = update_dname(ptr, threshold, offset);
|
||||
uint16_t type;
|
||||
std::memcpy(&type, ptr, sizeof(uint16_t));
|
||||
memcpy(&type, ptr, sizeof(uint16_t));
|
||||
type = Endian::be_to_host(type);
|
||||
ptr += sizeof(uint16_t) * 2 + sizeof(uint32_t);
|
||||
uint16_t size;
|
||||
std::memcpy(&size, ptr, sizeof(uint16_t));
|
||||
memcpy(&size, ptr, sizeof(uint16_t));
|
||||
size = Endian::be_to_host(size);
|
||||
ptr += sizeof(uint16_t);
|
||||
if(type == MX) {
|
||||
if (type == MX) {
|
||||
ptr += sizeof(uint16_t);
|
||||
size -= sizeof(uint16_t);
|
||||
}
|
||||
if(contains_dname(type)) {
|
||||
if (contains_dname(type)) {
|
||||
update_dname(ptr, threshold, offset);
|
||||
}
|
||||
ptr += size;
|
||||
@@ -527,26 +491,16 @@ void DNS::update_records(uint32_t §ion_start, uint32_t num_records, uint32_t
|
||||
|
||||
DNS::queries_type DNS::queries() const {
|
||||
queries_type output;
|
||||
if(!records_data.empty()) {
|
||||
const uint8_t *ptr = &records_data[0],
|
||||
*end = &records_data[0] + answers_idx;
|
||||
if (!records_data_.empty()) {
|
||||
InputMemoryStream stream(&records_data_[0], answers_idx_);
|
||||
char buffer[256];
|
||||
uint16_t tmp_query_type;
|
||||
uint16_t tmp_query_class;
|
||||
while(ptr < end) {
|
||||
ptr = compose_name(ptr, buffer);
|
||||
if(ptr + sizeof(uint16_t) * 2 > end)
|
||||
throw malformed_packet();
|
||||
std::memcpy(&tmp_query_type, ptr, sizeof(uint16_t));
|
||||
std::memcpy(&tmp_query_class, ptr + 2, sizeof(uint16_t));
|
||||
while (stream) {
|
||||
stream.skip(compose_name(stream.pointer(), buffer));
|
||||
uint16_t query_type = stream.read_be<uint16_t>();
|
||||
uint16_t query_class = stream.read_be<uint16_t>();
|
||||
output.push_back(
|
||||
Query(
|
||||
buffer,
|
||||
(QueryType)Endian::be_to_host(tmp_query_type),
|
||||
(QueryClass)Endian::be_to_host(tmp_query_class)
|
||||
)
|
||||
Query(buffer, (QueryType)query_type, (QueryClass)query_class)
|
||||
);
|
||||
ptr += sizeof(uint16_t) * 2;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
@@ -554,10 +508,10 @@ DNS::queries_type DNS::queries() const {
|
||||
|
||||
DNS::resources_type DNS::answers() const {
|
||||
resources_type res;
|
||||
if(answers_idx < records_data.size()) {
|
||||
if (answers_idx_ < records_data_.size()) {
|
||||
convert_records(
|
||||
&records_data[0] + answers_idx,
|
||||
&records_data[0] + authority_idx,
|
||||
&records_data_[0] + answers_idx_,
|
||||
&records_data_[0] + authority_idx_,
|
||||
res
|
||||
);
|
||||
}
|
||||
@@ -566,10 +520,10 @@ DNS::resources_type DNS::answers() const {
|
||||
|
||||
DNS::resources_type DNS::authority() const {
|
||||
resources_type res;
|
||||
if(authority_idx < records_data.size()) {
|
||||
if (authority_idx_ < records_data_.size()) {
|
||||
convert_records(
|
||||
&records_data[0] + authority_idx,
|
||||
&records_data[0] + additional_idx,
|
||||
&records_data_[0] + authority_idx_,
|
||||
&records_data_[0] + additional_idx_,
|
||||
res
|
||||
);
|
||||
}
|
||||
@@ -578,20 +532,22 @@ DNS::resources_type DNS::authority() const {
|
||||
|
||||
DNS::resources_type DNS::additional() const {
|
||||
resources_type res;
|
||||
if(additional_idx < records_data.size()) {
|
||||
if (additional_idx_ < records_data_.size()) {
|
||||
convert_records(
|
||||
&records_data[0] + additional_idx,
|
||||
&records_data[0] + records_data.size(),
|
||||
&records_data_[0] + additional_idx_,
|
||||
&records_data_[0] + records_data_.size(),
|
||||
res
|
||||
);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool DNS::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
if(total_sz < sizeof(dnshdr))
|
||||
bool DNS::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
if (total_sz < sizeof(header_)) {
|
||||
return false;
|
||||
const dnshdr *hdr = (const dnshdr*)ptr;
|
||||
return hdr->id == dns.id;
|
||||
}
|
||||
}
|
||||
const dns_header* hdr = (const dns_header*)ptr;
|
||||
return hdr->id == header_.id;
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
@@ -37,168 +37,159 @@ using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
/* Diassoc */
|
||||
|
||||
Dot11Disassoc::Dot11Disassoc(const address_type &dst_hw_addr,
|
||||
const address_type &src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr), _body()
|
||||
{
|
||||
this->subtype(Dot11::DISASSOC);
|
||||
// Disassoc
|
||||
|
||||
Dot11Disassoc::Dot11Disassoc(const address_type& dst_hw_addr,
|
||||
const address_type& src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr), body_() {
|
||||
this->subtype(Dot11::DISASSOC);
|
||||
}
|
||||
|
||||
Dot11Disassoc::Dot11Disassoc(const uint8_t *buffer, uint32_t total_sz)
|
||||
Dot11Disassoc::Dot11Disassoc(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11ManagementFrame(buffer, total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(management_frame_size());
|
||||
stream.read(_body);
|
||||
stream.read(body_);
|
||||
parse_tagged_parameters(stream);
|
||||
}
|
||||
|
||||
void Dot11Disassoc::reason_code(uint16_t new_reason_code) {
|
||||
this->_body.reason_code = Endian::host_to_le(new_reason_code);
|
||||
body_.reason_code = Endian::host_to_le(new_reason_code);
|
||||
}
|
||||
|
||||
uint32_t Dot11Disassoc::header_size() const {
|
||||
return Dot11ManagementFrame::header_size() + sizeof(DisassocBody);
|
||||
return Dot11ManagementFrame::header_size() + sizeof(body_);
|
||||
}
|
||||
|
||||
void Dot11Disassoc::write_fixed_parameters(OutputMemoryStream& stream) {
|
||||
stream.write(_body);
|
||||
stream.write(body_);
|
||||
}
|
||||
|
||||
/* Assoc request. */
|
||||
// Assoc request
|
||||
|
||||
Dot11AssocRequest::Dot11AssocRequest(const address_type &dst_hw_addr,
|
||||
const address_type &src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr), _body()
|
||||
{
|
||||
Dot11AssocRequest::Dot11AssocRequest(const address_type& dst_hw_addr,
|
||||
const address_type& src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr), body_() {
|
||||
subtype(Dot11::ASSOC_REQ);
|
||||
}
|
||||
|
||||
Dot11AssocRequest::Dot11AssocRequest(const uint8_t *buffer, uint32_t total_sz)
|
||||
: Dot11ManagementFrame(buffer, total_sz)
|
||||
{
|
||||
Dot11AssocRequest::Dot11AssocRequest(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11ManagementFrame(buffer, total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(management_frame_size());
|
||||
stream.read(_body);
|
||||
stream.read(body_);
|
||||
parse_tagged_parameters(stream);
|
||||
}
|
||||
|
||||
void Dot11AssocRequest::listen_interval(uint16_t new_listen_interval) {
|
||||
this->_body.listen_interval = Endian::host_to_le(new_listen_interval);
|
||||
body_.listen_interval = Endian::host_to_le(new_listen_interval);
|
||||
}
|
||||
|
||||
uint32_t Dot11AssocRequest::header_size() const {
|
||||
return Dot11ManagementFrame::header_size() + sizeof(AssocReqBody);
|
||||
return Dot11ManagementFrame::header_size() + sizeof(body_);
|
||||
}
|
||||
|
||||
void Dot11AssocRequest::write_fixed_parameters(OutputMemoryStream& stream) {
|
||||
stream.write(_body);
|
||||
stream.write(body_);
|
||||
}
|
||||
|
||||
/* Assoc response. */
|
||||
// Assoc response
|
||||
|
||||
Dot11AssocResponse::Dot11AssocResponse(const address_type &dst_hw_addr,
|
||||
const address_type &src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr)
|
||||
{
|
||||
Dot11AssocResponse::Dot11AssocResponse(const address_type& dst_hw_addr,
|
||||
const address_type& src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr), body_() {
|
||||
subtype(Dot11::ASSOC_RESP);
|
||||
memset(&_body, 0, sizeof(_body));
|
||||
}
|
||||
|
||||
Dot11AssocResponse::Dot11AssocResponse(const uint8_t *buffer, uint32_t total_sz)
|
||||
: Dot11ManagementFrame(buffer, total_sz)
|
||||
{
|
||||
Dot11AssocResponse::Dot11AssocResponse(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11ManagementFrame(buffer, total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(management_frame_size());
|
||||
stream.read(_body);
|
||||
stream.read(body_);
|
||||
parse_tagged_parameters(stream);
|
||||
}
|
||||
|
||||
void Dot11AssocResponse::status_code(uint16_t new_status_code) {
|
||||
this->_body.status_code = Endian::host_to_le(new_status_code);
|
||||
body_.status_code = Endian::host_to_le(new_status_code);
|
||||
}
|
||||
|
||||
void Dot11AssocResponse::aid(uint16_t new_aid) {
|
||||
this->_body.aid = Endian::host_to_le(new_aid);
|
||||
body_.aid = Endian::host_to_le(new_aid);
|
||||
}
|
||||
|
||||
uint32_t Dot11AssocResponse::header_size() const {
|
||||
return Dot11ManagementFrame::header_size() + sizeof(AssocRespBody);
|
||||
return Dot11ManagementFrame::header_size() + sizeof(body_);
|
||||
}
|
||||
|
||||
void Dot11AssocResponse::write_fixed_parameters(OutputMemoryStream& stream) {
|
||||
stream.write(_body);
|
||||
stream.write(body_);
|
||||
}
|
||||
|
||||
/* ReAssoc request. */
|
||||
// ReAssoc request
|
||||
|
||||
Dot11ReAssocRequest::Dot11ReAssocRequest(const address_type &dst_hw_addr,
|
||||
const address_type &src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr)
|
||||
{
|
||||
this->subtype(Dot11::REASSOC_REQ);
|
||||
memset(&_body, 0, sizeof(_body));
|
||||
Dot11ReAssocRequest::Dot11ReAssocRequest(const address_type& dst_hw_addr,
|
||||
const address_type& src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr), body_() {
|
||||
subtype(Dot11::REASSOC_REQ);
|
||||
}
|
||||
|
||||
Dot11ReAssocRequest::Dot11ReAssocRequest(const uint8_t *buffer, uint32_t total_sz)
|
||||
: Dot11ManagementFrame(buffer, total_sz)
|
||||
{
|
||||
Dot11ReAssocRequest::Dot11ReAssocRequest(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11ManagementFrame(buffer, total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(management_frame_size());
|
||||
stream.read(_body);
|
||||
stream.read(body_);
|
||||
parse_tagged_parameters(stream);
|
||||
}
|
||||
|
||||
void Dot11ReAssocRequest::listen_interval(uint16_t new_listen_interval) {
|
||||
this->_body.listen_interval = Endian::host_to_le(new_listen_interval);
|
||||
body_.listen_interval = Endian::host_to_le(new_listen_interval);
|
||||
}
|
||||
|
||||
void Dot11ReAssocRequest::current_ap(const address_type &new_current_ap) {
|
||||
new_current_ap.copy(_body.current_ap);
|
||||
void Dot11ReAssocRequest::current_ap(const address_type& new_current_ap) {
|
||||
new_current_ap.copy(body_.current_ap);
|
||||
}
|
||||
|
||||
uint32_t Dot11ReAssocRequest::header_size() const {
|
||||
return Dot11ManagementFrame::header_size() + sizeof(this->_body);
|
||||
return Dot11ManagementFrame::header_size() + sizeof(body_);
|
||||
}
|
||||
|
||||
void Dot11ReAssocRequest::write_fixed_parameters(OutputMemoryStream& stream) {
|
||||
stream.write(_body);
|
||||
stream.write(body_);
|
||||
}
|
||||
|
||||
/* ReAssoc response. */
|
||||
// ReAssoc response
|
||||
|
||||
Dot11ReAssocResponse::Dot11ReAssocResponse(const address_type &dst_hw_addr,
|
||||
const address_type &src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr)
|
||||
{
|
||||
this->subtype(Dot11::REASSOC_RESP);
|
||||
memset(&_body, 0, sizeof(_body));
|
||||
Dot11ReAssocResponse::Dot11ReAssocResponse(const address_type& dst_hw_addr,
|
||||
const address_type& src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr), body_() {
|
||||
subtype(Dot11::REASSOC_RESP);
|
||||
}
|
||||
|
||||
Dot11ReAssocResponse::Dot11ReAssocResponse(const uint8_t *buffer, uint32_t total_sz)
|
||||
Dot11ReAssocResponse::Dot11ReAssocResponse(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11ManagementFrame(buffer, total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(management_frame_size());
|
||||
stream.read(_body);
|
||||
stream.read(body_);
|
||||
parse_tagged_parameters(stream);
|
||||
}
|
||||
|
||||
void Dot11ReAssocResponse::status_code(uint16_t new_status_code) {
|
||||
this->_body.status_code = Endian::host_to_le(new_status_code);
|
||||
body_.status_code = Endian::host_to_le(new_status_code);
|
||||
}
|
||||
|
||||
void Dot11ReAssocResponse::aid(uint16_t new_aid) {
|
||||
this->_body.aid = Endian::host_to_le(new_aid);
|
||||
body_.aid = Endian::host_to_le(new_aid);
|
||||
}
|
||||
|
||||
uint32_t Dot11ReAssocResponse::header_size() const {
|
||||
return Dot11ManagementFrame::header_size() + sizeof(this->_body);
|
||||
return Dot11ManagementFrame::header_size() + sizeof(body_);
|
||||
}
|
||||
|
||||
void Dot11ReAssocResponse::write_fixed_parameters(OutputMemoryStream& stream) {
|
||||
stream.write(_body);
|
||||
stream.write(body_);
|
||||
}
|
||||
} // namespace Tins
|
||||
|
||||
} // Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -37,74 +37,71 @@ using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
/* Auth */
|
||||
|
||||
Dot11Authentication::Dot11Authentication(const address_type &dst_hw_addr,
|
||||
const address_type &src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr)
|
||||
{
|
||||
this->subtype(Dot11::AUTH);
|
||||
memset(&_body, 0, sizeof(_body));
|
||||
// Auth
|
||||
|
||||
Dot11Authentication::Dot11Authentication(const address_type& dst_hw_addr,
|
||||
const address_type& src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr), body_() {
|
||||
subtype(Dot11::AUTH);
|
||||
}
|
||||
|
||||
Dot11Authentication::Dot11Authentication(const uint8_t *buffer, uint32_t total_sz)
|
||||
: Dot11ManagementFrame(buffer, total_sz)
|
||||
{
|
||||
Dot11Authentication::Dot11Authentication(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11ManagementFrame(buffer, total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(management_frame_size());
|
||||
stream.read(_body);
|
||||
stream.read(body_);
|
||||
parse_tagged_parameters(stream);
|
||||
}
|
||||
|
||||
void Dot11Authentication::auth_algorithm(uint16_t new_auth_algorithm) {
|
||||
this->_body.auth_algorithm = Endian::host_to_le(new_auth_algorithm);
|
||||
body_.auth_algorithm = Endian::host_to_le(new_auth_algorithm);
|
||||
}
|
||||
|
||||
void Dot11Authentication::auth_seq_number(uint16_t new_auth_seq_number) {
|
||||
this->_body.auth_seq_number = Endian::host_to_le(new_auth_seq_number);
|
||||
body_.auth_seq_number = Endian::host_to_le(new_auth_seq_number);
|
||||
}
|
||||
|
||||
void Dot11Authentication::status_code(uint16_t new_status_code) {
|
||||
this->_body.status_code = Endian::host_to_le(new_status_code);
|
||||
body_.status_code = Endian::host_to_le(new_status_code);
|
||||
}
|
||||
|
||||
uint32_t Dot11Authentication::header_size() const {
|
||||
return Dot11ManagementFrame::header_size() + sizeof(_body);
|
||||
return Dot11ManagementFrame::header_size() + sizeof(body_);
|
||||
}
|
||||
|
||||
void Dot11Authentication::write_fixed_parameters(OutputMemoryStream& stream) {
|
||||
stream.write(_body);
|
||||
stream.write(body_);
|
||||
}
|
||||
|
||||
/* Deauth */
|
||||
// Deauth
|
||||
|
||||
Dot11Deauthentication::Dot11Deauthentication(const address_type &dst_hw_addr,
|
||||
const address_type &src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr)
|
||||
{
|
||||
this->subtype(Dot11::DEAUTH);
|
||||
memset(&_body, 0, sizeof(_body));
|
||||
Dot11Deauthentication::Dot11Deauthentication(const address_type& dst_hw_addr,
|
||||
const address_type& src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr), body_() {
|
||||
subtype(Dot11::DEAUTH);
|
||||
}
|
||||
|
||||
Dot11Deauthentication::Dot11Deauthentication(const uint8_t *buffer, uint32_t total_sz)
|
||||
Dot11Deauthentication::Dot11Deauthentication(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11ManagementFrame(buffer, total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(management_frame_size());
|
||||
stream.read(_body);
|
||||
stream.read(body_);
|
||||
parse_tagged_parameters(stream);
|
||||
}
|
||||
|
||||
void Dot11Deauthentication::reason_code(uint16_t new_reason_code) {
|
||||
this->_body.reason_code = Endian::host_to_le(new_reason_code);
|
||||
body_.reason_code = Endian::host_to_le(new_reason_code);
|
||||
}
|
||||
|
||||
uint32_t Dot11Deauthentication::header_size() const {
|
||||
return Dot11ManagementFrame::header_size() + sizeof(this->_body);
|
||||
return Dot11ManagementFrame::header_size() + sizeof(body_);
|
||||
}
|
||||
|
||||
void Dot11Deauthentication::write_fixed_parameters(OutputMemoryStream& stream) {
|
||||
stream.write(_body);
|
||||
stream.write(body_);
|
||||
}
|
||||
} // namespace Tins
|
||||
|
||||
} // Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -59,24 +59,23 @@ using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
const Dot11::address_type Dot11::BROADCAST = "ff:ff:ff:ff:ff:ff";
|
||||
|
||||
Dot11::Dot11(const address_type &dst_hw_addr)
|
||||
: _header(), _options_size(0)
|
||||
{
|
||||
Dot11::Dot11(const address_type& dst_hw_addr)
|
||||
: header_(), options_size_(0) {
|
||||
addr1(dst_hw_addr);
|
||||
}
|
||||
|
||||
Dot11::Dot11(const ieee80211_header *header_ptr)
|
||||
{
|
||||
Dot11::Dot11(const dot11_header* header_ptr)
|
||||
: header_(), options_size_(0) {
|
||||
|
||||
}
|
||||
|
||||
Dot11::Dot11(const uint8_t *buffer, uint32_t total_sz)
|
||||
: _options_size(0)
|
||||
{
|
||||
Dot11::Dot11(const uint8_t* buffer, uint32_t total_sz)
|
||||
: options_size_(0) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_header);
|
||||
stream.read(header_);
|
||||
}
|
||||
|
||||
void Dot11::parse_tagged_parameters(InputMemoryStream& stream) {
|
||||
@@ -93,104 +92,104 @@ void Dot11::parse_tagged_parameters(InputMemoryStream& stream) {
|
||||
}
|
||||
}
|
||||
|
||||
void Dot11::add_tagged_option(OptionTypes opt, uint8_t len, const uint8_t *val) {
|
||||
void Dot11::add_tagged_option(OptionTypes opt, uint8_t len, const uint8_t* val) {
|
||||
uint32_t opt_size = len + sizeof(uint8_t) * 2;
|
||||
_options.push_back(option((uint8_t)opt, val, val + len));
|
||||
_options_size += opt_size;
|
||||
options_.push_back(option((uint8_t)opt, val, val + len));
|
||||
options_size_ += opt_size;
|
||||
}
|
||||
|
||||
void Dot11::internal_add_option(const option &opt) {
|
||||
_options_size += static_cast<uint32_t>(opt.data_size() + sizeof(uint8_t) * 2);
|
||||
void Dot11::internal_add_option(const option& opt) {
|
||||
options_size_ += static_cast<uint32_t>(opt.data_size() + sizeof(uint8_t) * 2);
|
||||
}
|
||||
|
||||
bool Dot11::remove_option(OptionTypes type) {
|
||||
options_type::iterator iter = search_option_iterator(type);
|
||||
if (iter == _options.end()) {
|
||||
if (iter == options_.end()) {
|
||||
return false;
|
||||
}
|
||||
_options_size -= static_cast<uint32_t>(iter->data_size() + sizeof(uint8_t) * 2);
|
||||
_options.erase(iter);
|
||||
options_size_ -= static_cast<uint32_t>(iter->data_size() + sizeof(uint8_t) * 2);
|
||||
options_.erase(iter);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Dot11::add_option(const option &opt) {
|
||||
void Dot11::add_option(const option& opt) {
|
||||
internal_add_option(opt);
|
||||
_options.push_back(opt);
|
||||
options_.push_back(opt);
|
||||
}
|
||||
|
||||
const Dot11::option *Dot11::search_option(OptionTypes type) const {
|
||||
const Dot11::option* Dot11::search_option(OptionTypes type) const {
|
||||
// Search for the iterator. If we found something, return it, otherwise return nullptr.
|
||||
options_type::const_iterator iter = search_option_iterator(type);
|
||||
return (iter != _options.end()) ? &*iter : 0;
|
||||
return (iter != options_.end()) ? &*iter : 0;
|
||||
}
|
||||
|
||||
Dot11::options_type::const_iterator Dot11::search_option_iterator(OptionTypes type) const {
|
||||
Internals::option_type_equality_comparator<option> comparator(static_cast<uint8_t>(type));
|
||||
return find_if(_options.begin(), _options.end(), comparator);
|
||||
return find_if(options_.begin(), options_.end(), comparator);
|
||||
}
|
||||
|
||||
Dot11::options_type::iterator Dot11::search_option_iterator(OptionTypes type) {
|
||||
Internals::option_type_equality_comparator<option> comparator(static_cast<uint8_t>(type));
|
||||
return find_if(_options.begin(), _options.end(), comparator);
|
||||
return find_if(options_.begin(), options_.end(), comparator);
|
||||
}
|
||||
|
||||
void Dot11::protocol(small_uint<2> new_proto) {
|
||||
this->_header.control.protocol = new_proto;
|
||||
header_.control.protocol = new_proto;
|
||||
}
|
||||
|
||||
void Dot11::type(small_uint<2> new_type) {
|
||||
this->_header.control.type = new_type;
|
||||
header_.control.type = new_type;
|
||||
}
|
||||
|
||||
void Dot11::subtype(small_uint<4> new_subtype) {
|
||||
this->_header.control.subtype = new_subtype;
|
||||
header_.control.subtype = new_subtype;
|
||||
}
|
||||
|
||||
void Dot11::to_ds(small_uint<1> new_value) {
|
||||
this->_header.control.to_ds = (new_value)? 1 : 0;
|
||||
header_.control.to_ds = (new_value)? 1 : 0;
|
||||
}
|
||||
|
||||
void Dot11::from_ds(small_uint<1> new_value) {
|
||||
this->_header.control.from_ds = (new_value)? 1 : 0;
|
||||
header_.control.from_ds = (new_value)? 1 : 0;
|
||||
}
|
||||
|
||||
void Dot11::more_frag(small_uint<1> new_value) {
|
||||
this->_header.control.more_frag = (new_value)? 1 : 0;
|
||||
header_.control.more_frag = (new_value)? 1 : 0;
|
||||
}
|
||||
|
||||
void Dot11::retry(small_uint<1> new_value) {
|
||||
this->_header.control.retry = (new_value)? 1 : 0;
|
||||
header_.control.retry = (new_value)? 1 : 0;
|
||||
}
|
||||
|
||||
void Dot11::power_mgmt(small_uint<1> new_value) {
|
||||
this->_header.control.power_mgmt = (new_value)? 1 : 0;
|
||||
header_.control.power_mgmt = (new_value)? 1 : 0;
|
||||
}
|
||||
|
||||
void Dot11::wep(small_uint<1> new_value) {
|
||||
this->_header.control.wep = (new_value)? 1 : 0;
|
||||
header_.control.wep = (new_value)? 1 : 0;
|
||||
}
|
||||
|
||||
void Dot11::order(small_uint<1> new_value) {
|
||||
this->_header.control.order = (new_value)? 1 : 0;
|
||||
header_.control.order = (new_value)? 1 : 0;
|
||||
}
|
||||
|
||||
void Dot11::duration_id(uint16_t new_duration_id) {
|
||||
this->_header.duration_id = Endian::host_to_le(new_duration_id);
|
||||
header_.duration_id = Endian::host_to_le(new_duration_id);
|
||||
}
|
||||
|
||||
void Dot11::addr1(const address_type &new_addr1) {
|
||||
std::copy(new_addr1.begin(), new_addr1.end(), _header.addr1);
|
||||
void Dot11::addr1(const address_type& new_addr1) {
|
||||
new_addr1.copy(header_.addr1);
|
||||
}
|
||||
|
||||
uint32_t Dot11::header_size() const {
|
||||
uint32_t sz = sizeof(ieee80211_header) + _options_size;
|
||||
return sz;
|
||||
return sizeof(header_) + options_size_;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
void Dot11::send(PacketSender &sender, const NetworkInterface &iface) {
|
||||
if(!iface)
|
||||
void Dot11::send(PacketSender& sender, const NetworkInterface& iface) {
|
||||
if (!iface) {
|
||||
throw invalid_interface();
|
||||
}
|
||||
|
||||
#if !defined(BSD) && !defined(__FreeBSD_kernel__)
|
||||
sockaddr_ll addr;
|
||||
@@ -201,7 +200,7 @@ void Dot11::send(PacketSender &sender, const NetworkInterface &iface) {
|
||||
addr.sll_protocol = Endian::host_to_be<uint16_t>(ETH_P_ALL);
|
||||
addr.sll_halen = 6;
|
||||
addr.sll_ifindex = iface.id();
|
||||
memcpy(&(addr.sll_addr), _header.addr1, 6);
|
||||
memcpy(&(addr.sll_addr), header_.addr1, 6);
|
||||
sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
|
||||
#else
|
||||
sender.send_l2(*this, 0, 0, iface);
|
||||
@@ -209,74 +208,84 @@ void Dot11::send(PacketSender &sender, const NetworkInterface &iface) {
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
void Dot11::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
|
||||
void Dot11::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
stream.write(_header);
|
||||
stream.write(header_);
|
||||
write_ext_header(stream);
|
||||
write_fixed_parameters(stream);
|
||||
for (std::list<option>::const_iterator it = _options.begin(); it != _options.end(); ++it) {
|
||||
for (std::list<option>::const_iterator it = options_.begin(); it != options_.end(); ++it) {
|
||||
stream.write<uint8_t>(it->option());
|
||||
stream.write<uint8_t>(it->length_field());
|
||||
stream.write(it->data_ptr(), it->data_size());
|
||||
}
|
||||
}
|
||||
|
||||
Dot11 *Dot11::from_bytes(const uint8_t *buffer, uint32_t total_sz) {
|
||||
Dot11* Dot11::from_bytes(const uint8_t* buffer, uint32_t total_sz) {
|
||||
// We only need the control field, the length of the PDU will depend on the flags set.
|
||||
|
||||
// This should be sizeof(ieee80211_header::control), but gcc 4.2 complains
|
||||
if(total_sz < 2)
|
||||
// This should be sizeof(dot11_header::control), but gcc 4.2 complains
|
||||
if (total_sz < 2) {
|
||||
throw malformed_packet();
|
||||
const ieee80211_header *hdr = (const ieee80211_header*)buffer;
|
||||
Dot11 *ret = 0;
|
||||
if(hdr->control.type == MANAGEMENT) {
|
||||
if(hdr->control.subtype == BEACON)
|
||||
ret = new Dot11Beacon(buffer, total_sz);
|
||||
else if(hdr->control.subtype == DISASSOC)
|
||||
ret = new Dot11Disassoc(buffer, total_sz);
|
||||
else if(hdr->control.subtype == ASSOC_REQ)
|
||||
ret = new Dot11AssocRequest(buffer, total_sz);
|
||||
else if(hdr->control.subtype == ASSOC_RESP)
|
||||
ret = new Dot11AssocResponse(buffer, total_sz);
|
||||
else if(hdr->control.subtype == REASSOC_REQ)
|
||||
ret = new Dot11ReAssocRequest(buffer, total_sz);
|
||||
else if(hdr->control.subtype == REASSOC_RESP)
|
||||
ret = new Dot11ReAssocResponse(buffer, total_sz);
|
||||
else if(hdr->control.subtype == AUTH)
|
||||
ret = new Dot11Authentication(buffer, total_sz);
|
||||
else if(hdr->control.subtype == DEAUTH)
|
||||
ret = new Dot11Deauthentication(buffer, total_sz);
|
||||
else if(hdr->control.subtype == PROBE_REQ)
|
||||
ret = new Dot11ProbeRequest(buffer, total_sz);
|
||||
else if(hdr->control.subtype == PROBE_RESP)
|
||||
ret = new Dot11ProbeResponse(buffer, total_sz);
|
||||
}
|
||||
else if(hdr->control.type == DATA){
|
||||
if(hdr->control.subtype <= 4)
|
||||
ret = new Dot11Data(buffer, total_sz);
|
||||
else
|
||||
ret = new Dot11QoSData(buffer, total_sz);
|
||||
const dot11_header* hdr = (const dot11_header*)buffer;
|
||||
if (hdr->control.type == MANAGEMENT) {
|
||||
switch (hdr->control.subtype) {
|
||||
case BEACON:
|
||||
return new Dot11Beacon(buffer, total_sz);
|
||||
case DISASSOC:
|
||||
return new Dot11Disassoc(buffer, total_sz);
|
||||
case ASSOC_REQ:
|
||||
return new Dot11AssocRequest(buffer, total_sz);
|
||||
case ASSOC_RESP:
|
||||
return new Dot11AssocResponse(buffer, total_sz);
|
||||
case REASSOC_REQ:
|
||||
return new Dot11ReAssocRequest(buffer, total_sz);
|
||||
case REASSOC_RESP:
|
||||
return new Dot11ReAssocResponse(buffer, total_sz);
|
||||
case AUTH:
|
||||
return new Dot11Authentication(buffer, total_sz);
|
||||
case DEAUTH:
|
||||
return new Dot11Deauthentication(buffer, total_sz);
|
||||
case PROBE_REQ:
|
||||
return new Dot11ProbeRequest(buffer, total_sz);
|
||||
case PROBE_RESP:
|
||||
return new Dot11ProbeResponse(buffer, total_sz);
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
else if(hdr->control.type == CONTROL){
|
||||
if(hdr->control.subtype == ACK)
|
||||
ret = new Dot11Ack(buffer, total_sz);
|
||||
else if(hdr->control.subtype == CF_END)
|
||||
ret = new Dot11CFEnd(buffer, total_sz);
|
||||
else if(hdr->control.subtype == CF_END_ACK)
|
||||
ret = new Dot11EndCFAck(buffer, total_sz);
|
||||
else if(hdr->control.subtype == PS)
|
||||
ret = new Dot11PSPoll(buffer, total_sz);
|
||||
else if(hdr->control.subtype == RTS)
|
||||
ret = new Dot11RTS(buffer, total_sz);
|
||||
else if(hdr->control.subtype == BLOCK_ACK)
|
||||
ret = new Dot11BlockAck(buffer, total_sz);
|
||||
else if(hdr->control.subtype == BLOCK_ACK_REQ)
|
||||
ret = new Dot11BlockAckRequest(buffer, total_sz);
|
||||
else if (hdr->control.type == DATA) {
|
||||
if (hdr->control.subtype <= 4) {
|
||||
return new Dot11Data(buffer, total_sz);
|
||||
}
|
||||
else {
|
||||
return new Dot11QoSData(buffer, total_sz);
|
||||
}
|
||||
}
|
||||
if(ret == 0)
|
||||
ret = new Dot11(buffer, total_sz);
|
||||
return ret;
|
||||
else if (hdr->control.type == CONTROL) {
|
||||
switch (hdr->control.subtype) {
|
||||
case ACK:
|
||||
return new Dot11Ack(buffer, total_sz);
|
||||
case CF_END:
|
||||
return new Dot11CFEnd(buffer, total_sz);
|
||||
case CF_END_ACK:
|
||||
return new Dot11EndCFAck(buffer, total_sz);
|
||||
case PS:
|
||||
return new Dot11PSPoll(buffer, total_sz);
|
||||
case RTS:
|
||||
return new Dot11RTS(buffer, total_sz);
|
||||
case BLOCK_ACK:
|
||||
return new Dot11BlockAck(buffer, total_sz);
|
||||
case BLOCK_ACK_REQ:
|
||||
return new Dot11BlockAckRequest(buffer, total_sz);
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
// Fallback to just building a dot11
|
||||
return new Dot11(buffer, total_sz);
|
||||
}
|
||||
} // namespace Tins
|
||||
|
||||
} // Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -37,40 +37,39 @@ using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
/* Dot11Beacon */
|
||||
|
||||
Dot11Beacon::Dot11Beacon(const address_type &dst_hw_addr,
|
||||
const address_type &src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr)
|
||||
{
|
||||
// Dot11Beacon
|
||||
|
||||
Dot11Beacon::Dot11Beacon(const address_type& dst_hw_addr,
|
||||
const address_type& src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr), body_() {
|
||||
subtype(Dot11::BEACON);
|
||||
std::memset(&_body, 0, sizeof(_body));
|
||||
}
|
||||
|
||||
Dot11Beacon::Dot11Beacon(const uint8_t *buffer, uint32_t total_sz)
|
||||
: Dot11ManagementFrame(buffer, total_sz)
|
||||
{
|
||||
Dot11Beacon::Dot11Beacon(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11ManagementFrame(buffer, total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(management_frame_size());
|
||||
stream.read(_body);
|
||||
stream.read(body_);
|
||||
parse_tagged_parameters(stream);
|
||||
}
|
||||
|
||||
void Dot11Beacon::timestamp(uint64_t new_timestamp) {
|
||||
this->_body.timestamp = Endian::host_to_le(new_timestamp);
|
||||
body_.timestamp = Endian::host_to_le(new_timestamp);
|
||||
}
|
||||
|
||||
void Dot11Beacon::interval(uint16_t new_interval) {
|
||||
this->_body.interval = Endian::host_to_le(new_interval);
|
||||
body_.interval = Endian::host_to_le(new_interval);
|
||||
}
|
||||
|
||||
uint32_t Dot11Beacon::header_size() const {
|
||||
return Dot11ManagementFrame::header_size() + sizeof(_body);
|
||||
return Dot11ManagementFrame::header_size() + sizeof(body_);
|
||||
}
|
||||
|
||||
void Dot11Beacon::write_fixed_parameters(OutputMemoryStream& stream) {
|
||||
stream.write(_body);
|
||||
stream.write(body_);
|
||||
}
|
||||
} // namespace Tins
|
||||
|
||||
} // Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -30,237 +30,225 @@
|
||||
#include "dot11/dot11_control.h"
|
||||
#ifdef HAVE_DOT11
|
||||
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::copy;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
/* Dot11Control */
|
||||
|
||||
Dot11Control::Dot11Control(const address_type &dst_addr)
|
||||
: Dot11(dst_addr)
|
||||
{
|
||||
// Dot11Control
|
||||
|
||||
Dot11Control::Dot11Control(const address_type& dst_addr)
|
||||
: Dot11(dst_addr) {
|
||||
type(CONTROL);
|
||||
}
|
||||
|
||||
Dot11Control::Dot11Control(const uint8_t *buffer, uint32_t total_sz)
|
||||
Dot11Control::Dot11Control(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11(buffer, total_sz) {
|
||||
|
||||
}
|
||||
|
||||
/* Dot11ControlTA */
|
||||
// Dot11ControlTA
|
||||
|
||||
Dot11ControlTA::Dot11ControlTA(const address_type &dst_addr,
|
||||
const address_type &target_address)
|
||||
: Dot11Control(dst_addr)
|
||||
{
|
||||
Dot11ControlTA::Dot11ControlTA(const address_type& dst_addr,
|
||||
const address_type& target_address)
|
||||
: Dot11Control(dst_addr) {
|
||||
target_addr(target_address);
|
||||
}
|
||||
|
||||
Dot11ControlTA::Dot11ControlTA(const uint8_t *buffer, uint32_t total_sz) : Dot11Control(buffer, total_sz) {
|
||||
Dot11ControlTA::Dot11ControlTA(const uint8_t* buffer, uint32_t total_sz) : Dot11Control(buffer, total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(sizeof(ieee80211_header));
|
||||
stream.read(_taddr);
|
||||
stream.skip(sizeof(dot11_header));
|
||||
stream.read(taddr_);
|
||||
}
|
||||
|
||||
uint32_t Dot11ControlTA::header_size() const {
|
||||
return Dot11::header_size() + sizeof(_taddr);
|
||||
return Dot11::header_size() + taddr_.size();
|
||||
}
|
||||
|
||||
void Dot11ControlTA::write_ext_header(OutputMemoryStream& stream) {
|
||||
stream.write(_taddr);
|
||||
stream.write(taddr_);
|
||||
}
|
||||
|
||||
void Dot11ControlTA::target_addr(const address_type &addr) {
|
||||
_taddr = addr;
|
||||
void Dot11ControlTA::target_addr(const address_type& addr) {
|
||||
taddr_ = addr;
|
||||
}
|
||||
|
||||
/* Dot11RTS */
|
||||
// Dot11RTS
|
||||
|
||||
Dot11RTS::Dot11RTS(const address_type &dst_addr,
|
||||
const address_type &target_addr)
|
||||
: Dot11ControlTA(dst_addr, target_addr)
|
||||
{
|
||||
Dot11RTS::Dot11RTS(const address_type& dst_addr,
|
||||
const address_type& target_addr)
|
||||
: Dot11ControlTA(dst_addr, target_addr) {
|
||||
subtype(RTS);
|
||||
}
|
||||
|
||||
Dot11RTS::Dot11RTS(const uint8_t *buffer, uint32_t total_sz)
|
||||
Dot11RTS::Dot11RTS(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11ControlTA(buffer, total_sz) {
|
||||
|
||||
}
|
||||
|
||||
/* Dot11PSPoll */
|
||||
// Dot11PSPoll
|
||||
|
||||
Dot11PSPoll::Dot11PSPoll(const address_type &dst_addr,
|
||||
const address_type &target_addr)
|
||||
: Dot11ControlTA(dst_addr, target_addr)
|
||||
{
|
||||
Dot11PSPoll::Dot11PSPoll(const address_type& dst_addr,
|
||||
const address_type& target_addr)
|
||||
: Dot11ControlTA(dst_addr, target_addr) {
|
||||
subtype(PS);
|
||||
}
|
||||
|
||||
Dot11PSPoll::Dot11PSPoll(const uint8_t *buffer, uint32_t total_sz)
|
||||
Dot11PSPoll::Dot11PSPoll(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11ControlTA(buffer, total_sz) {
|
||||
|
||||
}
|
||||
|
||||
/* Dot11CFEnd */
|
||||
// Dot11CFEnd
|
||||
|
||||
Dot11CFEnd::Dot11CFEnd(const address_type &dst_addr,
|
||||
const address_type &target_addr)
|
||||
: Dot11ControlTA(dst_addr, target_addr)
|
||||
{
|
||||
Dot11CFEnd::Dot11CFEnd(const address_type& dst_addr,
|
||||
const address_type& target_addr)
|
||||
: Dot11ControlTA(dst_addr, target_addr) {
|
||||
subtype(CF_END);
|
||||
}
|
||||
|
||||
Dot11CFEnd::Dot11CFEnd(const uint8_t *buffer, uint32_t total_sz)
|
||||
Dot11CFEnd::Dot11CFEnd(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11ControlTA(buffer, total_sz) {
|
||||
|
||||
}
|
||||
|
||||
/* Dot11EndCFAck */
|
||||
// Dot11EndCFAck
|
||||
|
||||
Dot11EndCFAck::Dot11EndCFAck(const address_type &dst_addr,
|
||||
const address_type &target_addr)
|
||||
: Dot11ControlTA(dst_addr, target_addr)
|
||||
{
|
||||
Dot11EndCFAck::Dot11EndCFAck(const address_type& dst_addr,
|
||||
const address_type& target_addr)
|
||||
: Dot11ControlTA(dst_addr, target_addr) {
|
||||
subtype(CF_END_ACK);
|
||||
}
|
||||
|
||||
Dot11EndCFAck::Dot11EndCFAck(const uint8_t *buffer, uint32_t total_sz)
|
||||
Dot11EndCFAck::Dot11EndCFAck(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11ControlTA(buffer, total_sz) {
|
||||
|
||||
}
|
||||
|
||||
/* Dot11Ack */
|
||||
// Dot11Ack
|
||||
|
||||
Dot11Ack::Dot11Ack(const address_type &dst_addr)
|
||||
: Dot11Control(dst_addr)
|
||||
{
|
||||
Dot11Ack::Dot11Ack(const address_type& dst_addr)
|
||||
: Dot11Control(dst_addr) {
|
||||
subtype(ACK);
|
||||
}
|
||||
|
||||
Dot11Ack::Dot11Ack(const uint8_t *buffer, uint32_t total_sz)
|
||||
: Dot11Control(buffer, total_sz)
|
||||
{
|
||||
Dot11Ack::Dot11Ack(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11Control(buffer, total_sz) {
|
||||
|
||||
}
|
||||
|
||||
/* Dot11BlockAck */
|
||||
// Dot11BlockAck
|
||||
|
||||
Dot11BlockAckRequest::Dot11BlockAckRequest(const address_type &dst_addr,
|
||||
const address_type &target_addr)
|
||||
: Dot11ControlTA(dst_addr, target_addr)
|
||||
{
|
||||
init_block_ack();
|
||||
Dot11BlockAckRequest::Dot11BlockAckRequest(const address_type& dst_addr,
|
||||
const address_type& target_addr)
|
||||
: Dot11ControlTA(dst_addr, target_addr), bar_control_(0), start_sequence_(0) {
|
||||
subtype(BLOCK_ACK_REQ);
|
||||
}
|
||||
|
||||
Dot11BlockAckRequest::Dot11BlockAckRequest(const uint8_t *buffer, uint32_t total_sz)
|
||||
: Dot11ControlTA(buffer, total_sz)
|
||||
{
|
||||
Dot11BlockAckRequest::Dot11BlockAckRequest(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11ControlTA(buffer, total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(controlta_size());
|
||||
stream.read(_bar_control);
|
||||
stream.read(_start_sequence);
|
||||
}
|
||||
|
||||
void Dot11BlockAckRequest::init_block_ack() {
|
||||
subtype(BLOCK_ACK_REQ);
|
||||
std::memset(&_bar_control, 0, sizeof(_bar_control));
|
||||
std::memset(&_start_sequence, 0, sizeof(_start_sequence));
|
||||
stream.read(bar_control_);
|
||||
stream.read(start_sequence_);
|
||||
}
|
||||
|
||||
void Dot11BlockAckRequest::write_ext_header(OutputMemoryStream& stream) {
|
||||
Dot11ControlTA::write_ext_header(stream);
|
||||
stream.write(_bar_control);
|
||||
stream.write(_start_sequence);
|
||||
stream.write(bar_control_);
|
||||
stream.write(start_sequence_);
|
||||
}
|
||||
|
||||
void Dot11BlockAckRequest::bar_control(small_uint<4> bar) {
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
_bar_control = bar | (_bar_control & 0xfff0);
|
||||
bar_control_ = bar | (bar_control_ & 0xfff0);
|
||||
#else
|
||||
_bar_control = (bar << 8) | (_bar_control & 0xf0ff);
|
||||
bar_control_ = (bar << 8) | (bar_control_ & 0xf0ff);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Dot11BlockAckRequest::start_sequence(small_uint<12> seq) {
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
_start_sequence = (seq << 4) | (_start_sequence & 0xf);
|
||||
start_sequence_ = (seq << 4) | (start_sequence_ & 0xf);
|
||||
#else
|
||||
_start_sequence = Endian::host_to_le<uint16_t>(seq << 4) | (_start_sequence & 0xf00);
|
||||
start_sequence_ = Endian::host_to_le<uint16_t>(seq << 4) | (start_sequence_ & 0xf00);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Dot11BlockAckRequest::fragment_number(small_uint<4> frag) {
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
_start_sequence = frag | (_start_sequence & 0xfff0);
|
||||
start_sequence_ = frag | (start_sequence_ & 0xfff0);
|
||||
#else
|
||||
_start_sequence = (frag << 8) | (_start_sequence & 0xf0ff);
|
||||
start_sequence_ = (frag << 8) | (start_sequence_ & 0xf0ff);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t Dot11BlockAckRequest::header_size() const {
|
||||
return Dot11ControlTA::header_size() + sizeof(_start_sequence) + sizeof(_start_sequence);
|
||||
return Dot11ControlTA::header_size() + sizeof(start_sequence_) + sizeof(start_sequence_);
|
||||
}
|
||||
|
||||
/* Dot11BlockAck */
|
||||
// Dot11BlockAck
|
||||
|
||||
Dot11BlockAck::Dot11BlockAck(const address_type &dst_addr,
|
||||
const address_type &target_addr)
|
||||
: Dot11ControlTA(dst_addr, target_addr)
|
||||
{
|
||||
Dot11BlockAck::Dot11BlockAck(const address_type& dst_addr,
|
||||
const address_type& target_addr)
|
||||
: Dot11ControlTA(dst_addr, target_addr), bitmap_() {
|
||||
subtype(BLOCK_ACK);
|
||||
std::memset(_bitmap, 0, sizeof(_bitmap));
|
||||
}
|
||||
|
||||
Dot11BlockAck::Dot11BlockAck(const uint8_t *buffer, uint32_t total_sz) : Dot11ControlTA(buffer, total_sz) {
|
||||
Dot11BlockAck::Dot11BlockAck(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11ControlTA(buffer, total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(controlta_size());
|
||||
stream.read(_bar_control);
|
||||
stream.read(_start_sequence);
|
||||
stream.read(_bitmap);
|
||||
stream.read(bar_control_);
|
||||
stream.read(start_sequence_);
|
||||
stream.read(bitmap_);
|
||||
}
|
||||
|
||||
void Dot11BlockAck::bar_control(small_uint<4> bar) {
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
_bar_control = bar | (_bar_control & 0xfff0);
|
||||
bar_control_ = bar | (bar_control_ & 0xfff0);
|
||||
#else
|
||||
_bar_control = (bar << 8) | (_bar_control & 0xf0ff);
|
||||
bar_control_ = (bar << 8) | (bar_control_ & 0xf0ff);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Dot11BlockAck::start_sequence(small_uint<12> seq) {
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
_start_sequence = (seq << 4) | (_start_sequence & 0xf);
|
||||
start_sequence_ = (seq << 4) | (start_sequence_ & 0xf);
|
||||
#else
|
||||
_start_sequence = Endian::host_to_le<uint16_t>(seq << 4) | (_start_sequence & 0xf00);
|
||||
start_sequence_ = Endian::host_to_le<uint16_t>(seq << 4) | (start_sequence_ & 0xf00);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Dot11BlockAck::fragment_number(small_uint<4> frag) {
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
_start_sequence = frag | (_start_sequence & 0xfff0);
|
||||
start_sequence_ = frag | (start_sequence_ & 0xfff0);
|
||||
#else
|
||||
_start_sequence = (frag << 8) | (_start_sequence & 0xf0ff);
|
||||
start_sequence_ = (frag << 8) | (start_sequence_ & 0xf0ff);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Dot11BlockAck::bitmap(const uint8_t *bit) {
|
||||
std::memcpy(_bitmap, bit, sizeof(_bitmap));
|
||||
void Dot11BlockAck::bitmap(const uint8_t* bit) {
|
||||
copy(bit, bit + bitmap_size, bitmap_);
|
||||
}
|
||||
|
||||
void Dot11BlockAck::write_ext_header(OutputMemoryStream& stream) {
|
||||
Dot11ControlTA::write_ext_header(stream);
|
||||
stream.write(_bar_control);
|
||||
stream.write(_start_sequence);
|
||||
stream.write(_bitmap);
|
||||
stream.write(bar_control_);
|
||||
stream.write(start_sequence_);
|
||||
stream.write(bitmap_);
|
||||
}
|
||||
|
||||
uint32_t Dot11BlockAck::header_size() const {
|
||||
return Dot11ControlTA::header_size() + sizeof(_start_sequence) + sizeof(_start_sequence) + sizeof(_bitmap);
|
||||
return Dot11ControlTA::header_size() + sizeof(start_sequence_) +
|
||||
sizeof(start_sequence_) + sizeof(bitmap_);
|
||||
}
|
||||
} // namespace Tins
|
||||
|
||||
} // Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -39,17 +39,17 @@ using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
/* Dot11Data */
|
||||
|
||||
Dot11Data::Dot11Data(const uint8_t *buffer, uint32_t total_sz)
|
||||
: Dot11(buffer, total_sz)
|
||||
{
|
||||
// Dot11Data
|
||||
|
||||
Dot11Data::Dot11Data(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11(buffer, total_sz) {
|
||||
const uint32_t offset = init(buffer, total_sz);
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(offset);
|
||||
if (stream) {
|
||||
// If the wep bit is on, then just use a RawPDU
|
||||
if(wep()) {
|
||||
if (wep()) {
|
||||
inner_pdu(new Tins::RawPDU(stream.pointer(), stream.size()));
|
||||
}
|
||||
else {
|
||||
@@ -58,89 +58,84 @@ Dot11Data::Dot11Data(const uint8_t *buffer, uint32_t total_sz)
|
||||
}
|
||||
}
|
||||
|
||||
Dot11Data::Dot11Data(const uint8_t *buffer, uint32_t total_sz, no_inner_pdu)
|
||||
: Dot11(buffer, total_sz)
|
||||
{
|
||||
Dot11Data::Dot11Data(const uint8_t* buffer, uint32_t total_sz, no_inner_pdu)
|
||||
: Dot11(buffer, total_sz) {
|
||||
init(buffer, total_sz);
|
||||
}
|
||||
|
||||
uint32_t Dot11Data::init(const uint8_t *buffer, uint32_t total_sz) {
|
||||
uint32_t Dot11Data::init(const uint8_t* buffer, uint32_t total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(Dot11::header_size());
|
||||
stream.read(_ext_header);
|
||||
stream.read(ext_header_);
|
||||
if (from_ds() && to_ds()) {
|
||||
stream.read(_addr4);
|
||||
stream.read(addr4_);
|
||||
}
|
||||
return total_sz - stream.size();
|
||||
}
|
||||
|
||||
Dot11Data::Dot11Data(const address_type &dst_hw_addr,
|
||||
const address_type &src_hw_addr)
|
||||
: Dot11(dst_hw_addr)
|
||||
{
|
||||
Dot11Data::Dot11Data(const address_type& dst_hw_addr,
|
||||
const address_type& src_hw_addr)
|
||||
: Dot11(dst_hw_addr), ext_header_() {
|
||||
type(Dot11::DATA);
|
||||
memset(&_ext_header, 0, sizeof(_ext_header));
|
||||
addr2(src_hw_addr);
|
||||
}
|
||||
|
||||
uint32_t Dot11Data::header_size() const {
|
||||
uint32_t sz = Dot11::header_size() + sizeof(_ext_header);
|
||||
if (this->from_ds() && this->to_ds())
|
||||
uint32_t sz = Dot11::header_size() + sizeof(ext_header_);
|
||||
if (this->from_ds() && this->to_ds()) {
|
||||
sz += 6;
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
void Dot11Data::addr2(const address_type &new_addr2) {
|
||||
std::copy(new_addr2.begin(), new_addr2.end(), _ext_header.addr2);
|
||||
void Dot11Data::addr2(const address_type& new_addr2) {
|
||||
new_addr2.copy(ext_header_.addr2);
|
||||
}
|
||||
|
||||
void Dot11Data::addr3(const address_type &new_addr3) {
|
||||
std::copy(new_addr3.begin(), new_addr3.end(), _ext_header.addr3);
|
||||
void Dot11Data::addr3(const address_type& new_addr3) {
|
||||
new_addr3.copy(ext_header_.addr3);
|
||||
}
|
||||
|
||||
void Dot11Data::frag_num(small_uint<4> new_frag_num) {
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
_ext_header.frag_seq = new_frag_num | (_ext_header.frag_seq & 0xfff0);
|
||||
ext_header_.frag_seq = new_frag_num | (ext_header_.frag_seq & 0xfff0);
|
||||
#else
|
||||
_ext_header.frag_seq = (new_frag_num << 8) | (_ext_header.frag_seq & 0xf0ff);
|
||||
ext_header_.frag_seq = (new_frag_num << 8) | (ext_header_.frag_seq & 0xf0ff);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Dot11Data::seq_num(small_uint<12> new_seq_num) {
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
_ext_header.frag_seq = (new_seq_num << 4) | (_ext_header.frag_seq & 0xf);
|
||||
ext_header_.frag_seq = (new_seq_num << 4) | (ext_header_.frag_seq & 0xf);
|
||||
#else
|
||||
_ext_header.frag_seq = Endian::host_to_le<uint16_t>(new_seq_num << 4) | (_ext_header.frag_seq & 0xf00);
|
||||
ext_header_.frag_seq = Endian::host_to_le<uint16_t>(new_seq_num << 4) | (ext_header_.frag_seq & 0xf00);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Dot11Data::addr4(const address_type &new_addr4) {
|
||||
_addr4 = new_addr4;
|
||||
void Dot11Data::addr4(const address_type& new_addr4) {
|
||||
addr4_ = new_addr4;
|
||||
}
|
||||
|
||||
void Dot11Data::write_ext_header(OutputMemoryStream& stream) {
|
||||
stream.write(_ext_header);
|
||||
stream.write(ext_header_);
|
||||
if (from_ds() && to_ds()) {
|
||||
stream.write(_addr4);
|
||||
stream.write(addr4_);
|
||||
}
|
||||
}
|
||||
|
||||
/* QoS data. */
|
||||
// QoS data
|
||||
|
||||
Dot11QoSData::Dot11QoSData(const address_type &dst_hw_addr,
|
||||
const address_type &src_hw_addr)
|
||||
: Dot11Data(dst_hw_addr, src_hw_addr)
|
||||
{
|
||||
Dot11QoSData::Dot11QoSData(const address_type& dst_hw_addr,
|
||||
const address_type& src_hw_addr)
|
||||
: Dot11Data(dst_hw_addr, src_hw_addr), qos_control_() {
|
||||
subtype(Dot11::QOS_DATA_DATA);
|
||||
_qos_control = 0;
|
||||
}
|
||||
|
||||
Dot11QoSData::Dot11QoSData(const uint8_t *buffer, uint32_t total_sz)
|
||||
// Am I breaking something? :S
|
||||
Dot11QoSData::Dot11QoSData(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11Data(buffer, total_sz, no_inner_pdu()) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(data_frame_size());
|
||||
stream.read(_qos_control);
|
||||
stream.skip(Dot11Data::header_size());
|
||||
stream.read(qos_control_);
|
||||
if (total_sz) {
|
||||
// If the wep bit is on, then just use a RawPDU
|
||||
if (wep()) {
|
||||
@@ -153,16 +148,17 @@ Dot11QoSData::Dot11QoSData(const uint8_t *buffer, uint32_t total_sz)
|
||||
}
|
||||
|
||||
void Dot11QoSData::qos_control(uint16_t new_qos_control) {
|
||||
this->_qos_control = Endian::host_to_le(new_qos_control);
|
||||
qos_control_ = Endian::host_to_le(new_qos_control);
|
||||
}
|
||||
|
||||
uint32_t Dot11QoSData::header_size() const {
|
||||
return Dot11Data::header_size() + sizeof(this->_qos_control);
|
||||
return Dot11Data::header_size() + sizeof(qos_control_);
|
||||
}
|
||||
|
||||
void Dot11QoSData::write_fixed_parameters(OutputMemoryStream& stream) {
|
||||
stream.write(_qos_control);
|
||||
stream.write(qos_control_);
|
||||
}
|
||||
} // namespace Tins
|
||||
|
||||
} // Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -34,76 +34,88 @@
|
||||
#include "rsn_information.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::string;
|
||||
using std::copy;
|
||||
using std::vector;
|
||||
using std::back_inserter;
|
||||
using std::runtime_error;
|
||||
using std::pair;
|
||||
using std::make_pair;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
/* Dot11ManagementFrame */
|
||||
|
||||
Dot11ManagementFrame::Dot11ManagementFrame(const uint8_t *buffer, uint32_t total_sz)
|
||||
: Dot11(buffer, total_sz)
|
||||
{
|
||||
// Dot11ManagementFrame
|
||||
|
||||
Dot11ManagementFrame::Dot11ManagementFrame(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11(buffer, total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(sizeof(ieee80211_header));
|
||||
stream.read(_ext_header);
|
||||
stream.skip(sizeof(dot11_header));
|
||||
stream.read(ext_header_);
|
||||
if (from_ds() && to_ds()) {
|
||||
stream.read(_addr4);
|
||||
stream.read(addr4_);
|
||||
}
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::Dot11ManagementFrame(const address_type &dst_hw_addr,
|
||||
const address_type &src_hw_addr)
|
||||
: Dot11(dst_hw_addr), _ext_header()
|
||||
{
|
||||
Dot11ManagementFrame::Dot11ManagementFrame(const address_type& dst_hw_addr,
|
||||
const address_type& src_hw_addr)
|
||||
: Dot11(dst_hw_addr), ext_header_() {
|
||||
type(Dot11::MANAGEMENT);
|
||||
addr2(src_hw_addr);
|
||||
}
|
||||
|
||||
uint32_t Dot11ManagementFrame::header_size() const {
|
||||
uint32_t sz = Dot11::header_size() + sizeof(_ext_header);
|
||||
if (this->from_ds() && this->to_ds()) {
|
||||
uint32_t sz = Dot11::header_size() + sizeof(ext_header_);
|
||||
if (from_ds() && to_ds()) {
|
||||
sz += 6;
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::addr2(const address_type &new_addr2) {
|
||||
std::copy(new_addr2.begin(), new_addr2.end(), _ext_header.addr2);
|
||||
void Dot11ManagementFrame::addr2(const address_type& new_addr2) {
|
||||
new_addr2.copy(ext_header_.addr2);
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::addr3(const address_type &new_addr3) {
|
||||
std::copy(new_addr3.begin(), new_addr3.end(), _ext_header.addr3);
|
||||
void Dot11ManagementFrame::addr3(const address_type& new_addr3) {
|
||||
new_addr3.copy(ext_header_.addr3);
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::frag_num(small_uint<4> new_frag_num) {
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
_ext_header.frag_seq = new_frag_num | (_ext_header.frag_seq & 0xfff0);
|
||||
ext_header_.frag_seq = new_frag_num | (ext_header_.frag_seq & 0xfff0);
|
||||
#else
|
||||
_ext_header.frag_seq = (new_frag_num << 8) | (_ext_header.frag_seq & 0xf0ff);
|
||||
ext_header_.frag_seq = (new_frag_num << 8) | (ext_header_.frag_seq & 0xf0ff);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::seq_num(small_uint<12> new_seq_num) {
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
_ext_header.frag_seq = (new_seq_num << 4) | (_ext_header.frag_seq & 0xf);
|
||||
ext_header_.frag_seq = (new_seq_num << 4) | (ext_header_.frag_seq & 0xf);
|
||||
#else
|
||||
_ext_header.frag_seq = Endian::host_to_le<uint16_t>(new_seq_num << 4) | (_ext_header.frag_seq & 0xf00);
|
||||
ext_header_.frag_seq = Endian::host_to_le<uint16_t>(new_seq_num << 4) |
|
||||
(ext_header_.frag_seq & 0xf00);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::addr4(const address_type &new_addr4) {
|
||||
_addr4 = new_addr4;
|
||||
void Dot11ManagementFrame::addr4(const address_type& new_addr4) {
|
||||
addr4_ = new_addr4;
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::write_ext_header(OutputMemoryStream& stream) {
|
||||
stream.write(_ext_header);
|
||||
stream.write(ext_header_);
|
||||
if (from_ds() && to_ds()) {
|
||||
stream.write(_addr4);
|
||||
stream.write(addr4_);
|
||||
}
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::ssid(const std::string &new_ssid) {
|
||||
add_tagged_option(Dot11::SSID, static_cast<uint8_t>(new_ssid.size()), (const uint8_t*)new_ssid.c_str());
|
||||
void Dot11ManagementFrame::ssid(const string& new_ssid) {
|
||||
add_tagged_option(
|
||||
Dot11::SSID,
|
||||
static_cast<uint8_t>(new_ssid.size()),
|
||||
(const uint8_t*)new_ssid.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::rsn_information(const RSNInformation& info) {
|
||||
@@ -111,36 +123,36 @@ void Dot11ManagementFrame::rsn_information(const RSNInformation& info) {
|
||||
add_tagged_option(RSN, static_cast<uint8_t>(buffer.size()), &buffer[0]);
|
||||
}
|
||||
|
||||
uint8_t *Dot11ManagementFrame::serialize_rates(const rates_type &rates) {
|
||||
uint8_t *buffer = new uint8_t[rates.size()], *ptr = buffer;
|
||||
for(rates_type::const_iterator it = rates.begin(); it != rates.end(); ++it) {
|
||||
vector<uint8_t> Dot11ManagementFrame::serialize_rates(const rates_type& rates) {
|
||||
vector<uint8_t> buffer(rates.size());
|
||||
uint8_t* ptr = &buffer[0];
|
||||
for (rates_type::const_iterator it = rates.begin(); it != rates.end(); ++it) {
|
||||
uint8_t result = static_cast<uint8_t>(*it * 2);
|
||||
if(result == 2 || result == 4 || result == 11 || result == 22)
|
||||
if (result == 2 || result == 4 || result == 11 || result == 22) {
|
||||
result |= 0x80;
|
||||
}
|
||||
*(ptr++) = result;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::rates_type Dot11ManagementFrame::deserialize_rates(const option *opt) {
|
||||
Dot11ManagementFrame::rates_type Dot11ManagementFrame::deserialize_rates(const option* opt) {
|
||||
rates_type output;
|
||||
const uint8_t *ptr = opt->data_ptr(), *end = ptr + opt->data_size();
|
||||
while(ptr != end) {
|
||||
const uint8_t* ptr = opt->data_ptr(), *end = ptr + opt->data_size();
|
||||
while (ptr != end) {
|
||||
output.push_back(float(*(ptr++) & 0x7f) / 2);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::supported_rates(const rates_type &new_rates) {
|
||||
uint8_t *buffer = serialize_rates(new_rates);
|
||||
add_tagged_option(SUPPORTED_RATES, static_cast<uint8_t>(new_rates.size()), buffer);
|
||||
delete[] buffer;
|
||||
void Dot11ManagementFrame::supported_rates(const rates_type& new_rates) {
|
||||
vector<uint8_t> buffer = serialize_rates(new_rates);
|
||||
add_tagged_option(SUPPORTED_RATES, static_cast<uint8_t>(buffer.size()), &buffer[0]);
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::extended_supported_rates(const rates_type &new_rates) {
|
||||
uint8_t *buffer = serialize_rates(new_rates);
|
||||
add_tagged_option(EXT_SUPPORTED_RATES, static_cast<uint8_t>(new_rates.size()), buffer);
|
||||
delete[] buffer;
|
||||
void Dot11ManagementFrame::extended_supported_rates(const rates_type& new_rates) {
|
||||
vector<uint8_t> buffer = serialize_rates(new_rates);
|
||||
add_tagged_option(EXT_SUPPORTED_RATES, static_cast<uint8_t>(buffer.size()), &buffer[0]);
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::qos_capability(qos_capability_type new_qos_capability) {
|
||||
@@ -154,10 +166,10 @@ void Dot11ManagementFrame::power_capability(uint8_t min_power, uint8_t max_power
|
||||
add_tagged_option(POWER_CAPABILITY, 2, buffer);
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::supported_channels(const channels_type &new_channels) {
|
||||
std::vector<uint8_t> buffer(new_channels.size() * 2);
|
||||
void Dot11ManagementFrame::supported_channels(const channels_type& new_channels) {
|
||||
vector<uint8_t> buffer(new_channels.size() * 2);
|
||||
uint8_t* ptr = &buffer[0];
|
||||
for(channels_type::const_iterator it = new_channels.begin(); it != new_channels.end(); ++it) {
|
||||
for (channels_type::const_iterator it = new_channels.begin(); it != new_channels.end(); ++it) {
|
||||
*(ptr++) = it->first;
|
||||
*(ptr++) = it->second;
|
||||
}
|
||||
@@ -166,13 +178,13 @@ void Dot11ManagementFrame::supported_channels(const channels_type &new_channels)
|
||||
|
||||
void Dot11ManagementFrame::edca_parameter_set(uint32_t ac_be, uint32_t ac_bk, uint32_t ac_vi, uint32_t ac_vo) {
|
||||
uint8_t buffer[18];
|
||||
buffer[0] = 0;
|
||||
buffer[1] = 0;
|
||||
uint32_t* ptr = (uint32_t*)(buffer + 2);
|
||||
*(ptr++) = Endian::host_to_le(ac_be);
|
||||
*(ptr++) = Endian::host_to_le(ac_bk);
|
||||
*(ptr++) = Endian::host_to_le(ac_vi);
|
||||
*(ptr++) = Endian::host_to_le(ac_vo);
|
||||
OutputMemoryStream stream(buffer, sizeof(buffer));
|
||||
stream.write<uint8_t>(0);
|
||||
stream.write<uint8_t>(0);
|
||||
stream.write_le(ac_be);
|
||||
stream.write_le(ac_bk);
|
||||
stream.write_le(ac_vi);
|
||||
stream.write_le(ac_vo);
|
||||
add_tagged_option(EDCA, sizeof(buffer), buffer);
|
||||
}
|
||||
|
||||
@@ -180,30 +192,28 @@ void Dot11ManagementFrame::request_information(const request_info_type elements)
|
||||
add_tagged_option(REQUEST_INFORMATION, static_cast<uint8_t>(elements.size()), &elements[0]);
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::fh_parameter_set(const fh_params_set &fh_params) {
|
||||
uint8_t data[5];
|
||||
uint16_t dwell = Endian::host_to_le(fh_params.dwell_time);
|
||||
std::memcpy(data, &dwell, sizeof(dwell));
|
||||
data[2] = fh_params.hop_set;
|
||||
data[3] = fh_params.hop_pattern;
|
||||
data[4] = fh_params.hop_index;
|
||||
add_tagged_option(FH_SET, sizeof(data), data);
|
||||
|
||||
void Dot11ManagementFrame::fh_parameter_set(const fh_params_set& fh_params) {
|
||||
uint8_t buffer[5];
|
||||
OutputMemoryStream stream(buffer, sizeof(buffer));
|
||||
stream.write_le(fh_params.dwell_time);
|
||||
stream.write(fh_params.hop_set);
|
||||
stream.write(fh_params.hop_pattern);
|
||||
stream.write(fh_params.hop_index);
|
||||
add_tagged_option(FH_SET, sizeof(buffer), buffer);
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::ds_parameter_set(uint8_t current_channel) {
|
||||
add_tagged_option(DS_SET, 1, ¤t_channel);
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::cf_parameter_set(const cf_params_set ¶ms) {
|
||||
uint8_t data[6];
|
||||
data[0] = params.cfp_count;
|
||||
data[1] = params.cfp_period;
|
||||
uint16_t dummy = Endian::host_to_le(params.cfp_max_duration);
|
||||
std::memcpy(data + 2, &dummy, sizeof(uint16_t));
|
||||
dummy = Endian::host_to_le(params.cfp_dur_remaining);
|
||||
std::memcpy(data + 4, &dummy, sizeof(uint16_t));
|
||||
add_tagged_option(CF_SET, sizeof(data), data);
|
||||
void Dot11ManagementFrame::cf_parameter_set(const cf_params_set& params) {
|
||||
uint8_t buffer[6];
|
||||
OutputMemoryStream stream(buffer, sizeof(buffer));
|
||||
stream.write(params.cfp_count);
|
||||
stream.write(params.cfp_period);
|
||||
stream.write_le(params.cfp_max_duration);
|
||||
stream.write_le(params.cfp_dur_remaining);
|
||||
add_tagged_option(CF_SET, sizeof(buffer), buffer);
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::ibss_parameter_set(uint16_t atim_window) {
|
||||
@@ -211,35 +221,37 @@ void Dot11ManagementFrame::ibss_parameter_set(uint16_t atim_window) {
|
||||
add_tagged_option(IBSS_SET, 2, (uint8_t*)&atim_window);
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::ibss_dfs(const ibss_dfs_params ¶ms) {
|
||||
void Dot11ManagementFrame::ibss_dfs(const ibss_dfs_params& params) {
|
||||
const size_t sz = address_type::address_size + sizeof(uint8_t) +
|
||||
sizeof(uint8_t) * 2 * params.channel_map.size();
|
||||
std::vector<uint8_t> buffer(sz);
|
||||
uint8_t* ptr_buffer = &buffer[0];
|
||||
|
||||
ptr_buffer = params.dfs_owner.copy(ptr_buffer);
|
||||
*(ptr_buffer++) = params.recovery_interval;
|
||||
sizeof(uint8_t) * 2 * params.channel_map.size();
|
||||
vector<uint8_t> buffer(sz);
|
||||
OutputMemoryStream stream(buffer);
|
||||
stream.write(params.dfs_owner);
|
||||
stream.write(params.recovery_interval);
|
||||
for (channels_type::const_iterator it = params.channel_map.begin(); it != params.channel_map.end(); ++it) {
|
||||
*(ptr_buffer++) = it->first;
|
||||
*(ptr_buffer++) = it->second;
|
||||
stream.write(it->first);
|
||||
stream.write(it->second);
|
||||
}
|
||||
|
||||
add_tagged_option(IBSS_DFS, static_cast<uint8_t>(buffer.size()), &buffer[0]);
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::country(const country_params ¶ms) {
|
||||
void Dot11ManagementFrame::country(const country_params& params) {
|
||||
if ((params.first_channel.size() != params.number_channels.size()) ||
|
||||
(params.number_channels.size() != params.max_transmit_power.size()))
|
||||
throw std::runtime_error("The length of the lists are distinct");
|
||||
if(params.country.size() != 3)
|
||||
throw std::runtime_error("Invalid country identifier length");
|
||||
(params.number_channels.size() != params.max_transmit_power.size())) {
|
||||
throw runtime_error("The length of the lists are distinct");
|
||||
}
|
||||
if (params.country.size() != 3) {
|
||||
throw runtime_error("Invalid country identifier length");
|
||||
}
|
||||
size_t sz = sizeof(uint8_t) * 3 * params.first_channel.size() + params.country.size();
|
||||
// Use 1 byte padding at the end if the length is odd.
|
||||
if((sz & 1) == 1)
|
||||
if ((sz & 1) == 1) {
|
||||
sz++;
|
||||
std::vector<uint8_t> buffer(sz);
|
||||
uint8_t *ptr = std::copy(params.country.begin(), params.country.end(), &buffer[0]);
|
||||
for(size_t i(0); i < params.first_channel.size(); ++i) {
|
||||
}
|
||||
vector<uint8_t> buffer(sz);
|
||||
uint8_t* ptr = copy(params.country.begin(), params.country.end(), &buffer[0]);
|
||||
for (size_t i(0); i < params.first_channel.size(); ++i) {
|
||||
*(ptr++) = params.first_channel[i];
|
||||
*(ptr++) = params.number_channels[i];
|
||||
*(ptr++) = params.max_transmit_power[i];
|
||||
@@ -254,16 +266,17 @@ void Dot11ManagementFrame::fh_parameters(uint8_t prime_radix, uint8_t number_cha
|
||||
add_tagged_option(HOPPING_PATTERN_PARAMS, 2, buffer);
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::fh_pattern_table(const fh_pattern_type ¶ms) {
|
||||
std::vector<uint8_t> data(sizeof(uint8_t) * 4 + params.random_table.size());
|
||||
uint8_t *ptr = &data[0];
|
||||
void Dot11ManagementFrame::fh_pattern_table(const fh_pattern_type& params) {
|
||||
vector<uint8_t> data(sizeof(uint8_t) * 4 + params.random_table.size());
|
||||
uint8_t* ptr = &data[0];
|
||||
*(ptr++) = params.flag;
|
||||
*(ptr++) = params.number_of_sets;
|
||||
*(ptr++) = params.modulus;
|
||||
*(ptr++) = params.offset;
|
||||
byte_array::const_iterator it(params.random_table.begin());
|
||||
for(; it != params.random_table.end(); ++it)
|
||||
for (; it != params.random_table.end(); ++it) {
|
||||
*(ptr++) = *it;
|
||||
}
|
||||
add_tagged_option(HOPPING_PATTERN_TABLE, static_cast<uint8_t>(data.size()), &data[0]);
|
||||
}
|
||||
|
||||
@@ -271,7 +284,7 @@ void Dot11ManagementFrame::power_constraint(uint8_t local_power_constraint) {
|
||||
add_tagged_option(POWER_CONSTRAINT, 1, &local_power_constraint);
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::channel_switch(const channel_switch_type &data) {
|
||||
void Dot11ManagementFrame::channel_switch(const channel_switch_type& data) {
|
||||
uint8_t buffer[3];
|
||||
buffer[0] = data.switch_mode;
|
||||
buffer[1] = data.new_channel;
|
||||
@@ -280,14 +293,13 @@ void Dot11ManagementFrame::channel_switch(const channel_switch_type &data) {
|
||||
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::quiet(const quiet_type &data) {
|
||||
void Dot11ManagementFrame::quiet(const quiet_type& data) {
|
||||
uint8_t buffer[6];
|
||||
uint16_t* ptr_buffer = (uint16_t*)(buffer + 2);
|
||||
|
||||
buffer[0] = data.quiet_count;
|
||||
buffer[1] = data.quiet_period;
|
||||
ptr_buffer[0] = Endian::host_to_le(data.quiet_duration);
|
||||
ptr_buffer[1] = Endian::host_to_le(data.quiet_offset);
|
||||
OutputMemoryStream stream(buffer, sizeof(buffer));
|
||||
stream.write(data.quiet_count);
|
||||
stream.write(data.quiet_period);
|
||||
stream.write_le(data.quiet_duration);
|
||||
stream.write_le(data.quiet_offset);
|
||||
add_tagged_option(QUIET, sizeof(buffer), buffer);
|
||||
}
|
||||
|
||||
@@ -303,7 +315,7 @@ void Dot11ManagementFrame::erp_information(uint8_t value) {
|
||||
add_tagged_option(ERP_INFORMATION, 1, &value);
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::bss_load(const bss_load_type &data) {
|
||||
void Dot11ManagementFrame::bss_load(const bss_load_type& data) {
|
||||
uint8_t buffer[5];
|
||||
uint16_t dummy = Endian::host_to_le(data.station_count);
|
||||
|
||||
@@ -328,20 +340,21 @@ void Dot11ManagementFrame::bss_load(const bss_load_type &data) {
|
||||
add_tagged_option(BSS_LOAD, sizeof(buffer), buffer);
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::tim(const tim_type &data) {
|
||||
std::vector<uint8_t> buffer(sizeof(uint8_t) * 3 + data.partial_virtual_bitmap.size());
|
||||
buffer[0] = data.dtim_count;
|
||||
buffer[1] = data.dtim_period;
|
||||
buffer[2] = data.bitmap_control;
|
||||
std::copy(
|
||||
void Dot11ManagementFrame::tim(const tim_type& data) {
|
||||
vector<uint8_t> buffer(sizeof(uint8_t) * 3 + data.partial_virtual_bitmap.size());
|
||||
OutputMemoryStream stream(buffer);
|
||||
|
||||
stream.write(data.dtim_count);
|
||||
stream.write(data.dtim_period);
|
||||
stream.write(data.bitmap_control);
|
||||
stream.write(
|
||||
data.partial_virtual_bitmap.begin(),
|
||||
data.partial_virtual_bitmap.end(),
|
||||
&buffer[3]
|
||||
data.partial_virtual_bitmap.end()
|
||||
);
|
||||
add_tagged_option(TIM, static_cast<uint8_t>(buffer.size()), &buffer[0]);
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::challenge_text(const std::string &text) {
|
||||
void Dot11ManagementFrame::challenge_text(const string& text) {
|
||||
add_tagged_option(
|
||||
CHALLENGE_TEXT,
|
||||
static_cast<uint8_t>(text.size()),
|
||||
@@ -349,9 +362,9 @@ void Dot11ManagementFrame::challenge_text(const std::string &text) {
|
||||
);
|
||||
}
|
||||
|
||||
void Dot11ManagementFrame::vendor_specific(const vendor_specific_type &data) {
|
||||
void Dot11ManagementFrame::vendor_specific(const vendor_specific_type& data) {
|
||||
byte_array buffer(3 + data.data.size());
|
||||
std::copy(
|
||||
copy(
|
||||
data.data.begin(),
|
||||
data.data.end(),
|
||||
data.oui.copy(buffer.begin())
|
||||
@@ -365,14 +378,17 @@ RSNInformation Dot11ManagementFrame::rsn_information() const {
|
||||
return search_and_convert<RSNInformation>(RSN);
|
||||
}
|
||||
|
||||
std::string Dot11ManagementFrame::ssid() const {
|
||||
const Dot11::option *option = search_option(SSID);
|
||||
if(!option)
|
||||
string Dot11ManagementFrame::ssid() const {
|
||||
const Dot11::option* option = search_option(SSID);
|
||||
if (!option) {
|
||||
throw option_not_found();
|
||||
if(option->data_size() == 0 && this->subtype() == Dot11::PROBE_REQ)
|
||||
}
|
||||
if (option->data_size() == 0 && subtype() == Dot11::PROBE_REQ){
|
||||
return "BROADCAST";
|
||||
else
|
||||
return std::string((const char*)option->data_ptr(), option->data_size());
|
||||
}
|
||||
else {
|
||||
return string((const char*)option->data_ptr(), option->data_size());
|
||||
}
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::rates_type Dot11ManagementFrame::supported_rates() const {
|
||||
@@ -387,8 +403,8 @@ Dot11ManagementFrame::qos_capability_type Dot11ManagementFrame::qos_capability()
|
||||
return search_and_convert<uint8_t>(QOS_CAPABILITY);
|
||||
}
|
||||
|
||||
std::pair<uint8_t, uint8_t> Dot11ManagementFrame::power_capability() const {
|
||||
return search_and_convert<std::pair<uint8_t, uint8_t> >(POWER_CAPABILITY);
|
||||
pair<uint8_t, uint8_t> Dot11ManagementFrame::power_capability() const {
|
||||
return search_and_convert<pair<uint8_t, uint8_t> >(POWER_CAPABILITY);
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::channels_type Dot11ManagementFrame::supported_channels() const {
|
||||
@@ -423,8 +439,8 @@ Dot11ManagementFrame::country_params Dot11ManagementFrame::country() const {
|
||||
return search_and_convert<country_params>(COUNTRY);
|
||||
}
|
||||
|
||||
std::pair<uint8_t, uint8_t> Dot11ManagementFrame::fh_parameters() const {
|
||||
return search_and_convert<std::pair<uint8_t, uint8_t> >(HOPPING_PATTERN_PARAMS);
|
||||
pair<uint8_t, uint8_t> Dot11ManagementFrame::fh_parameters() const {
|
||||
return search_and_convert<pair<uint8_t, uint8_t> >(HOPPING_PATTERN_PARAMS);
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::fh_pattern_type Dot11ManagementFrame::fh_pattern_table() const {
|
||||
@@ -443,8 +459,8 @@ Dot11ManagementFrame::quiet_type Dot11ManagementFrame::quiet() const {
|
||||
return search_and_convert<quiet_type>(QUIET);
|
||||
}
|
||||
|
||||
std::pair<uint8_t, uint8_t> Dot11ManagementFrame::tpc_report() const {
|
||||
return search_and_convert<std::pair<uint8_t, uint8_t> >(TPC_REPORT);
|
||||
pair<uint8_t, uint8_t> Dot11ManagementFrame::tpc_report() const {
|
||||
return search_and_convert<pair<uint8_t, uint8_t> >(TPC_REPORT);
|
||||
}
|
||||
|
||||
uint8_t Dot11ManagementFrame::erp_information() const {
|
||||
@@ -459,23 +475,26 @@ Dot11ManagementFrame::tim_type Dot11ManagementFrame::tim() const {
|
||||
return search_and_convert<tim_type>(TIM);
|
||||
}
|
||||
|
||||
std::string Dot11ManagementFrame::challenge_text() const {
|
||||
return search_and_convert<std::string>(CHALLENGE_TEXT);
|
||||
string Dot11ManagementFrame::challenge_text() const {
|
||||
return search_and_convert<string>(CHALLENGE_TEXT);
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::vendor_specific_type Dot11ManagementFrame::vendor_specific() const {
|
||||
const Dot11::option *option = search_option(VENDOR_SPECIFIC);
|
||||
if(!option || option->data_size() < 3)
|
||||
const Dot11::option* option = search_option(VENDOR_SPECIFIC);
|
||||
if (!option || option->data_size() < 3) {
|
||||
throw option_not_found();
|
||||
return vendor_specific_type::from_bytes(option->data_ptr(),
|
||||
static_cast<uint32_t>(option->data_size()));
|
||||
}
|
||||
return vendor_specific_type::from_bytes(
|
||||
option->data_ptr(),
|
||||
static_cast<uint32_t>(option->data_size())
|
||||
);
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::vendor_specific_type
|
||||
Dot11ManagementFrame::vendor_specific_type::from_bytes(const uint8_t *buffer, uint32_t sz)
|
||||
{
|
||||
if(sz < 3)
|
||||
Dot11ManagementFrame::vendor_specific_type::from_bytes(const uint8_t* buffer, uint32_t sz) {
|
||||
if (sz < 3) {
|
||||
throw malformed_option();
|
||||
}
|
||||
return vendor_specific_type(
|
||||
buffer,
|
||||
byte_array(buffer + 3, buffer + sz)
|
||||
@@ -484,75 +503,81 @@ Dot11ManagementFrame::vendor_specific_type
|
||||
|
||||
// Options
|
||||
|
||||
Dot11ManagementFrame::fh_params_set Dot11ManagementFrame::fh_params_set::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() != 5)
|
||||
Dot11ManagementFrame::fh_params_set
|
||||
Dot11ManagementFrame::fh_params_set::from_option(const option& opt) {
|
||||
if (opt.data_size() != 5) {
|
||||
throw malformed_option();
|
||||
}
|
||||
fh_params_set output;
|
||||
std::memcpy(&output.dwell_time, opt.data_ptr(), sizeof(uint16_t));
|
||||
output.dwell_time = Endian::le_to_host(output.dwell_time);
|
||||
output.hop_set = opt.data_ptr()[2];
|
||||
output.hop_pattern = opt.data_ptr()[3];
|
||||
output.hop_index = opt.data_ptr()[4];
|
||||
InputMemoryStream stream(opt.data_ptr(), opt.data_size());
|
||||
output.dwell_time = stream.read_le<uint16_t>();
|
||||
output.hop_set = stream.read<uint8_t>();
|
||||
output.hop_pattern = stream.read<uint8_t>();
|
||||
output.hop_index = stream.read<uint8_t>();
|
||||
return output;
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::cf_params_set Dot11ManagementFrame::cf_params_set::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() != 6)
|
||||
Dot11ManagementFrame::cf_params_set
|
||||
Dot11ManagementFrame::cf_params_set::from_option(const option& opt) {
|
||||
if (opt.data_size() != 6) {
|
||||
throw malformed_option();
|
||||
}
|
||||
cf_params_set output;
|
||||
output.cfp_count = *opt.data_ptr();
|
||||
output.cfp_period = opt.data_ptr()[1];
|
||||
std::memcpy(&output.cfp_max_duration, &opt.data_ptr()[2], sizeof(uint16_t));
|
||||
std::memcpy(&output.cfp_dur_remaining, &opt.data_ptr()[4], sizeof(uint16_t));
|
||||
output.cfp_max_duration = Endian::le_to_host(output.cfp_max_duration);
|
||||
output.cfp_dur_remaining = Endian::le_to_host(output.cfp_dur_remaining);
|
||||
InputMemoryStream stream(opt.data_ptr(), opt.data_size());
|
||||
output.cfp_count = stream.read<uint8_t>();
|
||||
output.cfp_period = stream.read<uint8_t>();
|
||||
output.cfp_max_duration = stream.read_le<uint16_t>();
|
||||
output.cfp_dur_remaining = stream.read_le<uint16_t>();
|
||||
return output;
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::ibss_dfs_params Dot11ManagementFrame::ibss_dfs_params::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < ibss_dfs_params::minimum_size)
|
||||
Dot11ManagementFrame::ibss_dfs_params
|
||||
Dot11ManagementFrame::ibss_dfs_params::from_option(const option& opt) {
|
||||
if (opt.data_size() < ibss_dfs_params::minimum_size) {
|
||||
throw malformed_option();
|
||||
}
|
||||
ibss_dfs_params output;
|
||||
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
|
||||
const uint8_t* ptr = opt.data_ptr(), *end = ptr + opt.data_size();
|
||||
output.dfs_owner = ptr;
|
||||
ptr += output.dfs_owner.size();
|
||||
output.recovery_interval = *(ptr++);
|
||||
while(ptr != end) {
|
||||
while (ptr != end) {
|
||||
uint8_t first = *(ptr++);
|
||||
if(ptr == end)
|
||||
throw option_not_found();
|
||||
output.channel_map.push_back(std::make_pair(first, *(ptr++)));
|
||||
if (ptr == end) {
|
||||
throw malformed_option();
|
||||
}
|
||||
output.channel_map.push_back(make_pair(first, *(ptr++)));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::country_params Dot11ManagementFrame::country_params::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < country_params::minimum_size)
|
||||
Dot11ManagementFrame::country_params
|
||||
Dot11ManagementFrame::country_params::from_option(const option& opt) {
|
||||
if (opt.data_size() < country_params::minimum_size) {
|
||||
throw malformed_option();
|
||||
}
|
||||
country_params output;
|
||||
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
|
||||
std::copy(ptr, ptr + 3, std::back_inserter(output.country));
|
||||
const uint8_t* ptr = opt.data_ptr(), *end = ptr + opt.data_size();
|
||||
copy(ptr, ptr + 3, back_inserter(output.country));
|
||||
ptr += output.country.size();
|
||||
while(end - ptr >= 3) {
|
||||
while (end - ptr >= 3) {
|
||||
output.first_channel.push_back(*(ptr++));
|
||||
output.number_channels.push_back(*(ptr++));
|
||||
output.max_transmit_power.push_back(*(ptr++));
|
||||
}
|
||||
if(ptr != end)
|
||||
if (ptr != end) {
|
||||
throw malformed_option();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::fh_pattern_type Dot11ManagementFrame::fh_pattern_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < fh_pattern_type::minimum_size)
|
||||
Dot11ManagementFrame::fh_pattern_type
|
||||
Dot11ManagementFrame::fh_pattern_type::from_option(const option& opt) {
|
||||
if (opt.data_size() < fh_pattern_type::minimum_size) {
|
||||
throw malformed_option();
|
||||
}
|
||||
fh_pattern_type output;
|
||||
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
|
||||
const uint8_t* ptr = opt.data_ptr(), *end = ptr + opt.data_size();
|
||||
|
||||
output.flag = *(ptr++);
|
||||
output.number_of_sets = *(ptr++);
|
||||
@@ -563,11 +588,12 @@ Dot11ManagementFrame::fh_pattern_type Dot11ManagementFrame::fh_pattern_type::fro
|
||||
return output;
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::channel_switch_type Dot11ManagementFrame::channel_switch_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() != sizeof(uint8_t) * 3)
|
||||
Dot11ManagementFrame::channel_switch_type
|
||||
Dot11ManagementFrame::channel_switch_type::from_option(const option& opt) {
|
||||
if (opt.data_size() != sizeof(uint8_t) * 3) {
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr();
|
||||
}
|
||||
const uint8_t* ptr = opt.data_ptr();
|
||||
channel_switch_type output;
|
||||
output.switch_mode = *(ptr++);
|
||||
output.new_channel = *(ptr++);
|
||||
@@ -575,41 +601,39 @@ Dot11ManagementFrame::channel_switch_type Dot11ManagementFrame::channel_switch_t
|
||||
return output;
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::quiet_type Dot11ManagementFrame::quiet_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() != (sizeof(uint8_t) * 2 + sizeof(uint16_t) * 2))
|
||||
Dot11ManagementFrame::quiet_type
|
||||
Dot11ManagementFrame::quiet_type::from_option(const option& opt) {
|
||||
if (opt.data_size() != (sizeof(uint8_t) * 2 + sizeof(uint16_t) * 2)) {
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr();
|
||||
}
|
||||
quiet_type output;
|
||||
InputMemoryStream stream(opt.data_ptr(), opt.data_size());
|
||||
|
||||
output.quiet_count = *(ptr++);
|
||||
output.quiet_period = *(ptr++);
|
||||
const uint16_t *ptr_16 = (const uint16_t*)ptr;
|
||||
output.quiet_duration = Endian::le_to_host(*(ptr_16++));
|
||||
output.quiet_offset = Endian::le_to_host(*ptr_16);
|
||||
output.quiet_count = stream.read<uint8_t>();
|
||||
output.quiet_period = stream.read<uint8_t>();
|
||||
output.quiet_duration = stream.read_le<uint16_t>();
|
||||
output.quiet_offset = stream.read_le<uint16_t>();
|
||||
return output;
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::bss_load_type Dot11ManagementFrame::bss_load_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() != sizeof(uint8_t) + 2 * sizeof(uint16_t))
|
||||
Dot11ManagementFrame::bss_load_type
|
||||
Dot11ManagementFrame::bss_load_type::from_option(const option& opt) {
|
||||
if (opt.data_size() != sizeof(uint8_t) + 2 * sizeof(uint16_t)) {
|
||||
throw malformed_option();
|
||||
}
|
||||
bss_load_type output;
|
||||
|
||||
const uint8_t *ptr = opt.data_ptr();
|
||||
std::memcpy(&output.station_count, ptr, sizeof(uint16_t));
|
||||
std::memcpy(&output.available_capacity, ptr + 3, sizeof(uint16_t));
|
||||
output.channel_utilization = ptr[2];
|
||||
output.station_count = Endian::le_to_host(output.station_count);
|
||||
output.available_capacity = Endian::le_to_host(output.available_capacity);
|
||||
InputMemoryStream stream(opt.data_ptr(), opt.data_size());
|
||||
output.station_count = stream.read_le<uint16_t>();
|
||||
output.channel_utilization = stream.read<uint8_t>();
|
||||
output.available_capacity = stream.read_le<uint16_t>();
|
||||
return output;
|
||||
}
|
||||
|
||||
Dot11ManagementFrame::tim_type Dot11ManagementFrame::tim_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() < 4 * sizeof(uint8_t))
|
||||
Dot11ManagementFrame::tim_type Dot11ManagementFrame::tim_type::from_option(const option& opt) {
|
||||
if (opt.data_size() < 4 * sizeof(uint8_t)) {
|
||||
throw malformed_option();
|
||||
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
|
||||
}
|
||||
const uint8_t* ptr = opt.data_ptr(), *end = ptr + opt.data_size();
|
||||
tim_type output;
|
||||
|
||||
output.dtim_count = *(ptr++);
|
||||
@@ -619,6 +643,7 @@ Dot11ManagementFrame::tim_type Dot11ManagementFrame::tim_type::from_option(const
|
||||
output.partial_virtual_bitmap.assign(ptr, end);
|
||||
return output;
|
||||
}
|
||||
} // namespace Tins
|
||||
|
||||
} // Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -38,56 +38,54 @@ using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
/* Probe Request */
|
||||
|
||||
Dot11ProbeRequest::Dot11ProbeRequest(const address_type &dst_hw_addr,
|
||||
const address_type &src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr)
|
||||
{
|
||||
this->subtype(Dot11::PROBE_REQ);
|
||||
// Probe Request
|
||||
|
||||
Dot11ProbeRequest::Dot11ProbeRequest(const address_type& dst_hw_addr,
|
||||
const address_type& src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr) {
|
||||
subtype(Dot11::PROBE_REQ);
|
||||
}
|
||||
|
||||
Dot11ProbeRequest::Dot11ProbeRequest(const uint8_t *buffer, uint32_t total_sz)
|
||||
: Dot11ManagementFrame(buffer, total_sz)
|
||||
{
|
||||
Dot11ProbeRequest::Dot11ProbeRequest(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11ManagementFrame(buffer, total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(management_frame_size());
|
||||
parse_tagged_parameters(stream);
|
||||
}
|
||||
|
||||
/* Probe Response */
|
||||
// Probe Response
|
||||
|
||||
Dot11ProbeResponse::Dot11ProbeResponse(const address_type &dst_hw_addr,
|
||||
const address_type &src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr), _body()
|
||||
{
|
||||
this->subtype(Dot11::PROBE_RESP);
|
||||
Dot11ProbeResponse::Dot11ProbeResponse(const address_type& dst_hw_addr,
|
||||
const address_type& src_hw_addr)
|
||||
: Dot11ManagementFrame(dst_hw_addr, src_hw_addr), body_() {
|
||||
subtype(Dot11::PROBE_RESP);
|
||||
}
|
||||
|
||||
Dot11ProbeResponse::Dot11ProbeResponse(const uint8_t *buffer, uint32_t total_sz)
|
||||
: Dot11ManagementFrame(buffer, total_sz)
|
||||
{
|
||||
Dot11ProbeResponse::Dot11ProbeResponse(const uint8_t* buffer, uint32_t total_sz)
|
||||
: Dot11ManagementFrame(buffer, total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(management_frame_size());
|
||||
stream.read(_body);
|
||||
stream.read(body_);
|
||||
parse_tagged_parameters(stream);
|
||||
}
|
||||
|
||||
void Dot11ProbeResponse::timestamp(uint64_t new_timestamp) {
|
||||
this->_body.timestamp = Endian::host_to_le(new_timestamp);
|
||||
body_.timestamp = Endian::host_to_le(new_timestamp);
|
||||
}
|
||||
|
||||
void Dot11ProbeResponse::interval(uint16_t new_interval) {
|
||||
this->_body.interval = Endian::host_to_le(new_interval);
|
||||
body_.interval = Endian::host_to_le(new_interval);
|
||||
}
|
||||
|
||||
uint32_t Dot11ProbeResponse::header_size() const {
|
||||
return Dot11ManagementFrame::header_size() + sizeof(this->_body);
|
||||
return Dot11ManagementFrame::header_size() + sizeof(body_);
|
||||
}
|
||||
|
||||
void Dot11ProbeResponse::write_fixed_parameters(OutputMemoryStream& stream) {
|
||||
stream.write(_body);
|
||||
stream.write(body_);
|
||||
}
|
||||
|
||||
} // namespace Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -40,16 +40,14 @@ using Tins::Memory::OutputMemoryStream;
|
||||
namespace Tins {
|
||||
|
||||
Dot1Q::Dot1Q(small_uint<12> tag_id, bool append_pad)
|
||||
: _header(), _append_padding(append_pad)
|
||||
{
|
||||
: header_(), append_padding_(append_pad) {
|
||||
id(tag_id);
|
||||
}
|
||||
|
||||
Dot1Q::Dot1Q(const uint8_t *buffer, uint32_t total_sz)
|
||||
: _append_padding()
|
||||
{
|
||||
Dot1Q::Dot1Q(const uint8_t* buffer, uint32_t total_sz)
|
||||
: append_padding_() {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_header);
|
||||
stream.read(header_);
|
||||
|
||||
if (stream) {
|
||||
inner_pdu(
|
||||
@@ -63,33 +61,33 @@ Dot1Q::Dot1Q(const uint8_t *buffer, uint32_t total_sz)
|
||||
}
|
||||
|
||||
void Dot1Q::priority(small_uint<3> new_priority) {
|
||||
_header.priority = new_priority;
|
||||
header_.priority = new_priority;
|
||||
}
|
||||
|
||||
void Dot1Q::cfi(small_uint<1> new_cfi) {
|
||||
_header.cfi = new_cfi;
|
||||
header_.cfi = new_cfi;
|
||||
}
|
||||
|
||||
void Dot1Q::id(small_uint<12> new_id) {
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
_header.idL = new_id & 0xff;
|
||||
_header.idH = new_id >> 8;
|
||||
header_.idL = new_id & 0xff;
|
||||
header_.idH = new_id >> 8;
|
||||
#else
|
||||
_header.id = new_id;
|
||||
header_.id = new_id;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Dot1Q::payload_type(uint16_t new_type) {
|
||||
_header.type = Endian::host_to_be(new_type);
|
||||
header_.type = Endian::host_to_be(new_type);
|
||||
}
|
||||
|
||||
uint32_t Dot1Q::header_size() const {
|
||||
return sizeof(_header);
|
||||
return sizeof(header_);
|
||||
}
|
||||
|
||||
uint32_t Dot1Q::trailer_size() const {
|
||||
if (_append_padding) {
|
||||
uint32_t total_size = sizeof(_header);
|
||||
if (append_padding_) {
|
||||
uint32_t total_size = sizeof(header_);
|
||||
if (inner_pdu()) {
|
||||
total_size += inner_pdu()->size();
|
||||
}
|
||||
@@ -100,7 +98,7 @@ uint32_t Dot1Q::trailer_size() const {
|
||||
}
|
||||
}
|
||||
|
||||
void Dot1Q::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
|
||||
void Dot1Q::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
if (inner_pdu()) {
|
||||
// Set the appropriate payload type flag
|
||||
@@ -109,7 +107,7 @@ void Dot1Q::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *)
|
||||
);
|
||||
payload_type(static_cast<uint16_t>(flag));
|
||||
}
|
||||
stream.write(_header);
|
||||
stream.write(header_);
|
||||
|
||||
// Skip inner PDU size
|
||||
if (inner_pdu()) {
|
||||
@@ -120,29 +118,31 @@ void Dot1Q::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *)
|
||||
}
|
||||
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
uint16_t Dot1Q::get_id(const dot1q_hdr *hdr) {
|
||||
uint16_t Dot1Q::get_id(const dot1q_hdr* hdr) {
|
||||
return hdr->idL | (hdr->idH << 8);
|
||||
}
|
||||
#else
|
||||
uint16_t Dot1Q::get_id(const dot1q_hdr *hdr) {
|
||||
uint16_t Dot1Q::get_id(const dot1q_hdr* hdr) {
|
||||
return hdr->id;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Dot1Q::append_padding(bool value) {
|
||||
_append_padding = value;
|
||||
append_padding_ = value;
|
||||
}
|
||||
|
||||
bool Dot1Q::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
if(total_sz < sizeof(_header))
|
||||
bool Dot1Q::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
if (total_sz < sizeof(header_)) {
|
||||
return false;
|
||||
const dot1q_hdr *dot1q_ptr = (const dot1q_hdr*)ptr;
|
||||
if(get_id(dot1q_ptr) == get_id(&_header)) {
|
||||
ptr += sizeof(_header);
|
||||
total_sz -= sizeof(_header);
|
||||
}
|
||||
const dot1q_hdr* dot1q_ptr = (const dot1q_hdr*)ptr;
|
||||
if (get_id(dot1q_ptr) == get_id(&header_)) {
|
||||
ptr += sizeof(header_);
|
||||
total_sz -= sizeof(header_);
|
||||
return inner_pdu() ? inner_pdu()->matches_response(ptr, total_sz) : true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
70
src/dot3.cpp
70
src/dot3.cpp
@@ -46,6 +46,9 @@
|
||||
#include "exceptions.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::copy;
|
||||
using std::equal;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
@@ -53,44 +56,41 @@ namespace Tins {
|
||||
|
||||
const Dot3::address_type Dot3::BROADCAST("ff:ff:ff:ff:ff:ff");
|
||||
|
||||
Dot3::Dot3(const address_type &dst_hw_addr, const address_type &src_hw_addr)
|
||||
{
|
||||
memset(&_eth, 0, sizeof(ethhdr));
|
||||
Dot3::Dot3(const address_type& dst_hw_addr, const address_type& src_hw_addr)
|
||||
: header_() {
|
||||
this->dst_addr(dst_hw_addr);
|
||||
this->src_addr(src_hw_addr);
|
||||
this->_eth.length = 0;
|
||||
|
||||
}
|
||||
|
||||
Dot3::Dot3(const uint8_t *buffer, uint32_t total_sz)
|
||||
{
|
||||
Dot3::Dot3(const uint8_t* buffer, uint32_t total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_eth);
|
||||
stream.read(header_);
|
||||
if (stream) {
|
||||
inner_pdu(new Tins::LLC(stream.pointer(), stream.size()));
|
||||
}
|
||||
}
|
||||
|
||||
void Dot3::dst_addr(const address_type &new_dst_mac) {
|
||||
std::copy(new_dst_mac.begin(), new_dst_mac.end(), _eth.dst_mac);
|
||||
void Dot3::dst_addr(const address_type& address) {
|
||||
copy(address.begin(), address.end(), header_.dst_mac);
|
||||
}
|
||||
|
||||
void Dot3::src_addr(const address_type &new_src_mac) {
|
||||
std::copy(new_src_mac.begin(), new_src_mac.end(), _eth.src_mac);
|
||||
void Dot3::src_addr(const address_type& address) {
|
||||
copy(address.begin(), address.end(), header_.src_mac);
|
||||
}
|
||||
|
||||
void Dot3::length(uint16_t new_length) {
|
||||
this->_eth.length = Endian::host_to_be(new_length);
|
||||
void Dot3::length(uint16_t value) {
|
||||
header_.length = Endian::host_to_be(value);
|
||||
}
|
||||
|
||||
uint32_t Dot3::header_size() const {
|
||||
return sizeof(ethhdr);
|
||||
return sizeof(header_);
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) || defined(HAVE_PACKET_SENDER_PCAP_SENDPACKET)
|
||||
void Dot3::send(PacketSender &sender, const NetworkInterface &iface) {
|
||||
if(!iface)
|
||||
void Dot3::send(PacketSender& sender, const NetworkInterface& iface) {
|
||||
if (!iface) {
|
||||
throw invalid_interface();
|
||||
}
|
||||
|
||||
#if defined(BSD) || defined(__FreeBSD_kernel__) || defined(HAVE_PACKET_SENDER_PCAP_SENDPACKET)
|
||||
sender.send_l2(*this, 0, 0, iface);
|
||||
@@ -103,39 +103,41 @@ void Dot3::send(PacketSender &sender, const NetworkInterface &iface) {
|
||||
addr.sll_protocol = Endian::host_to_be<uint16_t>(ETH_P_ALL);
|
||||
addr.sll_halen = address_type::address_size;
|
||||
addr.sll_ifindex = iface.id();
|
||||
memcpy(&(addr.sll_addr), _eth.dst_mac, sizeof(_eth.dst_mac));
|
||||
memcpy(&(addr.sll_addr), header_.dst_mac, sizeof(header_.dst_mac));
|
||||
|
||||
sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
|
||||
#endif
|
||||
}
|
||||
#endif // !_WIN32 || HAVE_PACKET_SENDER_PCAP_SENDPACKET
|
||||
|
||||
bool Dot3::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
if(total_sz < sizeof(ethhdr))
|
||||
bool Dot3::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
if (total_sz < sizeof(header_)) {
|
||||
return false;
|
||||
}
|
||||
const size_t addr_sz = address_type::address_size;
|
||||
const ethhdr *eth_ptr = (const ethhdr*)ptr;
|
||||
if(std::equal(_eth.src_mac, _eth.src_mac + addr_sz, eth_ptr->dst_mac)) {
|
||||
if(std::equal(_eth.src_mac, _eth.src_mac + addr_sz, eth_ptr->dst_mac) || dst_addr() == BROADCAST)
|
||||
{
|
||||
ptr += sizeof(ethhdr);
|
||||
total_sz -= sizeof(ethhdr);
|
||||
const dot3_header* eth_ptr = (const dot3_header*)ptr;
|
||||
if (equal(header_.src_mac, header_.src_mac + addr_sz, eth_ptr->dst_mac)) {
|
||||
if (equal(header_.src_mac, header_.src_mac + addr_sz, eth_ptr->dst_mac) ||
|
||||
dst_addr() == BROADCAST) {
|
||||
ptr += sizeof(dot3_header);
|
||||
total_sz -= sizeof(dot3_header);
|
||||
return inner_pdu() ? inner_pdu()->matches_response(ptr, total_sz) : true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Dot3::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
|
||||
void Dot3::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
_eth.length = Endian::host_to_be<uint16_t>(size() - sizeof(_eth));
|
||||
stream.write(_eth);
|
||||
header_.length = Endian::host_to_be<uint16_t>(size() - sizeof(header_));
|
||||
stream.write(header_);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
PDU *Dot3::recv_response(PacketSender &sender, const NetworkInterface &iface) {
|
||||
if(!iface)
|
||||
PDU* Dot3::recv_response(PacketSender& sender, const NetworkInterface& iface) {
|
||||
if (!iface) {
|
||||
throw invalid_interface();
|
||||
}
|
||||
#if !defined(BSD) && !defined(__FreeBSD_kernel__)
|
||||
struct sockaddr_ll addr;
|
||||
memset(&addr, 0, sizeof(struct sockaddr_ll));
|
||||
@@ -144,12 +146,14 @@ PDU *Dot3::recv_response(PacketSender &sender, const NetworkInterface &iface) {
|
||||
addr.sll_protocol = Endian::host_to_be<uint16_t>(ETH_P_802_3);
|
||||
addr.sll_halen = address_type::address_size;
|
||||
addr.sll_ifindex = iface.id();
|
||||
memcpy(&(addr.sll_addr), _eth.dst_mac, sizeof(_eth.dst_mac));
|
||||
memcpy(&(addr.sll_addr), header_.dst_mac, sizeof(header_.dst_mac));
|
||||
|
||||
return sender.recv_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
|
||||
#else
|
||||
return sender.recv_l2(*this, 0, 0, iface);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
206
src/eapol.cpp
206
src/eapol.cpp
@@ -36,33 +36,36 @@
|
||||
#include "rawpdu.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::copy;
|
||||
using std::min;
|
||||
using std::memset;
|
||||
using std::memcpy;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
EAPOL::EAPOL(uint8_t packet_type, EAPOLTYPE type)
|
||||
: _header()
|
||||
{
|
||||
_header.version = 1;
|
||||
_header.packet_type = packet_type;
|
||||
_header.type = (uint8_t)type;
|
||||
: header_() {
|
||||
header_.version = 1;
|
||||
header_.packet_type = packet_type;
|
||||
header_.type = (uint8_t)type;
|
||||
}
|
||||
|
||||
EAPOL::EAPOL(const uint8_t *buffer, uint32_t total_sz)
|
||||
{
|
||||
EAPOL::EAPOL(const uint8_t* buffer, uint32_t total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_header);
|
||||
stream.read(header_);
|
||||
}
|
||||
|
||||
EAPOL *EAPOL::from_bytes(const uint8_t *buffer, uint32_t total_sz) {
|
||||
if (total_sz < sizeof(eapolhdr)) {
|
||||
EAPOL* EAPOL::from_bytes(const uint8_t* buffer, uint32_t total_sz) {
|
||||
if (total_sz < sizeof(eapol_header)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
const eapolhdr *ptr = (const eapolhdr*)buffer;
|
||||
const eapol_header* ptr = (const eapol_header*)buffer;
|
||||
uint32_t data_len = Endian::be_to_host<uint16_t>(ptr->length);
|
||||
// at least 4 for fields always present
|
||||
total_sz = std::min(
|
||||
total_sz = min(
|
||||
total_sz,
|
||||
data_len + 4
|
||||
);
|
||||
@@ -79,208 +82,203 @@ EAPOL *EAPOL::from_bytes(const uint8_t *buffer, uint32_t total_sz) {
|
||||
}
|
||||
|
||||
void EAPOL::version(uint8_t new_version) {
|
||||
_header.version = new_version;
|
||||
header_.version = new_version;
|
||||
}
|
||||
|
||||
void EAPOL::packet_type(uint8_t new_ptype) {
|
||||
_header.packet_type = new_ptype;
|
||||
header_.packet_type = new_ptype;
|
||||
}
|
||||
|
||||
void EAPOL::length(uint16_t new_length) {
|
||||
_header.length = Endian::host_to_be(new_length);
|
||||
header_.length = Endian::host_to_be(new_length);
|
||||
}
|
||||
|
||||
void EAPOL::type(uint8_t new_type) {
|
||||
_header.type = new_type;
|
||||
header_.type = new_type;
|
||||
}
|
||||
|
||||
void EAPOL::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
|
||||
void EAPOL::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
length(total_sz - 4);
|
||||
stream.write(_header);
|
||||
std::memcpy(buffer, &_header, sizeof(_header));
|
||||
stream.write(header_);
|
||||
memcpy(buffer, &header_, sizeof(header_));
|
||||
write_body(stream);
|
||||
}
|
||||
|
||||
/* RC4EAPOL */
|
||||
|
||||
RC4EAPOL::RC4EAPOL()
|
||||
: EAPOL(0x03, RC4)
|
||||
{
|
||||
std::memset(&_header, 0, sizeof(_header));
|
||||
: EAPOL(0x03, RC4) {
|
||||
memset(&header_, 0, sizeof(header_));
|
||||
}
|
||||
|
||||
RC4EAPOL::RC4EAPOL(const uint8_t *buffer, uint32_t total_sz)
|
||||
: EAPOL(buffer, total_sz)
|
||||
{
|
||||
RC4EAPOL::RC4EAPOL(const uint8_t* buffer, uint32_t total_sz)
|
||||
: EAPOL(buffer, total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(sizeof(eapolhdr));
|
||||
stream.read(_header);
|
||||
stream.skip(sizeof(eapol_header));
|
||||
stream.read(header_);
|
||||
if (stream.size() >= key_length()) {
|
||||
_key.assign(stream.pointer(), stream.pointer() + key_length());
|
||||
stream.skip(key_length());
|
||||
stream.read(key_, key_length());
|
||||
if (stream) {
|
||||
inner_pdu(new RawPDU(stream.pointer(), stream.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RC4EAPOL::key_length(uint16_t new_key_length) {
|
||||
_header.key_length = Endian::host_to_be(new_key_length);
|
||||
void RC4EAPOL::key_length(uint16_t length) {
|
||||
header_.key_length = Endian::host_to_be(length);
|
||||
}
|
||||
|
||||
void RC4EAPOL::replay_counter(uint64_t new_replay_counter) {
|
||||
_header.replay_counter = Endian::host_to_be(new_replay_counter);
|
||||
void RC4EAPOL::replay_counter(uint64_t value) {
|
||||
header_.replay_counter = Endian::host_to_be(value);
|
||||
}
|
||||
|
||||
void RC4EAPOL::key_iv(const uint8_t *new_key_iv) {
|
||||
std::copy(new_key_iv, new_key_iv + sizeof(_header.key_iv), _header.key_iv);
|
||||
void RC4EAPOL::key_iv(const uint8_t* ptr) {
|
||||
copy(ptr, ptr + sizeof(header_.key_iv), header_.key_iv);
|
||||
}
|
||||
|
||||
void RC4EAPOL::key_flag(small_uint<1> new_key_flag) {
|
||||
_header.key_flag = new_key_flag;
|
||||
void RC4EAPOL::key_flag(small_uint<1> flag) {
|
||||
header_.key_flag = flag;
|
||||
}
|
||||
|
||||
void RC4EAPOL::key_index(small_uint<7> new_key_index) {
|
||||
_header.key_index = new_key_index;
|
||||
header_.key_index = new_key_index;
|
||||
}
|
||||
|
||||
void RC4EAPOL::key_sign(const uint8_t *new_key_sign) {
|
||||
std::memcpy(_header.key_sign, new_key_sign, sizeof(_header.key_sign));
|
||||
void RC4EAPOL::key_sign(const uint8_t* ptr) {
|
||||
memcpy(header_.key_sign, ptr, sizeof(header_.key_sign));
|
||||
}
|
||||
|
||||
void RC4EAPOL::key(const key_type &new_key) {
|
||||
_key = new_key;
|
||||
void RC4EAPOL::key(const key_type& new_key) {
|
||||
key_ = new_key;
|
||||
}
|
||||
|
||||
uint32_t RC4EAPOL::header_size() const {
|
||||
return static_cast<uint32_t>(sizeof(eapolhdr) + sizeof(_header) + _key.size());
|
||||
return static_cast<uint32_t>(sizeof(eapol_header) + sizeof(header_) + key_.size());
|
||||
}
|
||||
|
||||
void RC4EAPOL::write_body(OutputMemoryStream& stream) {
|
||||
if (_key.size()) {
|
||||
_header.key_length = Endian::host_to_be(static_cast<uint16_t>(_key.size()));
|
||||
if (key_.size()) {
|
||||
header_.key_length = Endian::host_to_be(static_cast<uint16_t>(key_.size()));
|
||||
}
|
||||
stream.write(_header);
|
||||
stream.write(_key.begin(), _key.end());
|
||||
stream.write(header_);
|
||||
stream.write(key_.begin(), key_.end());
|
||||
}
|
||||
|
||||
/* RSNEAPOL */
|
||||
|
||||
|
||||
RSNEAPOL::RSNEAPOL()
|
||||
: EAPOL(0x03, RSN)
|
||||
{
|
||||
std::memset(&_header, 0, sizeof(_header));
|
||||
: EAPOL(0x03, RSN) {
|
||||
memset(&header_, 0, sizeof(header_));
|
||||
}
|
||||
|
||||
RSNEAPOL::RSNEAPOL(const uint8_t *buffer, uint32_t total_sz)
|
||||
: EAPOL(buffer, total_sz)
|
||||
{
|
||||
RSNEAPOL::RSNEAPOL(const uint8_t* buffer, uint32_t total_sz)
|
||||
: EAPOL(buffer, total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.skip(sizeof(eapolhdr));
|
||||
stream.read(_header);
|
||||
stream.skip(sizeof(eapol_header));
|
||||
stream.read(header_);
|
||||
if (stream.size() >= wpa_length()) {
|
||||
_key.assign(stream.pointer(), stream.pointer() + wpa_length());
|
||||
stream.skip(wpa_length());
|
||||
stream.read(key_, wpa_length());
|
||||
if (stream) {
|
||||
inner_pdu(new RawPDU(stream.pointer(), stream.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RSNEAPOL::nonce(const uint8_t *new_nonce) {
|
||||
std::copy(new_nonce, new_nonce + nonce_size, _header.nonce);
|
||||
void RSNEAPOL::nonce(const uint8_t* ptr) {
|
||||
copy(ptr, ptr + nonce_size, header_.nonce);
|
||||
}
|
||||
|
||||
void RSNEAPOL::rsc(const uint8_t *new_rsc) {
|
||||
std::copy(new_rsc, new_rsc + rsc_size, _header.rsc);
|
||||
void RSNEAPOL::rsc(const uint8_t* ptr) {
|
||||
copy(ptr, ptr + rsc_size, header_.rsc);
|
||||
}
|
||||
|
||||
void RSNEAPOL::id(const uint8_t *new_id) {
|
||||
std::copy(new_id, new_id + id_size, _header.id);
|
||||
void RSNEAPOL::id(const uint8_t* ptr) {
|
||||
copy(ptr, ptr + id_size, header_.id);
|
||||
}
|
||||
|
||||
void RSNEAPOL::replay_counter(uint64_t new_replay_counter) {
|
||||
_header.replay_counter = Endian::host_to_be(new_replay_counter);
|
||||
header_.replay_counter = Endian::host_to_be(new_replay_counter);
|
||||
}
|
||||
|
||||
void RSNEAPOL::mic(const uint8_t *new_mic) {
|
||||
std::copy(new_mic, new_mic + mic_size, _header.mic);
|
||||
void RSNEAPOL::mic(const uint8_t* ptr) {
|
||||
copy(ptr, ptr + mic_size, header_.mic);
|
||||
}
|
||||
|
||||
void RSNEAPOL::wpa_length(uint16_t new_wpa_length) {
|
||||
_header.wpa_length = Endian::host_to_be(new_wpa_length);
|
||||
void RSNEAPOL::wpa_length(uint16_t length) {
|
||||
header_.wpa_length = Endian::host_to_be(length);
|
||||
}
|
||||
|
||||
void RSNEAPOL::key_iv(const uint8_t *new_key_iv) {
|
||||
std::copy(new_key_iv, new_key_iv + sizeof(_header.key_iv), _header.key_iv);
|
||||
void RSNEAPOL::key_iv(const uint8_t* ptr) {
|
||||
copy(ptr, ptr + sizeof(header_.key_iv), header_.key_iv);
|
||||
}
|
||||
|
||||
void RSNEAPOL::key_length(uint16_t new_key_length) {
|
||||
_header.key_length = Endian::host_to_be(new_key_length);
|
||||
void RSNEAPOL::key_length(uint16_t length) {
|
||||
header_.key_length = Endian::host_to_be(length);
|
||||
}
|
||||
|
||||
void RSNEAPOL::key(const key_type &new_key) {
|
||||
_key = new_key;
|
||||
_header.key_t = 0;
|
||||
void RSNEAPOL::key(const key_type& value) {
|
||||
key_ = value;
|
||||
header_.key_t = 0;
|
||||
}
|
||||
|
||||
void RSNEAPOL::key_mic(small_uint<1> new_key_mic) {
|
||||
_header.key_mic = new_key_mic;
|
||||
void RSNEAPOL::key_mic(small_uint<1> flag) {
|
||||
header_.key_mic = flag;
|
||||
}
|
||||
|
||||
void RSNEAPOL::secure(small_uint<1> new_secure) {
|
||||
_header.secure = new_secure;
|
||||
void RSNEAPOL::secure(small_uint<1> flag) {
|
||||
header_.secure = flag;
|
||||
}
|
||||
|
||||
void RSNEAPOL::error(small_uint<1> new_error) {
|
||||
_header.error = new_error;
|
||||
void RSNEAPOL::error(small_uint<1> flag) {
|
||||
header_.error = flag;
|
||||
}
|
||||
|
||||
void RSNEAPOL::request(small_uint<1> new_request) {
|
||||
_header.request = new_request;
|
||||
void RSNEAPOL::request(small_uint<1> flag) {
|
||||
header_.request = flag;
|
||||
}
|
||||
|
||||
void RSNEAPOL::encrypted(small_uint<1 > new_encrypted) {
|
||||
_header.encrypted = new_encrypted;
|
||||
void RSNEAPOL::encrypted(small_uint<1> flag) {
|
||||
header_.encrypted = flag;
|
||||
}
|
||||
|
||||
void RSNEAPOL::key_descriptor(small_uint<3> new_key_descriptor) {
|
||||
_header.key_descriptor = new_key_descriptor;
|
||||
header_.key_descriptor = new_key_descriptor;
|
||||
}
|
||||
|
||||
void RSNEAPOL::key_t(small_uint<1> new_key_t) {
|
||||
_header.key_t = new_key_t;
|
||||
void RSNEAPOL::key_t(small_uint<1> flag) {
|
||||
header_.key_t = flag;
|
||||
}
|
||||
|
||||
void RSNEAPOL::key_index(small_uint<2> new_key_index) {
|
||||
_header.key_index = new_key_index;
|
||||
void RSNEAPOL::key_index(small_uint<2> value) {
|
||||
header_.key_index = value;
|
||||
}
|
||||
|
||||
void RSNEAPOL::install(small_uint<1> new_install) {
|
||||
_header.install = new_install;
|
||||
void RSNEAPOL::install(small_uint<1> flag) {
|
||||
header_.install = flag;
|
||||
}
|
||||
|
||||
void RSNEAPOL::key_ack(small_uint<1> new_key_ack) {
|
||||
_header.key_ack = new_key_ack;
|
||||
void RSNEAPOL::key_ack(small_uint<1> flag) {
|
||||
header_.key_ack = flag;
|
||||
}
|
||||
|
||||
uint32_t RSNEAPOL::header_size() const {
|
||||
return static_cast<uint32_t>(sizeof(eapolhdr) + sizeof(_header) + _key.size());
|
||||
return static_cast<uint32_t>(sizeof(eapol_header) + sizeof(header_) + key_.size());
|
||||
}
|
||||
|
||||
void RSNEAPOL::write_body(OutputMemoryStream& stream) {
|
||||
if (_key.size()) {
|
||||
if (!_header.key_t && _header.install) {
|
||||
_header.key_length = Endian::host_to_be<uint16_t>(32);
|
||||
wpa_length(static_cast<uint16_t>(_key.size()));
|
||||
if (key_.size()) {
|
||||
if (!header_.key_t && header_.install) {
|
||||
header_.key_length = Endian::host_to_be<uint16_t>(32);
|
||||
wpa_length(static_cast<uint16_t>(key_.size()));
|
||||
}
|
||||
else if (_key.size()) {
|
||||
wpa_length(static_cast<uint16_t>(_key.size()));
|
||||
else if (key_.size()) {
|
||||
wpa_length(static_cast<uint16_t>(key_.size()));
|
||||
}
|
||||
}
|
||||
stream.write(_header);
|
||||
stream.write(_key.begin(), _key.end());
|
||||
}
|
||||
stream.write(header_);
|
||||
stream.write(key_.begin(), key_.end());
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include "macros.h"
|
||||
#ifndef _WIN32
|
||||
@@ -53,6 +52,8 @@
|
||||
#include "exceptions.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::equal;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
@@ -60,18 +61,16 @@ namespace Tins {
|
||||
|
||||
const EthernetII::address_type EthernetII::BROADCAST("ff:ff:ff:ff:ff:ff");
|
||||
|
||||
EthernetII::EthernetII(const address_type &dst_hw_addr,
|
||||
const address_type &src_hw_addr)
|
||||
: _eth()
|
||||
{
|
||||
EthernetII::EthernetII(const address_type& dst_hw_addr,
|
||||
const address_type& src_hw_addr)
|
||||
: header_() {
|
||||
dst_addr(dst_hw_addr);
|
||||
src_addr(src_hw_addr);
|
||||
}
|
||||
|
||||
EthernetII::EthernetII(const uint8_t *buffer, uint32_t total_sz)
|
||||
{
|
||||
EthernetII::EthernetII(const uint8_t* buffer, uint32_t total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_eth);
|
||||
stream.read(header_);
|
||||
// If there's any size left
|
||||
if (stream) {
|
||||
inner_pdu(
|
||||
@@ -82,28 +81,26 @@ EthernetII::EthernetII(const uint8_t *buffer, uint32_t total_sz)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void EthernetII::dst_addr(const address_type &new_dst_addr) {
|
||||
new_dst_addr.copy(_eth.dst_mac);
|
||||
void EthernetII::dst_addr(const address_type& new_dst_addr) {
|
||||
new_dst_addr.copy(header_.dst_mac);
|
||||
}
|
||||
|
||||
void EthernetII::src_addr(const address_type &new_src_addr) {
|
||||
new_src_addr.copy(_eth.src_mac);
|
||||
void EthernetII::src_addr(const address_type& new_src_addr) {
|
||||
new_src_addr.copy(header_.src_mac);
|
||||
}
|
||||
|
||||
void EthernetII::payload_type(uint16_t new_payload_type) {
|
||||
this->_eth.payload_type = Endian::host_to_be(new_payload_type);
|
||||
header_.payload_type = Endian::host_to_be(new_payload_type);
|
||||
}
|
||||
|
||||
uint32_t EthernetII::header_size() const {
|
||||
|
||||
return sizeof(ethhdr);
|
||||
return sizeof(header_);
|
||||
}
|
||||
|
||||
uint32_t EthernetII::trailer_size() const {
|
||||
int32_t padding = 60 - sizeof(ethhdr); // EthernetII min size is 60, padding is sometimes needed
|
||||
int32_t padding = 60 - sizeof(header_); // EthernetII min size is 60, padding is sometimes needed
|
||||
if (inner_pdu()) {
|
||||
padding -= inner_pdu()->size();
|
||||
padding = std::max(0, padding);
|
||||
@@ -111,9 +108,10 @@ uint32_t EthernetII::trailer_size() const {
|
||||
return padding;
|
||||
}
|
||||
|
||||
void EthernetII::send(PacketSender &sender, const NetworkInterface &iface) {
|
||||
if(!iface)
|
||||
void EthernetII::send(PacketSender& sender, const NetworkInterface& iface) {
|
||||
if (!iface) {
|
||||
throw invalid_interface();
|
||||
}
|
||||
#if defined(HAVE_PACKET_SENDER_PCAP_SENDPACKET) || defined(BSD) || defined(__FreeBSD_kernel__)
|
||||
// Sending using pcap_sendpacket/BSD bpf packet mode is the same here
|
||||
sender.send_l2(*this, 0, 0, iface);
|
||||
@@ -130,27 +128,30 @@ void EthernetII::send(PacketSender &sender, const NetworkInterface &iface) {
|
||||
addr.sll_protocol = Endian::host_to_be<uint16_t>(ETH_P_ALL);
|
||||
addr.sll_halen = address_type::address_size;
|
||||
addr.sll_ifindex = iface.id();
|
||||
memcpy(&(addr.sll_addr), _eth.dst_mac, address_type::address_size);
|
||||
memcpy(&(addr.sll_addr), header_.dst_mac, address_type::address_size);
|
||||
|
||||
sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool EthernetII::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
if(total_sz < sizeof(ethhdr))
|
||||
bool EthernetII::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
if (total_sz < sizeof(header_)) {
|
||||
return false;
|
||||
}
|
||||
const size_t addr_sz = address_type::address_size;
|
||||
const ethhdr *eth_ptr = (const ethhdr*)ptr;
|
||||
if(std::equal(_eth.src_mac, _eth.src_mac + addr_sz, eth_ptr->dst_mac)) {
|
||||
if(std::equal(_eth.src_mac, _eth.src_mac + addr_sz, eth_ptr->dst_mac) || !dst_addr().is_unicast())
|
||||
{
|
||||
return (inner_pdu()) ? inner_pdu()->matches_response(ptr + sizeof(_eth), total_sz - sizeof(_eth)) : true;
|
||||
const ethernet_header* eth_ptr = (const ethernet_header*)ptr;
|
||||
if (equal(header_.src_mac, header_.src_mac + addr_sz, eth_ptr->dst_mac)) {
|
||||
if (equal(header_.src_mac, header_.src_mac + addr_sz, eth_ptr->dst_mac) ||
|
||||
!dst_addr().is_unicast()) {
|
||||
return inner_pdu() ?
|
||||
inner_pdu()->matches_response(ptr + sizeof(header_), total_sz - sizeof(header_)) :
|
||||
true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void EthernetII::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
|
||||
void EthernetII::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
if (inner_pdu()) {
|
||||
Constants::Ethernet::e flag;
|
||||
@@ -168,7 +169,7 @@ void EthernetII::write_serialization(uint8_t *buffer, uint32_t total_sz, const P
|
||||
payload_type(static_cast<uint16_t>(flag));
|
||||
}
|
||||
}
|
||||
stream.write(_eth);
|
||||
stream.write(header_);
|
||||
const uint32_t trailer = trailer_size();
|
||||
if (trailer) {
|
||||
if (inner_pdu()) {
|
||||
@@ -180,7 +181,7 @@ void EthernetII::write_serialization(uint8_t *buffer, uint32_t total_sz, const P
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
PDU *EthernetII::recv_response(PacketSender &sender, const NetworkInterface &iface) {
|
||||
PDU* EthernetII::recv_response(PacketSender& sender, const NetworkInterface& iface) {
|
||||
#if !defined(BSD) && !defined(__FreeBSD_kernel__)
|
||||
struct sockaddr_ll addr;
|
||||
memset(&addr, 0, sizeof(struct sockaddr_ll));
|
||||
@@ -189,7 +190,7 @@ PDU *EthernetII::recv_response(PacketSender &sender, const NetworkInterface &ifa
|
||||
addr.sll_protocol = Endian::host_to_be<uint16_t>(ETH_P_ALL);
|
||||
addr.sll_halen = address_type::address_size;
|
||||
addr.sll_ifindex = iface.id();
|
||||
memcpy(&(addr.sll_addr), _eth.dst_mac, address_type::address_size);
|
||||
memcpy(&(addr.sll_addr), header_.dst_mac, address_type::address_size);
|
||||
|
||||
return sender.recv_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
|
||||
#else
|
||||
|
||||
@@ -33,68 +33,77 @@
|
||||
|
||||
#include "dot11/dot11_data.h"
|
||||
|
||||
using std::max_element;
|
||||
using std::pair;
|
||||
|
||||
namespace Tins {
|
||||
bool RSNHandshakeCapturer::process_packet(const PDU &pdu) {
|
||||
const RSNEAPOL *eapol = pdu.find_pdu<RSNEAPOL>();
|
||||
const Dot11Data *dot11 = pdu.find_pdu<Dot11Data>();
|
||||
if(!eapol || !dot11)
|
||||
return false;
|
||||
|
||||
|
||||
std::pair<address_type, address_type> addresses;
|
||||
if(dot11->to_ds()) {
|
||||
addresses.first = dot11->addr1();
|
||||
addresses.second = dot11->addr2();
|
||||
}
|
||||
else if(dot11->from_ds()) {
|
||||
addresses.first = dot11->addr2();
|
||||
addresses.second = dot11->addr1();
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
// 1st
|
||||
if(eapol->key_t() && eapol->key_ack() && !eapol->key_mic() && !eapol->install()) {
|
||||
handshakes_[addresses].assign(eapol, eapol + 1);
|
||||
}
|
||||
else if(eapol->key_t() && eapol->key_mic() && !eapol->install() && !eapol->key_ack()) {
|
||||
if(*std::max_element(eapol->nonce(), eapol->nonce() + RSNEAPOL::nonce_size) > 0)
|
||||
do_insert(addresses, eapol, 1);
|
||||
else if(do_insert(addresses, eapol, 3)) {
|
||||
completed_handshakes_.push_back(
|
||||
handshake_type(
|
||||
addresses.first,
|
||||
addresses.second,
|
||||
handshakes_[addresses]
|
||||
)
|
||||
);
|
||||
handshakes_.erase(addresses);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if(eapol->key_t() && eapol->install() && eapol->key_ack() && eapol->key_mic()) {
|
||||
do_insert(addresses, eapol, 2);
|
||||
}
|
||||
|
||||
bool RSNHandshakeCapturer::process_packet(const PDU& pdu) {
|
||||
const RSNEAPOL* eapol = pdu.find_pdu<RSNEAPOL>();
|
||||
const Dot11Data* dot11 = pdu.find_pdu<Dot11Data>();
|
||||
if (!eapol || !dot11) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RSNHandshakeCapturer::do_insert(const handshake_map::key_type &key,
|
||||
const RSNEAPOL *eapol, size_t expected)
|
||||
{
|
||||
handshake_map::iterator iter = handshakes_.find(key);
|
||||
if(iter != handshakes_.end()) {
|
||||
if(iter->second.size() != expected) {
|
||||
// skip repeated
|
||||
if(iter->second.size() != expected + 1)
|
||||
iter->second.clear();
|
||||
}
|
||||
else {
|
||||
iter->second.push_back(*eapol);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
pair<address_type, address_type> addresses;
|
||||
if (dot11->to_ds()) {
|
||||
addresses.first = dot11->addr1();
|
||||
addresses.second = dot11->addr2();
|
||||
}
|
||||
else if (dot11->from_ds()) {
|
||||
addresses.first = dot11->addr2();
|
||||
addresses.second = dot11->addr1();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1st
|
||||
if (eapol->key_t() && eapol->key_ack() && !eapol->key_mic() && !eapol->install()) {
|
||||
handshakes_[addresses].assign(eapol, eapol + 1);
|
||||
}
|
||||
else if (eapol->key_t() && eapol->key_mic() && !eapol->install() && !eapol->key_ack()) {
|
||||
if (*max_element(eapol->nonce(), eapol->nonce() + RSNEAPOL::nonce_size) > 0) {
|
||||
do_insert(addresses, eapol, 1);
|
||||
}
|
||||
else if (do_insert(addresses, eapol, 3)) {
|
||||
completed_handshakes_.push_back(
|
||||
handshake_type(
|
||||
addresses.first,
|
||||
addresses.second,
|
||||
handshakes_[addresses]
|
||||
)
|
||||
);
|
||||
handshakes_.erase(addresses);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (eapol->key_t() && eapol->install() && eapol->key_ack() && eapol->key_mic()) {
|
||||
do_insert(addresses, eapol, 2);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RSNHandshakeCapturer::do_insert(const handshake_map::key_type& key,
|
||||
const RSNEAPOL* eapol,
|
||||
size_t expected) {
|
||||
handshake_map::iterator iter = handshakes_.find(key);
|
||||
if (iter != handshakes_.end()) {
|
||||
if (iter->second.size() != expected) {
|
||||
// skip repeated
|
||||
if (iter->second.size() != expected + 1) {
|
||||
iter->second.clear();
|
||||
}
|
||||
}
|
||||
else {
|
||||
iter->second.push_back(*eapol);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Tins;
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
95
src/icmp.cpp
95
src/icmp.cpp
@@ -38,28 +38,29 @@
|
||||
#include "icmp.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::memset;
|
||||
using std::max;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
ICMP::ICMP(Flags flag)
|
||||
: _orig_timestamp_or_address_mask(), _recv_timestamp(), _trans_timestamp()
|
||||
{
|
||||
std::memset(&_icmp, 0, sizeof(icmphdr));
|
||||
: orig_timestamp_or_address_mask_(), recv_timestamp_(), trans_timestamp_() {
|
||||
memset(&header_, 0, sizeof(icmp_header));
|
||||
type(flag);
|
||||
}
|
||||
|
||||
ICMP::ICMP(const uint8_t *buffer, uint32_t total_sz)
|
||||
{
|
||||
ICMP::ICMP(const uint8_t* buffer, uint32_t total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_icmp);
|
||||
if(type() == TIMESTAMP_REQUEST || type() == TIMESTAMP_REPLY) {
|
||||
stream.read(header_);
|
||||
if (type() == TIMESTAMP_REQUEST || type() == TIMESTAMP_REPLY) {
|
||||
original_timestamp(stream.read<uint32_t>());
|
||||
receive_timestamp(stream.read<uint32_t>());
|
||||
transmit_timestamp(stream.read<uint32_t>());
|
||||
}
|
||||
else if(type() == ADDRESS_MASK_REQUEST || type() == ADDRESS_MASK_REPLY) {
|
||||
else if (type() == ADDRESS_MASK_REQUEST || type() == ADDRESS_MASK_REPLY) {
|
||||
address_mask(address_type(stream.read<uint32_t>()));
|
||||
}
|
||||
// Attempt to parse ICMP extensions
|
||||
@@ -70,61 +71,63 @@ ICMP::ICMP(const uint8_t *buffer, uint32_t total_sz)
|
||||
}
|
||||
|
||||
void ICMP::code(uint8_t new_code) {
|
||||
_icmp.code = new_code;
|
||||
header_.code = new_code;
|
||||
}
|
||||
|
||||
void ICMP::type(Flags new_type) {
|
||||
_icmp.type = new_type;
|
||||
header_.type = new_type;
|
||||
}
|
||||
|
||||
void ICMP::checksum(uint16_t new_check) {
|
||||
_icmp.check = Endian::host_to_be(new_check);
|
||||
header_.check = Endian::host_to_be(new_check);
|
||||
}
|
||||
|
||||
void ICMP::id(uint16_t new_id) {
|
||||
_icmp.un.echo.id = Endian::host_to_be(new_id);
|
||||
header_.un.echo.id = Endian::host_to_be(new_id);
|
||||
}
|
||||
|
||||
void ICMP::sequence(uint16_t new_seq) {
|
||||
_icmp.un.echo.sequence = Endian::host_to_be(new_seq);
|
||||
header_.un.echo.sequence = Endian::host_to_be(new_seq);
|
||||
}
|
||||
|
||||
void ICMP::gateway(address_type new_gw) {
|
||||
_icmp.un.gateway = Endian::host_to_be(static_cast<uint32_t>(new_gw));
|
||||
header_.un.gateway = Endian::host_to_be(static_cast<uint32_t>(new_gw));
|
||||
}
|
||||
|
||||
void ICMP::mtu(uint16_t new_mtu) {
|
||||
_icmp.un.frag.mtu = Endian::host_to_be(new_mtu);
|
||||
header_.un.frag.mtu = Endian::host_to_be(new_mtu);
|
||||
}
|
||||
|
||||
void ICMP::pointer(uint8_t new_pointer) {
|
||||
_icmp.un.rfc4884.pointer = new_pointer;
|
||||
header_.un.rfc4884.pointer = new_pointer;
|
||||
}
|
||||
|
||||
void ICMP::original_timestamp(uint32_t new_timestamp) {
|
||||
_orig_timestamp_or_address_mask = Endian::host_to_be(new_timestamp);
|
||||
orig_timestamp_or_address_mask_ = Endian::host_to_be(new_timestamp);
|
||||
}
|
||||
|
||||
void ICMP::receive_timestamp(uint32_t new_timestamp) {
|
||||
_recv_timestamp = Endian::host_to_be(new_timestamp);
|
||||
recv_timestamp_ = Endian::host_to_be(new_timestamp);
|
||||
}
|
||||
|
||||
void ICMP::transmit_timestamp(uint32_t new_timestamp) {
|
||||
_trans_timestamp = Endian::host_to_be(new_timestamp);
|
||||
trans_timestamp_ = Endian::host_to_be(new_timestamp);
|
||||
}
|
||||
|
||||
void ICMP::address_mask(address_type new_mask) {
|
||||
_orig_timestamp_or_address_mask = Endian::host_to_be(static_cast<uint32_t>(new_mask));
|
||||
orig_timestamp_or_address_mask_ = Endian::host_to_be(static_cast<uint32_t>(new_mask));
|
||||
}
|
||||
|
||||
uint32_t ICMP::header_size() const {
|
||||
uint32_t extra = 0;
|
||||
if(type() == TIMESTAMP_REQUEST || type() == TIMESTAMP_REPLY)
|
||||
if (type() == TIMESTAMP_REQUEST || type() == TIMESTAMP_REPLY) {
|
||||
extra = sizeof(uint32_t) * 3;
|
||||
else if(type() == ADDRESS_MASK_REQUEST || type() == ADDRESS_MASK_REPLY)
|
||||
}
|
||||
else if (type() == ADDRESS_MASK_REQUEST || type() == ADDRESS_MASK_REPLY) {
|
||||
extra = sizeof(uint32_t);
|
||||
}
|
||||
|
||||
return sizeof(icmphdr) + extra;
|
||||
return sizeof(icmp_header) + extra;
|
||||
}
|
||||
|
||||
uint32_t ICMP::trailer_size() const {
|
||||
@@ -136,7 +139,7 @@ uint32_t ICMP::trailer_size() const {
|
||||
// If the next pdu size is lower than 128 bytes, then padding = 128 - pdu size
|
||||
// If the next pdu size is greater than 128 bytes,
|
||||
// then padding = pdu size padded to next 32 bit boundary - pdu size
|
||||
const uint32_t upper_bound = std::max(get_adjusted_inner_pdu_size(), 128U);
|
||||
const uint32_t upper_bound = max(get_adjusted_inner_pdu_size(), 128U);
|
||||
output += upper_bound - inner_pdu()->size();
|
||||
}
|
||||
}
|
||||
@@ -180,12 +183,13 @@ void ICMP::set_time_exceeded(bool ttl_exceeded) {
|
||||
|
||||
void ICMP::set_param_problem(bool set_pointer, uint8_t bad_octet) {
|
||||
type(PARAM_PROBLEM);
|
||||
if(set_pointer) {
|
||||
if (set_pointer) {
|
||||
code(0);
|
||||
pointer(bad_octet);
|
||||
}
|
||||
else
|
||||
else {
|
||||
code(1);
|
||||
}
|
||||
}
|
||||
|
||||
void ICMP::set_source_quench() {
|
||||
@@ -201,10 +205,10 @@ void ICMP::set_redirect(uint8_t icode, address_type address) {
|
||||
void ICMP::use_length_field(bool value) {
|
||||
// We just need a non 0 value here, we'll use the right value on
|
||||
// write_serialization
|
||||
_icmp.un.rfc4884.length = value ? 1 : 0;
|
||||
header_.un.rfc4884.length = value ? 1 : 0;
|
||||
}
|
||||
|
||||
void ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
|
||||
void ICMP::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
|
||||
// If extensions are allowed and we have to set the length field
|
||||
@@ -215,32 +219,32 @@ void ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *)
|
||||
if (length_value) {
|
||||
// If we have extensions, we'll have at least 128 bytes.
|
||||
// Otherwise, just use the length
|
||||
length_value = has_extensions() ? std::max(length_value, 128U)
|
||||
length_value = has_extensions() ? max(length_value, 128U)
|
||||
: length_value;
|
||||
}
|
||||
else {
|
||||
length_value = 0;
|
||||
}
|
||||
// This field uses 32 bit words as the unit
|
||||
_icmp.un.rfc4884.length = length_value / sizeof(uint32_t);
|
||||
header_.un.rfc4884.length = length_value / sizeof(uint32_t);
|
||||
}
|
||||
}
|
||||
|
||||
// Write the header using checksum 0
|
||||
_icmp.check = 0;
|
||||
stream.write(_icmp);
|
||||
header_.check = 0;
|
||||
stream.write(header_);
|
||||
|
||||
if(type() == TIMESTAMP_REQUEST || type() == TIMESTAMP_REPLY) {
|
||||
if (type() == TIMESTAMP_REQUEST || type() == TIMESTAMP_REPLY) {
|
||||
stream.write(original_timestamp());
|
||||
stream.write(receive_timestamp());
|
||||
stream.write(transmit_timestamp());
|
||||
}
|
||||
else if(type() == ADDRESS_MASK_REQUEST || type() == ADDRESS_MASK_REPLY) {
|
||||
else if (type() == ADDRESS_MASK_REQUEST || type() == ADDRESS_MASK_REPLY) {
|
||||
stream.write(address_mask());
|
||||
}
|
||||
|
||||
if (has_extensions()) {
|
||||
uint8_t* extensions_ptr = buffer + sizeof(icmphdr);
|
||||
uint8_t* extensions_ptr = buffer + sizeof(icmp_header);
|
||||
if (inner_pdu()) {
|
||||
// Get the size of the next pdu, padded to the next 32 bit boundary
|
||||
uint32_t inner_pdu_size = get_adjusted_inner_pdu_size();
|
||||
@@ -267,8 +271,8 @@ void ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *)
|
||||
checksum = (checksum & 0xffff) + (checksum >> 16);
|
||||
}
|
||||
// Write back only the 2 checksum bytes
|
||||
_icmp.check = ~checksum;
|
||||
memcpy(buffer + 2, &_icmp.check, sizeof(uint16_t));
|
||||
header_.check = ~checksum;
|
||||
memcpy(buffer + 2, &header_.check, sizeof(uint16_t));
|
||||
}
|
||||
|
||||
uint32_t ICMP::get_adjusted_inner_pdu_size() const {
|
||||
@@ -288,15 +292,18 @@ bool ICMP::are_extensions_allowed() const {
|
||||
return type() == DEST_UNREACHABLE || type() == TIME_EXCEEDED || type() == PARAM_PROBLEM;
|
||||
}
|
||||
|
||||
bool ICMP::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
if(total_sz < sizeof(icmphdr))
|
||||
bool ICMP::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
if (total_sz < sizeof(icmp_header)) {
|
||||
return false;
|
||||
const icmphdr *icmp_ptr = (const icmphdr*)ptr;
|
||||
if((_icmp.type == ECHO_REQUEST && icmp_ptr->type == ECHO_REPLY) ||
|
||||
(_icmp.type == TIMESTAMP_REQUEST && icmp_ptr->type == TIMESTAMP_REPLY) ||
|
||||
(_icmp.type == ADDRESS_MASK_REQUEST && icmp_ptr->type == ADDRESS_MASK_REPLY)) {
|
||||
return icmp_ptr->un.echo.id == _icmp.un.echo.id && icmp_ptr->un.echo.sequence == _icmp.un.echo.sequence;
|
||||
}
|
||||
const icmp_header* icmp_ptr = (const icmp_header*)ptr;
|
||||
if ((header_.type == ECHO_REQUEST && icmp_ptr->type == ECHO_REPLY) ||
|
||||
(header_.type == TIMESTAMP_REQUEST && icmp_ptr->type == TIMESTAMP_REPLY) ||
|
||||
(header_.type == ADDRESS_MASK_REQUEST && icmp_ptr->type == ADDRESS_MASK_REPLY)) {
|
||||
return icmp_ptr->un.echo.id == header_.un.echo.id &&
|
||||
icmp_ptr->un.echo.sequence == header_.un.echo.sequence;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Tins
|
||||
|
||||
@@ -60,7 +60,7 @@ ICMPExtension::ICMPExtension(uint8_t ext_class, uint8_t ext_type)
|
||||
ICMPExtension::ICMPExtension(const uint8_t* buffer, uint32_t total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
|
||||
uint16_t length = Endian::be_to_host(stream.read<uint16_t>());
|
||||
uint16_t length = stream.read_be<uint16_t>();
|
||||
extension_class_ = stream.read<uint8_t>();
|
||||
extension_type_ = stream.read<uint8_t>();
|
||||
// Length is BASE_HEADER_SIZE + payload size, make sure it's valid
|
||||
@@ -68,7 +68,7 @@ ICMPExtension::ICMPExtension(const uint8_t* buffer, uint32_t total_sz) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
length -= BASE_HEADER_SIZE;
|
||||
payload_.assign(stream.pointer(), stream.pointer() + length);
|
||||
stream.read(payload_, length);
|
||||
}
|
||||
|
||||
void ICMPExtension::extension_class(uint8_t value) {
|
||||
@@ -89,7 +89,7 @@ uint32_t ICMPExtension::size() const {
|
||||
|
||||
void ICMPExtension::serialize(uint8_t* buffer, uint32_t buffer_size) const {
|
||||
OutputMemoryStream stream(buffer, buffer_size);
|
||||
stream.write(Endian::host_to_be<uint16_t>(size()));
|
||||
stream.write_be<uint16_t>(size());
|
||||
stream.write(extension_class_);
|
||||
stream.write(extension_type_);
|
||||
stream.write(payload_.begin(), payload_.end());
|
||||
@@ -118,7 +118,7 @@ ICMPExtensionsStructure::ICMPExtensionsStructure(const uint8_t* buffer, uint32_t
|
||||
checksum_ = stream.read<uint16_t>();
|
||||
while (stream) {
|
||||
extensions_.push_back(ICMPExtension(stream.pointer(), stream.size()));
|
||||
uint16_t size = Endian::be_to_host(stream.read<uint16_t>());
|
||||
uint16_t size = stream.read_be<uint16_t>();
|
||||
stream.skip(size - sizeof(uint16_t));
|
||||
}
|
||||
}
|
||||
|
||||
737
src/icmpv6.cpp
737
src/icmpv6.cpp
File diff suppressed because it is too large
Load Diff
@@ -62,33 +62,38 @@ using Tins::Memory::InputMemoryStream;
|
||||
namespace Tins {
|
||||
namespace Internals {
|
||||
|
||||
bool from_hex(const string &str, uint32_t &result) {
|
||||
bool from_hex(const string& str, uint32_t& result) {
|
||||
unsigned i(0);
|
||||
result = 0;
|
||||
while(i < str.size()) {
|
||||
while (i < str.size()) {
|
||||
uint8_t tmp;
|
||||
if(str[i] >= 'A' && str[i] <= 'F')
|
||||
if (str[i] >= 'A' && str[i] <= 'F') {
|
||||
tmp = (str[i] - 'A' + 10);
|
||||
else if(str[i] >= '0' && str[i] <= '9')
|
||||
}
|
||||
else if (str[i] >= '0' && str[i] <= '9') {
|
||||
tmp = (str[i] - '0');
|
||||
else
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
result = (result << 4) | tmp;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void skip_line(std::istream &input) {
|
||||
void skip_line(std::istream& input) {
|
||||
int c = 0;
|
||||
while(c != '\n' && input)
|
||||
c = input.get();
|
||||
while (c != '\n' && input) {
|
||||
c = input.get();
|
||||
}
|
||||
}
|
||||
|
||||
Tins::PDU *pdu_from_flag(Constants::Ethernet::e flag, const uint8_t *buffer,
|
||||
uint32_t size, bool rawpdu_on_no_match)
|
||||
{
|
||||
switch(flag) {
|
||||
Tins::PDU* pdu_from_flag(Constants::Ethernet::e flag,
|
||||
const uint8_t* buffer,
|
||||
uint32_t size,
|
||||
bool rawpdu_on_no_match) {
|
||||
switch (flag) {
|
||||
case Tins::Constants::Ethernet::IP:
|
||||
return new IP(buffer, size);
|
||||
case Constants::Ethernet::IPV6:
|
||||
@@ -106,22 +111,24 @@ Tins::PDU *pdu_from_flag(Constants::Ethernet::e flag, const uint8_t *buffer,
|
||||
return new MPLS(buffer, size);
|
||||
default:
|
||||
{
|
||||
PDU *pdu = Internals::allocate<EthernetII>(
|
||||
PDU* pdu = Internals::allocate<EthernetII>(
|
||||
static_cast<uint16_t>(flag),
|
||||
buffer,
|
||||
size
|
||||
);
|
||||
if(pdu)
|
||||
if (pdu) {
|
||||
return pdu;
|
||||
}
|
||||
}
|
||||
return rawpdu_on_no_match ? new RawPDU(buffer, size) : 0;
|
||||
};
|
||||
}
|
||||
|
||||
Tins::PDU *pdu_from_flag(Constants::IP::e flag, const uint8_t *buffer,
|
||||
uint32_t size, bool rawpdu_on_no_match)
|
||||
{
|
||||
switch(flag) {
|
||||
Tins::PDU* pdu_from_flag(Constants::IP::e flag,
|
||||
const uint8_t* buffer,
|
||||
uint32_t size,
|
||||
bool rawpdu_on_no_match) {
|
||||
switch (flag) {
|
||||
case Constants::IP::PROTO_IPIP:
|
||||
return new Tins::IP(buffer, size);
|
||||
case Constants::IP::PROTO_TCP:
|
||||
@@ -141,14 +148,16 @@ Tins::PDU *pdu_from_flag(Constants::IP::e flag, const uint8_t *buffer,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(rawpdu_on_no_match)
|
||||
if (rawpdu_on_no_match) {
|
||||
return new Tins::RawPDU(buffer, size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PDU *pdu_from_dlt_flag(int flag, const uint8_t *buffer,
|
||||
uint32_t size, bool rawpdu_on_no_match)
|
||||
{
|
||||
PDU* pdu_from_dlt_flag(int flag,
|
||||
const uint8_t* buffer,
|
||||
uint32_t size,
|
||||
bool rawpdu_on_no_match) {
|
||||
switch (flag) {
|
||||
case DLT_EN10MB:
|
||||
return new EthernetII(buffer, size);
|
||||
@@ -175,8 +184,7 @@ PDU *pdu_from_dlt_flag(int flag, const uint8_t *buffer,
|
||||
};
|
||||
}
|
||||
|
||||
Tins::PDU *pdu_from_flag(PDU::PDUType type, const uint8_t *buffer, uint32_t size)
|
||||
{
|
||||
Tins::PDU* pdu_from_flag(PDU::PDUType type, const uint8_t* buffer, uint32_t size) {
|
||||
switch(type) {
|
||||
case Tins::PDU::ETHERNET_II:
|
||||
return new Tins::EthernetII(buffer, size);
|
||||
@@ -240,10 +248,11 @@ Constants::Ethernet::e pdu_flag_to_ether_type(PDU::PDUType flag) {
|
||||
case PDU::RC4EAPOL:
|
||||
return Constants::Ethernet::EAPOL;
|
||||
default:
|
||||
if(Internals::pdu_type_registered<EthernetII>(flag))
|
||||
if (Internals::pdu_type_registered<EthernetII>(flag)) {
|
||||
return static_cast<Constants::Ethernet::e>(
|
||||
Internals::pdu_type_to_id<EthernetII>(flag)
|
||||
);
|
||||
}
|
||||
return Constants::Ethernet::UNKNOWN;
|
||||
}
|
||||
}
|
||||
@@ -284,8 +293,9 @@ uint32_t get_padded_icmp_inner_pdu_size(const PDU* inner_pdu, uint32_t pad_align
|
||||
}
|
||||
}
|
||||
|
||||
void try_parse_icmp_extensions(InputMemoryStream& stream, uint32_t payload_length,
|
||||
ICMPExtensionsStructure& extensions) {
|
||||
void try_parse_icmp_extensions(InputMemoryStream& stream,
|
||||
uint32_t payload_length,
|
||||
ICMPExtensionsStructure& extensions) {
|
||||
if (!stream) {
|
||||
return;
|
||||
}
|
||||
@@ -315,40 +325,41 @@ void try_parse_icmp_extensions(InputMemoryStream& stream, uint32_t payload_lengt
|
||||
}
|
||||
}
|
||||
|
||||
bool increment(IPv4Address &addr) {
|
||||
bool increment(IPv4Address& addr) {
|
||||
uint32_t addr_int = Endian::be_to_host<uint32_t>(addr);
|
||||
bool reached_end = ++addr_int == 0xffffffff;
|
||||
addr = IPv4Address(Endian::be_to_host<uint32_t>(addr_int));
|
||||
return reached_end;
|
||||
}
|
||||
|
||||
bool increment(IPv6Address &addr) {
|
||||
bool increment(IPv6Address& addr) {
|
||||
return increment_buffer(addr);
|
||||
}
|
||||
|
||||
bool decrement(IPv4Address &addr) {
|
||||
bool decrement(IPv4Address& addr) {
|
||||
uint32_t addr_int = Endian::be_to_host<uint32_t>(addr);
|
||||
bool reached_end = --addr_int == 0;
|
||||
addr = IPv4Address(Endian::be_to_host<uint32_t>(addr_int));
|
||||
return reached_end;
|
||||
}
|
||||
|
||||
bool decrement(IPv6Address &addr) {
|
||||
bool decrement(IPv6Address& addr) {
|
||||
return decrement_buffer(addr);
|
||||
}
|
||||
|
||||
IPv4Address last_address_from_mask(IPv4Address addr, IPv4Address mask) {
|
||||
uint32_t addr_int = Endian::be_to_host<uint32_t>(addr),
|
||||
mask_int = Endian::be_to_host<uint32_t>(mask);
|
||||
mask_int = Endian::be_to_host<uint32_t>(mask);
|
||||
return IPv4Address(Endian::host_to_be(addr_int | ~mask_int));
|
||||
}
|
||||
|
||||
IPv6Address last_address_from_mask(IPv6Address addr, const IPv6Address &mask) {
|
||||
IPv6Address last_address_from_mask(IPv6Address addr, const IPv6Address& mask) {
|
||||
IPv6Address::iterator addr_iter = addr.begin();
|
||||
for(IPv6Address::const_iterator it = mask.begin(); it != mask.end(); ++it, ++addr_iter) {
|
||||
for (IPv6Address::const_iterator it = mask.begin(); it != mask.end(); ++it, ++addr_iter) {
|
||||
*addr_iter = *addr_iter | ~*it;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
} // namespace Internals
|
||||
} // namespace Tins
|
||||
|
||||
241
src/ip.cpp
241
src/ip.cpp
@@ -48,6 +48,9 @@
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::list;
|
||||
using std::min;
|
||||
using std::memcmp;
|
||||
using std::vector;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
@@ -56,22 +59,20 @@ namespace Tins {
|
||||
|
||||
const uint8_t IP::DEFAULT_TTL = 128;
|
||||
|
||||
IP::IP(address_type ip_dst, address_type ip_src)
|
||||
{
|
||||
IP::IP(address_type ip_dst, address_type ip_src) {
|
||||
init_ip_fields();
|
||||
this->dst_addr(ip_dst);
|
||||
this->src_addr(ip_src);
|
||||
}
|
||||
|
||||
IP::IP(const uint8_t *buffer, uint32_t total_sz)
|
||||
: _options_size(0)
|
||||
{
|
||||
IP::IP(const uint8_t* buffer, uint32_t total_sz)
|
||||
: options_size_(0) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_ip);
|
||||
stream.read(ip_);
|
||||
|
||||
// Make sure we have enough size for options and not less than we should
|
||||
if (head_len() * sizeof(uint32_t) > total_sz ||
|
||||
head_len() * sizeof(uint32_t) < sizeof(iphdr)) {
|
||||
head_len() * sizeof(uint32_t) < sizeof(ip_)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
const uint8_t* options_end = buffer + head_len() * sizeof(uint32_t);
|
||||
@@ -91,15 +92,15 @@ IP::IP(const uint8_t *buffer, uint32_t total_sz)
|
||||
if (stream.pointer() + data_size > options_end) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
_ip_options.push_back(
|
||||
ip_options_.push_back(
|
||||
option(opt_type, stream.pointer(), stream.pointer() + data_size)
|
||||
);
|
||||
stream.skip(data_size);
|
||||
}
|
||||
else {
|
||||
_ip_options.push_back(option(opt_type));
|
||||
ip_options_.push_back(option(opt_type));
|
||||
}
|
||||
_options_size += option_size;
|
||||
options_size_ += option_size;
|
||||
}
|
||||
else if (opt_type == END) {
|
||||
// If the end option found, we're done
|
||||
@@ -110,18 +111,17 @@ IP::IP(const uint8_t *buffer, uint32_t total_sz)
|
||||
break;
|
||||
}
|
||||
else {
|
||||
_ip_options.push_back(option(opt_type));
|
||||
_options_size++;
|
||||
ip_options_.push_back(option(opt_type));
|
||||
options_size_++;
|
||||
}
|
||||
}
|
||||
uint8_t padding = _options_size % 4;
|
||||
_padded_options_size = padding ? (_options_size - padding + 4) : _options_size;
|
||||
update_padded_options_size();
|
||||
if (stream) {
|
||||
// Don't avoid consuming more than we should if tot_len is 0,
|
||||
// since this is the case when using TCP segmentation offload
|
||||
if (tot_len() != 0) {
|
||||
const uint32_t advertised_length = (uint32_t)tot_len() - head_len() * sizeof(uint32_t);
|
||||
total_sz = std::min(stream.size(), advertised_length);
|
||||
total_sz = min(stream.size(), advertised_length);
|
||||
}
|
||||
else {
|
||||
total_sz = stream.size();
|
||||
@@ -131,7 +131,7 @@ IP::IP(const uint8_t *buffer, uint32_t total_sz)
|
||||
if (!is_fragmented()) {
|
||||
inner_pdu(
|
||||
Internals::pdu_from_flag(
|
||||
static_cast<Constants::IP::e>(_ip.protocol),
|
||||
static_cast<Constants::IP::e>(ip_.protocol),
|
||||
stream.pointer(),
|
||||
total_sz,
|
||||
false
|
||||
@@ -140,7 +140,7 @@ IP::IP(const uint8_t *buffer, uint32_t total_sz)
|
||||
if (!inner_pdu()) {
|
||||
inner_pdu(
|
||||
Internals::allocate<IP>(
|
||||
_ip.protocol,
|
||||
ip_.protocol,
|
||||
stream.pointer(),
|
||||
total_sz
|
||||
)
|
||||
@@ -158,74 +158,72 @@ IP::IP(const uint8_t *buffer, uint32_t total_sz)
|
||||
}
|
||||
|
||||
void IP::init_ip_fields() {
|
||||
memset(&_ip, 0, sizeof(iphdr));
|
||||
_ip.version = 4;
|
||||
memset(&ip_, 0, sizeof(ip_));
|
||||
ip_.version = 4;
|
||||
ttl(DEFAULT_TTL);
|
||||
id(1);
|
||||
_options_size = 0;
|
||||
_padded_options_size = 0;
|
||||
options_size_ = 0;
|
||||
padded_options_size_ = 0;
|
||||
}
|
||||
|
||||
bool IP::is_fragmented() const {
|
||||
return flags() == IP::MORE_FRAGMENTS || fragment_offset() != 0;
|
||||
}
|
||||
|
||||
/* Setters */
|
||||
// Setters
|
||||
|
||||
void IP::tos(uint8_t new_tos) {
|
||||
_ip.tos = new_tos;
|
||||
ip_.tos = new_tos;
|
||||
}
|
||||
|
||||
void IP::tot_len(uint16_t new_tot_len) {
|
||||
_ip.tot_len = Endian::host_to_be(new_tot_len);
|
||||
ip_.tot_len = Endian::host_to_be(new_tot_len);
|
||||
}
|
||||
|
||||
void IP::id(uint16_t new_id) {
|
||||
_ip.id = Endian::host_to_be(new_id);
|
||||
ip_.id = Endian::host_to_be(new_id);
|
||||
}
|
||||
|
||||
void IP::frag_off(uint16_t new_frag_off) {
|
||||
_ip.frag_off = Endian::host_to_be(new_frag_off);
|
||||
ip_.frag_off = Endian::host_to_be(new_frag_off);
|
||||
}
|
||||
|
||||
void IP::fragment_offset(small_uint<13> new_frag_off) {
|
||||
uint16_t value = (Endian::be_to_host(_ip.frag_off) & 0xe000) | new_frag_off;
|
||||
_ip.frag_off = Endian::host_to_be(value);
|
||||
uint16_t value = (Endian::be_to_host(ip_.frag_off) & 0xe000) | new_frag_off;
|
||||
ip_.frag_off = Endian::host_to_be(value);
|
||||
}
|
||||
|
||||
void IP::flags(Flags new_flags) {
|
||||
uint16_t value = (Endian::be_to_host(_ip.frag_off) & 0x1fff) | (new_flags << 13);
|
||||
_ip.frag_off = Endian::host_to_be(value);
|
||||
uint16_t value = (Endian::be_to_host(ip_.frag_off) & 0x1fff) | (new_flags << 13);
|
||||
ip_.frag_off = Endian::host_to_be(value);
|
||||
}
|
||||
|
||||
void IP::ttl(uint8_t new_ttl) {
|
||||
_ip.ttl = new_ttl;
|
||||
ip_.ttl = new_ttl;
|
||||
}
|
||||
|
||||
void IP::protocol(uint8_t new_protocol) {
|
||||
_ip.protocol = new_protocol;
|
||||
ip_.protocol = new_protocol;
|
||||
}
|
||||
|
||||
void IP::checksum(uint16_t new_check) {
|
||||
_ip.check = Endian::host_to_be(new_check);
|
||||
ip_.check = Endian::host_to_be(new_check);
|
||||
}
|
||||
|
||||
|
||||
void IP::src_addr(address_type ip) {
|
||||
_ip.saddr = ip;
|
||||
ip_.saddr = ip;
|
||||
}
|
||||
|
||||
|
||||
void IP::dst_addr(address_type ip) {
|
||||
_ip.daddr = ip;
|
||||
ip_.daddr = ip;
|
||||
}
|
||||
|
||||
void IP::head_len(small_uint<4> new_head_len) {
|
||||
_ip.ihl = new_head_len;
|
||||
ip_.ihl = new_head_len;
|
||||
}
|
||||
|
||||
void IP::version(small_uint<4> ver) {
|
||||
_ip.version = ver;
|
||||
ip_.version = ver;
|
||||
}
|
||||
|
||||
void IP::eol() {
|
||||
@@ -236,16 +234,16 @@ void IP::noop() {
|
||||
add_option(option_identifier(IP::NOOP, IP::CONTROL, 0));
|
||||
}
|
||||
|
||||
void IP::security(const security_type &data) {
|
||||
void IP::security(const security_type& data) {
|
||||
uint8_t array[9];
|
||||
uint16_t *ptr = reinterpret_cast<uint16_t*>(array);
|
||||
OutputMemoryStream stream(array, sizeof(array));
|
||||
uint32_t value = data.transmission_control;
|
||||
*ptr++ = Endian::host_to_be(data.security);
|
||||
*ptr++ = Endian::host_to_be(data.compartments);
|
||||
*ptr++ = Endian::host_to_be(data.handling_restrictions);
|
||||
array[8] = (value & 0xff);
|
||||
array[7] = ((value >> 8) & 0xff);
|
||||
array[6] = ((value >> 16) & 0xff);
|
||||
stream.write_be(data.security);
|
||||
stream.write_be(data.compartments);
|
||||
stream.write_be(data.handling_restrictions);
|
||||
stream.write<uint8_t>((value >> 16) & 0xff);
|
||||
stream.write<uint8_t>((value >> 8) & 0xff);
|
||||
stream.write<uint8_t>(value & 0xff);
|
||||
|
||||
add_option(
|
||||
option(
|
||||
@@ -258,7 +256,7 @@ void IP::security(const security_type &data) {
|
||||
|
||||
void IP::stream_identifier(uint16_t stream_id) {
|
||||
stream_id = Endian::host_to_be(stream_id);
|
||||
add_option(
|
||||
add_option(
|
||||
option(
|
||||
136,
|
||||
sizeof(uint16_t),
|
||||
@@ -267,10 +265,10 @@ void IP::stream_identifier(uint16_t stream_id) {
|
||||
);
|
||||
}
|
||||
|
||||
void IP::add_route_option(option_identifier id, const generic_route_option_type &data) {
|
||||
std::vector<uint8_t> opt_data(1 + sizeof(uint32_t) * data.routes.size());
|
||||
void IP::add_route_option(option_identifier id, const generic_route_option_type& data) {
|
||||
vector<uint8_t> opt_data(1 + sizeof(uint32_t) * data.routes.size());
|
||||
opt_data[0] = data.pointer;
|
||||
for(size_t i(0); i < data.routes.size(); ++i) {
|
||||
for (size_t i(0); i < data.routes.size(); ++i) {
|
||||
uint32_t ip = data.routes[i];
|
||||
#if TINS_IS_BIG_ENDIAN
|
||||
ip = Endian::change_endian(ip);
|
||||
@@ -290,68 +288,71 @@ void IP::add_route_option(option_identifier id, const generic_route_option_type
|
||||
}
|
||||
|
||||
IP::generic_route_option_type IP::search_route_option(option_identifier id) const {
|
||||
const option *opt = search_option(id);
|
||||
if(!opt)
|
||||
const option* opt = search_option(id);
|
||||
if (!opt) {
|
||||
throw option_not_found();
|
||||
}
|
||||
return opt->to<generic_route_option_type>();
|
||||
}
|
||||
|
||||
IP::security_type IP::security() const {
|
||||
const option *opt = search_option(130);
|
||||
if(!opt)
|
||||
const option* opt = search_option(130);
|
||||
if (!opt) {
|
||||
throw option_not_found();
|
||||
}
|
||||
return opt->to<security_type>();
|
||||
}
|
||||
|
||||
uint16_t IP::stream_identifier() const {
|
||||
const option *opt = search_option(136);
|
||||
if(!opt)
|
||||
const option* opt = search_option(136);
|
||||
if (!opt) {
|
||||
throw option_not_found();
|
||||
}
|
||||
return opt->to<uint16_t>();
|
||||
}
|
||||
|
||||
void IP::add_option(const option &opt) {
|
||||
void IP::add_option(const option& opt) {
|
||||
internal_add_option(opt);
|
||||
_ip_options.push_back(opt);
|
||||
ip_options_.push_back(opt);
|
||||
}
|
||||
|
||||
void IP::update_padded_options_size() {
|
||||
uint8_t padding = _options_size % 4;
|
||||
_padded_options_size = padding ? (_options_size - padding + 4) : _options_size;
|
||||
uint8_t padding = options_size_ % 4;
|
||||
padded_options_size_ = padding ? (options_size_ - padding + 4) : options_size_;
|
||||
}
|
||||
|
||||
void IP::internal_add_option(const option &opt) {
|
||||
_options_size += static_cast<uint16_t>(1 + opt.data_size());
|
||||
void IP::internal_add_option(const option& opt) {
|
||||
options_size_ += static_cast<uint16_t>(1 + opt.data_size());
|
||||
update_padded_options_size();
|
||||
}
|
||||
|
||||
bool IP::remove_option(option_identifier id) {
|
||||
options_type::iterator iter = search_option_iterator(id);
|
||||
if (iter == _ip_options.end()) {
|
||||
if (iter == ip_options_.end()) {
|
||||
return false;
|
||||
}
|
||||
_options_size -= static_cast<uint16_t>(1 + iter->data_size());
|
||||
_ip_options.erase(iter);
|
||||
options_size_ -= static_cast<uint16_t>(1 + iter->data_size());
|
||||
ip_options_.erase(iter);
|
||||
update_padded_options_size();
|
||||
return true;
|
||||
}
|
||||
|
||||
const IP::option *IP::search_option(option_identifier id) const {
|
||||
const IP::option* IP::search_option(option_identifier id) const {
|
||||
options_type::const_iterator iter = search_option_iterator(id);
|
||||
return (iter != _ip_options.end()) ? &*iter : 0;
|
||||
return (iter != ip_options_.end()) ? &*iter : 0;
|
||||
}
|
||||
|
||||
IP::options_type::const_iterator IP::search_option_iterator(option_identifier id) const {
|
||||
Internals::option_type_equality_comparator<option> comparator(id);
|
||||
return find_if(_ip_options.begin(), _ip_options.end(), comparator);
|
||||
return find_if(ip_options_.begin(), ip_options_.end(), comparator);
|
||||
}
|
||||
|
||||
IP::options_type::iterator IP::search_option_iterator(option_identifier id) {
|
||||
Internals::option_type_equality_comparator<option> comparator(id);
|
||||
return find_if(_ip_options.begin(), _ip_options.end(), comparator);
|
||||
return find_if(ip_options_.begin(), ip_options_.end(), comparator);
|
||||
}
|
||||
|
||||
void IP::write_option(const option &opt, OutputMemoryStream& stream) {
|
||||
void IP::write_option(const option& opt, OutputMemoryStream& stream) {
|
||||
stream.write(opt.option());
|
||||
// Check what we wrote. We'll do this for any option != [END, NOOP]
|
||||
if (*(stream.pointer() - 1) > NOOP) {
|
||||
@@ -364,10 +365,10 @@ void IP::write_option(const option &opt, OutputMemoryStream& stream) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Virtual method overriding. */
|
||||
// Virtual method overriding
|
||||
|
||||
uint32_t IP::header_size() const {
|
||||
return sizeof(iphdr) + _padded_options_size;
|
||||
return sizeof(ip_) + padded_options_size_;
|
||||
}
|
||||
|
||||
PacketSender::SocketType pdu_type_to_sender_type(PDU::PDUType type) {
|
||||
@@ -388,31 +389,33 @@ void IP::send(PacketSender& sender, const NetworkInterface &) {
|
||||
PacketSender::SocketType type = PacketSender::IP_RAW_SOCKET;
|
||||
link_addr.sin_family = AF_INET;
|
||||
link_addr.sin_port = 0;
|
||||
link_addr.sin_addr.s_addr = _ip.daddr;
|
||||
if(inner_pdu())
|
||||
link_addr.sin_addr.s_addr = ip_.daddr;
|
||||
if (inner_pdu()) {
|
||||
type = pdu_type_to_sender_type(inner_pdu()->pdu_type());
|
||||
}
|
||||
|
||||
sender.send_l3(*this, (struct sockaddr*)&link_addr, sizeof(link_addr), type);
|
||||
}
|
||||
|
||||
PDU *IP::recv_response(PacketSender &sender, const NetworkInterface &) {
|
||||
PDU* IP::recv_response(PacketSender& sender, const NetworkInterface &) {
|
||||
sockaddr_in link_addr;
|
||||
PacketSender::SocketType type = PacketSender::IP_RAW_SOCKET;
|
||||
std::memset(&link_addr, 0, sizeof(link_addr));
|
||||
if(inner_pdu())
|
||||
memset(&link_addr, 0, sizeof(link_addr));
|
||||
if (inner_pdu()) {
|
||||
type = pdu_type_to_sender_type(inner_pdu()->pdu_type());
|
||||
}
|
||||
|
||||
return sender.recv_l3(*this, 0, sizeof(link_addr), type);
|
||||
}
|
||||
|
||||
void IP::prepare_for_serialize(const PDU *parent) {
|
||||
if(!parent && _ip.saddr == 0) {
|
||||
void IP::prepare_for_serialize(const PDU* parent) {
|
||||
if (!parent && ip_.saddr == 0) {
|
||||
NetworkInterface iface(dst_addr());
|
||||
src_addr(iface.addresses().ip_addr);
|
||||
}
|
||||
}
|
||||
|
||||
void IP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU* parent) {
|
||||
void IP::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
checksum(0);
|
||||
if (inner_pdu()) {
|
||||
@@ -428,51 +431,54 @@ void IP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU* pare
|
||||
}
|
||||
|
||||
#if __FreeBSD__ || defined(__FreeBSD_kernel__) || __APPLE__
|
||||
if(!parent) {
|
||||
if (!parent) {
|
||||
total_sz = Endian::host_to_be<uint16_t>(total_sz);
|
||||
}
|
||||
#endif
|
||||
tot_len(total_sz);
|
||||
head_len(static_cast<uint8_t>(header_size() / sizeof(uint32_t)));
|
||||
|
||||
stream.write(_ip);
|
||||
stream.write(ip_);
|
||||
|
||||
for(options_type::const_iterator it = _ip_options.begin(); it != _ip_options.end(); ++it) {
|
||||
for (options_type::const_iterator it = ip_options_.begin(); it != ip_options_.end(); ++it) {
|
||||
write_option(*it, stream);
|
||||
}
|
||||
// Add option padding
|
||||
stream.fill(_padded_options_size - _options_size, 0);
|
||||
stream.fill(padded_options_size_ - options_size_, 0);
|
||||
|
||||
uint32_t check = Utils::do_checksum(buffer, buffer + sizeof(_ip) + _padded_options_size);
|
||||
uint32_t check = Utils::do_checksum(buffer, stream.pointer());
|
||||
while (check >> 16) {
|
||||
check = (check & 0xffff) + (check >> 16);
|
||||
}
|
||||
checksum(~check);
|
||||
((iphdr*)buffer)->check = _ip.check;
|
||||
((ip_header*)buffer)->check = ip_.check;
|
||||
}
|
||||
|
||||
bool IP::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
if(total_sz < sizeof(iphdr))
|
||||
bool IP::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
if (total_sz < sizeof(ip_)) {
|
||||
return false;
|
||||
const iphdr *ip_ptr = (const iphdr*)ptr;
|
||||
}
|
||||
const ip_header* ip_ptr = (const ip_header*)ptr;
|
||||
// dest unreachable?
|
||||
if(ip_ptr->protocol == Constants::IP::PROTO_ICMP) {
|
||||
const uint8_t *pkt_ptr = ptr + sizeof(iphdr);
|
||||
uint32_t pkt_sz = total_sz - sizeof(iphdr);
|
||||
if (ip_ptr->protocol == Constants::IP::PROTO_ICMP) {
|
||||
const uint8_t* pkt_ptr = ptr + sizeof(ip_header);
|
||||
uint32_t pkt_sz = total_sz - sizeof(ip_header);
|
||||
// It's an ICMP dest unreachable
|
||||
if(pkt_sz > 4 && pkt_ptr[0] == 3) {
|
||||
if (pkt_sz > 4 && pkt_ptr[0] == 3) {
|
||||
pkt_ptr += 4;
|
||||
pkt_sz -= 4;
|
||||
// If our IP header is in the ICMP payload, then it's the same packet.
|
||||
// This keeps in mind checksum and IP identifier, so I guess it's enough.
|
||||
if(pkt_sz >= sizeof(iphdr) && std::memcmp(&_ip, pkt_ptr, sizeof(iphdr)))
|
||||
if (pkt_sz >= sizeof(ip_) && memcmp(&ip_, pkt_ptr, sizeof(ip_header))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// checks for broadcast addr
|
||||
if((_ip.saddr == ip_ptr->daddr && (_ip.daddr == ip_ptr->saddr || dst_addr().is_broadcast())) ||
|
||||
(dst_addr().is_broadcast() && _ip.saddr == 0)) {
|
||||
uint32_t sz = std::min<uint32_t>(header_size(), total_sz);
|
||||
if ((ip_.saddr == ip_ptr->daddr &&
|
||||
(ip_.daddr == ip_ptr->saddr || dst_addr().is_broadcast())) ||
|
||||
(dst_addr().is_broadcast() && ip_.saddr == 0)) {
|
||||
uint32_t sz = min<uint32_t>(header_size(), total_sz);
|
||||
return inner_pdu() ? inner_pdu()->matches_response(ptr + sz, total_sz - sz) : true;
|
||||
}
|
||||
return false;
|
||||
@@ -480,41 +486,38 @@ bool IP::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
|
||||
// Option static constructors from options
|
||||
|
||||
IP::security_type IP::security_type::from_option(const option &opt)
|
||||
{
|
||||
if(opt.data_size() != 9)
|
||||
IP::security_type IP::security_type::from_option(const option& opt) {
|
||||
if (opt.data_size() != 9) {
|
||||
throw malformed_option();
|
||||
}
|
||||
security_type output;
|
||||
|
||||
memcpy(&output.security, opt.data_ptr(), sizeof(uint16_t));
|
||||
output.security = Endian::be_to_host(output.security);
|
||||
memcpy(&output.compartments, opt.data_ptr() + sizeof(uint16_t), sizeof(uint16_t));
|
||||
output.compartments = Endian::be_to_host(output.compartments);
|
||||
memcpy(&output.handling_restrictions, opt.data_ptr() + 2 * sizeof(uint16_t), sizeof(uint16_t));
|
||||
output.handling_restrictions = Endian::be_to_host(output.handling_restrictions);
|
||||
uint32_t tcc = opt.data_ptr()[6];
|
||||
tcc = (tcc << 8) | opt.data_ptr()[7];
|
||||
tcc = (tcc << 8) | opt.data_ptr()[8];
|
||||
InputMemoryStream stream(opt.data_ptr(), opt.data_size());
|
||||
output.security = stream.read_be<uint16_t>();
|
||||
output.compartments = stream.read_be<uint16_t>();
|
||||
output.handling_restrictions = stream.read_be<uint16_t>();
|
||||
uint32_t tcc = stream.read<uint8_t>();
|
||||
tcc = (tcc << 8) | stream.read<uint8_t>();
|
||||
tcc = (tcc << 8) | stream.read<uint8_t>();
|
||||
output.transmission_control = tcc;
|
||||
return output;
|
||||
}
|
||||
|
||||
IP::generic_route_option_type IP::generic_route_option_type::from_option(
|
||||
const option &opt)
|
||||
{
|
||||
if(opt.data_size() < 1 + sizeof(uint32_t) || ((opt.data_size() - 1) % sizeof(uint32_t)) != 0)
|
||||
IP::generic_route_option_type IP::generic_route_option_type::from_option(const option& opt) {
|
||||
if (opt.data_size() < 1 + sizeof(uint32_t) || ((opt.data_size() - 1) % sizeof(uint32_t)) != 0) {
|
||||
throw malformed_option();
|
||||
}
|
||||
generic_route_option_type output;
|
||||
output.pointer = *opt.data_ptr();
|
||||
const uint8_t *route = opt.data_ptr() + 1;
|
||||
const uint8_t *end = route + opt.data_size() - 1;
|
||||
const uint8_t* route = opt.data_ptr() + 1;
|
||||
const uint8_t* end = route + opt.data_size() - 1;
|
||||
|
||||
uint32_t uint32_t_buffer;
|
||||
while(route < end) {
|
||||
while (route < end) {
|
||||
memcpy(&uint32_t_buffer, route, sizeof(uint32_t));
|
||||
output.routes.push_back(address_type(uint32_t_buffer));
|
||||
route += sizeof(uint32_t);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#include "address_range.h"
|
||||
|
||||
using std::string;
|
||||
using std::ostringstream;
|
||||
using std::ostream;
|
||||
|
||||
namespace Tins{
|
||||
const IPv4Address IPv4Address::broadcast("255.255.255.255");
|
||||
@@ -54,66 +56,68 @@ const AddressRange<IPv4Address> loopback_range = IPv4Address("127.0.0.0") / 8;
|
||||
const AddressRange<IPv4Address> multicast_range = IPv4Address("224.0.0.0") / 4;
|
||||
|
||||
IPv4Address::IPv4Address(uint32_t ip)
|
||||
: ip_addr(Endian::be_to_host(ip)) {
|
||||
: ip_addr_(Endian::be_to_host(ip)) {
|
||||
|
||||
}
|
||||
|
||||
IPv4Address::IPv4Address(const char *ip) {
|
||||
ip_addr = ip ? ip_to_int(ip) : 0;
|
||||
IPv4Address::IPv4Address(const char* ip) {
|
||||
ip_addr_ = ip ? ip_to_int(ip) : 0;
|
||||
}
|
||||
|
||||
IPv4Address::IPv4Address(const std::string &ip)
|
||||
: ip_addr(ip_to_int(ip.c_str())) {
|
||||
IPv4Address::IPv4Address(const std::string& ip)
|
||||
: ip_addr_(ip_to_int(ip.c_str())) {
|
||||
|
||||
}
|
||||
|
||||
IPv4Address::operator uint32_t() const {
|
||||
return Endian::host_to_be(ip_addr);
|
||||
return Endian::host_to_be(ip_addr_);
|
||||
}
|
||||
|
||||
std::string IPv4Address::to_string() const {
|
||||
std::ostringstream oss;
|
||||
oss << *this;
|
||||
string IPv4Address::to_string() const {
|
||||
ostringstream oss;
|
||||
oss <<* this;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
uint32_t IPv4Address::ip_to_int(const char* ip) {
|
||||
#ifdef _WIN32
|
||||
in_addr addr;
|
||||
if(InetPtonA(AF_INET, ip, &addr)) {
|
||||
if (InetPtonA(AF_INET, ip, &addr)) {
|
||||
return Endian::be_to_host(addr.s_addr);
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("Invalid ip address");
|
||||
throw invalid_address();
|
||||
}
|
||||
#else // _WIN32
|
||||
in_addr addr;
|
||||
if(inet_pton(AF_INET, ip, &addr) == 1) {
|
||||
if (inet_pton(AF_INET, ip, &addr) == 1) {
|
||||
return Endian::be_to_host(addr.s_addr);
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("Invalid ip address");
|
||||
throw invalid_address();
|
||||
}
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &output, const IPv4Address &addr) {
|
||||
ostream& operator<<(ostream& output, const IPv4Address& addr) {
|
||||
int mask(24);
|
||||
uint32_t ip_addr = addr.ip_addr;
|
||||
while(mask >=0) {
|
||||
output << ((ip_addr >> mask) & 0xff);
|
||||
if(mask)
|
||||
uint32_t ip_addr_ = addr.ip_addr_;
|
||||
while (mask >=0) {
|
||||
output << ((ip_addr_ >> mask) & 0xff);
|
||||
if (mask) {
|
||||
output << '.';
|
||||
}
|
||||
mask -= 8;
|
||||
}
|
||||
return output;;
|
||||
}
|
||||
|
||||
bool IPv4Address::is_private() const {
|
||||
const AddressRange<IPv4Address> *iter = private_ranges;
|
||||
while(iter != private_ranges + 3) {
|
||||
if(iter->contains(*this))
|
||||
const AddressRange<IPv4Address>* iter = private_ranges;
|
||||
while (iter != private_ranges + 3) {
|
||||
if (iter->contains(*this)) {
|
||||
return true;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
return false;
|
||||
@@ -132,6 +136,7 @@ bool IPv4Address::is_unicast() const {
|
||||
}
|
||||
|
||||
bool IPv4Address::is_broadcast() const {
|
||||
return *this == broadcast;
|
||||
}
|
||||
return* this == broadcast;
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
@@ -33,82 +33,86 @@
|
||||
#include "internals.h"
|
||||
#include "ip_reassembler.h"
|
||||
|
||||
using std::make_pair;
|
||||
|
||||
namespace Tins {
|
||||
namespace Internals {
|
||||
|
||||
IPv4Stream::IPv4Stream()
|
||||
: received_end(false), received_size(), total_size()
|
||||
{
|
||||
: received_end_(false), received_size_(), total_size_() {
|
||||
|
||||
}
|
||||
|
||||
void IPv4Stream::add_fragment(IP *ip) {
|
||||
fragments_type::iterator it = fragments.begin();
|
||||
void IPv4Stream::add_fragment(IP* ip) {
|
||||
fragments_type::iterator it = fragments_.begin();
|
||||
uint16_t offset = extract_offset(ip);
|
||||
while(it != fragments.end() && offset > it->offset()) {
|
||||
while (it != fragments_.end() && offset > it->offset()) {
|
||||
++it;
|
||||
}
|
||||
// No duplicates plx
|
||||
if(it != fragments.end() && it->offset() == offset)
|
||||
if (it != fragments_.end() && it->offset() == offset) {
|
||||
return;
|
||||
fragments.insert(it, IPv4Fragment(ip->inner_pdu(), offset));
|
||||
received_size += ip->inner_pdu()->size();
|
||||
if(ip->flags() != IP::MORE_FRAGMENTS) {
|
||||
total_size = offset + ip->inner_pdu()->size();
|
||||
received_end = true;
|
||||
}
|
||||
if(offset == 0)
|
||||
transport_proto = ip->protocol();
|
||||
fragments_.insert(it, IPv4Fragment(ip->inner_pdu(), offset));
|
||||
received_size_ += ip->inner_pdu()->size();
|
||||
if (ip->flags() != IP::MORE_FRAGMENTS) {
|
||||
total_size_ = offset + ip->inner_pdu()->size();
|
||||
received_end_ = true;
|
||||
}
|
||||
if (offset == 0) {
|
||||
transport_proto_ = ip->protocol();
|
||||
}
|
||||
}
|
||||
|
||||
bool IPv4Stream::is_complete() const {
|
||||
return received_end && received_size == total_size;
|
||||
return received_end_ && received_size_ == total_size_;
|
||||
}
|
||||
|
||||
PDU *IPv4Stream::allocate_pdu() const {
|
||||
PDU* IPv4Stream::allocate_pdu() const {
|
||||
PDU::serialization_type buffer;
|
||||
buffer.reserve(total_size);
|
||||
buffer.reserve(total_size_);
|
||||
// Check if we actually have all the data we need. Otherwise return nullptr;
|
||||
uint16_t expected = 0;
|
||||
for(fragments_type::const_iterator it = fragments.begin(); it != fragments.end(); ++it) {
|
||||
if(expected != it->offset())
|
||||
for (fragments_type::const_iterator it = fragments_.begin(); it != fragments_.end(); ++it) {
|
||||
if (expected != it->offset()) {
|
||||
return 0;
|
||||
}
|
||||
expected = static_cast<uint16_t>(it->offset() + it->payload().size());
|
||||
buffer.insert(buffer.end(), it->payload().begin(), it->payload().end());
|
||||
}
|
||||
return Internals::pdu_from_flag(
|
||||
static_cast<Constants::IP::e>(transport_proto),
|
||||
buffer.empty() ? 0 : &buffer[0],
|
||||
static_cast<Constants::IP::e>(transport_proto_),
|
||||
buffer.empty() ? 0 :& buffer[0],
|
||||
static_cast<uint32_t>(buffer.size())
|
||||
);
|
||||
}
|
||||
|
||||
uint16_t IPv4Stream::extract_offset(const IP *ip) {
|
||||
uint16_t IPv4Stream::extract_offset(const IP* ip) {
|
||||
return ip->fragment_offset() * 8;
|
||||
}
|
||||
|
||||
} // namespace Internals
|
||||
} // Internals
|
||||
|
||||
IPv4Reassembler::IPv4Reassembler(overlapping_technique technique)
|
||||
: technique(technique)
|
||||
{
|
||||
: technique_(technique) {
|
||||
|
||||
}
|
||||
|
||||
IPv4Reassembler::packet_status IPv4Reassembler::process(PDU &pdu) {
|
||||
IP *ip = pdu.find_pdu<IP>();
|
||||
if(ip && ip->inner_pdu()) {
|
||||
IPv4Reassembler::packet_status IPv4Reassembler::process(PDU& pdu) {
|
||||
IP* ip = pdu.find_pdu<IP>();
|
||||
if (ip && ip->inner_pdu()) {
|
||||
// There's fragmentation
|
||||
if(ip->is_fragmented()) {
|
||||
if (ip->is_fragmented()) {
|
||||
key_type key = make_key(ip);
|
||||
// Create it or look it up, it's the same
|
||||
Internals::IPv4Stream &stream = streams[key];
|
||||
Internals::IPv4Stream& stream = streams_[key];
|
||||
stream.add_fragment(ip);
|
||||
if(stream.is_complete()) {
|
||||
PDU *pdu = stream.allocate_pdu();
|
||||
if (stream.is_complete()) {
|
||||
PDU* pdu = stream.allocate_pdu();
|
||||
// Erase this stream, since it's already assembled
|
||||
streams.erase(key);
|
||||
streams_.erase(key);
|
||||
// The packet is corrupt
|
||||
if(!pdu) {
|
||||
if (!pdu) {
|
||||
return FRAGMENTED;
|
||||
}
|
||||
ip->inner_pdu(pdu);
|
||||
@@ -116,38 +120,41 @@ IPv4Reassembler::packet_status IPv4Reassembler::process(PDU &pdu) {
|
||||
ip->flags(static_cast<IP::Flags>(0));
|
||||
return REASSEMBLED;
|
||||
}
|
||||
else
|
||||
else {
|
||||
return FRAGMENTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NOT_FRAGMENTED;
|
||||
}
|
||||
|
||||
IPv4Reassembler::key_type IPv4Reassembler::make_key(const IP *ip) const {
|
||||
return std::make_pair(
|
||||
IPv4Reassembler::key_type IPv4Reassembler::make_key(const IP* ip) const {
|
||||
return make_pair(
|
||||
ip->id(),
|
||||
make_address_pair(ip->src_addr(), ip->dst_addr())
|
||||
);
|
||||
}
|
||||
|
||||
IPv4Reassembler::address_pair IPv4Reassembler::make_address_pair(IPv4Address addr1, IPv4Address addr2) const {
|
||||
if(addr1 < addr2)
|
||||
return std::make_pair(addr1, addr2);
|
||||
else
|
||||
return std::make_pair(addr2, addr1);
|
||||
if (addr1 < addr2) {
|
||||
return make_pair(addr1, addr2);
|
||||
}
|
||||
else {
|
||||
return make_pair(addr2, addr1);
|
||||
}
|
||||
}
|
||||
|
||||
void IPv4Reassembler::clear_streams() {
|
||||
streams.clear();
|
||||
streams_.clear();
|
||||
}
|
||||
|
||||
void IPv4Reassembler::remove_stream(uint16_t id, IPv4Address addr1, IPv4Address addr2) {
|
||||
streams.erase(
|
||||
std::make_pair(
|
||||
streams_.erase(
|
||||
make_pair(
|
||||
id,
|
||||
make_address_pair(addr1, addr2)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace Tins
|
||||
} // Tins
|
||||
|
||||
@@ -31,31 +31,39 @@
|
||||
#include "ipsec.h"
|
||||
#include "internals.h"
|
||||
#include "rawpdu.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::memcpy;
|
||||
using std::copy;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
IPSecAH::IPSecAH()
|
||||
: _header(), _icv(4) {
|
||||
: header_(), icv_(4) {
|
||||
length(2);
|
||||
}
|
||||
|
||||
IPSecAH::IPSecAH(const uint8_t *buffer, uint32_t total_sz) {
|
||||
// At least size for the header + 32bits of ICV
|
||||
if(total_sz < sizeof(_header) + sizeof(uint32_t))
|
||||
throw malformed_packet();
|
||||
std::memcpy(&_header, buffer, sizeof(_header));
|
||||
IPSecAH::IPSecAH(const uint8_t* buffer, uint32_t total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(header_);
|
||||
const uint32_t ah_len = 4 * (static_cast<uint16_t>(length()) + 2);
|
||||
if(ah_len > total_sz)
|
||||
if (ah_len < sizeof(header_)) {
|
||||
throw malformed_packet();
|
||||
_icv.assign(buffer + sizeof(_header), buffer + ah_len);
|
||||
buffer += ah_len;
|
||||
total_sz -= ah_len;
|
||||
if(total_sz) {
|
||||
}
|
||||
const uint32_t icv_length = ah_len - sizeof(header_);
|
||||
if (!stream.can_read(icv_length)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
stream.read(icv_, icv_length);
|
||||
if (stream) {
|
||||
inner_pdu(
|
||||
Internals::pdu_from_flag(
|
||||
static_cast<Constants::IP::e>(next_header()),
|
||||
buffer,
|
||||
total_sz,
|
||||
stream.pointer(),
|
||||
stream.size(),
|
||||
true
|
||||
)
|
||||
);
|
||||
@@ -63,73 +71,69 @@ IPSecAH::IPSecAH(const uint8_t *buffer, uint32_t total_sz) {
|
||||
}
|
||||
|
||||
void IPSecAH::next_header(uint8_t new_next_header) {
|
||||
_header.next_header = new_next_header;
|
||||
header_.next_header = new_next_header;
|
||||
}
|
||||
|
||||
void IPSecAH::length(uint8_t new_length) {
|
||||
_header.length = new_length;
|
||||
header_.length = new_length;
|
||||
}
|
||||
|
||||
void IPSecAH::spi(uint32_t new_spi) {
|
||||
_header.spi = Endian::host_to_be(new_spi);
|
||||
header_.spi = Endian::host_to_be(new_spi);
|
||||
}
|
||||
|
||||
void IPSecAH::seq_number(uint32_t new_seq_number) {
|
||||
_header.seq_number = Endian::host_to_be(new_seq_number);
|
||||
header_.seq_number = Endian::host_to_be(new_seq_number);
|
||||
}
|
||||
|
||||
void IPSecAH::icv(const byte_array &new_icv) {
|
||||
_icv = new_icv;
|
||||
void IPSecAH::icv(const byte_array& newicv_) {
|
||||
icv_ = newicv_;
|
||||
}
|
||||
|
||||
uint32_t IPSecAH::header_size() const {
|
||||
return static_cast<uint32_t>(sizeof(_header) + _icv.size());
|
||||
return static_cast<uint32_t>(sizeof(header_) + icv_.size());
|
||||
}
|
||||
|
||||
void IPSecAH::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
|
||||
if(inner_pdu())
|
||||
void IPSecAH::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *) {
|
||||
if (inner_pdu()) {
|
||||
next_header(Internals::pdu_flag_to_ip_type(inner_pdu()->pdu_type()));
|
||||
std::memcpy(buffer, &_header, sizeof(_header));
|
||||
std::copy(
|
||||
_icv.begin(),
|
||||
_icv.end(),
|
||||
buffer + sizeof(_header)
|
||||
);
|
||||
}
|
||||
length(header_size() / sizeof(uint32_t) - 2);
|
||||
OutputMemoryStream output(buffer, total_sz);
|
||||
output.write(header_);
|
||||
output.write(icv_.begin(), icv_.end());
|
||||
}
|
||||
|
||||
// IPSecESP
|
||||
|
||||
IPSecESP::IPSecESP()
|
||||
: _header()
|
||||
{
|
||||
: header_() {
|
||||
|
||||
}
|
||||
|
||||
IPSecESP::IPSecESP(const uint8_t *buffer, uint32_t total_sz) {
|
||||
if(total_sz < sizeof(_header))
|
||||
throw malformed_packet();
|
||||
std::memcpy(&_header, buffer, sizeof(_header));
|
||||
buffer += sizeof(_header);
|
||||
total_sz -= sizeof(_header);
|
||||
if(total_sz) {
|
||||
inner_pdu(new RawPDU(buffer, total_sz));
|
||||
IPSecESP::IPSecESP(const uint8_t* buffer, uint32_t total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(header_);
|
||||
if (stream) {
|
||||
inner_pdu(new RawPDU(stream.pointer(), stream.size()));
|
||||
}
|
||||
}
|
||||
|
||||
void IPSecESP::spi(uint32_t new_spi) {
|
||||
_header.spi = Endian::host_to_be(new_spi);
|
||||
header_.spi = Endian::host_to_be(new_spi);
|
||||
}
|
||||
|
||||
void IPSecESP::seq_number(uint32_t new_seq_number) {
|
||||
_header.seq_number = Endian::host_to_be(new_seq_number);
|
||||
header_.seq_number = Endian::host_to_be(new_seq_number);
|
||||
}
|
||||
|
||||
uint32_t IPSecESP::header_size() const {
|
||||
return sizeof(_header);
|
||||
return sizeof(header_);
|
||||
}
|
||||
|
||||
void IPSecESP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
|
||||
std::memcpy(buffer, &_header, sizeof(_header));
|
||||
void IPSecESP::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *) {
|
||||
OutputMemoryStream output(buffer, total_sz);
|
||||
output.write(header_);
|
||||
}
|
||||
|
||||
}
|
||||
} // Tins
|
||||
|
||||
120
src/ipv6.cpp
120
src/ipv6.cpp
@@ -44,27 +44,27 @@
|
||||
#include "internals.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::copy;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
IPv6::IPv6(address_type ip_dst, address_type ip_src, PDU *child)
|
||||
: _header(), headers_size(0)
|
||||
{
|
||||
IPv6::IPv6(address_type ip_dst, address_type ip_src, PDU* child)
|
||||
: header_(), headers_size_(0) {
|
||||
version(6);
|
||||
dst_addr(ip_dst);
|
||||
src_addr(ip_src);
|
||||
}
|
||||
|
||||
IPv6::IPv6(const uint8_t *buffer, uint32_t total_sz)
|
||||
: headers_size(0)
|
||||
{
|
||||
IPv6::IPv6(const uint8_t* buffer, uint32_t total_sz)
|
||||
: headers_size_(0) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_header);
|
||||
uint8_t current_header = _header.next_header;
|
||||
stream.read(header_);
|
||||
uint8_t current_header = header_.next_header;
|
||||
while (stream) {
|
||||
if(is_extension_header(current_header)) {
|
||||
if (is_extension_header(current_header)) {
|
||||
const uint8_t ext_type = stream.read<uint8_t>();
|
||||
// every ext header is at least 8 bytes long
|
||||
// minus one, from the next_header field.
|
||||
@@ -88,7 +88,7 @@ IPv6::IPv6(const uint8_t *buffer, uint32_t total_sz)
|
||||
false
|
||||
)
|
||||
);
|
||||
if(!inner_pdu()) {
|
||||
if (!inner_pdu()) {
|
||||
inner_pdu(
|
||||
Internals::allocate<IPv6>(
|
||||
current_header,
|
||||
@@ -96,7 +96,7 @@ IPv6::IPv6(const uint8_t *buffer, uint32_t total_sz)
|
||||
stream.size()
|
||||
)
|
||||
);
|
||||
if(!inner_pdu()) {
|
||||
if (!inner_pdu()) {
|
||||
inner_pdu(new Tins::RawPDU(stream.pointer(), stream.size()));
|
||||
}
|
||||
}
|
||||
@@ -114,81 +114,85 @@ bool IPv6::is_extension_header(uint8_t header_id) {
|
||||
}
|
||||
|
||||
void IPv6::version(small_uint<4> new_version) {
|
||||
_header.version = new_version;
|
||||
header_.version = new_version;
|
||||
}
|
||||
|
||||
void IPv6::traffic_class(uint8_t new_traffic_class) {
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
_header.traffic_class = (new_traffic_class >> 4) & 0xf;
|
||||
_header.flow_label[0] = (_header.flow_label[0] & 0x0f) | ((new_traffic_class << 4) & 0xf0);
|
||||
header_.traffic_class = (new_traffic_class >> 4) & 0xf;
|
||||
header_.flow_label[0] = (header_.flow_label[0] & 0x0f) | ((new_traffic_class << 4) & 0xf0);
|
||||
#else
|
||||
_header.traffic_class = new_traffic_class;
|
||||
header_.traffic_class = new_traffic_class;
|
||||
#endif
|
||||
}
|
||||
|
||||
void IPv6::flow_label(small_uint<20> new_flow_label) {
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
uint32_t value = Endian::host_to_be<uint32_t>(new_flow_label);
|
||||
_header.flow_label[2] = (value >> 24) & 0xff;
|
||||
_header.flow_label[1] = (value >> 16) & 0xff;
|
||||
_header.flow_label[0] = ((value >> 8) & 0x0f) | (_header.flow_label[0] & 0xf0);
|
||||
header_.flow_label[2] = (value >> 24) & 0xff;
|
||||
header_.flow_label[1] = (value >> 16) & 0xff;
|
||||
header_.flow_label[0] = ((value >> 8) & 0x0f) | (header_.flow_label[0] & 0xf0);
|
||||
#else
|
||||
_header.flow_label = new_flow_label;
|
||||
header_.flow_label = new_flow_label;
|
||||
#endif
|
||||
}
|
||||
|
||||
void IPv6::payload_length(uint16_t new_payload_length) {
|
||||
_header.payload_length = Endian::host_to_be(new_payload_length);
|
||||
header_.payload_length = Endian::host_to_be(new_payload_length);
|
||||
}
|
||||
|
||||
void IPv6::next_header(uint8_t new_next_header) {
|
||||
_header.next_header = new_next_header;
|
||||
header_.next_header = new_next_header;
|
||||
}
|
||||
|
||||
void IPv6::hop_limit(uint8_t new_hop_limit) {
|
||||
_header.hop_limit = new_hop_limit;
|
||||
header_.hop_limit = new_hop_limit;
|
||||
}
|
||||
|
||||
void IPv6::src_addr(const address_type &new_src_addr) {
|
||||
new_src_addr.copy(_header.src_addr);
|
||||
void IPv6::src_addr(const address_type& new_src_addr) {
|
||||
new_src_addr.copy(header_.src_addr);
|
||||
}
|
||||
|
||||
void IPv6::dst_addr(const address_type &new_dst_addr) {
|
||||
new_dst_addr.copy(_header.dst_addr);
|
||||
void IPv6::dst_addr(const address_type& new_dst_addr) {
|
||||
new_dst_addr.copy(header_.dst_addr);
|
||||
}
|
||||
|
||||
uint32_t IPv6::header_size() const {
|
||||
return sizeof(_header) + headers_size;
|
||||
return sizeof(header_) + headers_size_;
|
||||
}
|
||||
|
||||
bool IPv6::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
if(total_sz < sizeof(ipv6_header))
|
||||
bool IPv6::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
if (total_sz < sizeof(ipv6_header)) {
|
||||
return false;
|
||||
const ipv6_header *hdr_ptr = (const ipv6_header*)ptr;
|
||||
}
|
||||
const ipv6_header* hdr_ptr = (const ipv6_header*)ptr;
|
||||
// checks for ff02 multicast
|
||||
if(src_addr() == hdr_ptr->dst_addr &&
|
||||
(dst_addr() == hdr_ptr->src_addr || (_header.dst_addr[0] == 0xff && _header.dst_addr[1] == 0x02))) {
|
||||
if (src_addr() == hdr_ptr->dst_addr &&
|
||||
(dst_addr() == hdr_ptr->src_addr || (header_.dst_addr[0] == 0xff && header_.dst_addr[1] == 0x02))) {
|
||||
// is this OK? there's no inner pdu, simple dst/src addr match should suffice
|
||||
if(!inner_pdu())
|
||||
if (!inner_pdu()) {
|
||||
return true;
|
||||
}
|
||||
ptr += sizeof(ipv6_header);
|
||||
total_sz -= sizeof(ipv6_header);
|
||||
uint8_t current = hdr_ptr->next_header;
|
||||
// 8 == minimum header size
|
||||
while(total_sz > 8 && is_extension_header(current)) {
|
||||
if(static_cast<uint32_t>(ptr[1] + 1) * 8 > total_sz)
|
||||
while (total_sz > 8 && is_extension_header(current)) {
|
||||
if (static_cast<uint32_t>(ptr[1] + 1) * 8 > total_sz) {
|
||||
return false;
|
||||
}
|
||||
current = ptr[0];
|
||||
total_sz -= (ptr[1] + 1) * 8;
|
||||
ptr += (ptr[1] + 1) * 8;
|
||||
}
|
||||
if(!is_extension_header(current))
|
||||
if (!is_extension_header(current)) {
|
||||
return inner_pdu()->matches_response(ptr, total_sz);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void IPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
|
||||
void IPv6::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
if (inner_pdu()) {
|
||||
uint8_t new_flag = Internals::pdu_flag_to_ip_type(inner_pdu()->pdu_type());
|
||||
@@ -199,52 +203,56 @@ void IPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *pa
|
||||
}
|
||||
set_last_next_header(new_flag);
|
||||
}
|
||||
payload_length(static_cast<uint16_t>(total_sz - sizeof(_header)));
|
||||
stream.write(_header);
|
||||
for(headers_type::const_iterator it = ext_headers.begin(); it != ext_headers.end(); ++it) {
|
||||
payload_length(static_cast<uint16_t>(total_sz - sizeof(header_)));
|
||||
stream.write(header_);
|
||||
for (headers_type::const_iterator it = ext_headers_.begin(); it != ext_headers_.end(); ++it) {
|
||||
write_header(*it, stream);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BSD
|
||||
void IPv6::send(PacketSender &sender, const NetworkInterface &) {
|
||||
void IPv6::send(PacketSender& sender, const NetworkInterface &) {
|
||||
struct sockaddr_in6 link_addr;
|
||||
PacketSender::SocketType type = PacketSender::IPV6_SOCKET;
|
||||
link_addr.sin6_family = AF_INET6;
|
||||
link_addr.sin6_port = 0;
|
||||
std::copy(_header.dst_addr, _header.dst_addr + address_type::address_size, (uint8_t*)&link_addr.sin6_addr);
|
||||
if(inner_pdu() && inner_pdu()->pdu_type() == PDU::ICMP)
|
||||
copy(header_.dst_addr, header_.dst_addr + address_type::address_size, (uint8_t*)&link_addr.sin6_addr);
|
||||
if (inner_pdu() && inner_pdu()->pdu_type() == PDU::ICMP) {
|
||||
type = PacketSender::ICMP_SOCKET;
|
||||
}
|
||||
|
||||
sender.send_l3(*this, (struct sockaddr*)&link_addr, sizeof(link_addr), type);
|
||||
}
|
||||
#endif
|
||||
|
||||
void IPv6::add_ext_header(const ext_header &header) {
|
||||
ext_headers.push_back(header);
|
||||
headers_size += static_cast<uint32_t>(header.data_size() + sizeof(uint8_t) * 2);
|
||||
void IPv6::add_ext_header(const ext_header& header) {
|
||||
ext_headers_.push_back(header);
|
||||
headers_size_ += static_cast<uint32_t>(header.data_size() + sizeof(uint8_t) * 2);
|
||||
}
|
||||
|
||||
const IPv6::ext_header *IPv6::search_header(ExtensionHeader id) const {
|
||||
uint8_t current_header = _header.next_header;
|
||||
headers_type::const_iterator it = ext_headers.begin();
|
||||
while(it != ext_headers.end() && current_header != id) {
|
||||
const IPv6::ext_header* IPv6::search_header(ExtensionHeader id) const {
|
||||
uint8_t current_header = header_.next_header;
|
||||
headers_type::const_iterator it = ext_headers_.begin();
|
||||
while (it != ext_headers_.end() && current_header != id) {
|
||||
current_header = it->option();
|
||||
++it;
|
||||
}
|
||||
if(it == ext_headers.end())
|
||||
if (it == ext_headers_.end()) {
|
||||
return 0;
|
||||
}
|
||||
return &*it;
|
||||
}
|
||||
|
||||
void IPv6::set_last_next_header(uint8_t value) {
|
||||
if(ext_headers.empty())
|
||||
_header.next_header = value;
|
||||
else
|
||||
ext_headers.back().option(value);
|
||||
if (ext_headers_.empty()) {
|
||||
header_.next_header = value;
|
||||
}
|
||||
else {
|
||||
ext_headers_.back().option(value);
|
||||
}
|
||||
}
|
||||
|
||||
void IPv6::write_header(const ext_header &header, OutputMemoryStream& stream) {
|
||||
void IPv6::write_header(const ext_header& header, OutputMemoryStream& stream) {
|
||||
const uint8_t length = header.length_field() / 8;
|
||||
stream.write(header.option());
|
||||
stream.write(length);
|
||||
|
||||
@@ -42,61 +42,72 @@
|
||||
#include <sstream>
|
||||
#include "ipv6_address.h"
|
||||
#include "address_range.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
using std::fill;
|
||||
using std::string;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
const IPv6Address loopback_address = "::1";
|
||||
const AddressRange<IPv6Address> multicast_range = IPv6Address("ff00::") / 8;
|
||||
|
||||
IPv6Address::IPv6Address() {
|
||||
std::fill(address, address + address_size, 0);
|
||||
fill(address_, address_ + address_size, 0);
|
||||
}
|
||||
|
||||
IPv6Address::IPv6Address(const char *addr) {
|
||||
IPv6Address::IPv6Address(const char* addr) {
|
||||
init(addr);
|
||||
}
|
||||
|
||||
IPv6Address::IPv6Address(const_iterator ptr) {
|
||||
std::copy(ptr, ptr + address_size, address);
|
||||
std::copy(ptr, ptr + address_size, address_);
|
||||
}
|
||||
|
||||
IPv6Address::IPv6Address(const std::string &addr) {
|
||||
IPv6Address::IPv6Address(const std::string& addr) {
|
||||
init(addr.c_str());
|
||||
}
|
||||
|
||||
void IPv6Address::init(const char *addr) {
|
||||
void IPv6Address::init(const char* addr) {
|
||||
#ifdef _WIN32
|
||||
// mingw on linux somehow doesn't have InetPton
|
||||
#ifdef _MSC_VER
|
||||
if(InetPtonA(AF_INET6, addr, address) != 1)
|
||||
throw malformed_address();
|
||||
if (InetPtonA(AF_INET6, addr, address_) != 1) {
|
||||
throw invalid_address();
|
||||
}
|
||||
#else
|
||||
ULONG dummy1;
|
||||
USHORT dummy2;
|
||||
// Maybe change this, mingw doesn't have any other conversion function
|
||||
if(RtlIpv6StringToAddressExA(addr, (IN6_ADDR*)address, &dummy1, &dummy2) != NO_ERROR)
|
||||
throw malformed_address();
|
||||
if (RtlIpv6StringToAddressExA(addr, (IN6_ADDR*)address_, &dummy1, &dummy2) != NO_ERROR) {
|
||||
throw invalid_address();
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
if(inet_pton(AF_INET6, addr, address) == 0)
|
||||
throw malformed_address();
|
||||
if (inet_pton(AF_INET6, addr, address_) == 0) {
|
||||
throw invalid_address();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string IPv6Address::to_string() const {
|
||||
string IPv6Address::to_string() const {
|
||||
char buffer[INET6_ADDRSTRLEN];
|
||||
#ifdef _WIN32
|
||||
// mingw on linux somehow doesn't have InetNtop
|
||||
#ifdef _MSC_VER
|
||||
if(InetNtopA(AF_INET6, (PVOID)address, buffer, sizeof(buffer)) == 0)
|
||||
throw malformed_address();
|
||||
if (InetNtopA(AF_INET6, (PVOID)address_, buffer, sizeof(buffer)) == 0) {
|
||||
throw invalid_address();
|
||||
}
|
||||
#else
|
||||
ULONG sz = sizeof(buffer);
|
||||
if(RtlIpv6AddressToStringExA((const IN6_ADDR*)address, 0, 0, buffer, &sz) != NO_ERROR)
|
||||
throw malformed_address();
|
||||
if (RtlIpv6AddressToStringExA((const IN6_ADDR*)address_, 0, 0, buffer, &sz) != NO_ERROR) {
|
||||
throw invalid_address();
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
if(inet_ntop(AF_INET6, address, buffer, sizeof(buffer)) == 0)
|
||||
throw malformed_address();
|
||||
if (inet_ntop(AF_INET6, address_, buffer, sizeof(buffer)) == 0) {
|
||||
throw invalid_address();
|
||||
}
|
||||
#endif
|
||||
return buffer;
|
||||
}
|
||||
@@ -108,5 +119,5 @@ bool IPv6Address::is_loopback() const {
|
||||
bool IPv6Address::is_multicast() const {
|
||||
return multicast_range.contains(*this);
|
||||
}
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
73
src/llc.cpp
73
src/llc.cpp
@@ -44,28 +44,26 @@ const uint8_t LLC::GLOBAL_DSAP_ADDR = 0xFF;
|
||||
const uint8_t LLC::NULL_ADDR = 0x00;
|
||||
|
||||
LLC::LLC()
|
||||
: _header(), control_field(), _type(LLC::INFORMATION)
|
||||
{
|
||||
control_field_length = 2;
|
||||
information_field_length = 0;
|
||||
: header_(), control_field(), type_(LLC::INFORMATION) {
|
||||
control_field_length_ = 2;
|
||||
information_field_length_ = 0;
|
||||
}
|
||||
|
||||
LLC::LLC(uint8_t dsap, uint8_t ssap)
|
||||
: control_field(), _type(LLC::INFORMATION)
|
||||
{
|
||||
_header.dsap = dsap;
|
||||
_header.ssap = ssap;
|
||||
control_field_length = 2;
|
||||
information_field_length = 0;
|
||||
: control_field(), type_(LLC::INFORMATION) {
|
||||
header_.dsap = dsap;
|
||||
header_.ssap = ssap;
|
||||
control_field_length_ = 2;
|
||||
information_field_length_ = 0;
|
||||
}
|
||||
|
||||
LLC::LLC(const uint8_t *buffer, uint32_t total_sz) {
|
||||
LLC::LLC(const uint8_t* buffer, uint32_t total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_header);
|
||||
stream.read(header_);
|
||||
if (!stream) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
information_field_length = 0;
|
||||
information_field_length_ = 0;
|
||||
if ((*stream.pointer() & 0x03) == LLC::UNNUMBERED) {
|
||||
type(LLC::UNNUMBERED);
|
||||
stream.read(control_field.unnumbered);
|
||||
@@ -73,7 +71,7 @@ LLC::LLC(const uint8_t *buffer, uint32_t total_sz) {
|
||||
}
|
||||
else {
|
||||
type((Format)(*stream.pointer() & 0x03));
|
||||
control_field_length = 2;
|
||||
control_field_length_ = 2;
|
||||
stream.read(control_field.info);
|
||||
}
|
||||
if (stream) {
|
||||
@@ -88,51 +86,52 @@ LLC::LLC(const uint8_t *buffer, uint32_t total_sz) {
|
||||
|
||||
void LLC::group(bool value) {
|
||||
if (value) {
|
||||
_header.dsap |= 0x01;
|
||||
header_.dsap |= 0x01;
|
||||
}
|
||||
else {
|
||||
_header.dsap &= 0xFE;
|
||||
header_.dsap &= 0xFE;
|
||||
}
|
||||
}
|
||||
|
||||
void LLC::dsap(uint8_t new_dsap) {
|
||||
_header.dsap = new_dsap;
|
||||
header_.dsap = new_dsap;
|
||||
}
|
||||
|
||||
void LLC::response(bool value) {
|
||||
if (value) {
|
||||
_header.ssap |= 0x01;
|
||||
header_.ssap |= 0x01;
|
||||
}
|
||||
else {
|
||||
_header.ssap &= 0xFE;
|
||||
header_.ssap &= 0xFE;
|
||||
}
|
||||
}
|
||||
|
||||
void LLC::ssap(uint8_t new_ssap) {
|
||||
_header.ssap = new_ssap;
|
||||
header_.ssap = new_ssap;
|
||||
}
|
||||
|
||||
void LLC::type(LLC::Format type) {
|
||||
_type = type;
|
||||
type_ = type;
|
||||
switch (type) {
|
||||
case LLC::INFORMATION:
|
||||
control_field_length = 2;
|
||||
control_field_length_ = 2;
|
||||
control_field.info.type_bit = 0;
|
||||
break;
|
||||
case LLC::SUPERVISORY:
|
||||
control_field_length = 2;
|
||||
control_field_length_ = 2;
|
||||
control_field.super.type_bit = 1;
|
||||
break;
|
||||
case LLC::UNNUMBERED:
|
||||
control_field_length = 1;
|
||||
control_field_length_ = 1;
|
||||
control_field.unnumbered.type_bits = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void LLC::send_seq_number(uint8_t seq_number) {
|
||||
if (type() != LLC::INFORMATION)
|
||||
if (type() != LLC::INFORMATION) {
|
||||
return;
|
||||
}
|
||||
control_field.info.send_seq_num = seq_number;
|
||||
}
|
||||
|
||||
@@ -165,14 +164,16 @@ void LLC::poll_final(bool value) {
|
||||
}
|
||||
|
||||
void LLC::supervisory_function(LLC::SupervisoryFunctions new_func) {
|
||||
if (type() != LLC::SUPERVISORY)
|
||||
if (type() != LLC::SUPERVISORY) {
|
||||
return;
|
||||
}
|
||||
control_field.super.supervisory_func = new_func;
|
||||
}
|
||||
|
||||
void LLC::modifier_function(LLC::ModifierFunctions mod_func) {
|
||||
if (type() != LLC::UNNUMBERED)
|
||||
if (type() != LLC::UNNUMBERED) {
|
||||
return;
|
||||
}
|
||||
control_field.unnumbered.mod_func1 = mod_func >> 3;
|
||||
control_field.unnumbered.mod_func2 = mod_func & 0x07;
|
||||
}
|
||||
@@ -182,26 +183,26 @@ void LLC::add_xid_information(uint8_t xid_id, uint8_t llc_type_class, uint8_t re
|
||||
xid[0] = xid_id;
|
||||
xid[1] = llc_type_class;
|
||||
xid[2] = receive_window;
|
||||
information_field_length += static_cast<uint8_t>(xid.size());
|
||||
information_fields.push_back(xid);
|
||||
information_field_length_ += static_cast<uint8_t>(xid.size());
|
||||
information_fields_.push_back(xid);
|
||||
}
|
||||
|
||||
uint32_t LLC::header_size() const {
|
||||
return sizeof(_header) + control_field_length + information_field_length;
|
||||
return sizeof(header_) + control_field_length_ + information_field_length_;
|
||||
}
|
||||
|
||||
void LLC::clear_information_fields() {
|
||||
information_field_length = 0;
|
||||
information_fields.clear();
|
||||
information_field_length_ = 0;
|
||||
information_fields_.clear();
|
||||
}
|
||||
|
||||
void LLC::write_serialization(uint8_t *buffer, uint32_t total_sz, const Tins::PDU *parent) {
|
||||
void LLC::write_serialization(uint8_t* buffer, uint32_t total_sz, const Tins::PDU* parent) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
if (inner_pdu() && inner_pdu()->pdu_type() == PDU::STP) {
|
||||
dsap(0x42);
|
||||
ssap(0x42);
|
||||
}
|
||||
stream.write(_header);
|
||||
stream.write(header_);
|
||||
switch (type()) {
|
||||
case LLC::UNNUMBERED:
|
||||
stream.write(control_field.unnumbered);
|
||||
@@ -214,9 +215,9 @@ void LLC::write_serialization(uint8_t *buffer, uint32_t total_sz, const Tins::PD
|
||||
break;
|
||||
}
|
||||
|
||||
for (field_list::const_iterator it = information_fields.begin(); it != information_fields.end(); it++) {
|
||||
for (field_list::const_iterator it = information_fields_.begin(); it != information_fields_.end(); it++) {
|
||||
stream.write(it->begin(), it->end());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // Tins
|
||||
|
||||
@@ -58,18 +58,16 @@ using Tins::Memory::OutputMemoryStream;
|
||||
namespace Tins {
|
||||
|
||||
Loopback::Loopback()
|
||||
: _family()
|
||||
{
|
||||
: family_() {
|
||||
|
||||
}
|
||||
|
||||
Loopback::Loopback(const uint8_t *buffer, uint32_t total_sz)
|
||||
{
|
||||
Loopback::Loopback(const uint8_t* buffer, uint32_t total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
_family = stream.read<uint32_t>();
|
||||
family_ = stream.read<uint32_t>();
|
||||
#ifndef _WIN32
|
||||
if (total_sz) {
|
||||
switch (_family) {
|
||||
switch (family_) {
|
||||
case PF_INET:
|
||||
inner_pdu(new Tins::IP(stream.pointer(), stream.size()));
|
||||
break;
|
||||
@@ -85,44 +83,46 @@ Loopback::Loopback(const uint8_t *buffer, uint32_t total_sz)
|
||||
}
|
||||
|
||||
void Loopback::family(uint32_t family_id) {
|
||||
_family = family_id;
|
||||
family_ = family_id;
|
||||
}
|
||||
|
||||
uint32_t Loopback::header_size() const {
|
||||
return sizeof(_family);
|
||||
return sizeof(family_);
|
||||
}
|
||||
|
||||
void Loopback::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
|
||||
void Loopback::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
#ifndef _WIN32
|
||||
if (tins_cast<const Tins::IP*>(inner_pdu())) {
|
||||
_family = PF_INET;
|
||||
family_ = PF_INET;
|
||||
}
|
||||
else if (tins_cast<const Tins::LLC*>(inner_pdu())) {
|
||||
_family = PF_LLC;
|
||||
family_ = PF_LLC;
|
||||
}
|
||||
stream.write(_family);
|
||||
stream.write(family_);
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
bool Loopback::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
if(total_sz < sizeof(_family)) {
|
||||
bool Loopback::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
if (total_sz < sizeof(family_)) {
|
||||
return false;
|
||||
}
|
||||
// If there's an inner_pdu, check if the inner pdu matches.
|
||||
// Otherwise, just check this loopback family.
|
||||
|
||||
return inner_pdu() ?
|
||||
inner_pdu()->matches_response(ptr + sizeof(_family), total_sz - sizeof(_family)) :
|
||||
(_family == *reinterpret_cast<const uint32_t*>(ptr));
|
||||
inner_pdu()->matches_response(ptr + sizeof(family_), total_sz - sizeof(family_)) :
|
||||
(family_ == *reinterpret_cast<const uint32_t*>(ptr));
|
||||
}
|
||||
|
||||
#ifdef BSD
|
||||
void Loopback::send(PacketSender &sender, const NetworkInterface &iface) {
|
||||
if(!iface)
|
||||
void Loopback::send(PacketSender& sender, const NetworkInterface& iface) {
|
||||
if (!iface) {
|
||||
throw invalid_interface();
|
||||
}
|
||||
|
||||
sender.send_l2(*this, 0, 0, iface);
|
||||
}
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
15
src/mpls.cpp
15
src/mpls.cpp
@@ -29,6 +29,8 @@
|
||||
|
||||
#include "mpls.h"
|
||||
#include "ip.h"
|
||||
#include "ipv6.h"
|
||||
#include "rawpdu.h"
|
||||
#include "memory_helpers.h"
|
||||
#include "icmp_extension.h"
|
||||
|
||||
@@ -52,7 +54,16 @@ MPLS::MPLS(const uint8_t* buffer, uint32_t total_sz) {
|
||||
if (stream) {
|
||||
// If this is the last MPLS, then construct an IP
|
||||
if (bottom_of_stack()) {
|
||||
inner_pdu(new Tins::IP(stream.pointer(), stream.size()));
|
||||
uint8_t version = (*stream.pointer() >> 4) & 0x0f;
|
||||
if (version == 4) {
|
||||
inner_pdu(new Tins::IP(stream.pointer(), stream.size()));
|
||||
}
|
||||
else if (version == 6) {
|
||||
inner_pdu(new Tins::IPv6(stream.pointer(), stream.size()));
|
||||
}
|
||||
else {
|
||||
inner_pdu(new Tins::RawPDU(stream.pointer(), stream.size()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
inner_pdu(new MPLS(stream.pointer(), stream.size()));
|
||||
@@ -80,7 +91,7 @@ uint32_t MPLS::header_size() const {
|
||||
return sizeof(header_);
|
||||
}
|
||||
|
||||
void MPLS::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
|
||||
void MPLS::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
// If we have a parent PDU, we might set the bottom-of-stack field
|
||||
if (parent) {
|
||||
|
||||
@@ -48,59 +48,65 @@
|
||||
#include "network_interface.h"
|
||||
#include "utils.h"
|
||||
#include "endianness.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::set;
|
||||
using std::copy;
|
||||
|
||||
/** \cond */
|
||||
struct InterfaceInfoCollector {
|
||||
typedef Tins::NetworkInterface::Info info_type;
|
||||
info_type *info;
|
||||
info_type* info;
|
||||
int iface_id;
|
||||
const char* iface_name;
|
||||
bool found_hw;
|
||||
bool found_ip;
|
||||
|
||||
InterfaceInfoCollector(info_type *res, int id, const char* if_name)
|
||||
InterfaceInfoCollector(info_type* res, int id, const char* if_name)
|
||||
: info(res), iface_id(id), iface_name(if_name), found_hw(false), found_ip(false) { }
|
||||
|
||||
#ifndef WIN32
|
||||
bool operator() (const struct ifaddrs *addr) {
|
||||
bool operator() (const struct ifaddrs* addr) {
|
||||
using Tins::Endian::host_to_be;
|
||||
using Tins::IPv4Address;
|
||||
using Tins::IPv4Address;
|
||||
#if defined(BSD) || defined(__FreeBSD_kernel__)
|
||||
const struct sockaddr_dl* addr_ptr = ((struct sockaddr_dl*)addr->ifa_addr);
|
||||
|
||||
if(addr->ifa_addr->sa_family == AF_LINK && addr_ptr->sdl_index == iface_id) {
|
||||
if (addr->ifa_addr->sa_family == AF_LINK && addr_ptr->sdl_index == iface_id) {
|
||||
info->hw_addr = (const uint8_t*)LLADDR(addr_ptr); // mmmm
|
||||
found_hw = true;
|
||||
}
|
||||
else if(addr->ifa_addr->sa_family == AF_INET && !std::strcmp(addr->ifa_name, iface_name)) {
|
||||
else if (addr->ifa_addr->sa_family == AF_INET && !std::strcmp(addr->ifa_name, iface_name)) {
|
||||
info->ip_addr = IPv4Address(((struct sockaddr_in *)addr->ifa_addr)->sin_addr.s_addr);
|
||||
info->netmask = IPv4Address(((struct sockaddr_in *)addr->ifa_netmask)->sin_addr.s_addr);
|
||||
if((addr->ifa_flags & (IFF_BROADCAST | IFF_POINTOPOINT)))
|
||||
if ((addr->ifa_flags & (IFF_BROADCAST | IFF_POINTOPOINT))) {
|
||||
info->bcast_addr = IPv4Address(((struct sockaddr_in *)addr->ifa_dstaddr)->sin_addr.s_addr);
|
||||
else
|
||||
}
|
||||
else {
|
||||
info->bcast_addr = 0;
|
||||
}
|
||||
info->is_up = (addr->ifa_flags & IFF_UP);
|
||||
found_ip = true;
|
||||
}
|
||||
#else
|
||||
const struct sockaddr_ll* addr_ptr = ((struct sockaddr_ll*)addr->ifa_addr);
|
||||
|
||||
if(addr->ifa_addr) {
|
||||
if(addr->ifa_addr->sa_family == AF_PACKET && addr_ptr->sll_ifindex == iface_id) {
|
||||
if (addr->ifa_addr) {
|
||||
if (addr->ifa_addr->sa_family == AF_PACKET && addr_ptr->sll_ifindex == iface_id) {
|
||||
info->hw_addr = addr_ptr->sll_addr;
|
||||
found_hw = true;
|
||||
}
|
||||
else if(addr->ifa_addr->sa_family == AF_INET && !std::strcmp(addr->ifa_name, iface_name)) {
|
||||
else if (addr->ifa_addr->sa_family == AF_INET && !std::strcmp(addr->ifa_name, iface_name)) {
|
||||
info->ip_addr = IPv4Address(((struct sockaddr_in *)addr->ifa_addr)->sin_addr.s_addr);
|
||||
info->netmask = IPv4Address(((struct sockaddr_in *)addr->ifa_netmask)->sin_addr.s_addr);
|
||||
if((addr->ifa_flags & (IFF_BROADCAST | IFF_POINTOPOINT)))
|
||||
if ((addr->ifa_flags & (IFF_BROADCAST | IFF_POINTOPOINT))) {
|
||||
info->bcast_addr = IPv4Address(((struct sockaddr_in *)addr->ifa_broadaddr)->sin_addr.s_addr);
|
||||
else
|
||||
}
|
||||
else {
|
||||
info->bcast_addr = 0;
|
||||
}
|
||||
info->is_up = (addr->ifa_flags & IFF_UP);
|
||||
found_ip = true;
|
||||
}
|
||||
@@ -110,13 +116,13 @@ struct InterfaceInfoCollector {
|
||||
return found_ip && found_hw;
|
||||
}
|
||||
#else // WIN32
|
||||
bool operator() (const IP_ADAPTER_ADDRESSES *iface) {
|
||||
bool operator() (const IP_ADAPTER_ADDRESSES* iface) {
|
||||
using Tins::IPv4Address;
|
||||
using Tins::Endian::host_to_be;
|
||||
if(iface_id == uint32_t(iface->IfIndex)) {
|
||||
std::copy(iface->PhysicalAddress, iface->PhysicalAddress + 6, info->hw_addr.begin());
|
||||
const IP_ADAPTER_UNICAST_ADDRESS *unicast = iface->FirstUnicastAddress;
|
||||
if(unicast) {
|
||||
if (iface_id == uint32_t(iface->IfIndex)) {
|
||||
copy(iface->PhysicalAddress, iface->PhysicalAddress + 6, info->hw_addr.begin());
|
||||
const IP_ADAPTER_UNICAST_ADDRESS* unicast = iface->FirstUnicastAddress;
|
||||
if (unicast) {
|
||||
info->ip_addr = IPv4Address(((const struct sockaddr_in *)unicast->Address.lpSockaddr)->sin_addr.s_addr);
|
||||
info->netmask = IPv4Address(host_to_be<uint32_t>(0xffffffff << (32 - unicast->OnLinkPrefixLength)));
|
||||
info->bcast_addr = IPv4Address((info->ip_addr & info->netmask) | ~info->netmask);
|
||||
@@ -132,6 +138,7 @@ struct InterfaceInfoCollector {
|
||||
/** \endcond */
|
||||
|
||||
namespace Tins {
|
||||
|
||||
// static
|
||||
NetworkInterface NetworkInterface::default_interface() {
|
||||
return NetworkInterface(IPv4Address(uint32_t(0)));
|
||||
@@ -140,77 +147,82 @@ NetworkInterface NetworkInterface::default_interface() {
|
||||
vector<NetworkInterface> NetworkInterface::all() {
|
||||
const set<string> interfaces = Utils::network_interfaces();
|
||||
vector<NetworkInterface> output;
|
||||
for(set<string>::const_iterator it = interfaces.begin(); it != interfaces.end(); ++it) {
|
||||
for (set<string>::const_iterator it = interfaces.begin(); it != interfaces.end(); ++it) {
|
||||
output.push_back(*it);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
NetworkInterface::NetworkInterface() : iface_id(0) {
|
||||
NetworkInterface::NetworkInterface()
|
||||
: iface_id_(0) {
|
||||
|
||||
}
|
||||
|
||||
NetworkInterface NetworkInterface::from_index(id_type identifier) {
|
||||
NetworkInterface iface;
|
||||
iface.iface_id = identifier;
|
||||
iface.iface_id_ = identifier;
|
||||
return iface;
|
||||
}
|
||||
|
||||
NetworkInterface::NetworkInterface(const char *name) {
|
||||
iface_id = name ? resolve_index(name) : 0;
|
||||
NetworkInterface::NetworkInterface(const char* name) {
|
||||
iface_id_ = name ? resolve_index(name) : 0;
|
||||
}
|
||||
|
||||
NetworkInterface::NetworkInterface(const std::string &name) {
|
||||
iface_id = resolve_index(name.c_str());
|
||||
NetworkInterface::NetworkInterface(const std::string& name) {
|
||||
iface_id_ = resolve_index(name.c_str());
|
||||
}
|
||||
|
||||
NetworkInterface::NetworkInterface(IPv4Address ip) : iface_id(0) {
|
||||
typedef std::vector<Utils::RouteEntry> entries_type;
|
||||
NetworkInterface::NetworkInterface(IPv4Address ip)
|
||||
: iface_id_(0) {
|
||||
typedef vector<Utils::RouteEntry> entries_type;
|
||||
|
||||
if(ip == "127.0.0.1")
|
||||
if (ip == "127.0.0.1") {
|
||||
#if defined(BSD) || defined(__FreeBSD_kernel__)
|
||||
iface_id = resolve_index("lo0");
|
||||
iface_id_ = resolve_index("lo0");
|
||||
#else
|
||||
iface_id = resolve_index("lo");
|
||||
iface_id_ = resolve_index("lo");
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
const Utils::RouteEntry *best_match = 0;
|
||||
const Utils::RouteEntry* best_match = 0;
|
||||
entries_type entries;
|
||||
uint32_t ip_int = ip;
|
||||
Utils::route_entries(std::back_inserter(entries));
|
||||
for(entries_type::const_iterator it(entries.begin()); it != entries.end(); ++it) {
|
||||
if((ip_int & it->mask) == it->destination) {
|
||||
if(!best_match || it->mask > best_match->mask || it->metric < best_match->metric) {
|
||||
for (entries_type::const_iterator it(entries.begin()); it != entries.end(); ++it) {
|
||||
if ((ip_int & it->mask) == it->destination) {
|
||||
if (!best_match || it->mask > best_match->mask || it->metric < best_match->metric) {
|
||||
best_match = &*it;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!best_match)
|
||||
throw std::runtime_error("Error looking up interface");
|
||||
iface_id = resolve_index(best_match->interface.c_str());
|
||||
if (!best_match) {
|
||||
throw invalid_interface();
|
||||
}
|
||||
iface_id_ = resolve_index(best_match->interface.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
std::string NetworkInterface::name() const {
|
||||
string NetworkInterface::name() const {
|
||||
#ifndef WIN32
|
||||
char iface_name[IF_NAMESIZE];
|
||||
if(!if_indextoname(iface_id, iface_name))
|
||||
throw std::runtime_error("Error fetching this interface's name");
|
||||
if (!if_indextoname(iface_id_, iface_name)) {
|
||||
throw invalid_interface();
|
||||
}
|
||||
return iface_name;
|
||||
#else // WIN32
|
||||
ULONG size;
|
||||
::GetAdaptersAddresses(AF_INET, 0, 0, 0, &size);
|
||||
std::vector<uint8_t> buffer(size);
|
||||
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 (iface->IfIndex == iface_id) {
|
||||
if (iface->IfIndex == iface_id_) {
|
||||
return iface->AdapterName;
|
||||
}
|
||||
iface = iface->Next;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Failed to find interface name");
|
||||
throw invalid_interface();
|
||||
#endif // WIN32
|
||||
}
|
||||
|
||||
@@ -219,15 +231,15 @@ NetworkInterface::Info NetworkInterface::addresses() const {
|
||||
}
|
||||
|
||||
NetworkInterface::Info NetworkInterface::info() const {
|
||||
const std::string &iface_name = name();
|
||||
const std::string& iface_name = name();
|
||||
Info info;
|
||||
InterfaceInfoCollector collector(&info, iface_id, iface_name.c_str());
|
||||
InterfaceInfoCollector collector(&info, iface_id_, iface_name.c_str());
|
||||
info.is_up = false;
|
||||
Utils::generic_iface_loop(collector);
|
||||
|
||||
// If we didn't even get the hw address or ip address, this went wrong
|
||||
if(!collector.found_hw && !collector.found_ip) {
|
||||
throw std::runtime_error("Error looking up interface address");
|
||||
if (!collector.found_hw && !collector.found_ip) {
|
||||
throw invalid_interface();
|
||||
}
|
||||
|
||||
return info;
|
||||
@@ -241,16 +253,17 @@ bool NetworkInterface::is_up() const {
|
||||
return addresses().is_up;
|
||||
}
|
||||
|
||||
NetworkInterface::id_type NetworkInterface::resolve_index(const char *name) {
|
||||
NetworkInterface::id_type NetworkInterface::resolve_index(const char* name) {
|
||||
#ifndef WIN32
|
||||
id_type id = if_nametoindex(name);
|
||||
if(!id)
|
||||
throw std::runtime_error("Invalid interface");
|
||||
if (!id) {
|
||||
throw invalid_interface();
|
||||
}
|
||||
return id;
|
||||
#else // Win32
|
||||
ULONG size;
|
||||
::GetAdaptersAddresses(AF_INET, 0, 0, 0, &size);
|
||||
std::vector<uint8_t> buffer(size);
|
||||
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) {
|
||||
@@ -260,8 +273,8 @@ NetworkInterface::id_type NetworkInterface::resolve_index(const char *name) {
|
||||
iface = iface->Next;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Invalid interface");
|
||||
throw invalid_interface();
|
||||
#endif // Win32
|
||||
}
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
@@ -30,51 +30,47 @@
|
||||
#include <stdexcept>
|
||||
#include "offline_packet_filter.h"
|
||||
#include "pdu.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
OfflinePacketFilter::OfflinePacketFilter(const OfflinePacketFilter& other)
|
||||
{
|
||||
OfflinePacketFilter::OfflinePacketFilter(const OfflinePacketFilter& other) {
|
||||
*this = other;
|
||||
}
|
||||
|
||||
OfflinePacketFilter& OfflinePacketFilter::operator=(const OfflinePacketFilter& other)
|
||||
{
|
||||
string_filter = other.string_filter;
|
||||
init(string_filter, pcap_datalink(other.handle), pcap_snapshot(other.handle));
|
||||
return *this;
|
||||
OfflinePacketFilter& OfflinePacketFilter::operator=(const OfflinePacketFilter& other) {
|
||||
string_filter_ = other.string_filter_;
|
||||
init(string_filter_, pcap_datalink(other.handle_), pcap_snapshot(other.handle_));
|
||||
return* this;
|
||||
}
|
||||
|
||||
OfflinePacketFilter::~OfflinePacketFilter()
|
||||
{
|
||||
pcap_freecode(&filter);
|
||||
pcap_close(handle);
|
||||
OfflinePacketFilter::~OfflinePacketFilter() {
|
||||
pcap_freecode(&filter_);
|
||||
pcap_close(handle_);
|
||||
}
|
||||
|
||||
void OfflinePacketFilter::init(const std::string& pcap_filter, int link_type,
|
||||
unsigned int snap_len)
|
||||
{
|
||||
handle = pcap_open_dead(
|
||||
void OfflinePacketFilter::init(const string& pcap_filter,
|
||||
int link_type,
|
||||
unsigned int snap_len) {
|
||||
handle_ = pcap_open_dead(
|
||||
link_type,
|
||||
snap_len
|
||||
);
|
||||
if(pcap_compile(handle, &filter, pcap_filter.c_str(), 1, 0xffffffff) == -1)
|
||||
{
|
||||
throw std::runtime_error(pcap_geterr(handle));
|
||||
if (pcap_compile(handle_, &filter_, pcap_filter.c_str(), 1, 0xffffffff) == -1) {
|
||||
throw invalid_pcap_filter(pcap_geterr(handle_));
|
||||
}
|
||||
}
|
||||
|
||||
bool OfflinePacketFilter::matches_filter(const uint8_t* buffer,
|
||||
uint32_t total_sz) const
|
||||
{
|
||||
bool OfflinePacketFilter::matches_filter(const uint8_t* buffer, uint32_t total_sz) const {
|
||||
pcap_pkthdr header = {};
|
||||
header.len = total_sz;
|
||||
header.caplen = total_sz;
|
||||
return pcap_offline_filter(&filter, &header, buffer) != 0;
|
||||
return pcap_offline_filter(&filter_, &header, buffer) != 0;
|
||||
}
|
||||
|
||||
bool OfflinePacketFilter::matches_filter(PDU& pdu) const
|
||||
{
|
||||
bool OfflinePacketFilter::matches_filter(PDU& pdu) const {
|
||||
PDU::serialization_type buffer = pdu.serialize();
|
||||
return matches_filter(&buffer[0], static_cast<uint32_t>(buffer.size()));
|
||||
}
|
||||
|
||||
@@ -67,73 +67,82 @@
|
||||
#include "internals.h"
|
||||
|
||||
using std::string;
|
||||
using std::ostringstream;
|
||||
using std::max;
|
||||
using std::make_pair;
|
||||
using std::vector;
|
||||
using std::runtime_error;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
const int PacketSender::INVALID_RAW_SOCKET = -1;
|
||||
const uint32_t PacketSender::DEFAULT_TIMEOUT = 2;
|
||||
|
||||
#ifndef _WIN32
|
||||
typedef int socket_type;
|
||||
|
||||
const char *make_error_string() {
|
||||
const char* make_error_string() {
|
||||
return strerror(errno);
|
||||
}
|
||||
#else
|
||||
typedef SOCKET socket_type;
|
||||
|
||||
// fixme
|
||||
const char *make_error_string() {
|
||||
const char* make_error_string() {
|
||||
return "error";
|
||||
}
|
||||
#endif
|
||||
|
||||
PacketSender::PacketSender(const NetworkInterface &iface, uint32_t recv_timeout,
|
||||
uint32_t usec)
|
||||
: _sockets(SOCKETS_END, INVALID_RAW_SOCKET),
|
||||
PacketSender::PacketSender(const NetworkInterface& iface,
|
||||
uint32_t recv_timeout,
|
||||
uint32_t usec)
|
||||
: sockets_(SOCKETS_END, INVALID_RAW_SOCKET),
|
||||
#if !defined(BSD) && !defined(_WIN32) && !defined(__FreeBSD_kernel__)
|
||||
_ether_socket(INVALID_RAW_SOCKET),
|
||||
ether_socket_(INVALID_RAW_SOCKET),
|
||||
#endif
|
||||
_timeout(recv_timeout), _timeout_usec(usec), default_iface(iface)
|
||||
{
|
||||
_types[IP_TCP_SOCKET] = IPPROTO_TCP;
|
||||
_types[IP_UDP_SOCKET] = IPPROTO_UDP;
|
||||
_types[IP_RAW_SOCKET] = IPPROTO_RAW;
|
||||
_types[IPV6_SOCKET] = IPPROTO_RAW;
|
||||
_types[ICMP_SOCKET] = IPPROTO_ICMP;
|
||||
_timeout(recv_timeout), timeout_usec_(usec), default_iface_(iface) {
|
||||
types_[IP_TCP_SOCKET] = IPPROTO_TCP;
|
||||
types_[IP_UDP_SOCKET] = IPPROTO_UDP;
|
||||
types_[IP_RAW_SOCKET] = IPPROTO_RAW;
|
||||
types_[IPV6_SOCKET] = IPPROTO_RAW;
|
||||
types_[ICMP_SOCKET] = IPPROTO_ICMP;
|
||||
}
|
||||
|
||||
PacketSender::~PacketSender() {
|
||||
for(unsigned i(0); i < _sockets.size(); ++i) {
|
||||
if(_sockets[i] != INVALID_RAW_SOCKET)
|
||||
#ifndef _WIN32
|
||||
::close(_sockets[i]);
|
||||
#else
|
||||
::closesocket(_sockets[i]);
|
||||
#endif
|
||||
for (unsigned i(0); i < sockets_.size(); ++i) {
|
||||
if (sockets_[i] != INVALID_RAW_SOCKET) {
|
||||
#ifndef _WIN32
|
||||
::close(sockets_[i]);
|
||||
#else
|
||||
::closesocket(sockets_[i]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if defined(BSD) || defined(__FreeBSD_kernel__)
|
||||
for(BSDEtherSockets::iterator it = _ether_socket.begin(); it != _ether_socket.end(); ++it)
|
||||
for (BSDEtherSockets::iterator it = ether_socket_.begin();
|
||||
it != ether_socket_.end(); ++it) {
|
||||
::close(it->second);
|
||||
}
|
||||
#elif !defined(_WIN32)
|
||||
if(_ether_socket != INVALID_RAW_SOCKET)
|
||||
::close(_ether_socket);
|
||||
if (ether_socket_ != INVALID_RAW_SOCKET) {
|
||||
::close(ether_socket_);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PACKET_SENDER_PCAP_SENDPACKET
|
||||
for (PcapHandleMap::iterator it = pcap_handles.begin(); it != pcap_handles.end(); ++it) {
|
||||
for (PcapHandleMap::iterator it = pcap_handles_.begin(); it != pcap_handles_.end(); ++it) {
|
||||
pcap_close(it->second);
|
||||
}
|
||||
pcap_handles.clear();
|
||||
pcap_handles_.clear();
|
||||
#endif // HAVE_PACKET_SENDER_PCAP_SENDPACKET
|
||||
}
|
||||
|
||||
void PacketSender::default_interface(const NetworkInterface &iface) {
|
||||
default_iface = iface;
|
||||
void PacketSender::default_interface(const NetworkInterface& iface) {
|
||||
default_iface_ = iface;
|
||||
}
|
||||
|
||||
const NetworkInterface& PacketSender::default_interface() const {
|
||||
return default_iface;
|
||||
return default_iface_;
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) || defined(HAVE_PACKET_SENDER_PCAP_SENDPACKET)
|
||||
@@ -141,19 +150,20 @@ const NetworkInterface& PacketSender::default_interface() const {
|
||||
#ifndef _WIN32
|
||||
bool PacketSender::ether_socket_initialized(const NetworkInterface& iface) const {
|
||||
#if defined(BSD) || defined(__FreeBSD_kernel__)
|
||||
return _ether_socket.count(iface.id());
|
||||
return ether_socket_.count(iface.id());
|
||||
#else
|
||||
return _ether_socket != INVALID_RAW_SOCKET;
|
||||
return ether_socket_ != INVALID_RAW_SOCKET;
|
||||
#endif
|
||||
}
|
||||
|
||||
int PacketSender::get_ether_socket(const NetworkInterface& iface) {
|
||||
if(!ether_socket_initialized(iface))
|
||||
int PacketSender::getether_socket_(const NetworkInterface& iface) {
|
||||
if (!ether_socket_initialized(iface)) {
|
||||
open_l2_socket(iface);
|
||||
}
|
||||
#if defined(BSD) || defined(__FreeBSD_kernel__)
|
||||
return _ether_socket[iface.id()];
|
||||
return ether_socket_[iface.id()];
|
||||
#else
|
||||
return _ether_socket;
|
||||
return ether_socket_;
|
||||
#endif
|
||||
}
|
||||
#endif // _WIN32
|
||||
@@ -161,6 +171,8 @@ int PacketSender::get_ether_socket(const NetworkInterface& iface) {
|
||||
#ifdef HAVE_PACKET_SENDER_PCAP_SENDPACKET
|
||||
|
||||
pcap_t* PacketSender::make_pcap_handle(const NetworkInterface& iface) const {
|
||||
// This is an ugly fix to make interface names look like what
|
||||
// libpcap expects on Windows
|
||||
#ifdef _WIN32
|
||||
#define TINS_PREFIX_INTERFACE(x) ("\\Device\\NPF_" + x)
|
||||
#else // _WIN32
|
||||
@@ -185,41 +197,45 @@ pcap_t* PacketSender::make_pcap_handle(const NetworkInterface& iface) const {
|
||||
|
||||
void PacketSender::open_l2_socket(const NetworkInterface& iface) {
|
||||
#ifdef HAVE_PACKET_SENDER_PCAP_SENDPACKET
|
||||
if (pcap_handles.count(iface) == 0) {
|
||||
pcap_handles.insert(std::make_pair(iface, make_pcap_handle(iface)));
|
||||
if (pcap_handles_.count(iface) == 0) {
|
||||
pcap_handles_.insert(make_pair(iface, make_pcap_handle(iface)));
|
||||
}
|
||||
#elif defined(BSD) || defined(__FreeBSD_kernel__)
|
||||
int sock = -1;
|
||||
// At some point, there should be an available device
|
||||
for (int i = 0; sock == -1;i++) {
|
||||
std::ostringstream oss;
|
||||
ostringstream oss;
|
||||
oss << "/dev/bpf" << i;
|
||||
|
||||
sock = open(oss.str().c_str(), O_RDWR);
|
||||
}
|
||||
if(sock == -1)
|
||||
if (sock == -1) {
|
||||
throw socket_open_error(make_error_string());
|
||||
}
|
||||
|
||||
struct ifreq ifr;
|
||||
strncpy(ifr.ifr_name, iface.name().c_str(), sizeof(ifr.ifr_name) - 1);
|
||||
if(ioctl(sock, BIOCSETIF, (caddr_t)&ifr) < 0) {
|
||||
if (ioctl(sock, BIOCSETIF, (caddr_t)&ifr) < 0) {
|
||||
::close(sock);
|
||||
throw socket_open_error(make_error_string());
|
||||
}
|
||||
// Use immediate mode
|
||||
u_int value = 1;
|
||||
if(ioctl(sock, BIOCIMMEDIATE, &value) < 0)
|
||||
if (ioctl(sock, BIOCIMMEDIATE, &value) < 0) {
|
||||
throw socket_open_error(make_error_string());
|
||||
}
|
||||
// Get the buffer size
|
||||
if(ioctl(sock, BIOCGBLEN, &buffer_size) < 0)
|
||||
if (ioctl(sock, BIOCGBLEN, &buffer_size_) < 0) {
|
||||
throw socket_open_error(make_error_string());
|
||||
_ether_socket[iface.id()] = sock;
|
||||
}
|
||||
ether_socket_[iface.id()] = sock;
|
||||
#else
|
||||
if (_ether_socket == INVALID_RAW_SOCKET) {
|
||||
_ether_socket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
|
||||
if (ether_socket_ == INVALID_RAW_SOCKET) {
|
||||
ether_socket_ = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
|
||||
|
||||
if (_ether_socket == -1)
|
||||
if (ether_socket_ == -1) {
|
||||
throw socket_open_error(make_error_string());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -227,13 +243,15 @@ void PacketSender::open_l2_socket(const NetworkInterface& iface) {
|
||||
|
||||
void PacketSender::open_l3_socket(SocketType type) {
|
||||
int socktype = find_type(type);
|
||||
if(socktype == -1)
|
||||
if (socktype == -1) {
|
||||
throw invalid_socket_type();
|
||||
if(_sockets[type] == INVALID_RAW_SOCKET) {
|
||||
}
|
||||
if (sockets_[type] == INVALID_RAW_SOCKET) {
|
||||
socket_type sockfd;
|
||||
sockfd = socket((type == IPV6_SOCKET) ? AF_INET6 : AF_INET, SOCK_RAW, socktype);
|
||||
if (sockfd < 0)
|
||||
if (sockfd < 0) {
|
||||
throw socket_open_error(make_error_string());
|
||||
}
|
||||
|
||||
const int on = 1;
|
||||
#ifndef _WIN32
|
||||
@@ -243,93 +261,109 @@ void PacketSender::open_l3_socket(SocketType type) {
|
||||
#endif
|
||||
setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL,(option_ptr)&on,sizeof(on));
|
||||
|
||||
_sockets[type] = static_cast<int>(sockfd);
|
||||
sockets_[type] = static_cast<int>(sockfd);
|
||||
}
|
||||
}
|
||||
|
||||
void PacketSender::close_socket(SocketType type, const NetworkInterface &iface) {
|
||||
if(type == ETHER_SOCKET) {
|
||||
void PacketSender::close_socket(SocketType type, const NetworkInterface& iface) {
|
||||
if (type == ETHER_SOCKET) {
|
||||
#if defined(BSD) || defined(__FreeBSD_kernel__)
|
||||
BSDEtherSockets::iterator it = _ether_socket.find(iface.id());
|
||||
if(it == _ether_socket.end())
|
||||
BSDEtherSockets::iterator it = ether_socket_.find(iface.id());
|
||||
if (it == ether_socket_.end()) {
|
||||
throw invalid_socket_type();
|
||||
if(::close(it->second) == -1)
|
||||
}
|
||||
if (::close(it->second) == -1) {
|
||||
throw socket_close_error(make_error_string());
|
||||
_ether_socket.erase(it);
|
||||
}
|
||||
ether_socket_.erase(it);
|
||||
#elif !defined(_WIN32)
|
||||
if(_ether_socket == INVALID_RAW_SOCKET)
|
||||
if (ether_socket_ == INVALID_RAW_SOCKET) {
|
||||
throw invalid_socket_type();
|
||||
if(::close(_ether_socket) == -1)
|
||||
}
|
||||
if (::close(ether_socket_) == -1) {
|
||||
throw socket_close_error(make_error_string());
|
||||
_ether_socket = INVALID_RAW_SOCKET;
|
||||
}
|
||||
ether_socket_ = INVALID_RAW_SOCKET;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
if(type >= SOCKETS_END || _sockets[type] == INVALID_RAW_SOCKET)
|
||||
if (type >= SOCKETS_END || sockets_[type] == INVALID_RAW_SOCKET) {
|
||||
throw invalid_socket_type();
|
||||
}
|
||||
#ifndef _WIN32
|
||||
if(close(_sockets[type]) == -1)
|
||||
if (close(sockets_[type]) == -1) {
|
||||
throw socket_close_error(make_error_string());
|
||||
}
|
||||
#else
|
||||
closesocket(_sockets[type]);
|
||||
closesocket(sockets_[type]);
|
||||
#endif
|
||||
_sockets[type] = INVALID_RAW_SOCKET;
|
||||
sockets_[type] = INVALID_RAW_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
void PacketSender::send(PDU &pdu) {
|
||||
pdu.send(*this, default_iface);
|
||||
void PacketSender::send(PDU& pdu) {
|
||||
pdu.send(*this, default_iface_);
|
||||
}
|
||||
|
||||
void PacketSender::send(PDU &pdu, const NetworkInterface &iface) {
|
||||
if (pdu.matches_flag(PDU::ETHERNET_II))
|
||||
void PacketSender::send(PDU& pdu, const NetworkInterface& iface) {
|
||||
if (pdu.matches_flag(PDU::ETHERNET_II)) {
|
||||
send<Tins::EthernetII>(pdu, iface);
|
||||
}
|
||||
#ifdef HAVE_DOT11
|
||||
else if (pdu.matches_flag(PDU::DOT11))
|
||||
else if (pdu.matches_flag(PDU::DOT11)) {
|
||||
send<Tins::Dot11>(pdu, iface);
|
||||
else if (pdu.matches_flag(PDU::RADIOTAP))
|
||||
}
|
||||
else if (pdu.matches_flag(PDU::RADIOTAP)) {
|
||||
send<Tins::RadioTap>(pdu, iface);
|
||||
}
|
||||
#endif // HAVE_DOT11
|
||||
else if (pdu.matches_flag(PDU::IEEE802_3))
|
||||
else if (pdu.matches_flag(PDU::IEEE802_3)) {
|
||||
send<Tins::IEEE802_3>(pdu, iface);
|
||||
else send(pdu);
|
||||
}
|
||||
else {
|
||||
send(pdu);
|
||||
}
|
||||
}
|
||||
|
||||
PDU *PacketSender::send_recv(PDU &pdu) {
|
||||
return send_recv(pdu, default_iface);
|
||||
PDU* PacketSender::send_recv(PDU& pdu) {
|
||||
return send_recv(pdu, default_iface_);
|
||||
}
|
||||
|
||||
PDU *PacketSender::send_recv(PDU &pdu, const NetworkInterface &iface) {
|
||||
PDU* PacketSender::send_recv(PDU& pdu, const NetworkInterface& iface) {
|
||||
try {
|
||||
pdu.send(*this, iface);
|
||||
}
|
||||
catch(runtime_error&) {
|
||||
catch (runtime_error&) {
|
||||
return 0;
|
||||
}
|
||||
return pdu.recv_response(*this, iface);
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) || defined(HAVE_PACKET_SENDER_PCAP_SENDPACKET)
|
||||
void PacketSender::send_l2(PDU &pdu, struct sockaddr* link_addr,
|
||||
uint32_t len_addr, const NetworkInterface &iface)
|
||||
{
|
||||
void PacketSender::send_l2(PDU& pdu,
|
||||
struct sockaddr* link_addr,
|
||||
uint32_t len_addr,
|
||||
const NetworkInterface& iface) {
|
||||
PDU::serialization_type buffer = pdu.serialize();
|
||||
|
||||
#ifdef HAVE_PACKET_SENDER_PCAP_SENDPACKET
|
||||
open_l2_socket(iface);
|
||||
pcap_t* handle = pcap_handles[iface];
|
||||
if (pcap_sendpacket(handle, (u_char*)&buffer[0], static_cast<int>(buffer.size())) != 0) {
|
||||
throw runtime_error("Failed to send packet: " + string(pcap_geterr(handle)));
|
||||
pcap_t* handle = pcap_handles_[iface];
|
||||
const int buf_size = static_cast<int>(buffer.size());
|
||||
if (pcap_sendpacket(handle, (u_char*)&buffer[0], buf_size) != 0) {
|
||||
throw runtime_error("Failed to send packet: " +
|
||||
string(pcap_geterr(handle)));
|
||||
}
|
||||
#else // HAVE_PACKET_SENDER_PCAP_SENDPACKET
|
||||
int sock = get_ether_socket(iface);
|
||||
if(!buffer.empty()) {
|
||||
int sock = getether_socket_(iface);
|
||||
if (!buffer.empty()) {
|
||||
#if defined(BSD) || defined(__FreeBSD_kernel__)
|
||||
if(::write(sock, &buffer[0], buffer.size()) == -1)
|
||||
if (::write(sock, &buffer[0], buffer.size()) == -1) {
|
||||
#else
|
||||
if(::sendto(sock, &buffer[0], buffer.size(), 0, link_addr, len_addr) == -1)
|
||||
if (::sendto(sock, &buffer[0], buffer.size(), 0, link_addr, len_addr) == -1) {
|
||||
#endif
|
||||
throw socket_write_error(make_error_string());
|
||||
}
|
||||
}
|
||||
#endif // HAVE_PACKET_SENDER_PCAP_SENDPACKET
|
||||
}
|
||||
@@ -337,37 +371,49 @@ void PacketSender::send_l2(PDU &pdu, struct sockaddr* link_addr,
|
||||
#endif // !_WIN32 || HAVE_PACKET_SENDER_PCAP_SENDPACKET
|
||||
|
||||
#ifndef _WIN32
|
||||
PDU *PacketSender::recv_l2(PDU &pdu, struct sockaddr *link_addr,
|
||||
uint32_t len_addr, const NetworkInterface &iface)
|
||||
{
|
||||
int sock = get_ether_socket(iface);
|
||||
std::vector<int> sockets(1, sock);
|
||||
PDU* PacketSender::recv_l2(PDU& pdu,
|
||||
struct sockaddr* link_addr,
|
||||
uint32_t len_addr,
|
||||
const NetworkInterface& iface) {
|
||||
int sock = getether_socket_(iface);
|
||||
vector<int> sockets(1, sock);
|
||||
return recv_match_loop(sockets, pdu, link_addr, len_addr);
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
PDU *PacketSender::recv_l3(PDU &pdu, struct sockaddr* link_addr, uint32_t len_addr, SocketType type) {
|
||||
PDU* PacketSender::recv_l3(PDU& pdu,
|
||||
struct sockaddr* link_addr,
|
||||
uint32_t len_addr,
|
||||
SocketType type) {
|
||||
open_l3_socket(type);
|
||||
std::vector<int> sockets(1, _sockets[type]);
|
||||
if(type == IP_TCP_SOCKET || type == IP_UDP_SOCKET) {
|
||||
vector<int> sockets(1, sockets_[type]);
|
||||
if (type == IP_TCP_SOCKET || type == IP_UDP_SOCKET) {
|
||||
#ifdef BSD
|
||||
throw runtime_error("Receiving L3 packets not supported on this platform");
|
||||
#endif
|
||||
open_l3_socket(ICMP_SOCKET);
|
||||
sockets.push_back(_sockets[ICMP_SOCKET]);
|
||||
sockets.push_back(sockets_[ICMP_SOCKET]);
|
||||
}
|
||||
return recv_match_loop(sockets, pdu, link_addr, len_addr);
|
||||
}
|
||||
|
||||
void PacketSender::send_l3(PDU &pdu, struct sockaddr* link_addr, uint32_t len_addr, SocketType type) {
|
||||
void PacketSender::send_l3(PDU& pdu,
|
||||
struct sockaddr* link_addr,
|
||||
uint32_t len_addr,
|
||||
SocketType type) {
|
||||
open_l3_socket(type);
|
||||
int sock = _sockets[type];
|
||||
int sock = sockets_[type];
|
||||
PDU::serialization_type buffer = pdu.serialize();
|
||||
if(sendto(sock, (const char*)&buffer[0], static_cast<int>(buffer.size()), 0, link_addr, len_addr) == -1)
|
||||
const int buf_size = static_cast<int>(buffer.size());
|
||||
if (sendto(sock, (const char*)&buffer[0], buf_size, 0, link_addr, len_addr) == -1) {
|
||||
throw socket_write_error(make_error_string());
|
||||
}
|
||||
}
|
||||
|
||||
PDU *PacketSender::recv_match_loop(const std::vector<int>& sockets, PDU &pdu, struct sockaddr* link_addr, uint32_t addrlen) {
|
||||
PDU* PacketSender::recv_match_loop(const vector<int>& sockets,
|
||||
PDU& pdu,
|
||||
struct sockaddr* link_addr,
|
||||
uint32_t addrlen) {
|
||||
#ifdef _WIN32
|
||||
typedef int socket_len_type;
|
||||
typedef int recvfrom_ret_type;
|
||||
@@ -379,9 +425,9 @@ PDU *PacketSender::recv_match_loop(const std::vector<int>& sockets, PDU &pdu, st
|
||||
struct timeval timeout, end_time;
|
||||
int read;
|
||||
#if defined(BSD) || defined(__FreeBSD_kernel__)
|
||||
// On *BSD, we need to allocate a buffer using the given size.
|
||||
std::vector<uint8_t> actual_buffer(buffer_size);
|
||||
uint8_t *buffer = &actual_buffer[0];
|
||||
// On* BSD, we need to allocate a buffer using the given size.
|
||||
vector<uint8_t> actual_buffer(buffer_size_);
|
||||
uint8_t* buffer = &actual_buffer[0];
|
||||
#else
|
||||
uint8_t buffer[2048];
|
||||
const int buffer_size = 2048;
|
||||
@@ -389,28 +435,29 @@ PDU *PacketSender::recv_match_loop(const std::vector<int>& sockets, PDU &pdu, st
|
||||
|
||||
timeout.tv_sec = _timeout;
|
||||
end_time.tv_sec = static_cast<long>(time(0) + _timeout);
|
||||
end_time.tv_usec = timeout.tv_usec = _timeout_usec;
|
||||
while(true) {
|
||||
end_time.tv_usec = timeout.tv_usec = timeout_usec_;
|
||||
while (true) {
|
||||
FD_ZERO(&readfds);
|
||||
int max_fd = 0;
|
||||
for(std::vector<int>::const_iterator it = sockets.begin(); it != sockets.end(); ++it) {
|
||||
for (vector<int>::const_iterator it = sockets.begin(); it != sockets.end(); ++it) {
|
||||
FD_SET(*it, &readfds);
|
||||
max_fd = std::max(max_fd, *it);
|
||||
max_fd = max(max_fd, *it);
|
||||
}
|
||||
if((read = select(max_fd + 1, &readfds, 0, 0, &timeout)) == -1)
|
||||
if ((read = select(max_fd + 1, &readfds, 0, 0, &timeout)) == -1) {
|
||||
return 0;
|
||||
if(read > 0) {
|
||||
for(std::vector<int>::const_iterator it = sockets.begin(); it != sockets.end(); ++it) {
|
||||
if(FD_ISSET(*it, &readfds)) {
|
||||
}
|
||||
if (read > 0) {
|
||||
for (vector<int>::const_iterator it = sockets.begin(); it != sockets.end(); ++it) {
|
||||
if (FD_ISSET(*it, &readfds)) {
|
||||
recvfrom_ret_type size;
|
||||
#if defined(BSD) || defined(__FreeBSD_kernel__)
|
||||
size = ::read(*it, buffer, buffer_size);
|
||||
size = ::read(*it, buffer, buffer_size_);
|
||||
const uint8_t* ptr = buffer;
|
||||
// We might see more than one packet
|
||||
while(ptr < (buffer + size)) {
|
||||
while (ptr < (buffer + size)) {
|
||||
const bpf_hdr* bpf_header = reinterpret_cast<const bpf_hdr*>(ptr);
|
||||
const uint8_t *pkt_start = ptr + bpf_header->bh_hdrlen;
|
||||
if(pdu.matches_response(pkt_start, bpf_header->bh_caplen)) {
|
||||
const uint8_t* pkt_start = ptr + bpf_header->bh_hdrlen;
|
||||
if (pdu.matches_response(pkt_start, bpf_header->bh_caplen)) {
|
||||
return Internals::pdu_from_flag(pdu.pdu_type(), pkt_start, bpf_header->bh_caplen);
|
||||
}
|
||||
ptr += BPF_WORDALIGN(bpf_header->bh_hdrlen + bpf_header->bh_caplen);
|
||||
@@ -418,7 +465,7 @@ PDU *PacketSender::recv_match_loop(const std::vector<int>& sockets, PDU &pdu, st
|
||||
#else
|
||||
socket_len_type length = addrlen;
|
||||
size = ::recvfrom(*it, (char*)buffer, buffer_size, 0, link_addr, &length);
|
||||
if(pdu.matches_response(buffer, size)) {
|
||||
if (pdu.matches_response(buffer, size)) {
|
||||
return Internals::pdu_from_flag(pdu.pdu_type(), buffer, size);
|
||||
}
|
||||
#endif
|
||||
@@ -431,15 +478,16 @@ PDU *PacketSender::recv_match_loop(const std::vector<int>& sockets, PDU &pdu, st
|
||||
#else
|
||||
gettimeofday(&this_time, 0);
|
||||
#endif // _WIN32
|
||||
if(timeval_subtract(&diff, &end_time, &this_time))
|
||||
if (timeval_subtract(&diff, &end_time, &this_time)) {
|
||||
return 0;
|
||||
}
|
||||
timeout.tv_sec = diff.tv_sec;
|
||||
timeout.tv_usec = diff.tv_usec;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PacketSender::timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y) {
|
||||
int PacketSender::timeval_subtract (struct timeval* result, struct timeval* x, struct timeval* y) {
|
||||
/* Perform the carry for the later subtraction by updating y. */
|
||||
if (x->tv_usec < y->tv_usec) {
|
||||
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
|
||||
@@ -463,10 +511,13 @@ int PacketSender::timeval_subtract (struct timeval *result, struct timeval *x, s
|
||||
}
|
||||
|
||||
int PacketSender::find_type(SocketType type) {
|
||||
SocketTypeMap::iterator it = _types.find(type);
|
||||
if(it == _types.end())
|
||||
SocketTypeMap::iterator it = types_.find(type);
|
||||
if (it == types_.end()) {
|
||||
return -1;
|
||||
else
|
||||
}
|
||||
else {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
@@ -34,20 +34,24 @@
|
||||
#include "packet_writer.h"
|
||||
#include "packet.h"
|
||||
#include "pdu.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace Tins {
|
||||
PacketWriter::PacketWriter(const std::string &file_name, LinkType lt) {
|
||||
|
||||
PacketWriter::PacketWriter(const string& file_name, LinkType lt) {
|
||||
init(file_name, lt);
|
||||
}
|
||||
|
||||
PacketWriter::~PacketWriter() {
|
||||
if(dumper && handle) {
|
||||
pcap_dump_close(dumper);
|
||||
pcap_close(handle);
|
||||
if (dumper_ && handle_) {
|
||||
pcap_dump_close(dumper_);
|
||||
pcap_close(handle_);
|
||||
}
|
||||
}
|
||||
|
||||
void PacketWriter::write(PDU &pdu) {
|
||||
void PacketWriter::write(PDU& pdu) {
|
||||
timeval tv;
|
||||
#ifndef _WIN32
|
||||
gettimeofday(&tv, 0);
|
||||
@@ -58,7 +62,7 @@ void PacketWriter::write(PDU &pdu) {
|
||||
write(pdu, tv);
|
||||
}
|
||||
|
||||
void PacketWriter::write(Packet &packet) {
|
||||
void PacketWriter::write(Packet& packet) {
|
||||
timeval tv;
|
||||
tv.tv_sec = packet.timestamp().seconds();
|
||||
tv.tv_usec = packet.timestamp().microseconds();
|
||||
@@ -72,19 +76,19 @@ void PacketWriter::write(PDU& pdu, const struct timeval& tv) {
|
||||
static_cast<bpf_u_int32>(buffer.size()),
|
||||
static_cast<bpf_u_int32>(buffer.size())
|
||||
};
|
||||
pcap_dump((u_char*)dumper, &header, &buffer[0]);
|
||||
pcap_dump((u_char*)dumper_, &header, &buffer[0]);
|
||||
}
|
||||
|
||||
void PacketWriter::init(const std::string& file_name, int link_type) {
|
||||
handle = pcap_open_dead(link_type, 65535);
|
||||
if(!handle)
|
||||
throw std::runtime_error("Error creating pcap handle");
|
||||
dumper = pcap_dump_open(handle, file_name.c_str());
|
||||
if(!dumper) {
|
||||
// RAII plx
|
||||
pcap_close(handle);
|
||||
throw std::runtime_error(pcap_geterr(handle));
|
||||
void PacketWriter::init(const string& file_name, int link_type) {
|
||||
handle_ = pcap_open_dead(link_type, 65535);
|
||||
if (!handle_) {
|
||||
throw pcap_open_failed();
|
||||
}
|
||||
dumper_ = pcap_dump_open(handle_, file_name.c_str());
|
||||
if (!dumper_) {
|
||||
pcap_close(handle_);
|
||||
throw pcap_error(pcap_geterr(handle_));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // Tins
|
||||
|
||||
56
src/pdu.cpp
56
src/pdu.cpp
@@ -31,36 +31,40 @@
|
||||
#include "rawpdu.h"
|
||||
#include "packet_sender.h"
|
||||
|
||||
using std::swap;
|
||||
using std::vector;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
PDU::PDU()
|
||||
: _inner_pdu()
|
||||
{
|
||||
: inner_pdu_() {
|
||||
|
||||
}
|
||||
|
||||
PDU::PDU(const PDU &other) : _inner_pdu(0) {
|
||||
PDU::PDU(const PDU& other)
|
||||
: inner_pdu_(0) {
|
||||
copy_inner_pdu(other);
|
||||
}
|
||||
|
||||
PDU &PDU::operator=(const PDU &other) {
|
||||
PDU& PDU::operator=(const PDU& other) {
|
||||
copy_inner_pdu(other);
|
||||
return *this;
|
||||
return* this;
|
||||
}
|
||||
|
||||
PDU::~PDU() {
|
||||
delete _inner_pdu;
|
||||
delete inner_pdu_;
|
||||
}
|
||||
|
||||
void PDU::copy_inner_pdu(const PDU &pdu) {
|
||||
if(pdu.inner_pdu())
|
||||
void PDU::copy_inner_pdu(const PDU& pdu) {
|
||||
if (pdu.inner_pdu()) {
|
||||
inner_pdu(pdu.inner_pdu()->clone());
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t PDU::size() const {
|
||||
uint32_t sz = header_size() + trailer_size();
|
||||
const PDU *ptr(_inner_pdu);
|
||||
while(ptr) {
|
||||
const PDU* ptr(inner_pdu_);
|
||||
while (ptr) {
|
||||
sz += ptr->header_size() + ptr->trailer_size();
|
||||
ptr = ptr->inner_pdu();
|
||||
}
|
||||
@@ -71,42 +75,42 @@ void PDU::send(PacketSender &, const NetworkInterface &) {
|
||||
|
||||
}
|
||||
|
||||
PDU *PDU::recv_response(PacketSender &, const NetworkInterface &) {
|
||||
PDU* PDU::recv_response(PacketSender &, const NetworkInterface &) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PDU::inner_pdu(PDU *next_pdu) {
|
||||
delete _inner_pdu;
|
||||
_inner_pdu = next_pdu;
|
||||
void PDU::inner_pdu(PDU* next_pdu) {
|
||||
delete inner_pdu_;
|
||||
inner_pdu_ = next_pdu;
|
||||
}
|
||||
|
||||
void PDU::inner_pdu(const PDU &next_pdu) {
|
||||
void PDU::inner_pdu(const PDU& next_pdu) {
|
||||
inner_pdu(next_pdu.clone());
|
||||
}
|
||||
|
||||
PDU *PDU::release_inner_pdu() {
|
||||
PDU *result = 0;
|
||||
std::swap(result, _inner_pdu);
|
||||
PDU* PDU::release_inner_pdu() {
|
||||
PDU* result = 0;
|
||||
swap(result, inner_pdu_);
|
||||
return result;
|
||||
}
|
||||
|
||||
PDU::serialization_type PDU::serialize() {
|
||||
std::vector<uint8_t> buffer(size());
|
||||
vector<uint8_t> buffer(size());
|
||||
serialize(&buffer[0], static_cast<uint32_t>(buffer.size()), 0);
|
||||
|
||||
// Copy elision, do your magic
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void PDU::serialize(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
|
||||
void PDU::serialize(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
uint32_t sz = header_size() + trailer_size();
|
||||
/* Must not happen... */
|
||||
// Must not happen...
|
||||
#ifdef TINS_DEBUG
|
||||
assert(total_sz >= sz);
|
||||
#endif
|
||||
prepare_for_serialize(parent);
|
||||
if(_inner_pdu)
|
||||
_inner_pdu->serialize(buffer + header_size(), total_sz - sz, this);
|
||||
if (inner_pdu_) {
|
||||
inner_pdu_->serialize(buffer + header_size(), total_sz - sz, this);
|
||||
}
|
||||
write_serialization(buffer, total_sz, parent);
|
||||
}
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "exceptions.h"
|
||||
#include "pktap.h"
|
||||
#include "internals.h"
|
||||
#include "exceptions.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
@@ -64,8 +65,8 @@ uint32_t PKTAP::header_size() const {
|
||||
return sizeof(header_);
|
||||
}
|
||||
|
||||
void PKTAP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
|
||||
throw std::runtime_error("PKTAP cannot be serialized");
|
||||
void PKTAP::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
throw pdu_not_serializable();
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
27
src/ppi.cpp
27
src/ppi.cpp
@@ -45,17 +45,16 @@ using Tins::Memory::InputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
PPI::PPI(const uint8_t *buffer, uint32_t total_sz) {
|
||||
PPI::PPI(const uint8_t* buffer, uint32_t total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_header);
|
||||
if (length() > total_sz || length() < sizeof(_header)) {
|
||||
stream.read(header_);
|
||||
if (length() > total_sz || length() < sizeof(header_)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
// There are some options
|
||||
const size_t options_length = length() - sizeof(_header);
|
||||
const size_t options_length = length() - sizeof(header_);
|
||||
if (options_length > 0) {
|
||||
_data.assign(stream.pointer(), stream.pointer() + options_length);
|
||||
stream.skip(options_length);
|
||||
stream.read(data_, options_length);
|
||||
}
|
||||
if (stream) {
|
||||
switch (dlt()) {
|
||||
@@ -67,10 +66,12 @@ PPI::PPI(const uint8_t *buffer, uint32_t total_sz) {
|
||||
#endif
|
||||
break;
|
||||
case DLT_EN10MB:
|
||||
if(Internals::is_dot3(stream.pointer(), stream.size()))
|
||||
if (Internals::is_dot3(stream.pointer(), stream.size())) {
|
||||
inner_pdu(new Dot3(stream.pointer(), stream.size()));
|
||||
else
|
||||
}
|
||||
else {
|
||||
inner_pdu(new EthernetII(stream.pointer(), stream.size()));
|
||||
}
|
||||
break;
|
||||
case DLT_IEEE802_11_RADIO:
|
||||
#ifdef HAVE_DOT11
|
||||
@@ -90,18 +91,18 @@ PPI::PPI(const uint8_t *buffer, uint32_t total_sz) {
|
||||
}
|
||||
|
||||
uint32_t PPI::header_size() const {
|
||||
return static_cast<uint32_t>(sizeof(_header) + _data.size());
|
||||
return static_cast<uint32_t>(sizeof(header_) + data_.size());
|
||||
}
|
||||
|
||||
void PPI::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
|
||||
throw std::runtime_error("PPI serialization not supported");
|
||||
void PPI::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *) {
|
||||
throw pdu_not_serializable();
|
||||
}
|
||||
|
||||
void PPI::parse_80211(const uint8_t* buffer, uint32_t total_sz) {
|
||||
#ifdef HAVE_DOT11
|
||||
if (_data.size() >= 13) {
|
||||
if (data_.size() >= 13) {
|
||||
// Is FCS-at-end on?
|
||||
if ((_data[12] & 1) == 1) {
|
||||
if ((data_[12] & 1) == 1) {
|
||||
// We need to reduce the total size since we're skipping the FCS
|
||||
if (total_sz < sizeof(uint32_t)) {
|
||||
throw malformed_packet();
|
||||
|
||||
119
src/pppoe.cpp
119
src/pppoe.cpp
@@ -33,23 +33,26 @@
|
||||
#include "exceptions.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::memcpy;
|
||||
using std::copy;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
PPPoE::PPPoE()
|
||||
: _header(), _tags_size()
|
||||
{
|
||||
: header_(), tags_size_() {
|
||||
version(1);
|
||||
type(1);
|
||||
}
|
||||
|
||||
PPPoE::PPPoE(const uint8_t *buffer, uint32_t total_sz)
|
||||
: _tags_size()
|
||||
{
|
||||
PPPoE::PPPoE(const uint8_t* buffer, uint32_t total_sz)
|
||||
: tags_size_() {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_header);
|
||||
stream.read(header_);
|
||||
stream.size(std::min(stream.size(), (uint32_t)payload_length()));
|
||||
// If this is a session data packet
|
||||
if (code() == 0) {
|
||||
@@ -60,11 +63,10 @@ PPPoE::PPPoE(const uint8_t *buffer, uint32_t total_sz)
|
||||
}
|
||||
}
|
||||
else {
|
||||
const uint8_t *end = stream.pointer() + stream.size();
|
||||
while (stream.pointer() < end) {
|
||||
while (stream) {
|
||||
TagTypes opt_type = static_cast<TagTypes>(stream.read<uint16_t>());
|
||||
uint16_t opt_len = Endian::be_to_host(stream.read<uint16_t>());
|
||||
if(!stream.can_read(opt_len)) {
|
||||
uint16_t opt_len = stream.read_be<uint16_t>();
|
||||
if (!stream.can_read(opt_len)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
add_tag(tag(opt_type, opt_len, stream.pointer()));
|
||||
@@ -73,55 +75,55 @@ PPPoE::PPPoE(const uint8_t *buffer, uint32_t total_sz)
|
||||
}
|
||||
}
|
||||
|
||||
const PPPoE::tag *PPPoE::search_tag(TagTypes identifier) const {
|
||||
for(tags_type::const_iterator it = _tags.begin(); it != _tags.end(); ++it) {
|
||||
if(it->option() == identifier)
|
||||
const PPPoE::tag* PPPoE::search_tag(TagTypes identifier) const {
|
||||
for (tags_type::const_iterator it = tags_.begin(); it != tags_.end(); ++it) {
|
||||
if (it->option() == identifier) {
|
||||
return &*it;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PPPoE::version(small_uint<4> new_version) {
|
||||
_header.version = new_version;
|
||||
header_.version = new_version;
|
||||
}
|
||||
|
||||
void PPPoE::type(small_uint<4> new_type) {
|
||||
_header.type = new_type;
|
||||
header_.type = new_type;
|
||||
}
|
||||
|
||||
void PPPoE::code(uint8_t new_code) {
|
||||
_header.code = new_code;
|
||||
header_.code = new_code;
|
||||
}
|
||||
|
||||
void PPPoE::session_id(uint16_t new_session_id) {
|
||||
_header.session_id = Endian::host_to_be(new_session_id);
|
||||
header_.session_id = Endian::host_to_be(new_session_id);
|
||||
}
|
||||
|
||||
void PPPoE::payload_length(uint16_t new_payload_length) {
|
||||
_header.payload_length = Endian::host_to_be(new_payload_length);
|
||||
header_.payload_length = Endian::host_to_be(new_payload_length);
|
||||
}
|
||||
|
||||
uint32_t PPPoE::header_size() const {
|
||||
return sizeof(_header) + _tags_size;
|
||||
return sizeof(header_) + tags_size_;
|
||||
}
|
||||
|
||||
void PPPoE::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *)
|
||||
{
|
||||
void PPPoE::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
if (_tags_size > 0) {
|
||||
payload_length(_tags_size);
|
||||
if (tags_size_ > 0) {
|
||||
payload_length(tags_size_);
|
||||
}
|
||||
stream.write(_header);
|
||||
for(tags_type::const_iterator it = _tags.begin(); it != _tags.end(); ++it) {
|
||||
stream.write(header_);
|
||||
for (tags_type::const_iterator it = tags_.begin(); it != tags_.end(); ++it) {
|
||||
stream.write<uint16_t>(it->option());
|
||||
stream.write(Endian::host_to_be<uint16_t>(it->length_field()));
|
||||
stream.write(it->data_ptr(), it->data_size());
|
||||
}
|
||||
}
|
||||
|
||||
void PPPoE::add_tag(const tag &option) {
|
||||
_tags_size += static_cast<uint16_t>(option.data_size() + sizeof(uint16_t) * 2);
|
||||
_tags.push_back(option);
|
||||
void PPPoE::add_tag(const tag& option) {
|
||||
tags_size_ += static_cast<uint16_t>(option.data_size() + sizeof(uint16_t) * 2);
|
||||
tags_.push_back(option);
|
||||
}
|
||||
|
||||
// *********************** Setters *************************
|
||||
@@ -132,27 +134,27 @@ void PPPoE::end_of_list() {
|
||||
);
|
||||
}
|
||||
|
||||
void PPPoE::service_name(const std::string &value) {
|
||||
void PPPoE::service_name(const string& value) {
|
||||
add_tag_iterable(SERVICE_NAME, value);
|
||||
}
|
||||
|
||||
void PPPoE::ac_name(const std::string &value) {
|
||||
void PPPoE::ac_name(const string& value) {
|
||||
add_tag_iterable(AC_NAME, value);
|
||||
}
|
||||
|
||||
void PPPoE::host_uniq(const byte_array &value) {
|
||||
void PPPoE::host_uniq(const byte_array& value) {
|
||||
add_tag_iterable(HOST_UNIQ, value);
|
||||
}
|
||||
|
||||
void PPPoE::ac_cookie(const byte_array &value) {
|
||||
void PPPoE::ac_cookie(const byte_array& value) {
|
||||
add_tag_iterable(AC_COOKIE, value);
|
||||
}
|
||||
|
||||
void PPPoE::vendor_specific(const vendor_spec_type &value) {
|
||||
std::vector<uint8_t> buffer(sizeof(uint32_t) + value.data.size());
|
||||
void PPPoE::vendor_specific(const vendor_spec_type& value) {
|
||||
vector<uint8_t> buffer(sizeof(uint32_t) + value.data.size());
|
||||
uint32_t tmp_vendor_id = Endian::host_to_be(value.vendor_id);
|
||||
std::memcpy(&buffer[0], &tmp_vendor_id, sizeof(uint32_t));
|
||||
std::copy(
|
||||
memcpy(&buffer[0], &tmp_vendor_id, sizeof(uint32_t));
|
||||
copy(
|
||||
value.data.begin(),
|
||||
value.data.end(),
|
||||
buffer.begin() + sizeof(uint32_t)
|
||||
@@ -166,29 +168,29 @@ void PPPoE::vendor_specific(const vendor_spec_type &value) {
|
||||
);
|
||||
}
|
||||
|
||||
void PPPoE::relay_session_id(const byte_array &value) {
|
||||
void PPPoE::relay_session_id(const byte_array& value) {
|
||||
add_tag_iterable(RELAY_SESSION_ID, value);
|
||||
}
|
||||
|
||||
void PPPoE::service_name_error(const std::string &value) {
|
||||
void PPPoE::service_name_error(const std::string& value) {
|
||||
add_tag_iterable(SERVICE_NAME_ERROR, value);
|
||||
}
|
||||
|
||||
void PPPoE::ac_system_error(const std::string &value) {
|
||||
void PPPoE::ac_system_error(const std::string& value) {
|
||||
add_tag_iterable(AC_SYSTEM_ERROR, value);
|
||||
}
|
||||
|
||||
void PPPoE::generic_error(const std::string &value) {
|
||||
void PPPoE::generic_error(const std::string& value) {
|
||||
add_tag_iterable(GENERIC_ERROR, value);
|
||||
}
|
||||
|
||||
// *********************** Getters *************************
|
||||
|
||||
std::string PPPoE::service_name() const {
|
||||
string PPPoE::service_name() const {
|
||||
return search_and_convert<std::string>(SERVICE_NAME);
|
||||
}
|
||||
|
||||
std::string PPPoE::ac_name() const {
|
||||
string PPPoE::ac_name() const {
|
||||
return search_and_convert<std::string>(AC_NAME);
|
||||
}
|
||||
|
||||
@@ -201,9 +203,10 @@ byte_array PPPoE::ac_cookie() const {
|
||||
}
|
||||
|
||||
PPPoE::vendor_spec_type PPPoE::vendor_specific() const {
|
||||
const tag *t = search_tag(VENDOR_SPECIFIC);
|
||||
if(!t)
|
||||
const tag* t = search_tag(VENDOR_SPECIFIC);
|
||||
if (!t) {
|
||||
throw option_not_found();
|
||||
}
|
||||
return t->to<vendor_spec_type>();
|
||||
}
|
||||
|
||||
@@ -211,29 +214,27 @@ byte_array PPPoE::relay_session_id() const {
|
||||
return search_and_convert<byte_array>(RELAY_SESSION_ID);
|
||||
}
|
||||
|
||||
std::string PPPoE::service_name_error() const {
|
||||
return search_and_convert<std::string>(SERVICE_NAME_ERROR);
|
||||
string PPPoE::service_name_error() const {
|
||||
return search_and_convert<string>(SERVICE_NAME_ERROR);
|
||||
}
|
||||
|
||||
std::string PPPoE::ac_system_error() const {
|
||||
return search_and_convert<std::string>(AC_SYSTEM_ERROR);
|
||||
string PPPoE::ac_system_error() const {
|
||||
return search_and_convert<string>(AC_SYSTEM_ERROR);
|
||||
}
|
||||
|
||||
std::string PPPoE::generic_error() const {
|
||||
return search_and_convert<std::string>(GENERIC_ERROR);
|
||||
string PPPoE::generic_error() const {
|
||||
return search_and_convert<string>(GENERIC_ERROR);
|
||||
}
|
||||
|
||||
PPPoE::vendor_spec_type PPPoE::vendor_spec_type::from_option(const tag &opt) {
|
||||
if(opt.data_size() < sizeof(uint32_t))
|
||||
PPPoE::vendor_spec_type PPPoE::vendor_spec_type::from_option(const tag& opt) {
|
||||
if (opt.data_size() < sizeof(uint32_t)) {
|
||||
throw malformed_option();
|
||||
}
|
||||
vendor_spec_type output;
|
||||
std::memcpy(&output.vendor_id, opt.data_ptr(), sizeof(uint32_t));
|
||||
output.vendor_id = Endian::be_to_host(output.vendor_id);
|
||||
output.data.assign(
|
||||
opt.data_ptr() + sizeof(uint32_t),
|
||||
opt.data_ptr() + opt.data_size()
|
||||
);
|
||||
InputMemoryStream stream(opt.data_ptr(), opt.data_size());
|
||||
output.vendor_id = stream.read_be<uint32_t>();
|
||||
stream.read(output.data, stream.size());
|
||||
return output;
|
||||
}
|
||||
} //namespace Tins
|
||||
|
||||
} //namespace Tins
|
||||
|
||||
429
src/radiotap.cpp
429
src/radiotap.cpp
@@ -49,33 +49,34 @@
|
||||
#include "exceptions.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::memcpy;
|
||||
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
void check_size(uint32_t total_sz, size_t field_size) {
|
||||
if(total_sz < field_size)
|
||||
if (total_sz < field_size) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void read_field(const uint8_t* &buffer, uint32_t &total_sz, T& field) {
|
||||
void read_field(const uint8_t* &buffer, uint32_t& total_sz, T& field) {
|
||||
check_size(total_sz, sizeof(field));
|
||||
memcpy(&field, buffer, sizeof(field));
|
||||
buffer += sizeof(field);
|
||||
total_sz -= sizeof(field);
|
||||
}
|
||||
|
||||
RadioTap::RadioTap() : _radio()
|
||||
{
|
||||
RadioTap::RadioTap() : radio_() {
|
||||
init();
|
||||
}
|
||||
|
||||
RadioTap::RadioTap(const uint8_t *buffer, uint32_t total_sz)
|
||||
{
|
||||
check_size(total_sz, sizeof(_radio));
|
||||
const uint8_t *buffer_start = buffer;
|
||||
std::memcpy(&_radio, buffer, sizeof(_radio));
|
||||
RadioTap::RadioTap(const uint8_t* buffer, uint32_t total_sz) {
|
||||
check_size(total_sz, sizeof(radio_));
|
||||
const uint8_t* buffer_start = buffer;
|
||||
memcpy(&radio_, buffer, sizeof(radio_));
|
||||
uint32_t radiotap_hdr_size = length();
|
||||
check_size(total_sz, radiotap_hdr_size);
|
||||
// We start on the first flags field, skipping version, pad and length.
|
||||
@@ -86,74 +87,81 @@ RadioTap::RadioTap(const uint8_t *buffer, uint32_t total_sz)
|
||||
buffer += extra_flags_size;
|
||||
radiotap_hdr_size -= extra_flags_size;
|
||||
// Also skip the header
|
||||
buffer += sizeof(_radio);
|
||||
radiotap_hdr_size -= sizeof(_radio);
|
||||
buffer += sizeof(radio_);
|
||||
radiotap_hdr_size -= sizeof(radio_);
|
||||
|
||||
while(true) {
|
||||
_radio.flags_32 |= *(const uint32_t*)current_flags;
|
||||
if(current_flags->tsft) {
|
||||
while (true) {
|
||||
radio_.flags_32 |= *(const uint32_t*)current_flags;
|
||||
if (current_flags->tsft) {
|
||||
align_buffer<8>(buffer_start, buffer, radiotap_hdr_size);
|
||||
read_field(buffer, radiotap_hdr_size, _tsft);
|
||||
read_field(buffer, radiotap_hdr_size, tsft_);
|
||||
}
|
||||
|
||||
if(current_flags->flags)
|
||||
read_field(buffer, radiotap_hdr_size, _flags);
|
||||
if (current_flags->flags) {
|
||||
read_field(buffer, radiotap_hdr_size, flags_);
|
||||
}
|
||||
|
||||
if(current_flags->rate)
|
||||
read_field(buffer, radiotap_hdr_size, _rate);
|
||||
if (current_flags->rate) {
|
||||
read_field(buffer, radiotap_hdr_size, rate_);
|
||||
}
|
||||
|
||||
if(current_flags->channel) {
|
||||
if (current_flags->channel) {
|
||||
align_buffer<2>(buffer_start, buffer, radiotap_hdr_size);
|
||||
read_field(buffer, radiotap_hdr_size, _channel_freq);
|
||||
read_field(buffer, radiotap_hdr_size, _channel_type);
|
||||
read_field(buffer, radiotap_hdr_size, channel_freq_);
|
||||
read_field(buffer, radiotap_hdr_size, channel_type_);
|
||||
}
|
||||
|
||||
if(current_flags->dbm_signal)
|
||||
read_field(buffer, radiotap_hdr_size, _dbm_signal);
|
||||
if (current_flags->dbm_signal) {
|
||||
read_field(buffer, radiotap_hdr_size, dbm_signal_);
|
||||
}
|
||||
|
||||
if(current_flags->dbm_noise)
|
||||
read_field(buffer, radiotap_hdr_size, _dbm_noise);
|
||||
if (current_flags->dbm_noise) {
|
||||
read_field(buffer, radiotap_hdr_size, dbm_noise_);
|
||||
}
|
||||
|
||||
if(current_flags->lock_quality)
|
||||
read_field(buffer, radiotap_hdr_size, _signal_quality);
|
||||
if (current_flags->lock_quality) {
|
||||
read_field(buffer, radiotap_hdr_size, signal_quality_);
|
||||
}
|
||||
|
||||
if(current_flags->antenna)
|
||||
read_field(buffer, radiotap_hdr_size, _antenna);
|
||||
if (current_flags->antenna) {
|
||||
read_field(buffer, radiotap_hdr_size, antenna_);
|
||||
}
|
||||
|
||||
if(current_flags->db_signal)
|
||||
read_field(buffer, radiotap_hdr_size, _db_signal);
|
||||
if (current_flags->db_signal) {
|
||||
read_field(buffer, radiotap_hdr_size, db_signal_);
|
||||
}
|
||||
|
||||
if(current_flags->rx_flags) {
|
||||
if (current_flags->rx_flags) {
|
||||
align_buffer<2>(buffer_start, buffer, radiotap_hdr_size);
|
||||
read_field(buffer, radiotap_hdr_size, _rx_flags);
|
||||
read_field(buffer, radiotap_hdr_size, rx_flags_);
|
||||
}
|
||||
|
||||
if(current_flags->tx_flags) {
|
||||
if (current_flags->tx_flags) {
|
||||
align_buffer<2>(buffer_start, buffer, radiotap_hdr_size);
|
||||
read_field(buffer, radiotap_hdr_size, _tx_flags);
|
||||
read_field(buffer, radiotap_hdr_size, tx_flags_);
|
||||
}
|
||||
|
||||
if(current_flags->data_retries) {
|
||||
read_field(buffer, radiotap_hdr_size, _data_retries);
|
||||
if (current_flags->data_retries) {
|
||||
read_field(buffer, radiotap_hdr_size, data_retries_);
|
||||
}
|
||||
|
||||
if(current_flags->channel_plus) {
|
||||
if (current_flags->channel_plus) {
|
||||
align_buffer<4>(buffer_start, buffer, radiotap_hdr_size);
|
||||
uint32_t dummy;
|
||||
read_field(buffer, radiotap_hdr_size, dummy);
|
||||
// nasty Big Endian fix
|
||||
_channel_type = Endian::le_to_host<uint16_t>(Endian::host_to_le<uint32_t>(dummy));
|
||||
read_field(buffer, radiotap_hdr_size, _channel_freq);
|
||||
read_field(buffer, radiotap_hdr_size, _channel);
|
||||
read_field(buffer, radiotap_hdr_size, _max_power);
|
||||
channel_type_ = Endian::le_to_host<uint16_t>(Endian::host_to_le<uint32_t>(dummy));
|
||||
read_field(buffer, radiotap_hdr_size, channel_freq_);
|
||||
read_field(buffer, radiotap_hdr_size, channel_);
|
||||
read_field(buffer, radiotap_hdr_size, max_power_);
|
||||
}
|
||||
if(current_flags->mcs) {
|
||||
read_field(buffer, radiotap_hdr_size, _mcs.known);
|
||||
read_field(buffer, radiotap_hdr_size, _mcs.flags);
|
||||
read_field(buffer, radiotap_hdr_size, _mcs.mcs);
|
||||
if (current_flags->mcs) {
|
||||
read_field(buffer, radiotap_hdr_size, mcs_.known);
|
||||
read_field(buffer, radiotap_hdr_size, mcs_.flags);
|
||||
read_field(buffer, radiotap_hdr_size, mcs_.mcs);
|
||||
}
|
||||
// We can do this safely because we checked the size on find_extra_flags...
|
||||
if(current_flags->ext == 1) {
|
||||
if (current_flags->ext == 1) {
|
||||
current_flags++;
|
||||
}
|
||||
else {
|
||||
@@ -164,15 +172,17 @@ RadioTap::RadioTap(const uint8_t *buffer, uint32_t total_sz)
|
||||
total_sz -= length();
|
||||
buffer += radiotap_hdr_size;
|
||||
|
||||
if(_radio.flags.flags && (flags() & FCS) != 0) {
|
||||
if (radio_.flags.flags && (flags() & FCS) != 0) {
|
||||
check_size(total_sz, sizeof(uint32_t));
|
||||
total_sz -= sizeof(uint32_t);
|
||||
if((flags() & FAILED_FCS) !=0)
|
||||
if ((flags() & FAILED_FCS) !=0) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
}
|
||||
|
||||
if(total_sz)
|
||||
if (total_sz) {
|
||||
inner_pdu(Dot11::from_bytes(buffer, total_sz));
|
||||
}
|
||||
}
|
||||
|
||||
void RadioTap::init() {
|
||||
@@ -200,241 +210,266 @@ uint32_t RadioTap::find_extra_flag_fields_size(const uint8_t* buffer, uint32_t t
|
||||
|
||||
// Setter for RadioTap fields
|
||||
void RadioTap::version(uint8_t new_version) {
|
||||
_radio.it_version = new_version;
|
||||
radio_.it_version = new_version;
|
||||
}
|
||||
|
||||
void RadioTap::padding(uint8_t new_padding) {
|
||||
_radio.it_pad = new_padding;
|
||||
radio_.it_pad = new_padding;
|
||||
}
|
||||
|
||||
void RadioTap::length(uint16_t new_length) {
|
||||
_radio.it_len = Endian::host_to_le(new_length);
|
||||
radio_.it_len = Endian::host_to_le(new_length);
|
||||
}
|
||||
|
||||
void RadioTap::tsft(uint64_t new_tsft) {
|
||||
_tsft = Endian::host_to_le(new_tsft);
|
||||
_radio.flags.tsft = 1;
|
||||
tsft_ = Endian::host_to_le(new_tsft);
|
||||
radio_.flags.tsft = 1;
|
||||
}
|
||||
|
||||
void RadioTap::flags(FrameFlags new_flags) {
|
||||
_flags = (uint8_t)new_flags;
|
||||
_radio.flags.flags = 1;
|
||||
flags_ = (uint8_t)new_flags;
|
||||
radio_.flags.flags = 1;
|
||||
}
|
||||
|
||||
void RadioTap::rate(uint8_t new_rate) {
|
||||
_rate = new_rate;
|
||||
_radio.flags.rate = 1;
|
||||
rate_ = new_rate;
|
||||
radio_.flags.rate = 1;
|
||||
}
|
||||
|
||||
void RadioTap::channel(uint16_t new_freq, uint16_t new_type) {
|
||||
_channel_freq = Endian::host_to_le(new_freq);
|
||||
_channel_type = Endian::host_to_le(new_type);
|
||||
_radio.flags.channel = 1;
|
||||
channel_freq_ = Endian::host_to_le(new_freq);
|
||||
channel_type_ = Endian::host_to_le(new_type);
|
||||
radio_.flags.channel = 1;
|
||||
}
|
||||
void RadioTap::dbm_signal(int8_t new_dbm_signal) {
|
||||
_dbm_signal = new_dbm_signal;
|
||||
_radio.flags.dbm_signal = 1;
|
||||
dbm_signal_ = new_dbm_signal;
|
||||
radio_.flags.dbm_signal = 1;
|
||||
}
|
||||
|
||||
void RadioTap::dbm_noise(int8_t new_dbm_noise) {
|
||||
_dbm_noise = new_dbm_noise;
|
||||
_radio.flags.dbm_noise = 1;
|
||||
dbm_noise_ = new_dbm_noise;
|
||||
radio_.flags.dbm_noise = 1;
|
||||
}
|
||||
|
||||
void RadioTap::signal_quality(uint8_t new_signal_quality) {
|
||||
_signal_quality = new_signal_quality;
|
||||
_radio.flags.lock_quality = 1;
|
||||
signal_quality_ = new_signal_quality;
|
||||
radio_.flags.lock_quality = 1;
|
||||
}
|
||||
|
||||
void RadioTap::data_retries(uint8_t new_data_retries) {
|
||||
_data_retries = new_data_retries;
|
||||
_radio.flags.data_retries = 1;
|
||||
data_retries_ = new_data_retries;
|
||||
radio_.flags.data_retries = 1;
|
||||
}
|
||||
|
||||
void RadioTap::antenna(uint8_t new_antenna) {
|
||||
_antenna = new_antenna;
|
||||
_radio.flags.antenna = 1;
|
||||
antenna_ = new_antenna;
|
||||
radio_.flags.antenna = 1;
|
||||
}
|
||||
|
||||
void RadioTap::db_signal(uint8_t new_db_signal) {
|
||||
_db_signal = new_db_signal;
|
||||
_radio.flags.db_signal = 1;
|
||||
db_signal_ = new_db_signal;
|
||||
radio_.flags.db_signal = 1;
|
||||
}
|
||||
|
||||
void RadioTap::rx_flags(uint16_t new_rx_flag) {
|
||||
_rx_flags = Endian::host_to_le(new_rx_flag);
|
||||
_radio.flags.rx_flags = 1;
|
||||
rx_flags_ = Endian::host_to_le(new_rx_flag);
|
||||
radio_.flags.rx_flags = 1;
|
||||
}
|
||||
|
||||
void RadioTap::tx_flags(uint16_t new_tx_flag) {
|
||||
_tx_flags = Endian::host_to_le(new_tx_flag);
|
||||
_radio.flags.tx_flags = 1;
|
||||
tx_flags_ = Endian::host_to_le(new_tx_flag);
|
||||
radio_.flags.tx_flags = 1;
|
||||
}
|
||||
|
||||
void RadioTap::mcs(const mcs_type& new_mcs) {
|
||||
_mcs = new_mcs;
|
||||
_radio.flags.mcs = 1;
|
||||
mcs_ = new_mcs;
|
||||
radio_.flags.mcs = 1;
|
||||
}
|
||||
|
||||
uint32_t RadioTap::header_size() const {
|
||||
uint32_t total_bytes = 0;
|
||||
if(_radio.flags.tsft)
|
||||
total_bytes += sizeof(_tsft);
|
||||
if(_radio.flags.flags)
|
||||
total_bytes += sizeof(_flags);
|
||||
if(_radio.flags.rate)
|
||||
total_bytes += sizeof(_rate);
|
||||
if(_radio.flags.channel) {
|
||||
if (radio_.flags.tsft) {
|
||||
total_bytes += sizeof(tsft_);
|
||||
}
|
||||
if (radio_.flags.flags) {
|
||||
total_bytes += sizeof(flags_);
|
||||
}
|
||||
if (radio_.flags.rate) {
|
||||
total_bytes += sizeof(rate_);
|
||||
}
|
||||
if (radio_.flags.channel) {
|
||||
total_bytes += (total_bytes & 1);
|
||||
total_bytes += sizeof(uint16_t) * 2;
|
||||
}
|
||||
if(_radio.flags.dbm_signal)
|
||||
total_bytes += sizeof(_dbm_signal);
|
||||
if(_radio.flags.dbm_noise)
|
||||
total_bytes += sizeof(_dbm_noise);
|
||||
if(_radio.flags.lock_quality) {
|
||||
total_bytes += (total_bytes & 1);
|
||||
total_bytes += sizeof(_signal_quality);
|
||||
if (radio_.flags.dbm_signal) {
|
||||
total_bytes += sizeof(dbm_signal_);
|
||||
}
|
||||
if(_radio.flags.antenna)
|
||||
total_bytes += sizeof(_antenna);
|
||||
if(_radio.flags.db_signal)
|
||||
total_bytes += sizeof(_db_signal);
|
||||
if(_radio.flags.rx_flags) {
|
||||
total_bytes += (total_bytes & 1);
|
||||
total_bytes += sizeof(_rx_flags);
|
||||
if (radio_.flags.dbm_noise) {
|
||||
total_bytes += sizeof(dbm_noise_);
|
||||
}
|
||||
if(_radio.flags.tx_flags) {
|
||||
if (radio_.flags.lock_quality) {
|
||||
total_bytes += (total_bytes & 1);
|
||||
total_bytes += sizeof(_tx_flags);
|
||||
total_bytes += sizeof(signal_quality_);
|
||||
}
|
||||
if(_radio.flags.data_retries)
|
||||
total_bytes += sizeof(_data_retries);
|
||||
if(_radio.flags.channel_plus) {
|
||||
if (radio_.flags.antenna) {
|
||||
total_bytes += sizeof(antenna_);
|
||||
}
|
||||
if (radio_.flags.db_signal) {
|
||||
total_bytes += sizeof(db_signal_);
|
||||
}
|
||||
if (radio_.flags.rx_flags) {
|
||||
total_bytes += (total_bytes & 1);
|
||||
total_bytes += sizeof(rx_flags_);
|
||||
}
|
||||
if (radio_.flags.tx_flags) {
|
||||
total_bytes += (total_bytes & 1);
|
||||
total_bytes += sizeof(tx_flags_);
|
||||
}
|
||||
if (radio_.flags.data_retries) {
|
||||
total_bytes += sizeof(data_retries_);
|
||||
}
|
||||
if (radio_.flags.channel_plus) {
|
||||
uint32_t offset = total_bytes % 4;
|
||||
if(offset)
|
||||
if (offset) {
|
||||
total_bytes += 4 - offset;
|
||||
}
|
||||
total_bytes += 8;
|
||||
}
|
||||
if(_radio.flags.mcs) {
|
||||
total_bytes += sizeof(_mcs);
|
||||
if (radio_.flags.mcs) {
|
||||
total_bytes += sizeof(mcs_);
|
||||
}
|
||||
|
||||
return sizeof(_radio) + total_bytes;
|
||||
return sizeof(radio_) + total_bytes;
|
||||
}
|
||||
|
||||
uint32_t RadioTap::trailer_size() const {
|
||||
// will be sizeof(uint32_t) if the FCS-at-the-end bit is on.
|
||||
return ((_flags & 0x10) != 0) ? sizeof(uint32_t) : 0;
|
||||
return ((flags_ & 0x10) != 0) ? sizeof(uint32_t) : 0;
|
||||
}
|
||||
|
||||
// Getter for RadioTap fields
|
||||
uint8_t RadioTap::version() const {
|
||||
return _radio.it_version;
|
||||
return radio_.it_version;
|
||||
}
|
||||
|
||||
uint8_t RadioTap::padding() const {
|
||||
return _radio.it_pad;
|
||||
return radio_.it_pad;
|
||||
}
|
||||
|
||||
uint16_t RadioTap::length() const {
|
||||
return Endian::le_to_host(_radio.it_len);
|
||||
return Endian::le_to_host(radio_.it_len);
|
||||
}
|
||||
|
||||
uint64_t RadioTap::tsft() const {
|
||||
if(!_radio.flags.tsft)
|
||||
if (!radio_.flags.tsft) {
|
||||
throw field_not_present();
|
||||
return Endian::le_to_host(_tsft);
|
||||
}
|
||||
return Endian::le_to_host(tsft_);
|
||||
}
|
||||
|
||||
RadioTap::FrameFlags RadioTap::flags() const {
|
||||
if(!_radio.flags.flags)
|
||||
if (!radio_.flags.flags) {
|
||||
throw field_not_present();
|
||||
return (FrameFlags)_flags;
|
||||
}
|
||||
return (FrameFlags)flags_;
|
||||
}
|
||||
|
||||
uint8_t RadioTap::rate() const {
|
||||
if(!_radio.flags.rate)
|
||||
if (!radio_.flags.rate) {
|
||||
throw field_not_present();
|
||||
return _rate;
|
||||
}
|
||||
return rate_;
|
||||
}
|
||||
|
||||
uint16_t RadioTap::channel_freq() const {
|
||||
if(!_radio.flags.channel)
|
||||
throw field_not_present();
|
||||
return Endian::le_to_host(_channel_freq);
|
||||
if (!radio_.flags.channel) {
|
||||
throw field_not_present();
|
||||
}
|
||||
return Endian::le_to_host(channel_freq_);
|
||||
}
|
||||
|
||||
uint16_t RadioTap::channel_type() const {
|
||||
if(!_radio.flags.channel)
|
||||
if (!radio_.flags.channel) {
|
||||
throw field_not_present();
|
||||
return Endian::le_to_host(_channel_type);
|
||||
}
|
||||
return Endian::le_to_host(channel_type_);
|
||||
}
|
||||
|
||||
int8_t RadioTap::dbm_signal() const {
|
||||
if(!_radio.flags.dbm_signal)
|
||||
if (!radio_.flags.dbm_signal) {
|
||||
throw field_not_present();
|
||||
return _dbm_signal;
|
||||
}
|
||||
return dbm_signal_;
|
||||
}
|
||||
|
||||
int8_t RadioTap::dbm_noise() const {
|
||||
if(!_radio.flags.dbm_noise)
|
||||
if (!radio_.flags.dbm_noise) {
|
||||
throw field_not_present();
|
||||
return _dbm_noise;
|
||||
}
|
||||
return dbm_noise_;
|
||||
}
|
||||
|
||||
uint16_t RadioTap::signal_quality() const {
|
||||
if(!_radio.flags.lock_quality)
|
||||
throw field_not_present();
|
||||
return _signal_quality;
|
||||
if (!radio_.flags.lock_quality) {
|
||||
throw field_not_present();
|
||||
}
|
||||
return signal_quality_;
|
||||
}
|
||||
|
||||
uint8_t RadioTap::antenna() const {
|
||||
if(!_radio.flags.antenna)
|
||||
throw field_not_present();
|
||||
return _antenna;
|
||||
if (!radio_.flags.antenna) {
|
||||
throw field_not_present();
|
||||
}
|
||||
return antenna_;
|
||||
}
|
||||
|
||||
RadioTap::mcs_type RadioTap::mcs() const {
|
||||
if(!_radio.flags.mcs)
|
||||
throw field_not_present();
|
||||
return _mcs;
|
||||
if (!radio_.flags.mcs) {
|
||||
throw field_not_present();
|
||||
}
|
||||
return mcs_;
|
||||
}
|
||||
|
||||
uint8_t RadioTap::db_signal() const {
|
||||
if(!_radio.flags.db_signal)
|
||||
throw field_not_present();
|
||||
return _db_signal;
|
||||
if (!radio_.flags.db_signal) {
|
||||
throw field_not_present();
|
||||
}
|
||||
return db_signal_;
|
||||
}
|
||||
|
||||
uint32_t RadioTap::channel_plus() const {
|
||||
if(!_radio.flags.channel_plus)
|
||||
if (!radio_.flags.channel_plus) {
|
||||
throw field_not_present();
|
||||
return Endian::le_to_host<uint32_t>(_channel_type);
|
||||
}
|
||||
return Endian::le_to_host<uint32_t>(channel_type_);
|
||||
}
|
||||
|
||||
uint16_t RadioTap::rx_flags() const {
|
||||
if(!_radio.flags.rx_flags)
|
||||
throw field_not_present();
|
||||
return Endian::le_to_host(_rx_flags);
|
||||
if (!radio_.flags.rx_flags) {
|
||||
throw field_not_present();
|
||||
}
|
||||
return Endian::le_to_host(rx_flags_);
|
||||
}
|
||||
|
||||
uint16_t RadioTap::tx_flags() const {
|
||||
if(!_radio.flags.tx_flags)
|
||||
throw field_not_present();
|
||||
return Endian::le_to_host(_tx_flags);
|
||||
if (!radio_.flags.tx_flags) {
|
||||
throw field_not_present();
|
||||
}
|
||||
return Endian::le_to_host(tx_flags_);
|
||||
}
|
||||
|
||||
uint8_t RadioTap::data_retries() const {
|
||||
if(!_radio.flags.data_retries)
|
||||
throw field_not_present();
|
||||
return _data_retries;
|
||||
if (!radio_.flags.data_retries) {
|
||||
throw field_not_present();
|
||||
}
|
||||
return data_retries_;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
void RadioTap::send(PacketSender &sender, const NetworkInterface &iface) {
|
||||
if(!iface)
|
||||
void RadioTap::send(PacketSender& sender, const NetworkInterface& iface) {
|
||||
if (!iface) {
|
||||
throw invalid_interface();
|
||||
}
|
||||
|
||||
#if !defined(BSD) && !defined(__FreeBSD_kernel__)
|
||||
struct sockaddr_ll addr;
|
||||
@@ -446,8 +481,8 @@ void RadioTap::send(PacketSender &sender, const NetworkInterface &iface) {
|
||||
addr.sll_halen = 6;
|
||||
addr.sll_ifindex = iface.id();
|
||||
|
||||
const Tins::Dot11 *wlan = tins_cast<Tins::Dot11*>(inner_pdu());
|
||||
if(wlan) {
|
||||
const Tins::Dot11* wlan = tins_cast<Tins::Dot11*>(inner_pdu());
|
||||
if (wlan) {
|
||||
Tins::Dot11::address_type dot11_addr(wlan->addr1());
|
||||
std::copy(dot11_addr.begin(), dot11_addr.end(), addr.sll_addr);
|
||||
}
|
||||
@@ -459,11 +494,12 @@ void RadioTap::send(PacketSender &sender, const NetworkInterface &iface) {
|
||||
}
|
||||
#endif
|
||||
|
||||
bool RadioTap::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
if(sizeof(_radio) < total_sz)
|
||||
bool RadioTap::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
if (sizeof(radio_) < total_sz) {
|
||||
return false;
|
||||
const radiotap_hdr *radio_ptr = (const radiotap_hdr*)ptr;
|
||||
if(radio_ptr->it_len <= total_sz) {
|
||||
}
|
||||
const radiotap_hdr* radio_ptr = (const radiotap_hdr*)ptr;
|
||||
if (radio_ptr->it_len <= total_sz) {
|
||||
ptr += radio_ptr->it_len;
|
||||
total_sz -= radio_ptr->it_len;
|
||||
return inner_pdu() ? inner_pdu()->matches_response(ptr, total_sz) : true;
|
||||
@@ -471,65 +507,65 @@ bool RadioTap::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void RadioTap::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
|
||||
void RadioTap::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
uint8_t *buffer_start = buffer;
|
||||
_radio.it_len = Endian::host_to_le<uint16_t>(header_size());
|
||||
stream.write(_radio);
|
||||
if(_radio.flags.tsft) {
|
||||
stream.write(_tsft);
|
||||
uint8_t* buffer_start = buffer;
|
||||
radio_.it_len = Endian::host_to_le<uint16_t>(header_size());
|
||||
stream.write(radio_);
|
||||
if (radio_.flags.tsft) {
|
||||
stream.write(tsft_);
|
||||
}
|
||||
if(_radio.flags.flags) {
|
||||
stream.write(_flags);
|
||||
if (radio_.flags.flags) {
|
||||
stream.write(flags_);
|
||||
}
|
||||
if(_radio.flags.rate) {
|
||||
stream.write(_rate);
|
||||
if (radio_.flags.rate) {
|
||||
stream.write(rate_);
|
||||
}
|
||||
if(_radio.flags.channel) {
|
||||
if(((buffer - buffer_start) & 1) == 1) {
|
||||
if (radio_.flags.channel) {
|
||||
if (((buffer - buffer_start) & 1) == 1) {
|
||||
stream.write<uint8_t>(0);
|
||||
}
|
||||
stream.write(_channel_freq);
|
||||
stream.write(_channel_type);
|
||||
stream.write(channel_freq_);
|
||||
stream.write(channel_type_);
|
||||
}
|
||||
if(_radio.flags.dbm_signal) {
|
||||
stream.write(_dbm_signal);
|
||||
if (radio_.flags.dbm_signal) {
|
||||
stream.write(dbm_signal_);
|
||||
}
|
||||
if(_radio.flags.dbm_noise) {
|
||||
stream.write(_dbm_noise);
|
||||
if (radio_.flags.dbm_noise) {
|
||||
stream.write(dbm_noise_);
|
||||
}
|
||||
if(_radio.flags.lock_quality) {
|
||||
if(((buffer - buffer_start) & 1) == 1) {
|
||||
if (radio_.flags.lock_quality) {
|
||||
if (((buffer - buffer_start) & 1) == 1) {
|
||||
stream.write<uint8_t>(0);
|
||||
}
|
||||
stream.write(_signal_quality);
|
||||
stream.write(signal_quality_);
|
||||
}
|
||||
if(_radio.flags.antenna) {
|
||||
stream.write(_antenna);
|
||||
if (radio_.flags.antenna) {
|
||||
stream.write(antenna_);
|
||||
}
|
||||
if(_radio.flags.db_signal) {
|
||||
stream.write(_db_signal);
|
||||
if (radio_.flags.db_signal) {
|
||||
stream.write(db_signal_);
|
||||
}
|
||||
if(_radio.flags.rx_flags) {
|
||||
if(((buffer - buffer_start) & 1) == 1) {
|
||||
if (radio_.flags.rx_flags) {
|
||||
if (((buffer - buffer_start) & 1) == 1) {
|
||||
stream.write<uint8_t>(0);
|
||||
}
|
||||
stream.write(_rx_flags);
|
||||
stream.write(rx_flags_);
|
||||
}
|
||||
if(_radio.flags.channel_plus) {
|
||||
if (radio_.flags.channel_plus) {
|
||||
const uint32_t padding = ((stream.pointer() - buffer_start) % 4);
|
||||
if (padding != 0) {
|
||||
stream.fill(4 - padding, 0);
|
||||
}
|
||||
uint32_t dummy = _channel_type;
|
||||
uint32_t dummy = channel_type_;
|
||||
// nasty Big Endian fix
|
||||
dummy = Endian::le_to_host<uint32_t>(Endian::host_to_le<uint16_t>(dummy));
|
||||
stream.write(dummy);
|
||||
stream.write(_channel_freq);
|
||||
stream.write(_channel);
|
||||
stream.write(_max_power);
|
||||
stream.write(channel_freq_);
|
||||
stream.write(channel_);
|
||||
stream.write(max_power_);
|
||||
}
|
||||
if ((_flags & 0x10) != 0 && inner_pdu()) {
|
||||
if ((flags_ & 0x10) != 0 && inner_pdu()) {
|
||||
uint32_t crc32 = Endian::host_to_le(
|
||||
Utils::crc32(stream.pointer(), inner_pdu()->size())
|
||||
);
|
||||
@@ -537,6 +573,7 @@ void RadioTap::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU
|
||||
stream.write(crc32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
@@ -34,31 +34,31 @@
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
RawPDU::RawPDU(const uint8_t *pload, uint32_t size)
|
||||
: _payload(pload, pload + size)
|
||||
{
|
||||
RawPDU::RawPDU(const uint8_t* pload, uint32_t size)
|
||||
: payload_(pload, pload + size) {
|
||||
|
||||
}
|
||||
|
||||
RawPDU::RawPDU(const std::string &data)
|
||||
: _payload(data.begin(), data.end()) {
|
||||
RawPDU::RawPDU(const std::string& data)
|
||||
: payload_(data.begin(), data.end()) {
|
||||
|
||||
}
|
||||
|
||||
uint32_t RawPDU::header_size() const {
|
||||
return static_cast<uint32_t>(_payload.size());
|
||||
return static_cast<uint32_t>(payload_.size());
|
||||
}
|
||||
|
||||
void RawPDU::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
|
||||
void RawPDU::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
stream.write(_payload.begin(), _payload.end());
|
||||
stream.write(payload_.begin(), payload_.end());
|
||||
}
|
||||
|
||||
void RawPDU::payload(const payload_type &pload) {
|
||||
_payload = pload;
|
||||
void RawPDU::payload(const payload_type& pload) {
|
||||
payload_ = pload;
|
||||
}
|
||||
|
||||
bool RawPDU::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
bool RawPDU::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
@@ -42,84 +42,81 @@ using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
RSNInformation::RSNInformation() : _version(1), _capabilities(0) {
|
||||
RSNInformation::RSNInformation()
|
||||
: version_(1), capabilities_(0) {
|
||||
|
||||
}
|
||||
|
||||
RSNInformation::RSNInformation(const serialization_type &buffer) {
|
||||
RSNInformation::RSNInformation(const serialization_type& buffer) {
|
||||
init(&buffer[0], static_cast<uint32_t>(buffer.size()));
|
||||
}
|
||||
|
||||
RSNInformation::RSNInformation(const uint8_t *buffer, uint32_t total_sz) {
|
||||
RSNInformation::RSNInformation(const uint8_t* buffer, uint32_t total_sz) {
|
||||
init(buffer, total_sz);
|
||||
}
|
||||
|
||||
void RSNInformation::init(const uint8_t *buffer, uint32_t total_sz) {
|
||||
void RSNInformation::init(const uint8_t* buffer, uint32_t total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
version(Endian::le_to_host(stream.read<uint16_t>()));
|
||||
group_suite((RSNInformation::CypherSuites)Endian::le_to_host(stream.read<uint32_t>()));
|
||||
int pairwise_cyphers_size = Endian::le_to_host(stream.read<uint16_t>());
|
||||
version(stream.read_le<uint16_t>());
|
||||
group_suite((RSNInformation::CypherSuites)stream.read_le<uint32_t>());
|
||||
int pairwise_cyphers_size = stream.read_le<uint16_t>();
|
||||
if (!stream.can_read(pairwise_cyphers_size)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
while (pairwise_cyphers_size--) {
|
||||
add_pairwise_cypher(
|
||||
(RSNInformation::CypherSuites)Endian::le_to_host(stream.read<uint32_t>())
|
||||
);
|
||||
add_pairwise_cypher((RSNInformation::CypherSuites)stream.read_le<uint32_t>());
|
||||
}
|
||||
int akm_cyphers_size = Endian::le_to_host(stream.read<uint16_t>());
|
||||
int akm_cyphers_size = stream.read_le<uint16_t>();
|
||||
if (!stream.can_read(akm_cyphers_size)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
while (akm_cyphers_size--) {
|
||||
add_akm_cypher(
|
||||
(RSNInformation::AKMSuites)Endian::le_to_host(stream.read<uint32_t>())
|
||||
);
|
||||
add_akm_cypher((RSNInformation::AKMSuites)stream.read_le<uint32_t>());
|
||||
}
|
||||
capabilities(Endian::le_to_host(stream.read<uint16_t>()));
|
||||
capabilities(stream.read_le<uint16_t>());
|
||||
}
|
||||
|
||||
void RSNInformation::add_pairwise_cypher(CypherSuites cypher) {
|
||||
_pairwise_cyphers.push_back(cypher);
|
||||
pairwise_cyphers_.push_back(cypher);
|
||||
}
|
||||
|
||||
void RSNInformation::add_akm_cypher(AKMSuites akm) {
|
||||
_akm_cyphers.push_back(akm);
|
||||
akm_cyphers_.push_back(akm);
|
||||
}
|
||||
|
||||
void RSNInformation::group_suite(CypherSuites group) {
|
||||
_group_suite = static_cast<CypherSuites>(Endian::host_to_le<uint32_t>(group));
|
||||
group_suite_ = static_cast<CypherSuites>(Endian::host_to_le<uint32_t>(group));
|
||||
}
|
||||
|
||||
void RSNInformation::version(uint16_t ver) {
|
||||
_version = Endian::host_to_le(ver);
|
||||
version_ = Endian::host_to_le(ver);
|
||||
}
|
||||
|
||||
void RSNInformation::capabilities(uint16_t cap) {
|
||||
_capabilities = Endian::host_to_le(cap);
|
||||
capabilities_ = Endian::host_to_le(cap);
|
||||
}
|
||||
|
||||
RSNInformation::serialization_type RSNInformation::serialize() const {
|
||||
size_t size = sizeof(_version) + sizeof(_capabilities) + sizeof(uint32_t);
|
||||
size_t size = sizeof(version_) + sizeof(capabilities_) + sizeof(uint32_t);
|
||||
size += (sizeof(uint16_t) << 1); // 2 lists count.
|
||||
size += sizeof(uint32_t) * (_akm_cyphers.size() + _pairwise_cyphers.size());
|
||||
size += sizeof(uint32_t) * (akm_cyphers_.size() + pairwise_cyphers_.size());
|
||||
|
||||
const uint16_t pairwise_cyphers_size = Endian::host_to_le<uint16_t>(_pairwise_cyphers.size());
|
||||
const uint16_t akm_cyphers_size = Endian::host_to_le<uint16_t>(_akm_cyphers.size());
|
||||
const uint16_t pairwise_cyphers_size = Endian::host_to_le<uint16_t>(pairwise_cyphers_.size());
|
||||
const uint16_t akm_cyphers_size = Endian::host_to_le<uint16_t>(akm_cyphers_.size());
|
||||
|
||||
serialization_type buffer(size);
|
||||
OutputMemoryStream stream(&buffer[0], buffer.size());
|
||||
stream.write(_version);
|
||||
stream.write(_group_suite);
|
||||
stream.write(version_);
|
||||
stream.write(group_suite_);
|
||||
stream.write(pairwise_cyphers_size);
|
||||
for (cyphers_type::const_iterator it = _pairwise_cyphers.begin(); it != _pairwise_cyphers.end(); ++it) {
|
||||
for (cyphers_type::const_iterator it = pairwise_cyphers_.begin(); it != pairwise_cyphers_.end(); ++it) {
|
||||
stream.write(Endian::host_to_le<uint32_t>(*it));
|
||||
}
|
||||
stream.write(akm_cyphers_size);
|
||||
for (akm_type::const_iterator it = _akm_cyphers.begin(); it != _akm_cyphers.end(); ++it) {
|
||||
for (akm_type::const_iterator it = akm_cyphers_.begin(); it != akm_cyphers_.end(); ++it) {
|
||||
stream.write(Endian::host_to_le<uint32_t>(*it));
|
||||
}
|
||||
stream.write(_capabilities);
|
||||
stream.write(capabilities_);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -131,11 +128,13 @@ RSNInformation RSNInformation::wpa2_psk() {
|
||||
return info;
|
||||
}
|
||||
|
||||
RSNInformation RSNInformation::from_option(const PDUOption<uint8_t, Dot11> &opt) {
|
||||
if(opt.data_size() < sizeof(uint16_t) * 2 + sizeof(uint32_t))
|
||||
RSNInformation RSNInformation::from_option(const PDUOption<uint8_t, Dot11>& opt) {
|
||||
if (opt.data_size() < sizeof(uint16_t) * 2 + sizeof(uint32_t)) {
|
||||
throw malformed_option();
|
||||
}
|
||||
return RSNInformation(opt.data_ptr(), static_cast<uint32_t>(opt.data_size()));
|
||||
}
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
#endif // HAVE_DOT11
|
||||
|
||||
24
src/sll.cpp
24
src/sll.cpp
@@ -39,13 +39,13 @@ using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
SLL::SLL() : _header() {
|
||||
SLL::SLL() : header_() {
|
||||
|
||||
}
|
||||
|
||||
SLL::SLL(const uint8_t *buffer, uint32_t total_sz) {
|
||||
SLL::SLL(const uint8_t* buffer, uint32_t total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_header);
|
||||
stream.read(header_);
|
||||
if (stream) {
|
||||
inner_pdu(
|
||||
Internals::pdu_from_flag(
|
||||
@@ -58,30 +58,30 @@ SLL::SLL(const uint8_t *buffer, uint32_t total_sz) {
|
||||
}
|
||||
|
||||
void SLL::packet_type(uint16_t new_packet_type) {
|
||||
_header.packet_type = Endian::host_to_be(new_packet_type);
|
||||
header_.packet_type = Endian::host_to_be(new_packet_type);
|
||||
}
|
||||
|
||||
void SLL::lladdr_type(uint16_t new_lladdr_type) {
|
||||
_header.lladdr_type = Endian::host_to_be(new_lladdr_type);
|
||||
header_.lladdr_type = Endian::host_to_be(new_lladdr_type);
|
||||
}
|
||||
|
||||
void SLL::lladdr_len(uint16_t new_lladdr_len) {
|
||||
_header.lladdr_len = Endian::host_to_be(new_lladdr_len);
|
||||
header_.lladdr_len = Endian::host_to_be(new_lladdr_len);
|
||||
}
|
||||
|
||||
void SLL::address(const address_type &new_address) {
|
||||
new_address.copy(_header.address);
|
||||
void SLL::address(const address_type& new_address) {
|
||||
new_address.copy(header_.address);
|
||||
}
|
||||
|
||||
void SLL::protocol(uint16_t new_protocol) {
|
||||
_header.protocol = Endian::host_to_be(new_protocol);
|
||||
header_.protocol = Endian::host_to_be(new_protocol);
|
||||
}
|
||||
|
||||
uint32_t SLL::header_size() const {
|
||||
return sizeof(_header);
|
||||
return sizeof(header_);
|
||||
}
|
||||
|
||||
void SLL::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
|
||||
void SLL::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
if (inner_pdu()) {
|
||||
Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_type(
|
||||
@@ -89,7 +89,7 @@ void SLL::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
|
||||
);
|
||||
protocol(static_cast<uint16_t>(flag));
|
||||
}
|
||||
stream.write(_header);
|
||||
stream.write(header_);
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
29
src/snap.cpp
29
src/snap.cpp
@@ -47,16 +47,15 @@ using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
SNAP::SNAP() : _snap()
|
||||
{
|
||||
_snap.dsap = _snap.ssap = 0xaa;
|
||||
SNAP::SNAP()
|
||||
: snap_() {
|
||||
snap_.dsap = snap_.ssap = 0xaa;
|
||||
control(3);
|
||||
}
|
||||
|
||||
SNAP::SNAP(const uint8_t *buffer, uint32_t total_sz)
|
||||
{
|
||||
SNAP::SNAP(const uint8_t* buffer, uint32_t total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_snap);
|
||||
stream.read(snap_);
|
||||
if (stream) {
|
||||
inner_pdu(
|
||||
Internals::pdu_from_flag(
|
||||
@@ -70,39 +69,39 @@ SNAP::SNAP(const uint8_t *buffer, uint32_t total_sz)
|
||||
|
||||
void SNAP::control(uint8_t new_control) {
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
_snap.control_org = (_snap.control_org & 0xffffff00) | (new_control);
|
||||
snap_.control_org = (snap_.control_org & 0xffffff00) | (new_control);
|
||||
#else
|
||||
_snap.control_org = (_snap.control_org & 0xffffff) | (new_control << 24);
|
||||
snap_.control_org = (snap_.control_org & 0xffffff) | (new_control << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SNAP::org_code(small_uint<24> new_org) {
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
_snap.control_org = Endian::host_to_be<uint32_t>(new_org) | control();
|
||||
snap_.control_org = Endian::host_to_be<uint32_t>(new_org) | control();
|
||||
#else
|
||||
_snap.control_org = new_org | (control() << 24);
|
||||
snap_.control_org = new_org | (control() << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SNAP::eth_type(uint16_t new_eth) {
|
||||
_snap.eth_type = Endian::host_to_be(new_eth);
|
||||
snap_.eth_type = Endian::host_to_be(new_eth);
|
||||
}
|
||||
|
||||
uint32_t SNAP::header_size() const {
|
||||
return sizeof(_snap);
|
||||
return sizeof(snap_);
|
||||
}
|
||||
|
||||
void SNAP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
|
||||
void SNAP::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
if (inner_pdu()) {
|
||||
Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_type(
|
||||
inner_pdu()->pdu_type()
|
||||
);
|
||||
_snap.eth_type = Endian::host_to_be(
|
||||
snap_.eth_type = Endian::host_to_be(
|
||||
static_cast<uint16_t>(flag)
|
||||
);
|
||||
}
|
||||
stream.write(_snap);
|
||||
stream.write(snap_);
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
274
src/sniffer.cpp
274
src/sniffer.cpp
@@ -50,83 +50,79 @@ using std::string;
|
||||
using std::runtime_error;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
BaseSniffer::BaseSniffer()
|
||||
: handle(0), mask(0), extract_raw(false)
|
||||
{
|
||||
: handle_(0), mask_(0), extract_raw_(false) {
|
||||
|
||||
}
|
||||
|
||||
BaseSniffer::~BaseSniffer()
|
||||
{
|
||||
if (handle) {
|
||||
pcap_close(handle);
|
||||
BaseSniffer::~BaseSniffer() {
|
||||
if (handle_) {
|
||||
pcap_close(handle_);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseSniffer::set_pcap_handle(pcap_t* const pcap_handle)
|
||||
{
|
||||
handle = pcap_handle;
|
||||
void BaseSniffer::set_pcap_handle(pcap_t* pcap_handle) {
|
||||
handle_ = pcap_handle;
|
||||
}
|
||||
|
||||
pcap_t* BaseSniffer::get_pcap_handle()
|
||||
{
|
||||
return handle;
|
||||
pcap_t* BaseSniffer::get_pcap_handle() {
|
||||
return handle_;
|
||||
}
|
||||
|
||||
const pcap_t* BaseSniffer::get_pcap_handle() const
|
||||
{
|
||||
return handle;
|
||||
const pcap_t* BaseSniffer::get_pcap_handle() const {
|
||||
return handle_;
|
||||
}
|
||||
|
||||
void BaseSniffer::set_if_mask(bpf_u_int32 if_mask)
|
||||
{
|
||||
mask = if_mask;
|
||||
void BaseSniffer::set_if_mask(bpf_u_int32 if_mask) {
|
||||
mask_ = if_mask;
|
||||
}
|
||||
|
||||
bpf_u_int32 BaseSniffer::get_if_mask() const
|
||||
{
|
||||
return mask;
|
||||
bpf_u_int32 BaseSniffer::get_if_mask() const {
|
||||
return mask_;
|
||||
}
|
||||
|
||||
struct sniff_data {
|
||||
struct timeval tv;
|
||||
PDU *pdu;
|
||||
PDU* pdu;
|
||||
bool packet_processed;
|
||||
|
||||
sniff_data() : pdu(0), packet_processed(true) { }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T *safe_alloc(const u_char *bytes, bpf_u_int32 len) {
|
||||
T* safe_alloc(const u_char* bytes, bpf_u_int32 len) {
|
||||
try {
|
||||
return new T((const uint8_t*)bytes, len);
|
||||
}
|
||||
catch(malformed_packet&) {
|
||||
catch (malformed_packet&) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void sniff_loop_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) {
|
||||
sniff_data *data = (sniff_data*)user;
|
||||
void sniff_loop_handler(u_char* user, const struct pcap_pkthdr* h, const u_char* bytes) {
|
||||
sniff_data* data = (sniff_data*)user;
|
||||
data->packet_processed = true;
|
||||
data->tv = h->ts;
|
||||
data->pdu = safe_alloc<T>(bytes, h->caplen);
|
||||
}
|
||||
|
||||
void sniff_loop_eth_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) {
|
||||
sniff_data *data = (sniff_data*)user;
|
||||
void sniff_loop_eth_handler(u_char* user, const struct pcap_pkthdr* h, const u_char* bytes) {
|
||||
sniff_data* data = (sniff_data*)user;
|
||||
data->packet_processed = true;
|
||||
data->tv = h->ts;
|
||||
if(Internals::is_dot3((const uint8_t*)bytes, h->caplen))
|
||||
if (Internals::is_dot3((const uint8_t*)bytes, h->caplen)) {
|
||||
data->pdu = safe_alloc<Dot3>((const uint8_t*)bytes, h->caplen);
|
||||
else
|
||||
}
|
||||
else {
|
||||
data->pdu = safe_alloc<EthernetII>((const uint8_t*)bytes, h->caplen);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_DOT11
|
||||
void sniff_loop_dot11_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) {
|
||||
sniff_data *data = (sniff_data*)user;
|
||||
void sniff_loop_dot11_handler(u_char* user, const struct pcap_pkthdr* h, const u_char* bytes) {
|
||||
sniff_data* data = (sniff_data*)user;
|
||||
data->packet_processed = true;
|
||||
data->tv = h->ts;
|
||||
try {
|
||||
@@ -140,20 +136,22 @@ void sniff_loop_dot11_handler(u_char *user, const struct pcap_pkthdr *h, const u
|
||||
|
||||
PtrPacket BaseSniffer::next_packet() {
|
||||
sniff_data data;
|
||||
const int iface_type = pcap_datalink(handle);
|
||||
const int iface_type = pcap_datalink(handle_);
|
||||
pcap_handler handler = 0;
|
||||
if(extract_raw)
|
||||
if (extract_raw_) {
|
||||
handler = &sniff_loop_handler<RawPDU>;
|
||||
else if(iface_type == DLT_EN10MB)
|
||||
}
|
||||
else if (iface_type == DLT_EN10MB) {
|
||||
handler = sniff_loop_eth_handler;
|
||||
else if(iface_type == DLT_IEEE802_11_RADIO) {
|
||||
}
|
||||
else if (iface_type == DLT_IEEE802_11_RADIO) {
|
||||
#ifdef HAVE_DOT11
|
||||
handler = &sniff_loop_handler<RadioTap>;
|
||||
#else
|
||||
throw protocol_disabled();
|
||||
#endif
|
||||
}
|
||||
else if(iface_type == DLT_IEEE802_11) {
|
||||
else if (iface_type == DLT_IEEE802_11) {
|
||||
#ifdef HAVE_DOT11
|
||||
handler = sniff_loop_dot11_handler;
|
||||
#else
|
||||
@@ -165,41 +163,46 @@ PtrPacket BaseSniffer::next_packet() {
|
||||
handler = &sniff_loop_handler<PKTAP>;
|
||||
}
|
||||
#endif // DLT_PKTAP
|
||||
else if(iface_type == DLT_NULL)
|
||||
else if (iface_type == DLT_NULL) {
|
||||
handler = &sniff_loop_handler<Tins::Loopback>;
|
||||
else if(iface_type == DLT_LINUX_SLL)
|
||||
}
|
||||
else if (iface_type == DLT_LINUX_SLL) {
|
||||
handler = &sniff_loop_handler<SLL>;
|
||||
else if(iface_type == DLT_PPI)
|
||||
}
|
||||
else if (iface_type == DLT_PPI) {
|
||||
handler = &sniff_loop_handler<PPI>;
|
||||
else
|
||||
}
|
||||
else {
|
||||
throw unknown_link_type();
|
||||
}
|
||||
// keep calling pcap_loop until a well-formed packet is found.
|
||||
while(data.pdu == 0 && data.packet_processed) {
|
||||
while (data.pdu == 0 && data.packet_processed) {
|
||||
data.packet_processed = false;
|
||||
if(pcap_loop(handle, 1, handler, (u_char*)&data) < 0)
|
||||
if (pcap_loop(handle_, 1, handler, (u_char*)&data) < 0) {
|
||||
return PtrPacket(0, Timestamp());
|
||||
}
|
||||
}
|
||||
return PtrPacket(data.pdu, data.tv);
|
||||
}
|
||||
|
||||
void BaseSniffer::set_extract_raw_pdus(bool value) {
|
||||
extract_raw = value;
|
||||
extract_raw_ = value;
|
||||
}
|
||||
|
||||
void BaseSniffer::stop_sniff() {
|
||||
pcap_breakloop(handle);
|
||||
pcap_breakloop(handle_);
|
||||
}
|
||||
|
||||
int BaseSniffer::get_fd() {
|
||||
#ifndef _WIN32
|
||||
return pcap_get_selectable_fd(handle);
|
||||
return pcap_get_selectable_fd(handle_);
|
||||
#else
|
||||
throw std::runtime_error("Method not supported in Windows platform");
|
||||
throw unsupported_function();
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
int BaseSniffer::link_type() const {
|
||||
return pcap_datalink(handle);
|
||||
return pcap_datalink(handle_);
|
||||
}
|
||||
|
||||
BaseSniffer::iterator BaseSniffer::begin() {
|
||||
@@ -210,24 +213,23 @@ BaseSniffer::iterator BaseSniffer::end() {
|
||||
return iterator(0);
|
||||
}
|
||||
|
||||
bool BaseSniffer::set_filter(const std::string &filter) {
|
||||
bool BaseSniffer::set_filter(const string& filter) {
|
||||
bpf_program prog;
|
||||
if(pcap_compile(handle, &prog, filter.c_str(), 0, mask) == -1) {
|
||||
if (pcap_compile(handle_, &prog, filter.c_str(), 0, mask_) == -1) {
|
||||
return false;
|
||||
}
|
||||
bool result = pcap_setfilter(handle, &prog) != -1;
|
||||
bool result = pcap_setfilter(handle_, &prog) != -1;
|
||||
pcap_freecode(&prog);
|
||||
return result;
|
||||
}
|
||||
|
||||
void BaseSniffer::set_timeout(int ms) {
|
||||
pcap_set_timeout(handle, ms);
|
||||
pcap_set_timeout(handle_, ms);
|
||||
}
|
||||
|
||||
// ****************************** Sniffer ******************************
|
||||
|
||||
Sniffer::Sniffer(const string &device, const SnifferConfiguration& configuration)
|
||||
{
|
||||
Sniffer::Sniffer(const string& device, const SnifferConfiguration& configuration) {
|
||||
char error[PCAP_ERRBUF_SIZE];
|
||||
pcap_t* phandle = pcap_create(TINS_PREFIX_INTERFACE(device).c_str(), error);
|
||||
if (!phandle) {
|
||||
@@ -246,16 +248,18 @@ Sniffer::Sniffer(const string &device, const SnifferConfiguration& configuration
|
||||
|
||||
// Finally, activate the pcap. In case of error throw runtime_error
|
||||
if (pcap_activate(get_pcap_handle()) < 0) {
|
||||
throw std::runtime_error(pcap_geterr(get_pcap_handle()));
|
||||
throw pcap_error(pcap_geterr(get_pcap_handle()));
|
||||
}
|
||||
|
||||
// Configure the sniffer's attributes after activation.
|
||||
configuration.configure_sniffer_post_activation(*this);
|
||||
}
|
||||
|
||||
Sniffer::Sniffer(const std::string &device, unsigned max_packet_size, bool promisc,
|
||||
const std::string &filter, bool rfmon)
|
||||
{
|
||||
Sniffer::Sniffer(const string& device,
|
||||
unsigned max_packet_size,
|
||||
bool promisc,
|
||||
const string& filter,
|
||||
bool rfmon) {
|
||||
SnifferConfiguration configuration;
|
||||
configuration.set_snap_len(max_packet_size);
|
||||
configuration.set_promisc_mode(promisc);
|
||||
@@ -280,16 +284,17 @@ Sniffer::Sniffer(const std::string &device, unsigned max_packet_size, bool promi
|
||||
|
||||
// Finally, activate the pcap. In case of error throw runtime_error
|
||||
if (pcap_activate(get_pcap_handle()) < 0) {
|
||||
throw std::runtime_error(pcap_geterr(get_pcap_handle()));
|
||||
throw pcap_error(pcap_geterr(get_pcap_handle()));
|
||||
}
|
||||
|
||||
// Configure the sniffer's attributes after activation.
|
||||
configuration.configure_sniffer_post_activation(*this);
|
||||
}
|
||||
|
||||
Sniffer::Sniffer(const std::string &device, promisc_type promisc, const std::string &filter,
|
||||
bool rfmon)
|
||||
{
|
||||
Sniffer::Sniffer(const string& device,
|
||||
promisc_type promisc,
|
||||
const string& filter,
|
||||
bool rfmon) {
|
||||
SnifferConfiguration configuration;
|
||||
configuration.set_promisc_mode(promisc == PROMISC);
|
||||
configuration.set_filter(filter);
|
||||
@@ -313,52 +318,47 @@ Sniffer::Sniffer(const std::string &device, promisc_type promisc, const std::str
|
||||
|
||||
// Finally, activate the pcap. In case of error throw runtime_error
|
||||
if (pcap_activate(get_pcap_handle()) < 0) {
|
||||
throw std::runtime_error(pcap_geterr(get_pcap_handle()));
|
||||
throw pcap_error(pcap_geterr(get_pcap_handle()));
|
||||
}
|
||||
|
||||
// Configure the sniffer's attributes after activation.
|
||||
configuration.configure_sniffer_post_activation(*this);
|
||||
}
|
||||
|
||||
void Sniffer::set_snap_len(unsigned snap_len)
|
||||
{
|
||||
void Sniffer::set_snap_len(unsigned snap_len) {
|
||||
if (pcap_set_snaplen(get_pcap_handle(), snap_len)) {
|
||||
throw std::runtime_error(pcap_geterr(get_pcap_handle()));
|
||||
throw pcap_error(pcap_geterr(get_pcap_handle()));
|
||||
}
|
||||
}
|
||||
|
||||
void Sniffer::set_buffer_size(unsigned buffer_size)
|
||||
{
|
||||
void Sniffer::set_buffer_size(unsigned buffer_size) {
|
||||
if (pcap_set_buffer_size(get_pcap_handle(), buffer_size)) {
|
||||
throw std::runtime_error(pcap_geterr(get_pcap_handle()));
|
||||
throw pcap_error(pcap_geterr(get_pcap_handle()));
|
||||
}
|
||||
}
|
||||
|
||||
void Sniffer::set_promisc_mode(bool promisc_enabled)
|
||||
{
|
||||
void Sniffer::set_promisc_mode(bool promisc_enabled) {
|
||||
if (pcap_set_promisc(get_pcap_handle(), promisc_enabled)) {
|
||||
throw runtime_error(pcap_geterr(get_pcap_handle()));
|
||||
throw pcap_error(pcap_geterr(get_pcap_handle()));
|
||||
}
|
||||
}
|
||||
|
||||
void Sniffer::set_immediate_mode(bool enabled)
|
||||
{
|
||||
void Sniffer::set_immediate_mode(bool enabled) {
|
||||
// As of libpcap version 1.5.0 this function exists. Before, it was
|
||||
// technically always immediate mode since capture used TPACKET_V1/2
|
||||
// which doesn't do packet buffering.
|
||||
#ifdef HAVE_PCAP_IMMEDIATE_MODE
|
||||
if (pcap_set_immediate_mode(get_pcap_handle(), enabled)) {
|
||||
throw runtime_error(pcap_geterr(get_pcap_handle()));
|
||||
throw pcap_error(pcap_geterr(get_pcap_handle()));
|
||||
}
|
||||
#endif // HAVE_PCAP_IMMEDIATE_MODE
|
||||
}
|
||||
|
||||
void Sniffer::set_rfmon(bool rfmon_enabled)
|
||||
{
|
||||
void Sniffer::set_rfmon(bool rfmon_enabled) {
|
||||
#ifndef _WIN32
|
||||
if (pcap_can_set_rfmon(get_pcap_handle()) == 1) {
|
||||
if (pcap_set_rfmon(get_pcap_handle(), rfmon_enabled)) {
|
||||
throw runtime_error(pcap_geterr(get_pcap_handle()));
|
||||
throw pcap_error(pcap_geterr(get_pcap_handle()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -367,11 +367,12 @@ void Sniffer::set_rfmon(bool rfmon_enabled)
|
||||
|
||||
// **************************** FileSniffer ****************************
|
||||
|
||||
FileSniffer::FileSniffer(const string &file_name, const SnifferConfiguration& configuration) {
|
||||
FileSniffer::FileSniffer(const string& file_name,
|
||||
const SnifferConfiguration& configuration) {
|
||||
char error[PCAP_ERRBUF_SIZE];
|
||||
pcap_t *phandle = pcap_open_offline(file_name.c_str(), error);
|
||||
if(!phandle) {
|
||||
throw std::runtime_error(error);
|
||||
pcap_t* phandle = pcap_open_offline(file_name.c_str(), error);
|
||||
if (!phandle) {
|
||||
throw pcap_error(error);
|
||||
}
|
||||
set_pcap_handle(phandle);
|
||||
|
||||
@@ -380,15 +381,14 @@ FileSniffer::FileSniffer(const string &file_name, const SnifferConfiguration& co
|
||||
|
||||
}
|
||||
|
||||
FileSniffer::FileSniffer(const std::string &file_name, const std::string &filter)
|
||||
{
|
||||
FileSniffer::FileSniffer(const string& file_name, const string& filter) {
|
||||
SnifferConfiguration config;
|
||||
config.set_filter(filter);
|
||||
|
||||
char error[PCAP_ERRBUF_SIZE];
|
||||
pcap_t *phandle = pcap_open_offline(file_name.c_str(), error);
|
||||
if(!phandle) {
|
||||
throw std::runtime_error(error);
|
||||
pcap_t* phandle = pcap_open_offline(file_name.c_str(), error);
|
||||
if (!phandle) {
|
||||
throw pcap_error(error);
|
||||
}
|
||||
set_pcap_handle(phandle);
|
||||
|
||||
@@ -401,92 +401,76 @@ FileSniffer::FileSniffer(const std::string &file_name, const std::string &filter
|
||||
const unsigned SnifferConfiguration::DEFAULT_SNAP_LEN = 65535;
|
||||
const unsigned SnifferConfiguration::DEFAULT_TIMEOUT = 1000;
|
||||
|
||||
SnifferConfiguration::SnifferConfiguration() :
|
||||
_flags(0),
|
||||
_snap_len(DEFAULT_SNAP_LEN),
|
||||
_buffer_size(0),
|
||||
_timeout(DEFAULT_TIMEOUT),
|
||||
_promisc(false),
|
||||
_rfmon(false),
|
||||
_immediate_mode(false)
|
||||
{
|
||||
SnifferConfiguration::SnifferConfiguration()
|
||||
: flags_(0), snap_len_(DEFAULT_SNAP_LEN), buffer_size_(0), timeout_(DEFAULT_TIMEOUT),
|
||||
promisc_(false), rfmon_(false), immediate_mode_(false) {
|
||||
|
||||
}
|
||||
|
||||
void SnifferConfiguration::configure_sniffer_pre_activation(Sniffer& sniffer) const
|
||||
{
|
||||
sniffer.set_snap_len(_snap_len);
|
||||
sniffer.set_timeout(_timeout);
|
||||
if ((_flags & BUFFER_SIZE) != 0) {
|
||||
sniffer.set_buffer_size(_buffer_size);
|
||||
void SnifferConfiguration::configure_sniffer_pre_activation(Sniffer& sniffer) const {
|
||||
sniffer.set_snap_len(snap_len_);
|
||||
sniffer.set_timeout(timeout_);
|
||||
if ((flags_ & BUFFER_SIZE) != 0) {
|
||||
sniffer.set_buffer_size(buffer_size_);
|
||||
}
|
||||
if ((_flags & PROMISCUOUS) != 0) {
|
||||
sniffer.set_promisc_mode(_promisc);
|
||||
if ((flags_ & PROMISCUOUS) != 0) {
|
||||
sniffer.set_promisc_mode(promisc_);
|
||||
}
|
||||
if ((_flags & RFMON) != 0) {
|
||||
sniffer.set_rfmon(_rfmon);
|
||||
if ((flags_ & RFMON) != 0) {
|
||||
sniffer.set_rfmon(rfmon_);
|
||||
}
|
||||
if ((_flags & IMMEDIATE_MODE) != 0) {
|
||||
sniffer.set_immediate_mode(_immediate_mode);
|
||||
if ((flags_ & IMMEDIATE_MODE) != 0) {
|
||||
sniffer.set_immediate_mode(immediate_mode_);
|
||||
}
|
||||
}
|
||||
|
||||
void SnifferConfiguration::configure_sniffer_pre_activation(FileSniffer& sniffer) const
|
||||
{
|
||||
if ((_flags & PACKET_FILTER) != 0) {
|
||||
if (!sniffer.set_filter(_filter)) {
|
||||
throw std::runtime_error("Could not set the filter!");
|
||||
void SnifferConfiguration::configure_sniffer_pre_activation(FileSniffer& sniffer) const {
|
||||
if ((flags_ & PACKET_FILTER) != 0) {
|
||||
if (!sniffer.set_filter(filter_)) {
|
||||
throw invalid_pcap_filter(pcap_geterr(sniffer.get_pcap_handle()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SnifferConfiguration::configure_sniffer_post_activation(Sniffer& sniffer) const
|
||||
{
|
||||
if ((_flags & PACKET_FILTER) != 0) {
|
||||
if (!sniffer.set_filter(_filter)) {
|
||||
throw std::runtime_error("Could not set the filter! ");
|
||||
void SnifferConfiguration::configure_sniffer_post_activation(Sniffer& sniffer) const {
|
||||
if ((flags_ & PACKET_FILTER) != 0) {
|
||||
if (!sniffer.set_filter(filter_)) {
|
||||
throw invalid_pcap_filter(pcap_geterr(sniffer.get_pcap_handle()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SnifferConfiguration::set_snap_len(unsigned snap_len)
|
||||
{
|
||||
_snap_len = snap_len;
|
||||
void SnifferConfiguration::set_snap_len(unsigned snap_len) {
|
||||
snap_len_ = snap_len;
|
||||
}
|
||||
|
||||
void SnifferConfiguration::set_buffer_size(unsigned buffer_size)
|
||||
{
|
||||
_flags |= BUFFER_SIZE;
|
||||
_buffer_size = buffer_size;
|
||||
void SnifferConfiguration::set_buffer_size(unsigned buffer_size) {
|
||||
flags_ |= BUFFER_SIZE;
|
||||
buffer_size_ = buffer_size;
|
||||
}
|
||||
|
||||
void SnifferConfiguration::set_promisc_mode(bool enabled)
|
||||
{
|
||||
_flags |= PROMISCUOUS;
|
||||
_promisc = enabled;
|
||||
void SnifferConfiguration::set_promisc_mode(bool enabled) {
|
||||
flags_ |= PROMISCUOUS;
|
||||
promisc_ = enabled;
|
||||
}
|
||||
|
||||
void SnifferConfiguration::set_filter(const std::string& filter)
|
||||
{
|
||||
_flags |= PACKET_FILTER;
|
||||
_filter = filter;
|
||||
void SnifferConfiguration::set_filter(const string& filter) {
|
||||
flags_ |= PACKET_FILTER;
|
||||
filter_ = filter;
|
||||
}
|
||||
|
||||
void SnifferConfiguration::set_rfmon(bool enabled)
|
||||
{
|
||||
_flags |= RFMON;
|
||||
_rfmon = enabled;
|
||||
void SnifferConfiguration::set_rfmon(bool enabled) {
|
||||
flags_ |= RFMON;
|
||||
rfmon_ = enabled;
|
||||
}
|
||||
|
||||
void SnifferConfiguration::set_timeout(unsigned timeout)
|
||||
{
|
||||
_timeout = timeout;
|
||||
void SnifferConfiguration::set_timeout(unsigned timeout) {
|
||||
timeout_ = timeout;
|
||||
}
|
||||
|
||||
void SnifferConfiguration::set_immediate_mode(bool enabled)
|
||||
{
|
||||
_flags |= IMMEDIATE_MODE;
|
||||
_immediate_mode = enabled;
|
||||
void SnifferConfiguration::set_immediate_mode(bool enabled) {
|
||||
flags_ |= IMMEDIATE_MODE;
|
||||
immediate_mode_ = enabled;
|
||||
}
|
||||
|
||||
}
|
||||
} // Tins
|
||||
|
||||
56
src/stp.cpp
56
src/stp.cpp
@@ -33,89 +33,89 @@
|
||||
#include "exceptions.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::copy;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
STP::STP()
|
||||
: _header()
|
||||
{
|
||||
: header_() {
|
||||
|
||||
}
|
||||
|
||||
STP::STP(const uint8_t *buffer, uint32_t total_sz)
|
||||
{
|
||||
STP::STP(const uint8_t* buffer, uint32_t total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_header);
|
||||
stream.read(header_);
|
||||
}
|
||||
|
||||
void STP::proto_id(uint16_t new_proto_id) {
|
||||
_header.proto_id = Endian::host_to_be(new_proto_id);
|
||||
header_.proto_id = Endian::host_to_be(new_proto_id);
|
||||
}
|
||||
|
||||
void STP::proto_version(uint8_t new_proto_version) {
|
||||
_header.proto_version = new_proto_version;
|
||||
header_.proto_version = new_proto_version;
|
||||
}
|
||||
|
||||
void STP::bpdu_type(uint8_t new_bpdu_type) {
|
||||
_header.bpdu_type = new_bpdu_type;
|
||||
header_.bpdu_type = new_bpdu_type;
|
||||
}
|
||||
|
||||
void STP::bpdu_flags(uint8_t new_bpdu_flags) {
|
||||
_header.bpdu_flags = new_bpdu_flags;
|
||||
header_.bpdu_flags = new_bpdu_flags;
|
||||
}
|
||||
|
||||
void STP::root_path_cost(uint32_t new_root_path_cost) {
|
||||
_header.root_path_cost = Endian::host_to_be(new_root_path_cost);
|
||||
header_.root_path_cost = Endian::host_to_be(new_root_path_cost);
|
||||
}
|
||||
|
||||
void STP::port_id(uint16_t new_port_id) {
|
||||
_header.port_id = Endian::host_to_be(new_port_id);
|
||||
header_.port_id = Endian::host_to_be(new_port_id);
|
||||
}
|
||||
|
||||
void STP::msg_age(uint16_t new_msg_age) {
|
||||
_header.msg_age = Endian::host_to_be<uint16_t>(new_msg_age * 256);
|
||||
header_.msg_age = Endian::host_to_be<uint16_t>(new_msg_age * 256);
|
||||
}
|
||||
|
||||
void STP::max_age(uint16_t new_max_age) {
|
||||
_header.max_age = Endian::host_to_be<uint16_t>(new_max_age * 256);
|
||||
header_.max_age = Endian::host_to_be<uint16_t>(new_max_age * 256);
|
||||
}
|
||||
|
||||
void STP::hello_time(uint16_t new_hello_time) {
|
||||
_header.hello_time = Endian::host_to_be<uint16_t>(new_hello_time * 256);
|
||||
header_.hello_time = Endian::host_to_be<uint16_t>(new_hello_time * 256);
|
||||
}
|
||||
|
||||
void STP::fwd_delay(uint16_t new_fwd_delay) {
|
||||
_header.fwd_delay = Endian::host_to_be<uint16_t>(new_fwd_delay * 256);
|
||||
header_.fwd_delay = Endian::host_to_be<uint16_t>(new_fwd_delay * 256);
|
||||
}
|
||||
|
||||
STP::bpdu_id_type STP::root_id() const {
|
||||
return convert(_header.root_id);
|
||||
return convert(header_.root_id);
|
||||
}
|
||||
|
||||
STP::bpdu_id_type STP::bridge_id() const {
|
||||
return convert(_header.bridge_id);
|
||||
return convert(header_.bridge_id);
|
||||
}
|
||||
|
||||
void STP::root_id(const bpdu_id_type &id) {
|
||||
_header.root_id = convert(id);
|
||||
void STP::root_id(const bpdu_id_type& id) {
|
||||
header_.root_id = convert(id);
|
||||
}
|
||||
|
||||
void STP::bridge_id(const bpdu_id_type &id) {
|
||||
_header.bridge_id = convert(id);
|
||||
void STP::bridge_id(const bpdu_id_type& id) {
|
||||
header_.bridge_id = convert(id);
|
||||
}
|
||||
|
||||
void STP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
|
||||
void STP::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
stream.write(_header);
|
||||
stream.write(header_);
|
||||
}
|
||||
|
||||
uint32_t STP::header_size() const {
|
||||
return sizeof(_header);
|
||||
return sizeof(header_);
|
||||
}
|
||||
|
||||
STP::bpdu_id_type STP::convert(const pvt_bpdu_id &id) {
|
||||
STP::bpdu_id_type STP::convert(const pvt_bpdu_id& id) {
|
||||
bpdu_id_type result(id.priority, 0, id.id);
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
result.ext_id = (id.ext_id << 8) | id.ext_idL;
|
||||
@@ -125,10 +125,10 @@ STP::bpdu_id_type STP::convert(const pvt_bpdu_id &id) {
|
||||
return result;
|
||||
}
|
||||
|
||||
STP::pvt_bpdu_id STP::convert(const bpdu_id_type &id) {
|
||||
STP::pvt_bpdu_id STP::convert(const bpdu_id_type& id) {
|
||||
pvt_bpdu_id result;
|
||||
result.priority = id.priority;
|
||||
std::copy(id.id.begin(), id.id.end(), result.id);
|
||||
copy(id.id.begin(), id.id.end(), result.id);
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
result.ext_id = (id.ext_id >> 8) & 0xf;
|
||||
result.ext_idL = id.ext_id & 0xff;
|
||||
@@ -137,5 +137,5 @@ STP::pvt_bpdu_id STP::convert(const bpdu_id_type &id) {
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
194
src/tcp.cpp
194
src/tcp.cpp
@@ -40,6 +40,9 @@
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using std::find_if;
|
||||
using std::min;
|
||||
using std::vector;
|
||||
using std::pair;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
@@ -49,25 +52,23 @@ namespace Tins {
|
||||
const uint16_t TCP::DEFAULT_WINDOW = 32678;
|
||||
|
||||
TCP::TCP(uint16_t dport, uint16_t sport)
|
||||
: _tcp(), _options_size(0), _total_options_size(0)
|
||||
{
|
||||
: header_(), options_size_(0), total_options_size_(0) {
|
||||
this->dport(dport);
|
||||
this->sport(sport);
|
||||
data_offset(sizeof(tcphdr) / sizeof(uint32_t));
|
||||
data_offset(sizeof(tcp_header) / sizeof(uint32_t));
|
||||
window(DEFAULT_WINDOW);
|
||||
}
|
||||
|
||||
TCP::TCP(const uint8_t *buffer, uint32_t total_sz)
|
||||
: _options_size(0), _total_options_size(0)
|
||||
{
|
||||
TCP::TCP(const uint8_t* buffer, uint32_t total_sz)
|
||||
: options_size_(0), total_options_size_(0) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_tcp);
|
||||
stream.read(header_);
|
||||
// Check that we have at least the amount of bytes we need and not less
|
||||
if (TINS_UNLIKELY(data_offset() * sizeof(uint32_t) > total_sz ||
|
||||
data_offset() * sizeof(uint32_t) < sizeof(tcphdr))) {
|
||||
data_offset() * sizeof(uint32_t) < sizeof(tcp_header))) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
const uint8_t *header_end = buffer + (data_offset() * sizeof(uint32_t));
|
||||
const uint8_t* header_end = buffer + (data_offset() * sizeof(uint32_t));
|
||||
|
||||
while (stream.pointer() < header_end) {
|
||||
const OptionTypes option_type = (OptionTypes)stream.read<uint8_t>();
|
||||
@@ -81,7 +82,7 @@ TCP::TCP(const uint8_t *buffer, uint32_t total_sz)
|
||||
else {
|
||||
// Extract the length
|
||||
uint32_t len = stream.read<uint8_t>();
|
||||
const uint8_t *data_start = stream.pointer();
|
||||
const uint8_t* data_start = stream.pointer();
|
||||
|
||||
// We need to subtract the option type and length from the size
|
||||
if (TINS_UNLIKELY(len < sizeof(uint8_t) << 1)) {
|
||||
@@ -109,35 +110,35 @@ TCP::TCP(const uint8_t *buffer, uint32_t total_sz)
|
||||
}
|
||||
|
||||
void TCP::dport(uint16_t new_dport) {
|
||||
_tcp.dport = Endian::host_to_be(new_dport);
|
||||
header_.dport = Endian::host_to_be(new_dport);
|
||||
}
|
||||
|
||||
void TCP::sport(uint16_t new_sport) {
|
||||
_tcp.sport = Endian::host_to_be(new_sport);
|
||||
header_.sport = Endian::host_to_be(new_sport);
|
||||
}
|
||||
|
||||
void TCP::seq(uint32_t new_seq) {
|
||||
_tcp.seq = Endian::host_to_be(new_seq);
|
||||
header_.seq = Endian::host_to_be(new_seq);
|
||||
}
|
||||
|
||||
void TCP::ack_seq(uint32_t new_ack_seq) {
|
||||
_tcp.ack_seq = Endian::host_to_be(new_ack_seq);
|
||||
header_.ack_seq = Endian::host_to_be(new_ack_seq);
|
||||
}
|
||||
|
||||
void TCP::window(uint16_t new_window) {
|
||||
_tcp.window = Endian::host_to_be(new_window);
|
||||
header_.window = Endian::host_to_be(new_window);
|
||||
}
|
||||
|
||||
void TCP::checksum(uint16_t new_check) {
|
||||
_tcp.check = Endian::host_to_be(new_check);
|
||||
header_.check = Endian::host_to_be(new_check);
|
||||
}
|
||||
|
||||
void TCP::urg_ptr(uint16_t new_urg_ptr) {
|
||||
_tcp.urg_ptr = Endian::host_to_be(new_urg_ptr);
|
||||
header_.urg_ptr = Endian::host_to_be(new_urg_ptr);
|
||||
}
|
||||
|
||||
void TCP::data_offset(small_uint<4> new_doff) {
|
||||
this->_tcp.doff = new_doff;
|
||||
this->header_.doff = new_doff;
|
||||
}
|
||||
|
||||
void TCP::mss(uint16_t value) {
|
||||
@@ -165,28 +166,22 @@ bool TCP::has_sack_permitted() const {
|
||||
return search_option(SACK_OK) != NULL;
|
||||
}
|
||||
|
||||
void TCP::sack(const sack_type &edges) {
|
||||
uint32_t *value = 0;
|
||||
if(edges.size()) {
|
||||
value = new uint32_t[edges.size()];
|
||||
uint32_t *ptr = value;
|
||||
for(sack_type::const_iterator it = edges.begin(); it != edges.end(); ++it)
|
||||
*(ptr++) = Endian::host_to_be(*it);
|
||||
void TCP::sack(const sack_type& edges) {
|
||||
vector<uint8_t> value(edges.size() * sizeof(uint32_t));
|
||||
if (edges.size()) {
|
||||
OutputMemoryStream stream(value);
|
||||
for (sack_type::const_iterator it = edges.begin(); it != edges.end(); ++it) {
|
||||
stream.write_be(*it);
|
||||
}
|
||||
}
|
||||
add_option(
|
||||
option(
|
||||
SACK,
|
||||
(uint8_t)(sizeof(uint32_t) * edges.size()),
|
||||
(const uint8_t*)value
|
||||
)
|
||||
);
|
||||
delete[] value;
|
||||
add_option(option(SACK, (uint8_t)value.size(), &value[0]));
|
||||
}
|
||||
|
||||
TCP::sack_type TCP::sack() const {
|
||||
const option *opt = search_option(SACK);
|
||||
if(!opt)
|
||||
const option* opt = search_option(SACK);
|
||||
if (!opt) {
|
||||
throw option_not_found();
|
||||
}
|
||||
return opt->to<sack_type>();
|
||||
}
|
||||
|
||||
@@ -196,11 +191,12 @@ void TCP::timestamp(uint32_t value, uint32_t reply) {
|
||||
add_option(option(TSOPT, 8, (uint8_t*)&buffer));
|
||||
}
|
||||
|
||||
std::pair<uint32_t, uint32_t> TCP::timestamp() const {
|
||||
const option *opt = search_option(TSOPT);
|
||||
if(!opt)
|
||||
pair<uint32_t, uint32_t> TCP::timestamp() const {
|
||||
const option* opt = search_option(TSOPT);
|
||||
if (!opt) {
|
||||
throw option_not_found();
|
||||
return opt->to<std::pair<uint32_t, uint32_t> >();
|
||||
}
|
||||
return opt->to<pair<uint32_t, uint32_t> >();
|
||||
}
|
||||
|
||||
void TCP::altchecksum(AltChecksums value) {
|
||||
@@ -213,30 +209,30 @@ TCP::AltChecksums TCP::altchecksum() const {
|
||||
}
|
||||
|
||||
small_uint<1> TCP::get_flag(Flags tcp_flag) const {
|
||||
switch(tcp_flag) {
|
||||
switch (tcp_flag) {
|
||||
case FIN:
|
||||
return _tcp.flags.fin;
|
||||
return header_.flags.fin;
|
||||
break;
|
||||
case SYN:
|
||||
return _tcp.flags.syn;
|
||||
return header_.flags.syn;
|
||||
break;
|
||||
case RST:
|
||||
return _tcp.flags.rst;
|
||||
return header_.flags.rst;
|
||||
break;
|
||||
case PSH:
|
||||
return _tcp.flags.psh;
|
||||
return header_.flags.psh;
|
||||
break;
|
||||
case ACK:
|
||||
return _tcp.flags.ack;
|
||||
return header_.flags.ack;
|
||||
break;
|
||||
case URG:
|
||||
return _tcp.flags.urg;
|
||||
return header_.flags.urg;
|
||||
break;
|
||||
case ECE:
|
||||
return _tcp.flags.ece;
|
||||
return header_.flags.ece;
|
||||
break;
|
||||
case CWR:
|
||||
return _tcp.flags.cwr;
|
||||
return header_.flags.cwr;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
@@ -245,69 +241,69 @@ small_uint<1> TCP::get_flag(Flags tcp_flag) const {
|
||||
}
|
||||
|
||||
small_uint<12> TCP::flags() const {
|
||||
return (_tcp.res1 << 8) | _tcp.flags_8;
|
||||
return (header_.res1 << 8) | header_.flags_8;
|
||||
}
|
||||
|
||||
void TCP::set_flag(Flags tcp_flag, small_uint<1> value) {
|
||||
switch(tcp_flag) {
|
||||
switch (tcp_flag) {
|
||||
case FIN:
|
||||
_tcp.flags.fin = value;
|
||||
header_.flags.fin = value;
|
||||
break;
|
||||
case SYN:
|
||||
_tcp.flags.syn = value;
|
||||
header_.flags.syn = value;
|
||||
break;
|
||||
case RST:
|
||||
_tcp.flags.rst = value;
|
||||
header_.flags.rst = value;
|
||||
break;
|
||||
case PSH:
|
||||
_tcp.flags.psh = value;
|
||||
header_.flags.psh = value;
|
||||
break;
|
||||
case ACK:
|
||||
_tcp.flags.ack = value;
|
||||
header_.flags.ack = value;
|
||||
break;
|
||||
case URG:
|
||||
_tcp.flags.urg = value;
|
||||
header_.flags.urg = value;
|
||||
break;
|
||||
case ECE:
|
||||
_tcp.flags.ece = value;
|
||||
header_.flags.ece = value;
|
||||
break;
|
||||
case CWR:
|
||||
_tcp.flags.cwr = value;
|
||||
header_.flags.cwr = value;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
void TCP::flags(small_uint<12> value) {
|
||||
_tcp.res1 = (value >> 8) & 0x0f;
|
||||
_tcp.flags_8 = value & 0xff;
|
||||
header_.res1 = (value >> 8) & 0x0f;
|
||||
header_.flags_8 = value & 0xff;
|
||||
}
|
||||
|
||||
void TCP::add_option(const option &opt) {
|
||||
_options.push_back(opt);
|
||||
void TCP::add_option(const option& opt) {
|
||||
options_.push_back(opt);
|
||||
internal_add_option(opt);
|
||||
}
|
||||
|
||||
uint32_t TCP::header_size() const {
|
||||
return sizeof(tcphdr) + _total_options_size;
|
||||
return sizeof(header_) + total_options_size_;
|
||||
}
|
||||
|
||||
void TCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
|
||||
void TCP::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
// Set checksum to 0, we'll calculate it at the end
|
||||
checksum(0);
|
||||
_tcp.doff = (sizeof(tcphdr) + _total_options_size) / sizeof(uint32_t);
|
||||
stream.write(_tcp);
|
||||
for(options_type::const_iterator it = _options.begin(); it != _options.end(); ++it) {
|
||||
header_.doff = (sizeof(tcp_header) + total_options_size_) / sizeof(uint32_t);
|
||||
stream.write(header_);
|
||||
for (options_type::const_iterator it = options_.begin(); it != options_.end(); ++it) {
|
||||
write_option(*it, stream);
|
||||
}
|
||||
|
||||
if (_options_size < _total_options_size) {
|
||||
const uint16_t padding = _total_options_size - _options_size;
|
||||
if (options_size_ < total_options_size_) {
|
||||
const uint16_t padding = total_options_size_ - options_size_;
|
||||
stream.fill(padding, 1);
|
||||
}
|
||||
|
||||
uint32_t check = 0;
|
||||
if (const Tins::IP *ip_packet = tins_cast<const Tins::IP*>(parent)) {
|
||||
if (const Tins::IP* ip_packet = tins_cast<const Tins::IP*>(parent)) {
|
||||
check = Utils::pseudoheader_checksum(
|
||||
ip_packet->src_addr(),
|
||||
ip_packet->dst_addr(),
|
||||
@@ -315,7 +311,7 @@ void TCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *par
|
||||
Constants::IP::PROTO_TCP
|
||||
) + Utils::sum_range(buffer, buffer + total_sz);
|
||||
}
|
||||
else if (const Tins::IPv6 *ipv6_packet = tins_cast<const Tins::IPv6*>(parent)) {
|
||||
else if (const Tins::IPv6* ipv6_packet = tins_cast<const Tins::IPv6*>(parent)) {
|
||||
check = Utils::pseudoheader_checksum(
|
||||
ipv6_packet->src_addr(),
|
||||
ipv6_packet->dst_addr(),
|
||||
@@ -331,35 +327,35 @@ void TCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *par
|
||||
check = (check & 0xffff) + (check >> 16);
|
||||
}
|
||||
checksum(Endian::host_to_be<uint16_t>(~check));
|
||||
((tcphdr*)buffer)->check = _tcp.check;
|
||||
((tcp_header*)buffer)->check = header_.check;
|
||||
}
|
||||
|
||||
const TCP::option *TCP::search_option(OptionTypes type) const {
|
||||
const TCP::option* TCP::search_option(OptionTypes type) const {
|
||||
// Search for the iterator. If we found something, return it, otherwise return nullptr.
|
||||
options_type::const_iterator iter = search_option_iterator(type);
|
||||
return (iter != _options.end()) ? &*iter : 0;
|
||||
return (iter != options_.end()) ? &*iter : 0;
|
||||
}
|
||||
|
||||
TCP::options_type::const_iterator TCP::search_option_iterator(OptionTypes type) const {
|
||||
Internals::option_type_equality_comparator<option> comparator(type);
|
||||
return find_if(_options.begin(), _options.end(), comparator);
|
||||
return find_if(options_.begin(), options_.end(), comparator);
|
||||
}
|
||||
|
||||
TCP::options_type::iterator TCP::search_option_iterator(OptionTypes type) {
|
||||
Internals::option_type_equality_comparator<option> comparator(type);
|
||||
return find_if(_options.begin(), _options.end(), comparator);
|
||||
return find_if(options_.begin(), options_.end(), comparator);
|
||||
}
|
||||
|
||||
/* options */
|
||||
|
||||
void TCP::write_option(const option &opt, OutputMemoryStream& stream) {
|
||||
void TCP::write_option(const option& opt, OutputMemoryStream& stream) {
|
||||
stream.write<uint8_t>(opt.option());
|
||||
// Only do this for non EOL nor NOP options
|
||||
if(opt.option() > 1) {
|
||||
if (opt.option() > 1) {
|
||||
uint8_t length = opt.length_field();
|
||||
// Only add the identifier and size field sizes if the length
|
||||
// field hasn't been spoofed.
|
||||
if(opt.length_field() == opt.data_size()) {
|
||||
if (opt.length_field() == opt.data_size()) {
|
||||
length += (sizeof(uint8_t) << 1);
|
||||
}
|
||||
stream.write(length);
|
||||
@@ -368,47 +364,47 @@ void TCP::write_option(const option &opt, OutputMemoryStream& stream) {
|
||||
}
|
||||
|
||||
void TCP::update_options_size() {
|
||||
uint8_t padding = _options_size & 3;
|
||||
_total_options_size = (padding) ? (_options_size - padding + 4) : _options_size;
|
||||
uint8_t padding = options_size_ & 3;
|
||||
total_options_size_ = (padding) ? (options_size_ - padding + 4) : options_size_;
|
||||
}
|
||||
|
||||
void TCP::internal_add_option(const option &opt) {
|
||||
_options_size += sizeof(uint8_t);
|
||||
void TCP::internal_add_option(const option& opt) {
|
||||
options_size_ += sizeof(uint8_t);
|
||||
// SACK_OK contains length but not data....
|
||||
if(opt.data_size() || opt.option() == SACK_OK) {
|
||||
_options_size += sizeof(uint8_t);
|
||||
_options_size += static_cast<uint16_t>(opt.data_size());
|
||||
if (opt.data_size() || opt.option() == SACK_OK) {
|
||||
options_size_ += sizeof(uint8_t);
|
||||
options_size_ += static_cast<uint16_t>(opt.data_size());
|
||||
}
|
||||
update_options_size();
|
||||
}
|
||||
|
||||
bool TCP::remove_option(OptionTypes type) {
|
||||
options_type::iterator iter = search_option_iterator(type);
|
||||
if (iter == _options.end()) {
|
||||
if (iter == options_.end()) {
|
||||
return false;
|
||||
}
|
||||
_options_size -= sizeof(uint8_t);
|
||||
options_size_ -= sizeof(uint8_t);
|
||||
// SACK_OK contains length but not data....
|
||||
if(iter->data_size() || iter->option() == SACK_OK) {
|
||||
_options_size -= sizeof(uint8_t);
|
||||
_options_size -= static_cast<uint16_t>(iter->data_size());
|
||||
if (iter->data_size() || iter->option() == SACK_OK) {
|
||||
options_size_ -= sizeof(uint8_t);
|
||||
options_size_ -= static_cast<uint16_t>(iter->data_size());
|
||||
}
|
||||
_options.erase(iter);
|
||||
options_.erase(iter);
|
||||
update_options_size();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TCP::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
if(total_sz < sizeof(tcphdr))
|
||||
bool TCP::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
if (total_sz < sizeof(header_)) {
|
||||
return false;
|
||||
const tcphdr *tcp_ptr = (const tcphdr*)ptr;
|
||||
if(tcp_ptr->sport == _tcp.dport && tcp_ptr->dport == _tcp.sport) {
|
||||
uint32_t sz = std::min<uint32_t>(total_sz, tcp_ptr->doff * sizeof(uint32_t));
|
||||
}
|
||||
const tcp_header* tcp_ptr = (const tcp_header*)ptr;
|
||||
if (tcp_ptr->sport == header_.dport && tcp_ptr->dport == header_.sport) {
|
||||
uint32_t sz = min<uint32_t>(total_sz, tcp_ptr->doff * sizeof(uint32_t));
|
||||
return inner_pdu() ? inner_pdu()->matches_response(ptr + sz, total_sz - sz) : true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
@@ -31,12 +31,15 @@
|
||||
#include "rawpdu.h"
|
||||
#include "tcp_stream.h"
|
||||
|
||||
using std::numeric_limits;
|
||||
using std::make_pair;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
// As defined by RFC 1982 - 2 ^ (SERIAL_BITS - 1)
|
||||
static const uint32_t seq_number_diff = 2147483648U;
|
||||
// As defined by RFC 1982 - 2 ^ (SERIAL_BITS)
|
||||
static const uint32_t addition_modulo = std::numeric_limits<uint32_t>::max();
|
||||
static const uint32_t addition_modulo = numeric_limits<uint32_t>::max();
|
||||
|
||||
// Sequence number add as defined by RFC 1982
|
||||
uint32_t add_sequence_numbers(uint32_t seq1, uint32_t seq2) {
|
||||
@@ -45,19 +48,22 @@ uint32_t add_sequence_numbers(uint32_t seq1, uint32_t seq2) {
|
||||
|
||||
// Subtract sequence numbers
|
||||
uint32_t subtract_sequence_numbers(uint32_t seq1, uint32_t seq2) {
|
||||
if(seq1 > seq2)
|
||||
if (seq1 > seq2) {
|
||||
return seq1 - seq2;
|
||||
else
|
||||
}
|
||||
else {
|
||||
// the numbers between seq2 and the maximum sequence number(including seq1)
|
||||
// + the numbers between 0 and seq1
|
||||
return (std::numeric_limits<uint32_t>::max() - seq2) + seq1 + 1;
|
||||
return (numeric_limits<uint32_t>::max() - seq2) + seq1 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Compares sequence numbers as defined by RFC 1982.
|
||||
int compare_seq_numbers(uint32_t seq1, uint32_t seq2) {
|
||||
if(seq1 == seq2)
|
||||
if (seq1 == seq2) {
|
||||
return 0;
|
||||
if(seq1 < seq2) {
|
||||
}
|
||||
if (seq1 < seq2) {
|
||||
return (seq2 - seq1 < seq_number_diff) ? -1 : 1;
|
||||
}
|
||||
else {
|
||||
@@ -70,84 +76,87 @@ Iterator erase_iterator(Iterator it, Container& cont) {
|
||||
Iterator output = it;
|
||||
++output;
|
||||
cont.erase(it);
|
||||
if(output == cont.end())
|
||||
if (output == cont.end()) {
|
||||
output = cont.begin();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
// TCPStreamFollower
|
||||
|
||||
TCPStreamFollower::TCPStreamFollower() : last_identifier(0) {
|
||||
TCPStreamFollower::TCPStreamFollower()
|
||||
: last_identifier_(0) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
TCPStream::StreamInfo::StreamInfo(IPv4Address client,
|
||||
IPv4Address server, uint16_t cport, uint16_t sport)
|
||||
IPv4Address server,
|
||||
uint16_t cport,
|
||||
uint16_t sport)
|
||||
: client_addr(client), server_addr(server), client_port(cport),
|
||||
server_port(sport)
|
||||
{
|
||||
|
||||
server_port(sport) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
TCPStream::TCPStream(IP *ip, TCP *tcp, uint64_t identifier)
|
||||
: client_seq(tcp->seq()), server_seq(0), info(ip->src_addr(),
|
||||
ip->dst_addr(), tcp->sport(), tcp->dport()), identifier(identifier),
|
||||
syn_ack_sent(false), fin_sent(false)
|
||||
{
|
||||
|
||||
TCPStream::TCPStream(IP* ip, TCP* tcp, uint64_t identifier)
|
||||
: client_seq_(tcp->seq()), server_seq_(0), info_(ip->src_addr(),
|
||||
ip->dst_addr(), tcp->sport(), tcp->dport()), identifier_(identifier),
|
||||
syn_ack_sent_(false), fin_sent_(false) {
|
||||
}
|
||||
|
||||
TCPStream::TCPStream(const TCPStream &rhs) {
|
||||
TCPStream::TCPStream(const TCPStream& rhs) {
|
||||
*this = rhs;
|
||||
}
|
||||
|
||||
TCPStream& TCPStream::operator=(const TCPStream &rhs) {
|
||||
client_seq = rhs.client_seq;
|
||||
server_seq = rhs.server_seq;
|
||||
info = rhs.info;
|
||||
identifier = rhs.identifier;
|
||||
syn_ack_sent = rhs.syn_ack_sent;
|
||||
fin_sent = rhs.fin_sent;
|
||||
TCPStream& TCPStream::operator=(const TCPStream& rhs) {
|
||||
client_seq_ = rhs.client_seq_;
|
||||
server_seq_ = rhs.server_seq_;
|
||||
info_ = rhs.info_;
|
||||
identifier_ = rhs.identifier_;
|
||||
syn_ack_sent_ = rhs.syn_ack_sent_;
|
||||
fin_sent_ = rhs.fin_sent_;
|
||||
client_payload_ = rhs.client_payload_;
|
||||
server_payload_ = rhs.server_payload_;
|
||||
client_frags = clone_fragments(rhs.client_frags);
|
||||
server_frags = clone_fragments(rhs.server_frags);
|
||||
return *this;
|
||||
client_frags_ = clone_fragments(rhs.client_frags_);
|
||||
server_frags_ = clone_fragments(rhs.server_frags_);
|
||||
return* this;
|
||||
}
|
||||
|
||||
TCPStream::~TCPStream() {
|
||||
free_fragments(client_frags);
|
||||
free_fragments(server_frags);
|
||||
free_fragments(client_frags_);
|
||||
free_fragments(server_frags_);
|
||||
}
|
||||
|
||||
void TCPStream::free_fragments(fragments_type &frags) {
|
||||
for(fragments_type::iterator it = frags.begin(); it != frags.end(); ++it)
|
||||
void TCPStream::free_fragments(fragments_type& frags) {
|
||||
for (fragments_type::iterator it = frags.begin(); it != frags.end(); ++it) {
|
||||
delete it->second;
|
||||
}
|
||||
}
|
||||
|
||||
TCPStream::fragments_type TCPStream::clone_fragments(const fragments_type &frags) {
|
||||
TCPStream::fragments_type TCPStream::clone_fragments(const fragments_type& frags) {
|
||||
fragments_type new_frags;
|
||||
for(fragments_type::const_iterator it = frags.begin(); it != frags.end(); ++it)
|
||||
new_frags.insert(std::make_pair(it->first, it->second->clone()));
|
||||
for (fragments_type::const_iterator it = frags.begin(); it != frags.end(); ++it) {
|
||||
new_frags.insert(make_pair(it->first, it->second->clone()));
|
||||
}
|
||||
return new_frags;
|
||||
}
|
||||
|
||||
void TCPStream::safe_insert(fragments_type &frags, uint32_t seq, RawPDU *raw)
|
||||
{
|
||||
void TCPStream::safe_insert(fragments_type& frags, uint32_t seq, RawPDU* raw) {
|
||||
RawPDU*& stored_raw = frags[seq];
|
||||
// New segment, insert it
|
||||
if(stored_raw == 0)
|
||||
if (stored_raw == 0) {
|
||||
stored_raw = raw;
|
||||
}
|
||||
else {
|
||||
// There was a segment in this position. Keep the largest one.
|
||||
if(stored_raw->payload_size() > raw->payload_size())
|
||||
if (stored_raw->payload_size() > raw->payload_size()) {
|
||||
delete raw;
|
||||
}
|
||||
else {
|
||||
delete stored_raw;
|
||||
stored_raw = raw;
|
||||
@@ -155,20 +164,23 @@ void TCPStream::safe_insert(fragments_type &frags, uint32_t seq, RawPDU *raw)
|
||||
}
|
||||
}
|
||||
|
||||
bool TCPStream::generic_process(uint32_t &my_seq, uint32_t &other_seq,
|
||||
payload_type &pload, fragments_type &frags, TCP *tcp)
|
||||
{
|
||||
bool TCPStream::generic_process(uint32_t& my_seq,
|
||||
uint32_t& other_seq,
|
||||
payload_type& pload,
|
||||
fragments_type& frags,
|
||||
TCP* tcp) {
|
||||
bool added_some(false);
|
||||
if(tcp->get_flag(TCP::FIN) || tcp->get_flag(TCP::RST))
|
||||
fin_sent = true;
|
||||
RawPDU *raw = static_cast<RawPDU*>(tcp->release_inner_pdu());
|
||||
if(raw) {
|
||||
if (tcp->get_flag(TCP::FIN) || tcp->get_flag(TCP::RST)) {
|
||||
fin_sent_ = true;
|
||||
}
|
||||
RawPDU* raw = static_cast<RawPDU*>(tcp->release_inner_pdu());
|
||||
if (raw) {
|
||||
const uint32_t chunk_end = add_sequence_numbers(tcp->seq(), raw->payload_size());
|
||||
// If the end of the chunk ends after our current sequence number, process it.
|
||||
if(compare_seq_numbers(chunk_end, my_seq) >= 0) {
|
||||
if (compare_seq_numbers(chunk_end, my_seq) >= 0) {
|
||||
uint32_t seq = tcp->seq();
|
||||
// If it starts before our sequence number, slice it
|
||||
if(compare_seq_numbers(seq, my_seq) < 0) {
|
||||
if (compare_seq_numbers(seq, my_seq) < 0) {
|
||||
const uint32_t diff = subtract_sequence_numbers(my_seq, seq);
|
||||
raw->payload().erase(
|
||||
raw->payload().begin(),
|
||||
@@ -179,13 +191,13 @@ bool TCPStream::generic_process(uint32_t &my_seq, uint32_t &other_seq,
|
||||
safe_insert(frags, seq, raw);
|
||||
fragments_type::iterator it = frags.find(my_seq);
|
||||
// Keep looping while the fragments seq is lower or equal to our seq
|
||||
while(it != frags.end() && compare_seq_numbers(it->first, my_seq) <= 0) {
|
||||
while (it != frags.end() && compare_seq_numbers(it->first, my_seq) <= 0) {
|
||||
// Does this fragment start before our sequence number?
|
||||
if(compare_seq_numbers(it->first, my_seq) < 0) {
|
||||
if (compare_seq_numbers(it->first, my_seq) < 0) {
|
||||
uint32_t fragment_end = add_sequence_numbers(it->first, it->second->payload_size());
|
||||
int comparison = compare_seq_numbers(fragment_end, my_seq);
|
||||
// Does it end after our sequence number?
|
||||
if(comparison > 0) {
|
||||
if (comparison > 0) {
|
||||
// Then slice it
|
||||
RawPDU::payload_type& payload = it->second->payload();
|
||||
payload.erase(
|
||||
@@ -212,48 +224,55 @@ bool TCPStream::generic_process(uint32_t &my_seq, uint32_t &other_seq,
|
||||
delete it->second;
|
||||
it = erase_iterator(it, frags);
|
||||
added_some = true;
|
||||
if(frags.empty())
|
||||
if (frags.empty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
else {
|
||||
delete raw;
|
||||
}
|
||||
}
|
||||
return added_some;
|
||||
}
|
||||
|
||||
bool TCPStream::update(IP *ip, TCP *tcp) {
|
||||
if(!syn_ack_sent) {
|
||||
if(tcp->flags() == (TCP::SYN | TCP::ACK)) {
|
||||
server_seq = tcp->seq() + 1;
|
||||
client_seq = tcp->ack_seq();
|
||||
syn_ack_sent = true;
|
||||
bool TCPStream::update(IP* ip, TCP* tcp) {
|
||||
if (!syn_ack_sent_) {
|
||||
if (tcp->flags() == (TCP::SYN | TCP::ACK)) {
|
||||
server_seq_ = tcp->seq() + 1;
|
||||
client_seq_ = tcp->ack_seq();
|
||||
syn_ack_sent_ = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if(ip->src_addr() == info.client_addr && tcp->sport() == info.client_port)
|
||||
return generic_process(client_seq, server_seq, client_payload_, client_frags, tcp);
|
||||
if (ip->src_addr() == info_.client_addr && tcp->sport() == info_.client_port) {
|
||||
return generic_process(client_seq_, server_seq_, client_payload_, client_frags_, tcp);
|
||||
}
|
||||
else {
|
||||
return generic_process(server_seq, client_seq, server_payload_, server_frags, tcp);
|
||||
return generic_process(server_seq_, client_seq_, server_payload_, server_frags_, tcp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TCPStream::StreamInfo::operator<(const StreamInfo &rhs) const {
|
||||
if(client_addr == rhs.client_addr) {
|
||||
if(server_addr == rhs.server_addr) {
|
||||
if(client_port == rhs.client_port) {
|
||||
bool TCPStream::StreamInfo::operator<(const StreamInfo& rhs) const {
|
||||
if (client_addr == rhs.client_addr) {
|
||||
if (server_addr == rhs.server_addr) {
|
||||
if (client_port == rhs.client_port) {
|
||||
return server_port < rhs.server_port;
|
||||
}
|
||||
else
|
||||
else {
|
||||
return client_port < rhs.client_port;
|
||||
}
|
||||
}
|
||||
else
|
||||
else {
|
||||
return server_addr < rhs.server_addr;
|
||||
}
|
||||
}
|
||||
else
|
||||
else {
|
||||
return client_addr < rhs.client_addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // Tins
|
||||
|
||||
79
src/udp.cpp
79
src/udp.cpp
@@ -43,50 +43,49 @@ using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
UDP::UDP(uint16_t dport, uint16_t sport) : _udp()
|
||||
{
|
||||
UDP::UDP(uint16_t dport, uint16_t sport)
|
||||
: header_() {
|
||||
this->dport(dport);
|
||||
this->sport(sport);
|
||||
}
|
||||
|
||||
UDP::UDP(const uint8_t *buffer, uint32_t total_sz)
|
||||
{
|
||||
UDP::UDP(const uint8_t* buffer, uint32_t total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(_udp);
|
||||
stream.read(header_);
|
||||
if (stream) {
|
||||
inner_pdu(new RawPDU(stream.pointer(), stream.size()));
|
||||
}
|
||||
}
|
||||
|
||||
void UDP::dport(uint16_t new_dport) {
|
||||
_udp.dport = Endian::host_to_be(new_dport);
|
||||
header_.dport = Endian::host_to_be(new_dport);
|
||||
}
|
||||
|
||||
void UDP::sport(uint16_t new_sport) {
|
||||
_udp.sport = Endian::host_to_be(new_sport);
|
||||
header_.sport = Endian::host_to_be(new_sport);
|
||||
}
|
||||
|
||||
void UDP::length(uint16_t new_len) {
|
||||
_udp.len = Endian::host_to_be(new_len);
|
||||
header_.len = Endian::host_to_be(new_len);
|
||||
}
|
||||
|
||||
uint32_t UDP::header_size() const {
|
||||
return sizeof(udphdr);
|
||||
return sizeof(udp_header);
|
||||
}
|
||||
|
||||
uint32_t sum_range(const uint8_t *start, const uint8_t *end) {
|
||||
uint32_t sum_range(const uint8_t* start, const uint8_t* end) {
|
||||
uint32_t checksum(0);
|
||||
const uint8_t *last = end;
|
||||
const uint8_t* last = end;
|
||||
uint16_t buffer = 0;
|
||||
uint16_t padding = 0;
|
||||
const uint8_t *ptr = start;
|
||||
const uint8_t* ptr = start;
|
||||
|
||||
if(((end - start) & 1) == 1) {
|
||||
if (((end - start) & 1) == 1) {
|
||||
last = end - 1;
|
||||
padding = Endian::host_to_le<uint16_t>(*(end - 1));
|
||||
}
|
||||
|
||||
while(ptr < last) {
|
||||
while (ptr < last) {
|
||||
memcpy(&buffer, ptr, sizeof(uint16_t));
|
||||
checksum += buffer;
|
||||
ptr += sizeof(uint16_t);
|
||||
@@ -104,26 +103,26 @@ uint32_t pseudoheader_checksum(IPv4Address source_ip, IPv4Address dest_ip, uint3
|
||||
stream.write(dest_ip);
|
||||
stream.write(Endian::host_to_be<uint16_t>(flag));
|
||||
stream.write(Endian::host_to_be<uint16_t>(len));
|
||||
uint16_t *ptr = (uint16_t*)buffer, *end = (uint16_t*)(buffer + sizeof(buffer));
|
||||
uint16_t* ptr = (uint16_t*)buffer, *end = (uint16_t*)(buffer + sizeof(buffer));
|
||||
while (ptr < end) {
|
||||
checksum += *ptr++;
|
||||
}
|
||||
return checksum;
|
||||
}
|
||||
|
||||
void UDP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
|
||||
void UDP::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
// Set checksum to 0, we'll calculate it at the end
|
||||
_udp.check = 0;
|
||||
if(inner_pdu()) {
|
||||
length(static_cast<uint16_t>(sizeof(udphdr) + inner_pdu()->size()));
|
||||
header_.check = 0;
|
||||
if (inner_pdu()) {
|
||||
length(static_cast<uint16_t>(sizeof(udp_header) + inner_pdu()->size()));
|
||||
}
|
||||
else {
|
||||
length(static_cast<uint16_t>(sizeof(udphdr)));
|
||||
length(static_cast<uint16_t>(sizeof(udp_header)));
|
||||
}
|
||||
stream.write(_udp);
|
||||
stream.write(header_);
|
||||
uint32_t checksum = 0;
|
||||
if (const Tins::IP *ip_packet = tins_cast<const Tins::IP*>(parent)) {
|
||||
if (const Tins::IP* ip_packet = tins_cast<const Tins::IP*>(parent)) {
|
||||
checksum = Utils::pseudoheader_checksum(
|
||||
ip_packet->src_addr(),
|
||||
ip_packet->dst_addr(),
|
||||
@@ -131,7 +130,7 @@ void UDP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *par
|
||||
Constants::IP::PROTO_UDP
|
||||
) + Utils::sum_range(buffer, buffer + total_sz);
|
||||
}
|
||||
else if (const Tins::IPv6 *ip6_packet = tins_cast<const Tins::IPv6*>(parent)) {
|
||||
else if (const Tins::IPv6* ip6_packet = tins_cast<const Tins::IPv6*>(parent)) {
|
||||
checksum = Utils::pseudoheader_checksum(
|
||||
ip6_packet->src_addr(),
|
||||
ip6_packet->dst_addr(),
|
||||
@@ -145,27 +144,29 @@ void UDP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *par
|
||||
while (checksum >> 16) {
|
||||
checksum = (checksum & 0xffff)+(checksum >> 16);
|
||||
}
|
||||
_udp.check = ~checksum;
|
||||
header_.check = ~checksum;
|
||||
// If checksum is 0, it has to be set to 0xffff
|
||||
_udp.check = (_udp.check == 0) ? 0xffff : _udp.check;
|
||||
((udphdr*)buffer)->check = _udp.check;
|
||||
header_.check = (header_.check == 0) ? 0xffff : header_.check;
|
||||
((udp_header*)buffer)->check = header_.check;
|
||||
}
|
||||
|
||||
bool UDP::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
|
||||
if(total_sz < sizeof(udphdr))
|
||||
bool UDP::matches_response(const uint8_t* ptr, uint32_t total_sz) const {
|
||||
if (total_sz < sizeof(udp_header)) {
|
||||
return false;
|
||||
const udphdr *udp_ptr = (const udphdr*)ptr;
|
||||
if(udp_ptr->sport == _udp.dport && udp_ptr->dport == _udp.sport) {
|
||||
return inner_pdu()
|
||||
?
|
||||
inner_pdu()->matches_response(
|
||||
ptr + sizeof(udphdr),
|
||||
total_sz - sizeof(udphdr)
|
||||
)
|
||||
:
|
||||
0;
|
||||
}
|
||||
const udp_header* udp_ptr = (const udp_header*)ptr;
|
||||
if (udp_ptr->sport == header_.dport && udp_ptr->dport == header_.sport) {
|
||||
if (inner_pdu()) {
|
||||
return inner_pdu()->matches_response(
|
||||
ptr + sizeof(udp_header),
|
||||
total_sz - sizeof(udp_header)
|
||||
);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
} // Tins
|
||||
|
||||
108
src/utils.cpp
108
src/utils.cpp
@@ -58,8 +58,13 @@
|
||||
#include "cxxstd.h"
|
||||
#include "memory_helpers.h"
|
||||
|
||||
using namespace std;
|
||||
using std::string;
|
||||
using std::set;
|
||||
using std::vector;
|
||||
using std::back_inserter;
|
||||
using std::runtime_error;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
/** \cond */
|
||||
@@ -72,22 +77,23 @@ struct InterfaceCollector {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
bool operator() (struct ifaddrs *addr) {
|
||||
bool operator() (struct ifaddrs* addr) {
|
||||
ifaces.insert(addr->ifa_name);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
addrinfo *resolve_domain(const std::string &to_resolve, int family) {
|
||||
addrinfo *result, hints = addrinfo();
|
||||
addrinfo* resolve_domain(const string& to_resolve, int family) {
|
||||
addrinfo* result, hints = addrinfo();
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
hints.ai_family = family;
|
||||
if(!getaddrinfo(to_resolve.c_str(), 0, &hints, &result))
|
||||
if (!getaddrinfo(to_resolve.c_str(), 0, &hints, &result)) {
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("Could not resolve address");
|
||||
throw runtime_error("Could not resolve address");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,51 +102,53 @@ namespace Tins {
|
||||
/** \endcond */
|
||||
namespace Utils {
|
||||
|
||||
IPv4Address resolve_domain(const std::string &to_resolve) {
|
||||
addrinfo *result = ::resolve_domain(to_resolve, AF_INET);
|
||||
IPv4Address resolve_domain(const string& to_resolve) {
|
||||
addrinfo* result = ::resolve_domain(to_resolve, AF_INET);
|
||||
IPv4Address addr(((sockaddr_in*)result->ai_addr)->sin_addr.s_addr);
|
||||
freeaddrinfo(result);
|
||||
return addr;
|
||||
}
|
||||
|
||||
IPv6Address resolve_domain6(const std::string &to_resolve) {
|
||||
addrinfo *result = ::resolve_domain(to_resolve, AF_INET6);
|
||||
IPv6Address resolve_domain6(const string& to_resolve) {
|
||||
addrinfo* result = ::resolve_domain(to_resolve, AF_INET6);
|
||||
IPv6Address addr((const uint8_t*)&((sockaddr_in6*)result->ai_addr)->sin6_addr);
|
||||
freeaddrinfo(result);
|
||||
return addr;
|
||||
}
|
||||
|
||||
HWAddress<6> resolve_hwaddr(const NetworkInterface &iface, IPv4Address ip, PacketSender &sender)
|
||||
{
|
||||
HWAddress<6> resolve_hwaddr(const NetworkInterface& iface,
|
||||
IPv4Address ip,
|
||||
PacketSender& sender) {
|
||||
IPv4Address my_ip;
|
||||
NetworkInterface::Info info(iface.addresses());
|
||||
EthernetII packet = ARP::make_arp_request(ip, info.ip_addr, info.hw_addr);
|
||||
Internals::smart_ptr<PDU>::type response(sender.send_recv(packet, iface));
|
||||
if(response.get()) {
|
||||
const ARP *arp_resp = response->find_pdu<ARP>();
|
||||
if(arp_resp)
|
||||
if (response.get()) {
|
||||
const ARP* arp_resp = response->find_pdu<ARP>();
|
||||
if (arp_resp) {
|
||||
return arp_resp->sender_hw_addr();
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Could not resolve hardware address");
|
||||
throw runtime_error("Could not resolve hardware address");
|
||||
}
|
||||
|
||||
HWAddress<6> resolve_hwaddr(IPv4Address ip, PacketSender &sender) {
|
||||
HWAddress<6> resolve_hwaddr(IPv4Address ip, PacketSender& sender) {
|
||||
return resolve_hwaddr(sender.default_interface(), ip, sender);
|
||||
}
|
||||
|
||||
std::vector<RouteEntry> route_entries() {
|
||||
std::vector<RouteEntry> entries;
|
||||
route_entries(std::back_inserter(entries));
|
||||
vector<RouteEntry> route_entries() {
|
||||
vector<RouteEntry> entries;
|
||||
route_entries(back_inserter(entries));
|
||||
return entries;
|
||||
}
|
||||
|
||||
bool gateway_from_ip(IPv4Address ip, IPv4Address &gw_addr) {
|
||||
typedef std::vector<RouteEntry> entries_type;
|
||||
bool gateway_from_ip(IPv4Address ip, IPv4Address& gw_addr) {
|
||||
typedef vector<RouteEntry> entries_type;
|
||||
entries_type entries;
|
||||
uint32_t ip_int = ip;
|
||||
route_entries(std::back_inserter(entries));
|
||||
for(entries_type::const_iterator it(entries.begin()); it != entries.end(); ++it) {
|
||||
if((ip_int & it->mask) == it->destination) {
|
||||
route_entries(back_inserter(entries));
|
||||
for (entries_type::const_iterator it(entries.begin()); it != entries.end(); ++it) {
|
||||
if ((ip_int & it->mask) == it->destination) {
|
||||
gw_addr = it->gateway;
|
||||
return true;
|
||||
}
|
||||
@@ -162,9 +170,9 @@ uint16_t mhz_to_channel(uint16_t mhz) {
|
||||
return (mhz - 2407) / 5;
|
||||
}
|
||||
|
||||
std::string to_string(PDU::PDUType pduType) {
|
||||
string to_string(PDU::PDUType pduType) {
|
||||
#define ENUM_TEXT(p) case(PDU::p): return #p;
|
||||
switch(pduType){
|
||||
switch (pduType){
|
||||
ENUM_TEXT(RAW);
|
||||
ENUM_TEXT(ETHERNET_II);
|
||||
ENUM_TEXT(IEEE802_3);
|
||||
@@ -215,29 +223,32 @@ std::string to_string(PDU::PDUType pduType) {
|
||||
ENUM_TEXT(PPI);
|
||||
ENUM_TEXT(IPSEC_AH);
|
||||
ENUM_TEXT(IPSEC_ESP);
|
||||
ENUM_TEXT(PKTAP);
|
||||
ENUM_TEXT(MPLS);
|
||||
ENUM_TEXT(USER_DEFINED_PDU);
|
||||
default: return "";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
#undef ENUM_TEXT
|
||||
}
|
||||
|
||||
uint32_t do_checksum(const uint8_t *start, const uint8_t *end) {
|
||||
uint32_t do_checksum(const uint8_t* start, const uint8_t* end) {
|
||||
return Endian::host_to_be<uint32_t>(sum_range(start, end));
|
||||
}
|
||||
|
||||
uint16_t sum_range(const uint8_t *start, const uint8_t *end) {
|
||||
uint16_t sum_range(const uint8_t* start, const uint8_t* end) {
|
||||
uint32_t checksum(0);
|
||||
const uint8_t *last = end;
|
||||
const uint8_t* last = end;
|
||||
uint16_t buffer = 0;
|
||||
uint16_t padding = 0;
|
||||
const uint8_t *ptr = start;
|
||||
const uint8_t* ptr = start;
|
||||
|
||||
if(((end - start) & 1) == 1) {
|
||||
if (((end - start) & 1) == 1) {
|
||||
last = end - 1;
|
||||
padding = Endian::host_to_le<uint16_t>(*(end - 1));
|
||||
}
|
||||
|
||||
while(ptr < last) {
|
||||
while (ptr < last) {
|
||||
memcpy(&buffer, ptr, sizeof(uint16_t));
|
||||
checksum += buffer;
|
||||
ptr += sizeof(uint16_t);
|
||||
@@ -251,9 +262,10 @@ uint16_t sum_range(const uint8_t *start, const uint8_t *end) {
|
||||
}
|
||||
|
||||
template <size_t buffer_size, typename AddressType>
|
||||
uint32_t generic_pseudoheader_checksum(const AddressType& source_ip, const AddressType& dest_ip,
|
||||
uint16_t len, uint16_t flag) {
|
||||
uint32_t checksum(0);
|
||||
uint32_t generic_pseudoheader_checksum(const AddressType& source_ip,
|
||||
const AddressType& dest_ip,
|
||||
uint16_t len,
|
||||
uint16_t flag) {
|
||||
uint8_t buffer[buffer_size];
|
||||
OutputMemoryStream stream(buffer, sizeof(buffer));
|
||||
stream.write(source_ip);
|
||||
@@ -261,20 +273,27 @@ uint32_t generic_pseudoheader_checksum(const AddressType& source_ip, const Addre
|
||||
stream.write(Endian::host_to_be(flag));
|
||||
stream.write(Endian::host_to_be(len));
|
||||
|
||||
uint16_t *ptr = (uint16_t*)buffer, *end = (uint16_t*)(buffer + sizeof(buffer));
|
||||
while (ptr < end) {
|
||||
checksum += *ptr++;
|
||||
InputMemoryStream input_stream(buffer, sizeof(buffer));
|
||||
uint32_t checksum = 0;
|
||||
while (input_stream) {
|
||||
checksum += input_stream.read<uint16_t>();
|
||||
}
|
||||
return checksum;
|
||||
}
|
||||
|
||||
uint32_t pseudoheader_checksum(IPv4Address source_ip, IPv4Address dest_ip, uint16_t len, uint16_t flag) {
|
||||
uint32_t pseudoheader_checksum(IPv4Address source_ip,
|
||||
IPv4Address dest_ip,
|
||||
uint16_t len,
|
||||
uint16_t flag) {
|
||||
return generic_pseudoheader_checksum<sizeof(uint32_t) * 3>(
|
||||
source_ip, dest_ip, len, flag
|
||||
);
|
||||
}
|
||||
|
||||
uint32_t pseudoheader_checksum(IPv6Address source_ip, IPv6Address dest_ip, uint16_t len, uint16_t flag) {
|
||||
uint32_t pseudoheader_checksum(IPv6Address source_ip,
|
||||
IPv6Address dest_ip,
|
||||
uint16_t len,
|
||||
uint16_t flag) {
|
||||
return generic_pseudoheader_checksum<IPv6Address::address_size * 2 + sizeof(uint16_t) * 2>(
|
||||
source_ip, dest_ip, len, flag
|
||||
);
|
||||
@@ -296,5 +315,6 @@ uint32_t crc32(const uint8_t* data, uint32_t data_size) {
|
||||
|
||||
return crc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // Utils
|
||||
} // Tins
|
||||
|
||||
Reference in New Issue
Block a user