1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 02:35:57 +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:
Matias Fontanini
2016-01-02 08:17:59 -08:00
parent f5a82b1a17
commit d84f10cf08
177 changed files with 13203 additions and 12272 deletions

View File

@@ -32,21 +32,25 @@
#include <iostream>
#include <functional>
using std::cout;
using std::endl;
using std::map;
using std::bind;
using namespace Tins;
class arp_monitor {
public:
void run(Sniffer &sniffer);
void run(Sniffer& sniffer);
private:
bool callback(const PDU &pdu);
bool callback(const PDU& pdu);
std::map<IPv4Address, HWAddress<6>> addresses;
map<IPv4Address, HWAddress<6>> addresses;
};
void arp_monitor::run(Sniffer &sniffer)
{
void arp_monitor::run(Sniffer& sniffer) {
sniffer.sniff_loop(
std::bind(
bind(
&arp_monitor::callback,
this,
std::placeholders::_1
@@ -54,36 +58,34 @@ void arp_monitor::run(Sniffer &sniffer)
);
}
bool arp_monitor::callback(const PDU &pdu)
{
bool arp_monitor::callback(const PDU& pdu) {
// Retrieve the ARP layer
const ARP &arp = pdu.rfind_pdu<ARP>();
const ARP& arp = pdu.rfind_pdu<ARP>();
// Is it an ARP reply?
if(arp.opcode() == ARP::REPLY) {
if (arp.opcode() == ARP::REPLY) {
// Let's check if there's already an entry for this address
auto iter = addresses.find(arp.sender_ip_addr());
if(iter == addresses.end()) {
if (iter == addresses.end()) {
// We haven't seen this address. Save it.
addresses.insert({ arp.sender_ip_addr(), arp.sender_hw_addr()});
std::cout << "[INFO] " << arp.sender_ip_addr() << " is at "
<< arp.sender_hw_addr() << std::endl;
cout << "[INFO] " << arp.sender_ip_addr() << " is at "
<< arp.sender_hw_addr() << std::endl;
}
else {
// We've seen this address. If it's not the same HW address, inform it
if(arp.sender_hw_addr() != iter->second) {
std::cout << "[WARNING] " << arp.sender_ip_addr() << " is at "
<< iter->second << " but also at " << arp.sender_hw_addr()
<< std::endl;
if (arp.sender_hw_addr() != iter->second) {
cout << "[WARNING] " << arp.sender_ip_addr() << " is at "
<< iter->second << " but also at " << arp.sender_hw_addr()
<< endl;
}
}
}
return true;
}
int main(int argc, char *argv[])
{
int main(int argc, char* argv[]) {
if(argc != 2) {
std::cout << "Usage: " << *argv << " <interface>\n";
cout << "Usage: " <<* argv << " <interface>" << endl;
return 1;
}
arp_monitor monitor;

View File

@@ -44,13 +44,17 @@
#include <tins/ethernetII.h>
#include <tins/packet_sender.h>
using namespace std;
using std::cout;
using std::runtime_error;
using std::endl;
using namespace Tins;
void do_arp_spoofing(NetworkInterface iface, IPv4Address gw, IPv4Address victim,
const NetworkInterface::Info &info)
{
void do_arp_spoofing(NetworkInterface iface,
IPv4Address gw,
IPv4Address victim,
const NetworkInterface::Info& info) {
PacketSender sender;
EthernetII::address_type gw_hw, victim_hw;
@@ -79,7 +83,7 @@ void do_arp_spoofing(NetworkInterface iface, IPv4Address gw, IPv4Address victim,
* performed by any routers. */
EthernetII to_gw = EthernetII(gw_hw, info.hw_addr) / gw_arp;
EthernetII to_victim = EthernetII(victim_hw, info.hw_addr) / victim_arp;
while(true) {
while (true) {
// Just send them once every 5 seconds.
sender.send(to_gw, iface);
sender.send(to_victim, iface);
@@ -91,9 +95,11 @@ void do_arp_spoofing(NetworkInterface iface, IPv4Address gw, IPv4Address victim,
}
}
int main(int argc, char *argv[]) {
if(argc != 3 && cout << "Usage: " << *argv << " <Gateway> <Victim>\n")
int main(int argc, char* argv[]) {
if (argc != 3) {
cout << "Usage: " <<* argv << " <Gateway> <Victim>" << endl;
return 1;
}
IPv4Address gw, victim;
EthernetII::address_type own_hw;
try {
@@ -101,7 +107,7 @@ int main(int argc, char *argv[]) {
gw = argv[1];
victim = argv[2];
}
catch(...) {
catch (...) {
cout << "Invalid ip found...\n";
return 2;
}
@@ -115,15 +121,15 @@ int main(int argc, char *argv[]) {
// Find the interface hardware and ip address.
info = iface.addresses();
}
catch(std::runtime_error &ex) {
catch (runtime_error& ex) {
cout << ex.what() << endl;
return 3;
}
try {
do_arp_spoofing(iface, gw, victim, info);
}
catch(std::runtime_error &ex) {
std::cout << "Runtime error: " << ex.what() << std::endl;
catch (runtime_error& ex) {
cout << "Runtime error: " << ex.what() << endl;
return 7;
}
}

View File

@@ -32,21 +32,27 @@
#include <string>
#include <tins/tins.h>
using std::set;
using std::cout;
using std::endl;
using std::string;
using std::runtime_error;
using namespace Tins;
class BeaconSniffer {
public:
void run(const std::string &iface);
void run(const string& iface);
private:
typedef Dot11::address_type address_type;
typedef std::set<address_type> ssids_type;
typedef set<address_type> ssids_type;
bool callback(PDU &pdu);
bool callback(PDU& pdu);
ssids_type ssids;
};
void BeaconSniffer::run(const std::string &iface) {
void BeaconSniffer::run(const std::string& iface) {
SnifferConfiguration config;
config.set_promisc_mode(true);
config.set_filter("type mgt subtype beacon");
@@ -55,28 +61,28 @@ void BeaconSniffer::run(const std::string &iface) {
sniffer.sniff_loop(make_sniffer_handler(this, &BeaconSniffer::callback));
}
bool BeaconSniffer::callback(PDU &pdu) {
bool BeaconSniffer::callback(PDU& pdu) {
// Get the Dot11 layer
const Dot11Beacon &beacon = pdu.rfind_pdu<Dot11Beacon>();
const Dot11Beacon& beacon = pdu.rfind_pdu<Dot11Beacon>();
// All beacons must have from_ds == to_ds == 0
if(!beacon.from_ds() && !beacon.to_ds()) {
if (!beacon.from_ds() && !beacon.to_ds()) {
// Get the AP address
address_type addr = beacon.addr2();
// Look it up in our set
ssids_type::iterator it = ssids.find(addr);
if(it == ssids.end()) {
if (it == ssids.end()) {
// First time we encounter this BSSID.
try {
/* If no ssid option is set, then Dot11::ssid will throw
* a std::runtime_error.
*/
std::string ssid = beacon.ssid();
string ssid = beacon.ssid();
// Save it so we don't show it again.
ssids.insert(addr);
// Display the tuple "address - ssid".
std::cout << addr << " - " << ssid << std::endl;
cout << addr << " - " << ssid << endl;
}
catch(std::runtime_error&) {
catch (runtime_error&) {
// No ssid, just ignore it.
}
}
@@ -85,10 +91,11 @@ bool BeaconSniffer::callback(PDU &pdu) {
}
int main(int argc, char* argv[]) {
// By default, sniff wlan0
std::string interface = "wlan0";
if(argc == 2)
interface = argv[1];
if (argc != 2) {
cout << "Usage: " <<* argv << " <interface>" << endl;
return 1;
}
string interface = argv[1];
BeaconSniffer sniffer;
sniffer.run(interface);
}

View File

@@ -30,10 +30,12 @@
#include <tins/tins.h>
#include <iostream>
using std::cout;
using std::endl;
using namespace Tins;
bool callback(const PDU &pdu)
{
bool callback(const PDU& pdu) {
// The packet probably looks like this:
//
// EthernetII / IP / UDP / RawPDU
@@ -43,15 +45,15 @@ bool callback(const PDU &pdu)
DNS dns = pdu.rfind_pdu<RawPDU>().to<DNS>();
// Retrieve the queries and print the domain name:
for(const auto &query : dns.queries())
std::cout << query.dname() << std::endl;
for (const auto& query : dns.queries()) {
cout << query.dname() << std::endl;
}
return true;
}
int main(int argc, char *argv[])
{
int main(int argc, char* argv[]) {
if(argc != 2) {
std::cout << "Usage: " << *argv << " <interface>" << std::endl;
cout << "Usage: " <<* argv << " <interface>" << endl;
return 1;
}
// Sniff on the provided interface in promiscuos mode

View File

@@ -30,11 +30,14 @@
#include <tins/tins.h>
#include <iostream>
using std::cout;
using std::endl;
using namespace Tins;
PacketSender sender;
bool callback(const PDU &pdu)
bool callback(const PDU& pdu)
{
// The packet probably looks like this:
//
@@ -48,10 +51,10 @@ bool callback(const PDU &pdu)
DNS dns = udp.rfind_pdu<RawPDU>().to<DNS>();
// Is it a DNS query?
if(dns.type() == DNS::QUERY) {
if (dns.type() == DNS::QUERY) {
// Let's see if there's any query for an "A" record.
for(const auto &query : dns.queries()) {
if(query.type() == DNS::A) {
for (const auto& query : dns.queries()) {
if (query.type() == DNS::A) {
// Here's one! Let's add an answer.
dns.add_answer(
DNS::Resource(
@@ -66,16 +69,16 @@ bool callback(const PDU &pdu)
}
}
// Have we added some answers?
if(dns.answers_count() > 0) {
if (dns.answers_count() > 0) {
// It's a response now
dns.type(DNS::RESPONSE);
// Recursion is available(just in case)
dns.recursion_available(1);
// Build our packet
auto pkt = EthernetII(eth.src_addr(), eth.dst_addr()) /
IP(ip.src_addr(), ip.dst_addr()) /
UDP(udp.sport(), udp.dport()) /
dns;
IP(ip.src_addr(), ip.dst_addr()) /
UDP(udp.sport(), udp.dport()) /
dns;
// Send it!
sender.send(pkt);
}
@@ -83,10 +86,9 @@ bool callback(const PDU &pdu)
return true;
}
int main(int argc, char *argv[])
{
int main(int argc, char* argv[]) {
if(argc != 2) {
std::cout << "Usage: " << *argv << " <interface>" << std::endl;
cout << "Usage: " <<* argv << " <interface>" << endl;
return 1;
}
// Sniff on the provided interface in promiscuos mode

View File

@@ -39,6 +39,25 @@
#include <algorithm>
#include <tins/tins.h>
using std::cout;
using std::endl;
using std::thread;
using std::string;
using std::bind;
using std::map;
using std::mutex;
using std::max;
using std::min;
using std::exception;
using std::lock_guard;
using std::tuple;
using std::make_tuple;
using std::this_thread::sleep_for;
using std::chrono::seconds;
using std::chrono::milliseconds;
using std::chrono::duration_cast;
using std::chrono::system_clock;
using namespace Tins;
// Holds the DNS response time statistics. The response time is
@@ -47,7 +66,7 @@ template<typename Duration>
class statistics {
public:
using duration_type = Duration;
using locker_type = std::lock_guard<std::mutex>;
using locker_type = lock_guard<mutex>;
struct information {
duration_type average, worst;
@@ -55,42 +74,41 @@ public:
};
statistics()
: m_duration(), m_worst(duration_type::min()), m_count()
{
: m_duration(), m_worst(duration_type::min()), m_count() {
}
void add_response_time(const duration_type& duration)
{
void add_response_time(const duration_type& duration) {
locker_type _(m_lock);
m_duration += duration;
m_count++;
m_worst = std::max(m_worst, duration);
m_worst = max(m_worst, duration);
}
information get_information() const
{
information get_information() const {
locker_type _(m_lock);
if(m_count == 0)
if(m_count == 0) {
return { };
else
}
else {
return { m_duration / m_count, m_worst, m_count };
}
};
private:
duration_type m_duration, m_worst;
size_t m_count;
mutable std::mutex m_lock;
mutable mutex m_lock;
};
// Sniffs and tracks DNS queries. When a matching DNS response is found,
// the response time is added to a statistics object.
//
// This class performs *no cleanup* on data associated with queries that
// This class performs* no cleanup* on data associated with queries that
// weren't answered.
class dns_monitor {
public:
// The response times are measured in milliseconds
using duration_type = std::chrono::milliseconds;
using duration_type = milliseconds;
// The statistics type used.
using statistics_type = statistics<duration_type>;
@@ -99,21 +117,21 @@ public:
return m_stats;
}
private:
using packet_info = std::tuple<IPv4Address, IPv4Address, uint16_t>;
using clock_type = std::chrono::system_clock;
using packet_info = tuple<IPv4Address, IPv4Address, uint16_t>;
using clock_type = system_clock;
using time_point_type = clock_type::time_point;
bool callback(const PDU& pdu);
static packet_info make_packet_info(const PDU& pdu, const DNS& dns);
statistics_type m_stats;
std::map<packet_info, time_point_type> m_packet_info;
map<packet_info, time_point_type> m_packet_info;
};
void dns_monitor::run(BaseSniffer& sniffer)
{
sniffer.sniff_loop(
std::bind(
bind(
&dns_monitor::callback,
this,
std::placeholders::_1
@@ -127,7 +145,7 @@ bool dns_monitor::callback(const PDU& pdu)
auto dns = pdu.rfind_pdu<RawPDU>().to<DNS>();
auto info = make_packet_info(pdu, dns);
// If it's a query, add the sniff time to our map.
if(dns.type() == DNS::QUERY) {
if (dns.type() == DNS::QUERY) {
m_packet_info.insert(
std::make_pair(info, now)
);
@@ -135,11 +153,11 @@ bool dns_monitor::callback(const PDU& pdu)
else {
// It's a response, we need to find the query in our map.
auto iter = m_packet_info.find(info);
if(iter != m_packet_info.end()) {
if (iter != m_packet_info.end()) {
// We found the query, let's add the response time to the
// statistics object.
m_stats.add_response_time(
std::chrono::duration_cast<duration_type>(now - iter->second)
duration_cast<duration_type>(now - iter->second)
);
// Forget about the query.
m_packet_info.erase(iter);
@@ -155,17 +173,17 @@ bool dns_monitor::callback(const PDU& pdu)
auto dns_monitor::make_packet_info(const PDU& pdu, const DNS& dns) -> packet_info
{
const auto& ip = pdu.rfind_pdu<IP>();
return std::make_tuple(
return make_tuple(
// smallest address first
std::min(ip.src_addr(), ip.dst_addr()),
min(ip.src_addr(), ip.dst_addr()),
// largest address second
std::max(ip.src_addr(), ip.dst_addr()),
max(ip.src_addr(), ip.dst_addr()),
dns.id()
);
}
int main(int argc, char *argv[]) {
std::string iface;
int main(int argc, char* argv[]) {
string iface;
if (argc == 2) {
// Use the provided interface
iface = argv[1];
@@ -180,21 +198,21 @@ int main(int argc, char *argv[]) {
config.set_filter("udp and port 53");
Sniffer sniffer(iface, config);
dns_monitor monitor;
std::thread thread(
thread thread(
[&]() {
monitor.run(sniffer);
}
);
while(true) {
while (true) {
auto info = monitor.stats().get_information();
std::cout << "\rAverage " << info.average.count()
<< "ms. Worst: " << info.worst.count() << "ms. Count: "
<< info.count;
std::cout.flush();
std::this_thread::sleep_for(std::chrono::seconds(1));
cout << "\rAverage " << info.average.count()
<< "ms. Worst: " << info.worst.count() << "ms. Count: "
<< info.count;
cout.flush();
sleep_for(seconds(1));
}
}
catch(std::exception& ex) {
std::cout << "[-] Error: " << ex.what() << std::endl;
catch (exception& ex) {
cout << "[-] Error: " << ex.what() << endl;
}
}

View File

@@ -33,7 +33,13 @@
#include <functional>
#include <tins/tins.h>
using namespace std;
using std::cout;
using std::endl;
using std::bind;
using std::string;
using std::runtime_error;
using std::exception;
using namespace Tins;
// This class captured packets on an interface, using the specified filter
@@ -42,93 +48,93 @@ using namespace Tins;
// has swapped HW and IP addresses (dst as src, src as dst).
class ICMPResponder {
public:
// Use the given interface and ICMP type/code on responses
ICMPResponder(string iface, int type, int code)
: m_iface(iface), m_sender(iface), m_type(type), m_code(code) {
// Use the given interface and ICMP type/code on responses
ICMPResponder(string iface, int type, int code)
: m_iface(iface), m_sender(iface), m_type(type), m_code(code) {
}
}
// Run using the given filter
void run(const string& filter) {
// Initialize the configuration
SnifferConfiguration config;
// Use promiscuous mode
config.set_promisc_mode(true);
// Use this packet filter
config.set_filter(filter);
// Use immediate mode (we don't want to buffer packets, we want the mright away).
config.set_immediate_mode(true);
// Run using the given filter
void run(const string& filter) {
// Initialize the configuration
SnifferConfiguration config;
// Use promiscuous mode
config.set_promisc_mode(true);
// Use this packet filter
config.set_filter(filter);
// Use immediate mode (we don't want to buffer packets, we want the mright away).
config.set_immediate_mode(true);
// Now create the Sniffer
Sniffer sniffer(m_iface, config);
if (sniffer.link_type() != DLT_EN10MB) {
throw runtime_error("Ethernet interfaces only supported");
}
// Start the sniffing! For each packet, ICMPReponder::callback will be called
sniffer.sniff_loop(bind(&ICMPResponder::callback, this, placeholders::_1));
}
// Now create the Sniffer
Sniffer sniffer(m_iface, config);
if (sniffer.link_type() != DLT_EN10MB) {
throw runtime_error("Ethernet interfaces only supported");
}
// Start the sniffing! For each packet, ICMPReponder::callback will be called
sniffer.sniff_loop(bind(&ICMPResponder::callback, this, std::placeholders::_1));
}
private:
// Extracts the payload to be used over the ICMP layer in the response.
// This will be the entire IP header + 8 bytes of the next header.
RawPDU extract_icmp_payload(IP& pdu) {
PDU::serialization_type buffer = pdu.serialize();
// Use whole IP + 8 bytes of next header.
size_t end_index = pdu.header_size() + 8;
return RawPDU(buffer.begin(), buffer.begin() + end_index);
}
// Extracts the payload to be used over the ICMP layer in the response.
// This will be the entire IP header + 8 bytes of the next header.
RawPDU extract_icmp_payload(IP& pdu) {
PDU::serialization_type buffer = pdu.serialize();
// Use whole IP + 8 bytes of next header.
size_t end_index = pdu.header_size() + 8;
return RawPDU(buffer.begin(), buffer.begin() + end_index);
}
// Generates an ICMP response given a packet.
EthernetII generate_response(PDU& pdu) {
// Find Ethernet and IP headers.
EthernetII& received_eth = pdu.rfind_pdu<EthernetII>();
IP& received_ip = pdu.rfind_pdu<IP>();
// Generates an ICMP response given a packet.
EthernetII generate_response(PDU& pdu) {
// Find Ethernet and IP headers.
EthernetII& received_eth = pdu.rfind_pdu<EthernetII>();
IP& received_ip = pdu.rfind_pdu<IP>();
// Create an Ethernet response, flipping the addresses
EthernetII output(received_eth.src_addr(), received_eth.dst_addr());
// Append an IP PDU, again flipping addresses.
//output /= IP(received_ip.src_addr(), received_ip.dst_addr());
output /= IP(received_ip.src_addr(), "8.8.8.8");
// Create an Ethernet response, flipping the addresses
EthernetII output(received_eth.src_addr(), received_eth.dst_addr());
// Append an IP PDU, again flipping addresses.
//output /= IP(received_ip.src_addr(), received_ip.dst_addr());
output /= IP(received_ip.src_addr(), "8.8.8.8");
// Now generate the ICMP layer using the type and code provided.
ICMP icmp;
icmp.type(static_cast<ICMP::Flags>(m_type));
icmp.code(m_code);
// Append the ICMP layer to our packet
output /= icmp;
// Extract the payload to be used over ICMP.
output /= extract_icmp_payload(received_ip);
return output;
}
// Now generate the ICMP layer using the type and code provided.
ICMP icmp;
icmp.type(static_cast<ICMP::Flags>(m_type));
icmp.code(m_code);
// Append the ICMP layer to our packet
output /= icmp;
// Extract the payload to be used over ICMP.
output /= extract_icmp_payload(received_ip);
return output;
}
// Packet capture callback
bool callback(PDU& pdu) {
// Generate a response for this packet
EthernetII response = generate_response(pdu);
// Send this packet!
m_sender.send(response);
return true;
}
// Packet capture callback
bool callback(PDU& pdu) {
// Generate a response for this packet
EthernetII response = generate_response(pdu);
// Send this packet!
m_sender.send(response);
return true;
}
string m_iface;
PacketSender m_sender;
int m_type;
int m_code;
string m_iface;
PacketSender m_sender;
int m_type;
int m_code;
};
int main(int argc, char *argv[]) {
const int type = 3;
const int code = 0;
if (argc < 3) {
cout << "Usage: " << argv[0] << " <interface> <pcap_filter>" << endl;
return 1;
}
string iface = argv[1];
string filter = argv[2];
try {
ICMPResponder responder(iface, type, code);
responder.run(filter);
}
catch (exception& ex) {
cout << "Error: " << ex.what() << endl;
}
int main(int argc, char* argv[]) {
const int type = 3;
const int code = 0;
if (argc < 3) {
cout << "Usage: " << argv[0] << " <interface> <pcap_filter>" << endl;
return 1;
}
string iface = argv[1];
string filter = argv[2];
try {
ICMPResponder responder(iface, type, code);
responder.run(filter);
}
catch (exception& ex) {
cout << "Error: " << ex.what() << endl;
}
}

View File

@@ -31,28 +31,31 @@
#include <iostream>
#include <tins/network_interface.h>
using std::cout;
using std::endl;
using std::string;
using namespace Tins;
using namespace std;
int main() {
// Get all interfaces and iterate over them.
for (const NetworkInterface& iface : NetworkInterface::all()) {
// Get the name of this interface
string name = iface.name();
// Get all interfaces and iterate over them.
for (const NetworkInterface& iface : NetworkInterface::all()) {
// Get the name of this interface
string name = iface.name();
// "stringify" the status of the interface
string status = iface.is_up() ? "up" : "down";
// Get this interface's information (addresses).
NetworkInterface::Info info = iface.info();
// Now print all of this info.
cout << name << ": " << endl;
cout << " HW address: " << info.hw_addr << endl
<< " IP address: " << info.ip_addr << endl
<< " Netmask: " << info.netmask << endl
<< " Broadcast: " << info.bcast_addr << endl
<< " Iface index: " << iface.id() << endl
<< " Status: " << "interface " << status << endl << endl;
}
// "stringify" the status of the interface
string status = iface.is_up() ? "up" : "down";
// Get this interface's information (addresses).
NetworkInterface::Info info = iface.info();
// Now print all of this info.
cout << name << ": " << endl;
cout << " HW address: " << info.hw_addr << endl
<< " IP address: " << info.ip_addr << endl
<< " Netmask: " << info.netmask << endl
<< " Broadcast: " << info.bcast_addr << endl
<< " Iface index: " << iface.id() << endl
<< " Status: " << "interface " << status << endl << endl;
}
}

View File

@@ -44,22 +44,30 @@
#include <tins/utils.h>
#include <tins/packet_sender.h>
using std::cout;
using std::endl;
using std::vector;
using std::pair;
using std::setw;
using std::string;
using std::set;
using std::runtime_error;
using namespace std;
using namespace Tins;
typedef std::pair<Sniffer*, std::string> sniffer_data;
typedef pair<Sniffer*, string> sniffer_data;
class Scanner {
public:
Scanner(const NetworkInterface& interface, const IPv4Address& address,
const vector<string>& ports);
Scanner(const NetworkInterface& interface,
const IPv4Address& address,
const vector<string>& ports);
void run();
private:
void send_syns(const NetworkInterface &iface, IPv4Address dest_ip);
bool callback(PDU &pdu);
static void *thread_proc(void *param);
void send_syns(const NetworkInterface& iface, IPv4Address dest_ip);
bool callback(PDU& pdu);
static void* thread_proc(void* param);
void launch_sniffer();
NetworkInterface iface;
@@ -68,37 +76,35 @@ private:
Sniffer sniffer;
};
Scanner::Scanner(const NetworkInterface& interface, const IPv4Address& address,
const vector<string>& ports)
: iface(interface), host_to_scan(address), sniffer(interface.name())
{
Scanner::Scanner(const NetworkInterface& interface,
const IPv4Address& address,
const vector<string>& ports)
: iface(interface), host_to_scan(address), sniffer(interface.name()) {
sniffer.set_filter(
"tcp and ip src " + address.to_string() + " and tcp[tcpflags] & (tcp-rst|tcp-syn) != 0"
);
for(size_t i = 0; i < ports.size(); ++i) {
for (size_t i = 0; i < ports.size(); ++i) {
ports_to_scan.insert(atoi(ports[i].c_str()));
}
}
void *Scanner::thread_proc(void *param) {
Scanner *data = (Scanner*)param;
void* Scanner::thread_proc(void* param) {
Scanner* data = (Scanner*)param;
data->launch_sniffer();
return 0;
}
void Scanner::launch_sniffer()
{
void Scanner::launch_sniffer() {
sniffer.sniff_loop(make_sniffer_handler(this, &Scanner::callback));
}
/* Our scan handler. This will receive SYNs and RSTs and inform us
* the scanned port's status.
*/
bool Scanner::callback(PDU &pdu)
{
bool Scanner::callback(PDU& pdu) {
// Find the layers we want.
const IP &ip = pdu.rfind_pdu<IP>();
const TCP &tcp = pdu.rfind_pdu<TCP>();
const IP& ip = pdu.rfind_pdu<IP>();
const TCP& tcp = pdu.rfind_pdu<TCP>();
// Check if the host that we're scanning sent this packet and
// the source port is one of those that we scanned.
if(ip.src_addr() == host_to_scan && ports_to_scan.count(tcp.sport()) == 1) {
@@ -117,8 +123,7 @@ bool Scanner::callback(PDU &pdu)
return true;
}
void Scanner::run()
{
void Scanner::run() {
pthread_t thread;
// Launch our sniff thread.
pthread_create(&thread, 0, &Scanner::thread_proc, this);
@@ -126,25 +131,25 @@ void Scanner::run()
send_syns(iface, host_to_scan);
// Wait for our sniffer.
void *dummy;
void* dummy;
pthread_join(thread, &dummy);
}
// Send syns to the given ip address, using the destination ports provided.
void Scanner::send_syns(const NetworkInterface &iface, IPv4Address dest_ip) {
void Scanner::send_syns(const NetworkInterface& iface, IPv4Address dest_ip) {
// Retrieve the addresses.
NetworkInterface::Info info = iface.addresses();
PacketSender sender;
// Allocate the IP PDU
IP ip = IP(dest_ip, info.ip_addr) / TCP();
// Get the reference to the TCP PDU
TCP &tcp = ip.rfind_pdu<TCP>();
TCP& tcp = ip.rfind_pdu<TCP>();
// Set the SYN flag on.
tcp.set_flag(TCP::SYN, 1);
// Just some random port.
tcp.sport(1337);
cout << "Sending SYNs..." << endl;
for(set<uint16_t>::const_iterator it = ports_to_scan.begin(); it != ports_to_scan.end(); ++it) {
for (set<uint16_t>::const_iterator it = ports_to_scan.begin(); it != ports_to_scan.end(); ++it) {
// Set the new port and send the packet!
tcp.dport(*it);
sender.send(ip);
@@ -163,7 +168,7 @@ void Scanner::send_syns(const NetworkInterface &iface, IPv4Address dest_ip) {
sender.send(eth, iface);
}
void scan(int argc, char *argv[]) {
void scan(int argc, char* argv[]) {
IPv4Address ip(argv[1]);
// Resolve the interface which will be our gateway
NetworkInterface iface(ip);
@@ -176,13 +181,15 @@ void scan(int argc, char *argv[]) {
scanner.run();
}
int main(int argc, char *argv[]) {
if(argc < 3 && cout << "Usage: " << *argv << " <IPADDR> <port1> [port2] [port3]\n")
int main(int argc, char* argv[]) {
if (argc < 3) {
cout << "Usage: " <<* argv << " <IPADDR> <port1> [port2] [port3]" << endl;
return 1;
}
try {
scan(argc, argv);
}
catch(std::runtime_error &ex) {
catch(runtime_error& ex) {
cout << "Error - " << ex.what() << endl;
}
}

View File

@@ -32,17 +32,21 @@
#include <vector>
#include <tins/tins.h>
using namespace std;
using std::cout;
using std::endl;
using std::setw;
using std::vector;
using namespace Tins;
int main() {
vector<Utils::RouteEntry> entries = Utils::route_entries();
for (size_t i = 0; i < entries.size(); ++i) {
cout << "Entry " << setw(2) << i << ": " << endl
<< "Interface: " << entries[i].interface << endl
<< "Destination: " << entries[i].destination << endl
<< "Gateway: " << entries[i].gateway << endl
<< "Genmask: " << entries[i].mask << endl
<< "Metric: " << entries[i].metric << endl << endl;
}
vector<Utils::RouteEntry> entries = Utils::route_entries();
for (size_t i = 0; i < entries.size(); ++i) {
cout << "Entry " << setw(2) << i << ": " << endl
<< "Interface: " << entries[i].interface << endl
<< "Destination: " << entries[i].destination << endl
<< "Gateway: " << entries[i].gateway << endl
<< "Genmask: " << entries[i].mask << endl
<< "Metric: " << entries[i].metric << endl << endl;
}
}

View File

@@ -43,6 +43,25 @@
#include <mutex>
#include <tins/tins.h>
using std::cout;
using std::endl;
using std::move;
using std::map;
using std::min;
using std::setw;
using std::atomic;
using std::runtime_error;
using std::string;
using std::to_string;
using std::thread;
using std::this_thread::sleep_for;
using std::lock_guard;
using std::mutex;
using std::random_device;
using std::numeric_limits;
using std::bind;
using std::chrono::milliseconds;
using namespace Tins;
class Traceroute {
@@ -50,8 +69,8 @@ public:
typedef std::map<uint16_t, IPv4Address> result_type;
Traceroute(NetworkInterface interface, IPv4Address address)
: iface(interface), addr(address), lowest_dest_ttl(std::numeric_limits<int>::max()) {
sequence = std::random_device()();
: iface(interface), addr(address), lowest_dest_ttl(numeric_limits<int>::max()) {
sequence = random_device()();
}
result_type trace() {
@@ -64,7 +83,7 @@ public:
PacketSender sender;
// Create our handler
auto handler = std::bind(
auto handler = bind(
&Traceroute::sniff_callback,
this,
std::placeholders::_1
@@ -72,7 +91,7 @@ public:
// We're running
running = true;
// Start the sniff thread
std::thread sniff_thread(
thread sniff_thread(
[&]() {
sniffer.sniff_loop(handler);
}
@@ -80,23 +99,23 @@ public:
send_packets(sender);
sniff_thread.join();
// If the final hop responded, add its address at the appropriate ttl
if (lowest_dest_ttl != std::numeric_limits<int>::max()) {
if (lowest_dest_ttl != numeric_limits<int>::max()) {
results[lowest_dest_ttl] = addr;
}
// Clear our results and return what we've found
return std::move(results);
return move(results);
}
private:
typedef std::map<uint16_t, size_t> ttl_map;
typedef map<uint16_t, size_t> ttl_map;
void send_packets(PacketSender &sender) {
void send_packets(PacketSender& sender) {
// ICMPs are icmp-requests by default
IP ip = IP(addr, iface.addresses().ip_addr) / ICMP();
ICMP& icmp = ip.rfind_pdu<ICMP>();
icmp.sequence(sequence);
// We'll find at most 20 hops.
for(auto i = 1; i <= 20; ++i) {
for (auto i = 1; i <= 20; ++i) {
// Set this ICMP id
icmp.id(i);
// Set the time-to-live option
@@ -104,22 +123,22 @@ private:
// Critical section
{
std::lock_guard<std::mutex> _(lock);
lock_guard<mutex> _(lock);
ttls[i] = i;
}
sender.send(ip);
// Give him a little time
std::this_thread::sleep_for(std::chrono::milliseconds(100));
sleep_for(milliseconds(100));
}
running = false;
sender.send(ip);
}
bool sniff_callback(PDU &pdu) {
bool sniff_callback(PDU& pdu) {
// Find IP and ICMP PDUs
const IP &ip = pdu.rfind_pdu<IP>();
const ICMP &icmp = pdu.rfind_pdu<ICMP>();
const IP& ip = pdu.rfind_pdu<IP>();
const ICMP& icmp = pdu.rfind_pdu<ICMP>();
// Check if this is an ICMP TTL exceeded error response
if (icmp.type() == ICMP::TIME_EXCEEDED) {
// Fetch the IP PDU attached to the ICMP response
@@ -147,39 +166,42 @@ private:
else if (icmp.type() == ICMP::ECHO_REPLY && icmp.sequence() == sequence &&
ip.src_addr() == addr) {
// Keep the lowest ttl seen for the destination.
lowest_dest_ttl = std::min(lowest_dest_ttl, static_cast<int>(icmp.id()));
lowest_dest_ttl = min(lowest_dest_ttl, static_cast<int>(icmp.id()));
}
return running;
}
NetworkInterface iface;
IPv4Address addr;
std::atomic<bool> running;
atomic<bool> running;
ttl_map ttls;
result_type results;
std::mutex lock;
mutex lock;
uint16_t sequence;
int lowest_dest_ttl;
};
int main(int argc, char* argv[]) {
if(argc <= 1 && std::cout << "Usage: " << *argv << " <ip_address>\n")
if (argc <= 1) {
cout << "Usage: " <<* argv << " <ip_address>" << endl;
return 1;
}
try {
IPv4Address addr((std::string(argv[1])));
IPv4Address addr = string(argv[1]);
Traceroute tracer(addr, addr);
auto results = tracer.trace();
if(results.empty())
std::cout << "No hops found" << std::endl;
if (results.empty()) {
cout << "No hops found" << endl;
}
else {
std::cout << "Results: " << std::endl;
for(const auto &entry : results) {
std::cout << std::setw(2) << entry.first << " - " << entry.second << std::endl;
cout << "Results: " << endl;
for(const auto& entry : results) {
cout << setw(2) << entry.first << " - " << entry.second << endl;
}
}
}
catch(std::runtime_error &ex) {
std::cout << "Error - " << ex.what() << std::endl;
catch (runtime_error& ex) {
cout << "Error - " << ex.what() << endl;
return 2;
}
}

View File

@@ -41,11 +41,11 @@ std::set<HWAddress<6>> addrs;
const HWAddress<3> expected_oui("00:50:F2");
bool handler(const PDU& pdu) {
const Dot11Beacon &beacon = pdu.rfind_pdu<Dot11Beacon>();
const Dot11Beacon& beacon = pdu.rfind_pdu<Dot11Beacon>();
// Only process it once
if(addrs.insert(beacon.addr3()).second) {
// Iterate the tagged options
for(const auto &opt : beacon.options()) {
for(const auto& opt : beacon.options()) {
// Is this a vendor-specific tag?
if(opt.option() == Dot11::VENDOR_SPECIFIC) {
// Make sure there's enough size for the OUI + identifier
@@ -63,9 +63,9 @@ bool handler(const PDU& pdu) {
return true;
}
int main(int argc, char *argv[]) {
int main(int argc, char* argv[]) {
if(argc != 2) {
std::cout << "Usage: " << *argv << " <DEVICE>\n";
std::cout << "Usage: " <<* argv << " <DEVICE>\n";
return 1;
}
// Only sniff beacons

View File

@@ -53,9 +53,8 @@ public:
*
* \param first The address held by this iterator.
*/
AddressRangeIterator(const value_type &addr)
: addr(addr), reached_end(false)
{
AddressRangeIterator(const value_type& address)
: address_(address), reached_end_(false) {
}
@@ -64,24 +63,23 @@ public:
*
* \param first The address held by this iterator.
*/
AddressRangeIterator(const value_type &address, end_iterator)
: addr(address)
{
reached_end = Internals::increment(addr);
AddressRangeIterator(const value_type& address, end_iterator)
: address_(address) {
reached_end_ = Internals::increment(address_);
}
/**
* Retrieves the current address pointed by this iterator.
*/
const value_type& operator*() const {
return addr;
return address_;
}
/**
* Retrieves a pointer to the current address pointed by this iterator.
*/
const value_type* operator->() const {
return &addr;
return& address_;
}
/**
@@ -89,8 +87,8 @@ public:
*
* \param rhs The iterator with which to compare.
*/
bool operator==(const AddressRangeIterator &rhs) const {
return reached_end == rhs.reached_end && addr == rhs.addr;
bool operator==(const AddressRangeIterator& rhs) const {
return reached_end_ == rhs.reached_end_ && address_ == rhs.address_;
}
/**
@@ -98,7 +96,7 @@ public:
*
* \param rhs The iterator with which to compare.
*/
bool operator!=(const AddressRangeIterator &rhs) const {
bool operator!=(const AddressRangeIterator& rhs) const {
return !(*this == rhs);
}
@@ -106,8 +104,8 @@ public:
* Increments this iterator.
*/
AddressRangeIterator& operator++() {
reached_end = Internals::increment(addr);
return *this;
reached_end_ = Internals::increment(address_);
return* this;
}
/**
@@ -119,8 +117,8 @@ public:
return copy;
}
private:
Address addr;
bool reached_end;
Address address_;
bool reached_end_;
};
/**
@@ -135,7 +133,7 @@ private:
*
* \code
* auto range = IPv4Address("192.168.5.0") / 24;
* for(const auto &addr : range) {
* for(const auto& addr : range) {
* // process 192.168.5.1-254, .0 and .255 are discarded
* process(addr);
* }
@@ -151,7 +149,7 @@ private:
*
* \code
* AddressRange<IPv4Address> range("192.168.5.0", "192.168.5.255");
* for(const auto &addr : range) {
* for(const auto& addr : range) {
* // process 192.168.5.0-255, no addresses are discarded
* process(addr);
* }
@@ -197,11 +195,11 @@ public:
* \param only_hosts Indicates whether only host addresses
* should be accessed when using iterators.
*/
AddressRange(const address_type &first, const address_type &last, bool only_hosts = false)
: first(first), last(last), only_hosts(only_hosts)
{
if(last < first)
AddressRange(const address_type& first, const address_type& last, bool only_hosts = false)
: first_(first), last_(last), only_hosts_(only_hosts){
if (last_ < first_) {
throw std::runtime_error("Invalid address range");
}
}
/**
@@ -211,7 +209,7 @@ public:
* \param first The base address.
* \param mask The network mask to be used.
*/
static AddressRange from_mask(const address_type &first, const address_type &mask) {
static AddressRange from_mask(const address_type& first, const address_type& mask) {
return AddressRange<address_type>(
first,
Internals::last_address_from_mask(first, mask),
@@ -224,8 +222,8 @@ public:
* \param addr The address to test.
* \return a bool indicating whether the address is in the range.
*/
bool contains(const address_type &addr) const {
return (first < addr && addr < last) || addr == first || addr == last;
bool contains(const address_type& addr) const {
return (first_ < addr && addr < last_) || addr == first_ || addr == last_;
}
/**
@@ -233,9 +231,10 @@ public:
* \brief const_iterator pointing to the beginning of this range.
*/
const_iterator begin() const {
address_type addr = first;
if(only_hosts)
address_type addr = first_;
if (only_hosts_) {
Internals::increment(addr);
}
return const_iterator(addr);
}
@@ -244,9 +243,10 @@ public:
* \brief const_iterator pointing to the end of this range.
*/
const_iterator end() const {
address_type addr = last;
if(only_hosts)
address_type addr = last_;
if (only_hosts_) {
Internals::decrement(addr);
}
return const_iterator(addr, typename const_iterator::end_iterator());
}
@@ -266,21 +266,23 @@ public:
*/
bool is_iterable() const {
// Since first < last, it's iterable
if(!only_hosts)
if (!only_hosts_) {
return true;
}
// We need that distance(first, last) >= 4
address_type addr(first);
for(int i = 0; i < 3; ++i) {
address_type addr(first_);
for (int i = 0; i < 3; ++i) {
// If there's overflow before the last iteration, we're done
if(Internals::increment(addr) && i != 2)
if (Internals::increment(addr) && i != 2) {
return false;
}
}
// If addr <= last, it's OK.
return addr < last || addr == last;
return addr < last_ || addr == last_;
}
private:
address_type first, last;
bool only_hosts;
address_type first_, last_;
bool only_hosts_;
};
/**
@@ -299,12 +301,13 @@ typedef AddressRange<IPv6Address> IPv6Range;
* \param mask The bit-length of the prefix.
*/
template<size_t n>
AddressRange<HWAddress<n> > operator/(const HWAddress<n> &addr, int mask) {
if(mask > 48)
AddressRange<HWAddress<n> > operator/(const HWAddress<n>& addr, int mask) {
if (mask > 48) {
throw std::logic_error("Prefix length cannot exceed 48");
}
HWAddress<n> last_addr;
typename HWAddress<n>::iterator it = last_addr.begin();
while(mask > 8) {
while (mask > 8) {
*it = 0xff;
++it;
mask -= 8;
@@ -318,14 +321,14 @@ AddressRange<HWAddress<n> > operator/(const HWAddress<n> &addr, int mask) {
* \param addr The range's first address.
* \param mask The bit-length of the prefix.
*/
IPv6Range operator/(const IPv6Address &addr, int mask);
IPv6Range operator/(const IPv6Address& addr, int mask);
/**
* \brief Constructs an IPv4Range from a base IPv4Address and a mask.
* \param addr The range's first address.
* \param mask The bit-length of the prefix.
*/
IPv4Range operator/(const IPv4Address &addr, int mask);
IPv4Range operator/(const IPv4Address& addr, int mask);
} // namespace Tins
#endif // TINS_ADDRESS_RANGE

View File

@@ -38,280 +38,299 @@
#include "ip_address.h"
namespace Tins {
class NetworkInterface;
class EthernetII;
class NetworkInterface;
class EthernetII;
/**
* \class ARP
* \brief Represents an ARP PDU.
*
*/
class TINS_API ARP : public PDU {
public:
/**
* The type of the hardware address.
*/
typedef HWAddress<6> hwaddress_type;
/**
* The type of the IP address.
*/
typedef IPv4Address ipaddress_type;
/**
* \class ARP
* \brief Represents an ARP PDU.
*
* \brief This PDU's flag.
*/
class TINS_API ARP : public PDU {
public:
/**
* The type of the hardware address.
*/
typedef HWAddress<6> hwaddress_type;
/**
* The type of the IP address.
*/
typedef IPv4Address ipaddress_type;
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::ARP;
/**
* \brief Enum which indicates the type of ARP packet.
*/
enum Flags {
REQUEST = 0x0001,
REPLY = 0x0002
};
static const PDU::PDUType pdu_flag = PDU::ARP;
/**
* \brief Constructs an ARP object using the provided addresses.
*
* ARP requests and replies can be constructed easily using
* ARP::make_arp_request/reply static member functions.
*
* \sa ARP::make_arp_request
* \sa ARP::make_arp_reply
*
* \param target_ip The target IP address.
* \param sender_ip The sender IP address.
* \param target_hw The target hardware address.
* \param sender_hw The sender hardware address.
*/
ARP(ipaddress_type target_ip = ipaddress_type(),
ipaddress_type sender_ip = ipaddress_type(),
const hwaddress_type &target_hw = hwaddress_type(),
const hwaddress_type &sender_hw = hwaddress_type());
/**
* \brief Constructs an ARP object from a buffer.
*
* If there is not enough size for an ARP header in the buffer,
* a malformed_packet exception is thrown.
*
* If the buffer is bigger than the size of the ARP header,
* then the extra data is stored in a RawPDU.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
ARP(const uint8_t *buffer, uint32_t total_sz);
/* Getters */
/**
* \brief Getter for the sender's hardware address.
*
* \return The sender hardware address.
*/
hwaddress_type sender_hw_addr() const { return _arp.ar_sha; }
/**
* \brief Getter for the sender's IP address.
*
* \return The sender IP address.
*/
ipaddress_type sender_ip_addr() const { return ipaddress_type(_arp.ar_sip); }
/**
* \brief Getter for the target's hardware address.
*
* \return The target hardware address.
*/
hwaddress_type target_hw_addr() const { return _arp.ar_tha; }
/**
* \brief Getter for the target's IP address.
*
* \return The target IP address.
*/
ipaddress_type target_ip_addr() const { return ipaddress_type(_arp.ar_tip); }
/**
* \brief Getter for the hardware address format field.
*
* \return The hardware address format.
*/
uint16_t hw_addr_format() const { return Endian::be_to_host(_arp.ar_hrd); }
/**
* \brief Getter for the protocol address format field.
*
* \return The protocol address format.
*/
uint16_t prot_addr_format() const { return Endian::be_to_host(_arp.ar_pro); }
/**
* \brief Getter for the hardware address length field.
*
* \return The hardware address length.
*/
uint8_t hw_addr_length() const { return _arp.ar_hln; }
/**
* \brief Getter for the protocol address length field.
*
* \return The protocol address length.
*/
uint8_t prot_addr_length() const { return _arp.ar_pln; }
/**
* \brief Getter for the ARP opcode field.
*
* \return The ARP opcode.
*/
uint16_t opcode() const { return Endian::be_to_host(_arp.ar_op); }
/**
* \brief Getter for the header size.
* \return Returns the ARP header size.
* \sa PDU::header_size
*/
uint32_t header_size() const;
/* Setters */
/**
* \brief Setter for the sender's hardware address.
*
* \param new_snd_hw_addr The new sender hardware address.
*/
void sender_hw_addr(const hwaddress_type &new_snd_hw_addr);
/**
* \brief Setter for the sender's IP address.
*
* \param new_snd_ip_addr The new sender IP address.
*/
void sender_ip_addr(ipaddress_type new_snd_ip_addr);
/**
* \brief Setter for the target's hardware address.
*
* \param new_tgt_hw_addr The new target hardware address.
*/
void target_hw_addr(const hwaddress_type &new_tgt_hw_addr);
/**
* \brief Setter for the target's IP address.
*
* \param new_tgt_ip_addr The new target IP address.
*/
void target_ip_addr(ipaddress_type new_tgt_ip_addr);
/**
* \brief Setter for the hardware address format field.
*
* \param new_hw_addr_fmt The new hardware address format.
*/
void hw_addr_format(uint16_t new_hw_addr_fmt);
/**
* \brief Setter for the protocol address format field.
*
* \param new_prot_addr_fmt The new protocol address format.
*/
void prot_addr_format(uint16_t new_prot_addr_fmt);
/**
* \brief Setter for the hardware address length field.
*
* \param new_hw_addr_len The new hardware address length.
*/
void hw_addr_length(uint8_t new_hw_addr_len);
/**
* \brief Setter for the protocol address length field.
*
* \param new_prot_addr_len The new protocol address length.
*/
void prot_addr_length(uint8_t new_prot_addr_len);
/**
* \brief Setter for the ARP opcode field.
*
* \param new_opcode Flag enum value of the ARP opcode to set.
*/
void opcode(Flags new_opcode);
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Creates an ARP Request within an EthernetII PDU.
*
* Creates an ARP Request PDU and embeds it inside an EthernetII
* PDU.
*
* \param target The target's IP address.
* \param sender The sender's IP address.
* \param hw_snd The sender's hardware address.
* \return EthernetII object containing the ARP Request.
*/
static EthernetII make_arp_request(ipaddress_type target,
ipaddress_type sender, const hwaddress_type &hw_snd = hwaddress_type());
/**
* \brief Creates an ARP Reply within an EthernetII PDU.
*
* Creates an ARP Reply PDU and embeds it inside an EthernetII
* PDU.
*
* \param target The target's IP address.
* \param sender The sender's IP address.
* \param hw_tgt The target's hardware address.
* \param hw_snd The sender's hardware address.
* \return EthetnetII containing the ARP Replay.
*/
static EthernetII make_arp_reply(ipaddress_type target,
ipaddress_type sender, const hwaddress_type &hw_tgt = hwaddress_type(),
const hwaddress_type &hw_snd = hwaddress_type());
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \sa PDU::clone
*/
ARP *clone() const {
return new ARP(*this);
}
private:
TINS_BEGIN_PACK
struct arphdr {
uint16_t ar_hrd; /* format of hardware address */
uint16_t ar_pro; /* format of protocol address */
uint8_t ar_hln; /* length of hardware address */
uint8_t ar_pln; /* length of protocol address */
uint16_t ar_op; /* ARP opcode (command) */
/* sender hardware address */
uint8_t ar_sha[hwaddress_type::address_size];
/* sender IP address */
uint32_t ar_sip;
/* target hardware address */
uint8_t ar_tha[hwaddress_type::address_size];
/* target IP address */
uint32_t ar_tip;
} TINS_END_PACK;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
arphdr _arp;
/**
* \brief Enum which indicates the type of ARP packet.
*/
enum Flags {
REQUEST = 0x0001,
REPLY = 0x0002
};
}
#endif //TINS_ARP_H
/**
* \brief Constructs an ARP object using the provided addresses.
*
* ARP requests and replies can be constructed easily using
* ARP::make_arp_request/reply static member functions.
*
* \sa ARP::make_arp_request
* \sa ARP::make_arp_reply
*
* \param target_ip The target IP address.
* \param sender_ip The sender IP address.
* \param target_hw The target hardware address.
* \param sender_hw The sender hardware address.
*/
ARP(ipaddress_type target_ip = ipaddress_type(),
ipaddress_type sender_ip = ipaddress_type(),
const hwaddress_type& target_hw = hwaddress_type(),
const hwaddress_type& sender_hw = hwaddress_type());
/**
* \brief Constructs an ARP object from a buffer.
*
* If there is not enough size for an ARP header in the buffer,
* a malformed_packet exception is thrown.
*
* If the buffer is bigger than the size of the ARP header,
* then the extra data is stored in a RawPDU.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
ARP(const uint8_t* buffer, uint32_t total_sz);
/* Getters */
/**
* \brief Getter for the sender's hardware address.
*
* \return The sender hardware address.
*/
hwaddress_type sender_hw_addr() const {
return header_.sender_hw_address;
}
/**
* \brief Getter for the sender's IP address.
*
* \return The sender IP address.
*/
ipaddress_type sender_ip_addr() const {
return ipaddress_type(header_.sender_ip_address);
}
/**
* \brief Getter for the target's hardware address.
*
* \return The target hardware address.
*/
hwaddress_type target_hw_addr() const {
return header_.target_hw_address;
}
/**
* \brief Getter for the target's IP address.
*
* \return The target IP address.
*/
ipaddress_type target_ip_addr() const {
return ipaddress_type(header_.target_ip_address);
}
/**
* \brief Getter for the hardware address format field.
*
* \return The hardware address format.
*/
uint16_t hw_addr_format() const {
return Endian::be_to_host(header_.hw_address_format);
}
/**
* \brief Getter for the protocol address format field.
*
* \return The protocol address format.
*/
uint16_t prot_addr_format() const {
return Endian::be_to_host(header_.proto_address_format);
}
/**
* \brief Getter for the hardware address length field.
*
* \return The hardware address length.
*/
uint8_t hw_addr_length() const {
return header_.hw_address_length;
}
/**
* \brief Getter for the protocol address length field.
*
* \return The protocol address length.
*/
uint8_t prot_addr_length() const {
return header_.proto_address_length;
}
/**
* \brief Getter for the ARP opcode field.
*
* \return The ARP opcode.
*/
uint16_t opcode() const {
return Endian::be_to_host(header_.opcode);
}
/**
* \brief Getter for the header size.
* \return Returns the ARP header size.
* \sa PDU::header_size
*/
uint32_t header_size() const;
/* Setters */
/**
* \brief Setter for the sender's hardware address.
*
* \param address The new sender hardware address.
*/
void sender_hw_addr(const hwaddress_type& address);
/**
* \brief Setter for the sender's IP address.
*
* \param address The new sender IP address.
*/
void sender_ip_addr(ipaddress_type address);
/**
* \brief Setter for the target's hardware address.
*
* \param address The new target hardware address.
*/
void target_hw_addr(const hwaddress_type& address);
/**
* \brief Setter for the target's IP address.
*
* \param address The new target IP address.
*/
void target_ip_addr(ipaddress_type address);
/**
* \brief Setter for the hardware address format field.
*
* \param format The new hardware address format.
*/
void hw_addr_format(uint16_t format);
/**
* \brief Setter for the protocol address format field.
*
* \param format The new protocol address format.
*/
void prot_addr_format(uint16_t format);
/**
* \brief Setter for the hardware address length field.
*
* \param length The new hardware address length.
*/
void hw_addr_length(uint8_t length);
/**
* \brief Setter for the protocol address length field.
*
* \param length The new protocol address length.
*/
void prot_addr_length(uint8_t length);
/**
* \brief Setter for the ARP opcode field.
*
* \param code Flag enum value of the ARP opcode to set.
*/
void opcode(Flags code);
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Creates an ARP Request within an EthernetII PDU.
*
* Creates an ARP Request PDU and embeds it inside an EthernetII
* PDU.
*
* \param target The target's IP address.
* \param sender The sender's IP address.
* \param hw_snd The sender's hardware address.
* \return EthernetII object containing the ARP Request.
*/
static EthernetII make_arp_request(ipaddress_type target,
ipaddress_type sender,
const hwaddress_type& hw_snd = hwaddress_type());
/**
* \brief Creates an ARP Reply within an EthernetII PDU.
*
* Creates an ARP Reply PDU and embeds it inside an EthernetII
* PDU.
*
* \param target The target's IP address.
* \param sender The sender's IP address.
* \param hw_tgt The target's hardware address.
* \param hw_snd The sender's hardware address.
* \return EthetnetII containing the ARP Replay.
*/
static EthernetII make_arp_reply(ipaddress_type target,
ipaddress_type sender,
const hwaddress_type& hw_tgt = hwaddress_type(),
const hwaddress_type& hw_snd = hwaddress_type());
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t* ptr, uint32_t total_sz) const;
/**
* \sa PDU::clone
*/
ARP* clone() const {
return new ARP(*this);
}
private:
TINS_BEGIN_PACK
struct arp_header {
uint16_t hw_address_format;
uint16_t proto_address_format;
uint8_t hw_address_length;
uint8_t proto_address_length;
uint16_t opcode;
uint8_t sender_hw_address[hwaddress_type::address_size];
uint32_t sender_ip_address;
uint8_t target_hw_address[hwaddress_type::address_size];
uint32_t target_ip_address;
} TINS_END_PACK;
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
arp_header header_;
};
} // Tins
#endif // TINS_ARP_H

View File

@@ -41,322 +41,324 @@
namespace Tins {
/**
* \class BootP
* \brief Represents a BootP PDU
*/
class TINS_API BootP : public PDU {
public:
/**
* \class BootP
* \brief Class representing a BootP packet.
* The type of the IP addresses.
*/
class TINS_API BootP : public PDU {
public:
/**
* The type of the IP addresses.
*/
typedef IPv4Address ipaddress_type;
/**
* The type of the chaddr field.
*/
typedef HWAddress<16> chaddr_type;
/**
* The type of the vend field.
*/
typedef std::vector<uint8_t> vend_type;
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::BOOTP;
typedef IPv4Address ipaddress_type;
/**
* \brief Enum which contains the different opcodes BootP messages.
*/
enum OpCodes {
BOOTREQUEST = 1,
BOOTREPLY = 2
};
/**
* The type of the chaddr field.
*/
typedef HWAddress<16> chaddr_type;
/**
* The type of the vend field.
*/
typedef std::vector<uint8_t> vend_type;
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::BOOTP;
/**
* \brief Creates an instance of BootP.
*
* This sets the size of the vend field to 64, as the BootP RFC
* states.
*/
BootP();
/**
* \brief Constructs a BootP object from a buffer .
*
* If there's not enough size for a BootP header, then a
* malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
* \param vend_field_size The vend field size to allocate.
* Subclasses might use 0 to provide their own interpretation of this field.
*/
BootP(const uint8_t *buffer, uint32_t total_sz, uint32_t vend_field_size = 64);
/* Getters */
/**
* \brief Getter for the opcode field.
* \return The opcode field for this BootP PDU.
*/
uint8_t opcode() const { return _bootp.opcode; }
/**
* \brief Getter for the htype field.
* \return The htype field for this BootP PDU.
*/
uint8_t htype() const { return _bootp.htype; }
/**
* \brief Getter for the hlen field.
* \return The hlen field for this BootP PDU.
*/
uint8_t hlen() const { return _bootp.hlen; }
/**
* \brief Getter for the hops field.
* \return The hops field for this BootP PDU.
*/
uint8_t hops() const { return _bootp.hops; }
/**
* \brief Getter for the xid field.
* \return The xid field for this BootP PDU.
*/
uint32_t xid() const { return Endian::be_to_host(_bootp.xid); }
/**
* \brief Getter for the secs field.
* \return The secs field for this BootP PDU.
*/
uint16_t secs() const { return Endian::be_to_host(_bootp.secs); }
/** \brief Getter for the padding field.
* \return The padding field for this BootP PDU.
*/
uint16_t padding() const { return Endian::be_to_host(_bootp.padding); }
/**
* \brief Getter for the ciaddr field.
* \return The ciaddr field for this BootP PDU.
*/
ipaddress_type ciaddr() const { return ipaddress_type(_bootp.ciaddr); }
/**
* \brief Getter for the yiaddr field.
* \return The yiaddr field for this BootP PDU.
*/
ipaddress_type yiaddr() const { return ipaddress_type(_bootp.yiaddr); }
/**
* \brief Getter for the siaddr field.
* \return The siaddr field for this BootP PDU.
*/
ipaddress_type siaddr() const { return ipaddress_type(_bootp.siaddr); }
/**
* \brief Getter for the giaddr field.
* \return The giaddr field for this BootP PDU.
*/
ipaddress_type giaddr() const { return ipaddress_type(_bootp.giaddr); }
/**
* \brief Getter for the chaddr field.
* \return The chddr field for this BootP PDU.
*/
chaddr_type chaddr() const { return _bootp.chaddr; }
/**
* \brief Getter for the sname field.
* \return The sname field for this BootP PDU.
*/
const uint8_t *sname() const { return _bootp.sname; }
/**
* \brief Getter for the file field.
* \return The file field for this BootP PDU.
*/
const uint8_t *file() const { return _bootp.file; }
/**
* \brief Getter for the vend field.
* \return The vend field for this BootP PDU.
*/
const vend_type &vend() const { return _vend; }
/**
* \brief Getter for the header size.
* \return Returns the BOOTP header size.
* \sa PDU::header_size
*/
uint32_t header_size() const;
/* Setters */
/**
* \brief Setter for the opcode field.
* \param new_opcode The opcode to be set.
*/
void opcode(uint8_t new_opcode);
/**
* \brief Setter for the htype field.
* \param new_htype The htype to be set.
*/
void htype(uint8_t new_htype);
/**
* \brief Setter for the hlen field.
* \param new_hlen The hlen to be set.
*/
void hlen(uint8_t new_hlen);
/**
* \brief Setter for the hops field.
* \param new_hops The hops to be set.
*/
void hops(uint8_t new_hops);
/**
* \brief Setter for the xid field.
* \param new_xid The xid to be set.
*/
void xid(uint32_t new_xid);
/**
* \brief Setter for the secs field.
* \param new_secs The secs to be set.
*/
void secs(uint16_t new_secs);
/**
* \brief Setter for the padding field.
* \param new_padding The padding to be set.
*/
void padding(uint16_t new_padding);
/**
* \brief Setter for the ciaddr field.
* \param new_ciaddr The ciaddr to be set.
*/
void ciaddr(ipaddress_type new_ciaddr);
/**
* \brief Setter for the yiaddr field.
* \param new_yiaddr The yiaddr to be set.
*/
void yiaddr(ipaddress_type new_yiaddr);
/**
* \brief Setter for the siaddr field.
* \param new_siaddr The siaddr to be set.
*/
void siaddr(ipaddress_type new_siaddr);
/**
* \brief Setter for the giaddr field.
* \param new_giaddr The giaddr to be set.
*/
void giaddr(ipaddress_type new_giaddr);
/**
* \brief Setter for the chaddr field.
* The new_chaddr pointer must be at least BOOTP::hlen() bytes long.
* \param new_chaddr The chaddr to be set.
*/
template<size_t n>
void chaddr(const HWAddress<n> &new_chaddr) {
// Copy the new addr
uint8_t *end = std::copy(
new_chaddr.begin(),
new_chaddr.begin() + std::min(n, sizeof(_bootp.chaddr)),
_bootp.chaddr
);
// Fill what's left with zeros
if(end < _bootp.chaddr + chaddr_type::address_size)
std::fill(end, _bootp.chaddr + chaddr_type::address_size, 0);
}
/**
* \brief Setter for the sname field.
* \param new_sname The sname to be set.
*/
void sname(const uint8_t *new_sname);
/**
* \brief Setter for the file field.
* \param new_file The file to be set.
*/
void file(const uint8_t *new_file);
/**
* \brief Setter for the vend field.
* \param new_vend The vend to be set.
*/
void vend(const vend_type &new_vend);
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* This returns true if the xid field is equal.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \sa PDU::clone
*/
BootP *clone() const {
return new BootP(*this);
}
protected:
/**
* \brief Getter for the vend field.
*
* This getter can be used by subclasses to avoid copying the
* vend field around.
*
* \return The vend field for this BootP PDU.
*/
vend_type &vend() { return _vend; }
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
private:
/**
* Struct that represents the Bootp datagram.
*/
TINS_BEGIN_PACK
struct bootphdr {
uint8_t opcode;
uint8_t htype;
uint8_t hlen;
uint8_t hops;
uint32_t xid;
uint16_t secs;
uint16_t padding;
uint32_t ciaddr;
uint32_t yiaddr;
uint32_t siaddr;
uint32_t giaddr;
uint8_t chaddr[16];
uint8_t sname[64];
uint8_t file[128];
} TINS_END_PACK;
bootphdr _bootp;
vend_type _vend;
/**
* \brief Enum which contains the different opcodes BootP messages.
*/
enum OpCodes {
BOOTREQUEST = 1,
BOOTREPLY = 2
};
}
/**
* \brief Creates an instance of BootP.
*
* This sets the size of the vend field to 64, as the BootP RFC
* states.
*/
BootP();
/**
* \brief Constructs a BootP object from a buffer .
*
* If there's not enough size for a BootP header, then a
* malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
* \param vend_field_size The vend field size to allocate.
* Subclasses might use 0 to provide their own interpretation of this field.
*/
BootP(const uint8_t* buffer, uint32_t total_sz, uint32_t vend_field_size = 64);
/* Getters */
/**
* \brief Getter for the opcode field.
* \return The opcode field for this BootP PDU.
*/
uint8_t opcode() const { return bootp_.opcode; }
/**
* \brief Getter for the htype field.
* \return The htype field for this BootP PDU.
*/
uint8_t htype() const { return bootp_.htype; }
/**
* \brief Getter for the hlen field.
* \return The hlen field for this BootP PDU.
*/
uint8_t hlen() const { return bootp_.hlen; }
/**
* \brief Getter for the hops field.
* \return The hops field for this BootP PDU.
*/
uint8_t hops() const { return bootp_.hops; }
/**
* \brief Getter for the xid field.
* \return The xid field for this BootP PDU.
*/
uint32_t xid() const { return Endian::be_to_host(bootp_.xid); }
/**
* \brief Getter for the secs field.
* \return The secs field for this BootP PDU.
*/
uint16_t secs() const { return Endian::be_to_host(bootp_.secs); }
/** \brief Getter for the padding field.
* \return The padding field for this BootP PDU.
*/
uint16_t padding() const { return Endian::be_to_host(bootp_.padding); }
/**
* \brief Getter for the ciaddr field.
* \return The ciaddr field for this BootP PDU.
*/
ipaddress_type ciaddr() const { return ipaddress_type(bootp_.ciaddr); }
/**
* \brief Getter for the yiaddr field.
* \return The yiaddr field for this BootP PDU.
*/
ipaddress_type yiaddr() const { return ipaddress_type(bootp_.yiaddr); }
/**
* \brief Getter for the siaddr field.
* \return The siaddr field for this BootP PDU.
*/
ipaddress_type siaddr() const { return ipaddress_type(bootp_.siaddr); }
/**
* \brief Getter for the giaddr field.
* \return The giaddr field for this BootP PDU.
*/
ipaddress_type giaddr() const { return ipaddress_type(bootp_.giaddr); }
/**
* \brief Getter for the chaddr field.
* \return The chddr field for this BootP PDU.
*/
chaddr_type chaddr() const { return bootp_.chaddr; }
/**
* \brief Getter for the sname field.
* \return The sname field for this BootP PDU.
*/
const uint8_t* sname() const { return bootp_.sname; }
/**
* \brief Getter for the file field.
* \return The file field for this BootP PDU.
*/
const uint8_t* file() const { return bootp_.file; }
/**
* \brief Getter for the vend field.
* \return The vend field for this BootP PDU.
*/
const vend_type& vend() const { return vend_; }
/**
* \brief Getter for the header size.
* \return Returns the BOOTP header size.
* \sa PDU::header_size
*/
uint32_t header_size() const;
/* Setters */
/**
* \brief Setter for the opcode field.
* \param code The opcode to be set.
*/
void opcode(uint8_t code);
/**
* \brief Setter for the hardware type field.
* \param type The hardware type field value to be set.
*/
void htype(uint8_t type);
/**
* \brief Setter for the hlen field.
* \param length The hlen field value to be set.
*/
void hlen(uint8_t length);
/**
* \brief Setter for the hops field.
* \param count The hops field value to be set.
*/
void hops(uint8_t count);
/**
* \brief Setter for the xid field.
* \param identifier The xid to be set.
*/
void xid(uint32_t identifier);
/**
* \brief Setter for the secs field.
* \param value The secs to be set.
*/
void secs(uint16_t value);
/**
* \brief Setter for the padding field.
* \param value The padding to be set.
*/
void padding(uint16_t value);
/**
* \brief Setter for the ciaddr field.
* \param address The ciaddr to be set.
*/
void ciaddr(ipaddress_type address);
/**
* \brief Setter for the yiaddr field.
* \param address The yiaddr to be set.
*/
void yiaddr(ipaddress_type address);
/**
* \brief Setter for the siaddr field.
* \param address The siaddr to be set.
*/
void siaddr(ipaddress_type address);
/**
* \brief Setter for the giaddr field.
* \param address The giaddr to be set.
*/
void giaddr(ipaddress_type address);
/**
* \brief Setter for the chaddr field.
* The new_chaddr pointer must be at least BOOTP::hlen() bytes long.
* \param new_chaddr The chaddr to be set.
*/
template<size_t n>
void chaddr(const HWAddress<n>& new_chaddr) {
// Copy the new addr
uint8_t* end = std::copy(
new_chaddr.begin(),
new_chaddr.begin() + std::min(n, sizeof(bootp_.chaddr)),
bootp_.chaddr
);
// Fill what's left with zeros
if (end < bootp_.chaddr + chaddr_type::address_size) {
std::fill(end, bootp_.chaddr + chaddr_type::address_size, 0);
}
}
/**
* \brief Setter for the sname field.
* \param new_sname The sname to be set.
*/
void sname(const uint8_t* new_sname);
/**
* \brief Setter for the file field.
* \param new_file The file to be set.
*/
void file(const uint8_t* new_file);
/**
* \brief Setter for the vend field.
* \param newvend_ The vend to be set.
*/
void vend(const vend_type& newvend_);
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* This returns true if the xid field is equal.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t* ptr, uint32_t total_sz) const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \sa PDU::clone
*/
BootP* clone() const {
return new BootP(*this);
}
protected:
/**
* \brief Getter for the vend field.
*
* This getter can be used by subclasses to avoid copying the
* vend field around.
*
* \return The vend field for this BootP PDU.
*/
vend_type& vend() { return vend_; }
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
private:
/**
* Struct that represents the Bootp datagram.
*/
TINS_BEGIN_PACK
struct bootp_header {
uint8_t opcode;
uint8_t htype;
uint8_t hlen;
uint8_t hops;
uint32_t xid;
uint16_t secs;
uint16_t padding;
uint32_t ciaddr;
uint32_t yiaddr;
uint32_t siaddr;
uint32_t giaddr;
uint8_t chaddr[16];
uint8_t sname[64];
uint8_t file[128];
} TINS_END_PACK;
bootp_header bootp_;
vend_type vend_;
};
} // Tins
#endif // TINS_BOOTP_H

View File

@@ -31,131 +31,131 @@
#define TINS_CONSTANTS_H
namespace Tins {
/**
* \brief Constants used in protocols.
*/
namespace Constants {
/** \cond */
struct IP {
/** \endcond */
enum e {
PROTO_IP = 0, /* Dummy protocol for TCP. */
PROTO_HOPOPTS = 0, /* IPv6 Hop-by-Hop options. */
PROTO_ICMP = 1, /* Internet Control Message Protocol. */
PROTO_IGMP = 2, /* Internet Group Management Protocol. */
PROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94). */
PROTO_TCP = 6, /* Transmission Control Protocol. */
PROTO_EGP = 8, /* Exterior Gateway Protocol. */
PROTO_PUP = 12, /* PUP protocol. */
PROTO_UDP = 17, /* User Datagram Protocol. */
PROTO_IDP = 22, /* XNS IDP protocol. */
PROTO_TP = 29, /* SO Transport Protocol Class 4. */
PROTO_DCCP = 33, /* Datagram Congestion Control Protocol. */
PROTO_IPV6 = 41, /* IPv6 header. */
PROTO_ROUTING = 43, /* IPv6 routing header. */
PROTO_FRAGMENT = 44, /* IPv6 fragmentation header. */
PROTO_RSVP = 46, /* Reservation Protocol. */
PROTO_GRE = 47, /* General Routing Encapsulation. */
PROTO_ESP = 50, /* encapsulating security payload. */
PROTO_AH = 51, /* authentication header. */
PROTO_ICMPV6 = 58, /* ICMPv6. */
PROTO_NONE = 59, /* IPv6 no next header. */
PROTO_DSTOPTS = 60, /* IPv6 destination options. */
PROTO_MTP = 92, /* Multicast Transport Protocol. */
PROTO_ENCAP = 98, /* Encapsulation Header. */
PROTO_PIM = 103, /* Protocol Independent Multicast. */
PROTO_COMP = 108, /* Compression Header Protocol. */
PROTO_SCTP = 132, /* Stream Control Transmission Protocol. */
PROTO_UDPLITE = 136, /* UDP-Lite protocol. */
PROTO_RAW = 255 /* Raw IP packets. */
};
};
struct Ethernet {
enum e {
UNKNOWN = 0,
//~ PUP = 0x0200, /* Xerox PUP */
SPRITE = 0x0500, /* Sprite */
IP = 0x0800, /* IP */
ARP = 0x0806, /* Address resolution */
MPLS = 0x8847, /* MPLS */
REVARP = 0x8035, /* Reverse ARP */
AT = 0x809B, /* AppleTalk protocol */
AARP = 0x80F3, /* AppleTalk ARP */
VLAN = 0x8100, /* IEEE 802.1Q VLAN tagging */
IPX = 0x8137, /* IPX */
IPV6 = 0x86dd, /* IP protocol version 6 */
PPPOED = 0x8863, /* PPPoE Discovery */
PPPOES = 0x8864, /* PPPoE Session */
EAPOL = 0x888e, /* EAPOL */
LOOPBACK = 0x9000 /* used to test interfaces */
};
};
struct ARP {
enum e {
NETROM = 0, /* From KA9Q: NET/ROM pseudo. */
ETHER = 1, /* Ethernet 10/100Mbps. */
EETHER = 2, /* Experimental Ethernet. */
AX25 = 3, /* AX.25 Level 2. */
PRONET = 4, /* PROnet token ring. */
CHAOS = 5, /* Chaosnet. */
IEEE802 = 6, /* IEEE 802.2 Ethernet/TR/TB. */
ARCNET = 7, /* ARCnet. */
APPLETLK = 8, /* APPLEtalk. */
DLCI = 15, /* Frame Relay DLCI. */
ATM = 19, /* ATM. */
METRICOM = 23, /* Metricom STRIP (new IANA id). */
IEEE1394 = 24, /* IEEE 1394 IPv4 - RFC 2734. */
EUI64 = 27, /* EUI-64. */
INFINIBAND = 32, /* InfiniBand. */
SLIP = 256,
CSLIP = 257,
SLIP6 = 258,
CSLIP6 = 259,
RSRVD = 260, /* Notional KISS type. */
ADAPT = 264,
ROSE = 270,
X25 = 271, /* CCITT X.25. */
HWX25 = 272, /* Boards with X.25 in firmware. */
PPP = 512,
CISCO = 513, /* Cisco HDLC. */
HDLC = CISCO,
LAPB = 516, /* LAPB. */
DDCMP = 517, /* Digital's DDCMP. */
RAWHDLC = 518, /* Raw HDLC. */
TUNNEL = 768, /* IPIP tunnel. */
TUNNEL6 = 769, /* IPIP6 tunnel. */
FRAD = 770, /* Frame Relay Access Device. */
SKIP = 771, /* SKIP vif. */
LOOPBACK = 772, /* Loopback device. */
LOCALTLK = 773, /* Localtalk device. */
FDDI = 774, /* Fiber Distributed Data Interface. */
BIF = 775, /* AP1000 BIF. */
SIT = 776, /* sit0 device - IPv6-in-IPv4. */
IPDDP = 777, /* IP-in-DDP tunnel. */
IPGRE = 778, /* GRE over IP. */
PIMREG = 779, /* PIMSM register interface. */
HIPPI = 780, /* High Performance Parallel I'face. */
ASH = 781, /* (Nexus Electronics) Ash. */
ECONET = 782, /* Acorn Econet. */
IRDA = 783, /* Linux-IrDA. */
FCPP = 784, /* Point to point fibrechanel. */
FCAL = 785, /* Fibrechanel arbitrated loop. */
FCPL = 786, /* Fibrechanel public loop. */
FCFABRIC = 787, /* Fibrechanel fabric. */
IEEE802_TR = 800, /* Magic type ident for TR. */
IEEE80211 = 801, /* IEEE 802.11. */
IEEE80211_PRISM = 802, /* IEEE 802.11 + Prism2 header. */
IEEE80211_RADIOTAP = 803, /* IEEE 802.11 + radiotap header. */
IEEE802154 = 804, /* IEEE 802.15.4 header. */
IEEE802154_PHY = 805, /* IEEE 802.15.4 PHY header. */
VOID_TYPE = 0xFFFF, /* Void type, nothing is known. */
NONE = 0xFFFE /* Zero header length. */
};
};
}
}
/**
* \brief Constants used in protocols.
*/
namespace Constants {
/** \cond */
struct IP {
/** \endcond */
enum e {
PROTO_IP = 0, // Dummy protocol for TCP.
PROTO_HOPOPTS = 0, // IPv6 Hop-by-Hop options.
PROTO_ICMP = 1, // Internet Control Message Protocol.
PROTO_IGMP = 2, // Internet Group Management Protocol.
PROTO_IPIP = 4, // IPIP tunnels (older KA9Q tunnels use 94).
PROTO_TCP = 6, // Transmission Control Protocol.
PROTO_EGP = 8, // Exterior Gateway Protocol.
PROTO_PUP = 12, // PUP protocol.
PROTO_UDP = 17, // User Datagram Protocol.
PROTO_IDP = 22, // XNS IDP protocol.
PROTO_TP = 29, // SO Transport Protocol Class 4.
PROTO_DCCP = 33, // Datagram Congestion Control Protocol.
PROTO_IPV6 = 41, // IPv6 header.
PROTO_ROUTING = 43, // IPv6 routing header.
PROTO_FRAGMENT = 44, // IPv6 fragmentation header.
PROTO_RSVP = 46, // Reservation Protocol.
PROTO_GRE = 47, // General Routing Encapsulation.
PROTO_ESP = 50, // encapsulating security payload.
PROTO_AH = 51, // authentication header.
PROTO_ICMPV6 = 58, // ICMPv6.
PROTO_NONE = 59, // IPv6 no next header.
PROTO_DSTOPTS = 60, // IPv6 destination options.
PROTO_MTP = 92, // Multicast Transport Protocol.
PROTO_ENCAP = 98, // Encapsulation Header.
PROTO_PIM = 103, // Protocol Independent Multicast.
PROTO_COMP = 108, // Compression Header Protocol.
PROTO_SCTP = 132, // Stream Control Transmission Protocol.
PROTO_UDPLITE = 136, // UDP-Lite protocol.
PROTO_RAW = 255 // Raw IP packets.
};
};
struct Ethernet {
enum e {
UNKNOWN = 0,
SPRITE = 0x0500, // Sprite
IP = 0x0800, // IP
ARP = 0x0806, // Address resolution
MPLS = 0x8847, // MPLS
REVARP = 0x8035, // Reverse ARP
AT = 0x809B, // AppleTalk protocol
AARP = 0x80F3, // AppleTalk ARP
VLAN = 0x8100, // IEEE 802.1Q VLAN tagging
IPX = 0x8137, // IPX
IPV6 = 0x86dd, // IP protocol version 6
PPPOED = 0x8863, // PPPoE Discovery
PPPOES = 0x8864, // PPPoE Session
EAPOL = 0x888e, // EAPOL
LOOPBACK = 0x9000 // used to test interfaces
};
};
struct ARP {
enum e {
NETROM = 0, // From KA9Q: NET/ROM pseudo.
ETHER = 1, // Ethernet 10/100Mbps.
EETHER = 2, // Experimental Ethernet.
AX25 = 3, // AX.25 Level 2.
PRONET = 4, // PROnet token ring.
CHAOS = 5, // Chaosnet.
IEEE802 = 6, // IEEE 802.2 Ethernet/TR/TB.
ARCNET = 7, // ARCnet.
APPLETLK = 8, // APPLEtalk.
DLCI = 15, // Frame Relay DLCI.
ATM = 19, // ATM.
METRICOM = 23, // Metricom STRIP (new IANA id).
IEEE1394 = 24, // IEEE 1394 IPv4 - RFC 2734.
EUI64 = 27, // EUI-64.
INFINIBAND = 32, // InfiniBand.
SLIP = 256,
CSLIP = 257,
SLIP6 = 258,
CSLIP6 = 259,
RSRVD = 260, // Notional KISS type.
ADAPT = 264,
ROSE = 270,
X25 = 271, // CCITT X.25.
HWX25 = 272, // Boards with X.25 in firmware.
PPP = 512,
CISCO = 513, // Cisco HDLC.
HDLC = CISCO,
LAPB = 516, // LAPB.
DDCMP = 517, // Digital's DDCMP.
RAWHDLC = 518, // Raw HDLC.
TUNNEL = 768, // IPIP tunnel.
TUNNEL6 = 769, // IPIP6 tunnel.
FRAD = 770, // Frame Relay Access Device.
SKIP = 771, // SKIP vif.
LOOPBACK = 772, // Loopback device.
LOCALTLK = 773, // Localtalk device.
FDDI = 774, // Fiber Distributed Data Interface.
BIF = 775, // AP1000 BIF.
SIT = 776, // sit0 device - IPv6-in-IPv4.
IPDDP = 777, // IP-in-DDP tunnel.
IPGRE = 778, // GRE over IP.
PIMREG = 779, // PIMSM register interface.
HIPPI = 780, // High Performance Parallel I'face.
ASH = 781, // (Nexus Electronics) Ash.
ECONET = 782, // Acorn Econet.
IRDA = 783, // Linux-IrDA.
FCPP = 784, // Point to point fibrechanel.
FCAL = 785, // Fibrechanel arbitrated loop.
FCPL = 786, // Fibrechanel public loop.
FCFABRIC = 787, // Fibrechanel fabric.
IEEE802_TR = 800, // Magic type ident for TR.
IEEE80211 = 801, // IEEE 802.11.
IEEE80211_PRISM = 802, // IEEE 802.11 + Prism2 header.
IEEE80211_RADIOTAP = 803, // IEEE 802.11 + radiotap header.
IEEE802154 = 804, // IEEE 802.15.4 header.
IEEE802154_PHY = 805, // IEEE 802.15.4 PHY header.
VOID_TYPE = 0xFFFF, // Void type, nothing is known.
NONE = 0xFFFE // Zero header length.
};
};
} // Constants
} // Tins
#endif // TINS_CONSTANTS_H

View File

@@ -43,494 +43,499 @@
#include "handshake_capturer.h"
namespace Tins {
class PDU;
class Dot11;
class Dot11Data;
namespace Crypto {
struct RC4Key;
#ifdef HAVE_WPA2_DECRYPTION
namespace WPA2 {
/**
* \brief Class that represents the keys used to decrypt a session.
*/
class TINS_API SessionKeys {
public:
/**
* The size of the Pairwise Master Key.
*/
static const size_t PMK_SIZE;
/**
* The size of the Pairwise Transient Key.
*/
static const size_t PTK_SIZE;
struct RC4Key;
/**
* The type used to hold the PTK (this has to be PTK_SIZE bytes long).
*/
typedef std::vector<uint8_t> ptk_type;
/**
* The type used to hold the PMK (this has to be PMK_SIZE bytes long).
*/
typedef std::vector<uint8_t> pmk_type;
/**
* Default constructs a SessionKeys object.
*/
SessionKeys();
/**
* \brief Constructs an instance using the provided PTK and a flag
* indicating whether it should use ccmp.
*
* \param ptk The PTK to use.
* \param is_ccmp Indicates whether to use CCMP to decrypt this traffic.
*/
SessionKeys(const ptk_type& ptk, bool is_ccmp);
/**
* \brief Constructs an instance using a handshake and a PMK.
*
* This will internally construct the PTK from the input parameters.
*
* \param hs The handshake to use.
* \param pmk The PMK to use.
*/
SessionKeys(const RSNHandshake &hs, const pmk_type &pmk);
/**
* \brief Decrypts a unicast packet.
*
* \param dot11 The encrypted packet to decrypt.
* \param raw The raw layer on the packet to decrypt.
* \return A SNAP layer containing the decrypted traffic or a null pointer
* if decryption failed.
*/
SNAP *decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) const;
/**
* \brief Gets the PTK for this session keys.
* \return The Pairwise Transcient Key.
*/
const ptk_type& get_ptk() const;
/**
* \brief Indicates whether CCMP is used to decrypt packets
* /return true iff CCMP is used.
*/
bool uses_ccmp() const;
private:
SNAP *ccmp_decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) const;
SNAP *tkip_decrypt_unicast(const Dot11Data &dot11, RawPDU &raw) const;
RC4Key generate_rc4_key(const Dot11Data &dot11, const RawPDU &raw) const;
ptk_type ptk;
bool is_ccmp;
};
/**
* \brief Represents a WPA2 supplicant's data.
*
* Objects of this class can be given the pre-shared key and the SSID
* of some access point, and this will generate the Pairwise Master Key
* from those parameters.
*/
class TINS_API SupplicantData {
public:
/**
* The type used to store the PMK.
*/
typedef SessionKeys::pmk_type pmk_type;
/**
* \brief Constructs a SupplicantData.
* \param psk The pre-shared key.
* \param ssid The access point's SSID.
*/
SupplicantData(const std::string &psk, const std::string &ssid);
/**
* \brief Getter for the PMK.
* \return The generated PMK.
*/
const pmk_type &pmk() const;
private:
pmk_type pmk_;
};
} // WPA2
#endif // HAVE_WPA2_DECRYPTION
#ifdef HAVE_WPA2_DECRYPTION
namespace WPA2 {
/**
* \brief Class that represents the keys used to decrypt a session.
*/
class TINS_API SessionKeys {
public:
/**
* \brief RC4 Key abstraction.
* The size of the Pairwise Master Key.
*/
struct RC4Key {
static const size_t data_size = 256;
/**
* \brief Initializes the key using the provided iterator range.
*
* \param start The start of the range.
* \param end The end of the range.
*/
template<typename ForwardIterator>
RC4Key(ForwardIterator start, ForwardIterator end);
/**
* The actual key data.
*/
uint8_t data[data_size];
};
static const size_t PMK_SIZE;
/**
* \brief Decrypts WEP-encrypted traffic.
* The size of the Pairwise Transient Key.
*/
class TINS_API WEPDecrypter {
public:
typedef HWAddress<6> address_type;
/**
* \brief Constructs a WEPDecrypter object.
*/
WEPDecrypter();
/**
* \brief Adds a decryption password.
*
* \param addr The access point's BSSID.
* \param password The password which will be used to decrypt
* packets sent from and to the AP identifier by the BSSID addr.
*/
void add_password(const address_type &addr, const std::string &password);
/**
* \brief Removes a decryption password
*
* \param addr The BSSID of the access point.
*/
void remove_password(const address_type &addr);
/**
* \brief Decrypts the provided PDU.
*
* A Dot11Data PDU is looked up inside the provided PDU chain.
* If no such PDU exists or there is no password associated
* with the Dot11 packet's BSSID, then the PDU is left intact.
*
* Otherwise, the packet is decrypted using the given password.
* If the CRC found after decrypting is invalid, false is
* returned.
*
* \return false if no decryption was performed or decryption
* failed, true otherwise.
*/
bool decrypt(PDU &pdu);
private:
typedef std::map<address_type, std::string> passwords_type;
PDU *decrypt(RawPDU &raw, const std::string &password);
passwords_type passwords;
std::vector<uint8_t> key_buffer;
};
static const size_t PTK_SIZE;
#ifdef HAVE_WPA2_DECRYPTION
/**
* \brief Decrypts WPA2-encrypted traffic.
* The type used to hold the PTK (this has to be PTK_SIZE bytes long).
*/
typedef std::vector<uint8_t> ptk_type;
/**
* The type used to hold the PMK (this has to be PMK_SIZE bytes long).
*/
typedef std::vector<uint8_t> pmk_type;
/**
* Default constructs a SessionKeys object.
*/
SessionKeys();
/**
* \brief Constructs an instance using the provided PTK and a flag
* indicating whether it should use ccmp.
*
* This class takes valid PSK and SSID tuples, captures client handshakes,
* and decrypts their traffic afterwards.
* \param ptk The PTK to use.
* \param is_ccmp Indicates whether to use CCMP to decrypt this traffic.
*/
class TINS_API WPA2Decrypter {
public:
/*
* \brief The type used to store Dot11 addresses.
*/
typedef HWAddress<6> address_type;
/**
* \brief Represents a pair of mac addresses.
*
* This is used to identify a host and the access point to which
* it is connected. The first element in the pair will always de
* lower or equal than the second one, so that given any host and
* the access point it's connected to, we can uniquely identify
* it with an address pair.
*/
typedef std::pair<address_type, address_type> addr_pair;
/**
* \brief Maps an address pair to the session keys.
*
* This type associates an address pair (host, access point) with the
* session keys, as generated using the packets seen on a handshake.
*
* \sa addr_pair
*/
typedef std::map<addr_pair, WPA2::SessionKeys> keys_map;
/**
* \brief Adds an access points's information.
*
* This associates an SSID with a PSK, and allows the decryption of
* any BSSIDs that broadcast the same SSID.
*
* The decrypter will inspect beacon frames, looking for SSID tags
* that contain the given SSID.
*
* Note that using this overload, the decryption of data frames and
* handshake capturing will be disabled until any access point
* broadcasts the provided SSID(this shouldn't take long at all).
* If this is not the desired behaviour, then you should check out
* the ovther add_ap_data overload.
*
* \param psk The PSK associated with the SSID.
* \param ssid The network's SSID.
*/
void add_ap_data(const std::string &psk, const std::string &ssid);
/**
* \brief Adds a access points's information, including its BSSID.
*
* This overload can be used if the BSSID associated with this SSID is
* known beforehand. The addr parameter indicates which specific BSSID
* is associated to the SSID.
*
* Note that if any other access point broadcasts the provided SSID,
* it will be taken into account as well.
*
* \param psk The PSK associated with this SSID.
* \param ssid The network's SSID.
* \param addr The access point's BSSID.
*/
void add_ap_data(const std::string &psk, const std::string &ssid, const address_type &addr);
/**
* \brief Explicitly add decryption keys.
*
* This method associates a pair (host, access point) with the given decryption keys.
* All encrypted packets sent between the given addresses will be decrypted using the
* provided keys.
*
* This method shouldn't normally be required. The WPA2Decrypter will be waiting for
* handshakes and will automatically extract the session keys, decrypting all
* encrypted packets with them. You should only use this method if for some reason
* you know the actual keys being used (because you checked and stored the keys_map
* somewhere).
*
* The actual order of the addresses doesn't matter, this method will make sure
* they're sorted.
*
* \param addresses The address pair (host, access point) to associate.
* \param session_keys The keys to use when decrypting messages sent between the
* given addresses.
*/
void add_decryption_keys(const addr_pair& addresses, const WPA2::SessionKeys& session_keys);
/**
* \brief Decrypts the provided PDU.
*
* A Dot11Data PDU is looked up inside the provided PDU chain.
* If no such PDU exists or no PSK was associated with the SSID
* broadcasted by the Dot11 packet's BSSID, or no EAPOL handshake
* was captured for the client involved in the communication,
* then the PDU is left intact.
*
* Otherwise, the packet is decrypted using the generated PTK.
* If the resulting MIC is invalid, then the packet is left intact.
*
* \return false if no decryption was performed, or the decryption
* failed, true otherwise.
*/
bool decrypt(PDU &pdu);
/**
* \brief Getter for the keys on this decrypter
*
* The returned map will be populated every time a new, complete, handshake
* is captured.
*
* \return The WPA2Decrypter keys map.
*/
const keys_map& get_keys() const;
private:
typedef std::map<std::string, WPA2::SupplicantData> pmks_map;
typedef std::map<address_type, WPA2::SupplicantData> bssids_map;
void try_add_keys(const Dot11Data &dot11, const RSNHandshake &hs);
addr_pair make_addr_pair(const address_type &addr1, const address_type &addr2) {
return (addr1 < addr2) ?
std::make_pair(addr1, addr2) :
std::make_pair(addr2, addr1);
}
addr_pair extract_addr_pair(const Dot11Data &dot11);
addr_pair extract_addr_pair_dst(const Dot11Data &dot11);
bssids_map::const_iterator find_ap(const Dot11Data &dot11);
void add_access_point(const std::string &ssid, const address_type &addr);
RSNHandshakeCapturer capturer;
pmks_map pmks;
bssids_map aps;
keys_map keys;
};
#endif // HAVE_WPA2_DECRYPTION
SessionKeys(const ptk_type& ptk, bool is_ccmp);
/**
* \brief Pluggable decrypter object which can be used to decrypt
* data on sniffing sessions.
*
* This class holds a decrypter object and a functor, and implements
* a suitable operator() to be used on BaseSniffer::sniff_loop, which
* decrypts packets and forwards them to the given functor.
* \brief Constructs an instance using a handshake and a PMK.
*
* This will internally construct the PTK from the input parameters.
*
* \param hs The handshake to use.
* \param pmk The PMK to use.
*/
template<typename Functor, typename Decrypter>
class DecrypterProxy {
public:
/**
* The type of the functor object.
*/
typedef Functor functor_type;
/**
* The type of the decrypter object.
*/
typedef Decrypter decrypter_type;
/**
* \brief Constructs an object from a functor and a decrypter.
* \param func The functor to be used to forward decrypted
* packets.
* \param decrypter The decrypter which will be used to decrypt
* packets
*/
DecrypterProxy(const functor_type &func,
const decrypter_type &decr = decrypter_type());
/**
* \brief Retrieves a reference to the decrypter object.
*/
decrypter_type &decrypter();
/**
* \brief Retrieves a const reference to the decrypter object.
*/
const decrypter_type &decrypter() const;
/**
* \brief The operator() which decrypts packets and forwards
* them to the functor.
*/
bool operator() (PDU &pdu);
private:
Functor functor_;
decrypter_type decrypter_;
};
SessionKeys(const RSNHandshake& hs, const pmk_type& pmk);
/**
* \brief Performs RC4 encription/decryption of the given byte range,
* using the provided key.
*
* The decrypted range will be copied to the OutputIterator provided.
*
* \param start The beginning of the range.
* \param start The end of the range.
* \param key The key to be used.
* \param output The iterator in which to write the output.
* \brief Decrypts a unicast packet.
*
* \param dot11 The encrypted packet to decrypt.
* \param raw The raw layer on the packet to decrypt.
* \return A SNAP layer containing the decrypted traffic or a null pointer
* if decryption failed.
*/
template<typename ForwardIterator, typename OutputIterator>
void rc4(ForwardIterator start, ForwardIterator end, RC4Key &key, OutputIterator output);
SNAP* decrypt_unicast(const Dot11Data& dot11, RawPDU& raw) const;
/**
* \brief Gets the PTK for this session keys.
* \return The Pairwise Transcient Key.
*/
const ptk_type& get_ptk() const;
/**
* \brief Indicates whether CCMP is used to decrypt packets
* /return true iff CCMP is used.
*/
bool uses_ccmp() const;
private:
SNAP* ccmp_decrypt_unicast(const Dot11Data& dot11, RawPDU& raw) const;
SNAP* tkip_decrypt_unicast(const Dot11Data& dot11, RawPDU& raw) const;
RC4Key generate_rc4_key(const Dot11Data& dot11, const RawPDU& raw) const;
ptk_type ptk_;
bool is_ccmp_;
};
/**
* \brief Represents a WPA2 supplicant's data.
*
* Objects of this class can be given the pre-shared key and the SSID
* of some access point, and this will generate the Pairwise Master Key
* from those parameters.
*/
class TINS_API SupplicantData {
public:
/**
* The type used to store the PMK.
*/
typedef SessionKeys::pmk_type pmk_type;
/**
* \brief Wrapper function to create a DecrypterProxy using a
* WEPDecrypter as the Decrypter template parameter.
*
* \param functor The functor to be forwarded to the DecrypterProxy
* constructor.
* \brief Constructs a SupplicantData.
* \param psk The pre-shared key.
* \param ssid The access point's SSID.
*/
template<typename Functor>
DecrypterProxy<Functor, WEPDecrypter> make_wep_decrypter_proxy(const Functor &functor);
#ifdef HAVE_WPA2_DECRYPTION
SupplicantData(const std::string& psk, const std::string& ssid);
/**
* \brief Wrapper function to create a DecrypterProxy using a
* WPA2Decrypter as the Decrypter template parameter.
*
* \param functor The functor to be forwarded to the DecrypterProxy
* constructor.
* \brief Getter for the PMK.
* \return The generated PMK.
*/
template<typename Functor>
DecrypterProxy<Functor, WPA2Decrypter> make_wpa2_decrypter_proxy(const Functor &functor) {
return DecrypterProxy<Functor, WPA2Decrypter>(functor);
}
#endif // HAVE_WPA2_DECRYPTION
// Implementation section
// DecrypterProxy
template<typename Functor, typename Decrypter>
DecrypterProxy<Functor, Decrypter>::DecrypterProxy(
const functor_type &func, const decrypter_type& decr)
: functor_(func), decrypter_(decr)
{
}
const pmk_type& pmk() const;
private:
pmk_type pmk_;
};
template<typename Functor, typename Decrypter>
typename DecrypterProxy<Functor, Decrypter>::decrypter_type &
DecrypterProxy<Functor, Decrypter>::decrypter()
{
return decrypter_;
}
} // WPA2
#endif // HAVE_WPA2_DECRYPTION
template<typename Functor, typename Decrypter>
const typename DecrypterProxy<Functor, Decrypter>::decrypter_type &
DecrypterProxy<Functor, Decrypter>::decrypter() const
{
return decrypter_;
}
/**
* \brief RC4 Key abstraction.
*/
struct RC4Key {
static const size_t data_size = 256;
template<typename Functor, typename Decrypter>
bool DecrypterProxy<Functor, Decrypter>::operator() (PDU &pdu)
{
return decrypter_.decrypt(pdu) ? functor_(pdu) : true;
}
template<typename Functor>
DecrypterProxy<Functor, WEPDecrypter> make_wep_decrypter_proxy(const Functor &functor)
{
return DecrypterProxy<Functor, WEPDecrypter>(functor);
}
// RC4 stuff
/**
* \brief Initializes the key using the provided iterator range.
*
* \param start The start of the range.
* \param end The end of the range.
*/
template<typename ForwardIterator>
RC4Key::RC4Key(ForwardIterator start, ForwardIterator end) {
for(size_t i = 0; i < data_size; ++i) {
data[i] = static_cast<uint8_t>(i);
}
size_t j = 0;
ForwardIterator iter = start;
for(size_t i = 0; i < data_size; ++i) {
j = (j + data[i] + *iter++) % 256;
if(iter == end)
iter = start;
std::swap(data[i], data[j]);
}
}
RC4Key(ForwardIterator start, ForwardIterator end);
/**
* The actual key data.
*/
uint8_t data[data_size];
};
/**
* \brief Decrypts WEP-encrypted traffic.
*/
class TINS_API WEPDecrypter {
public:
typedef HWAddress<6> address_type;
/**
* \brief Constructs a WEPDecrypter object.
*/
WEPDecrypter();
template<typename ForwardIterator, typename OutputIterator>
void rc4(ForwardIterator start, ForwardIterator end, RC4Key &key, OutputIterator output) {
size_t i = 0, j = 0;
while(start != end) {
i = (i + 1) % RC4Key::data_size;
j = (j + key.data[i]) % RC4Key::data_size;
std::swap(key.data[i], key.data[j]);
*output++ = *start++ ^ key.data[(key.data[i] + key.data[j]) % RC4Key::data_size];
/**
* \brief Adds a decryption password.
*
* \param addr The access point's BSSID.
* \param password The password which will be used to decrypt
* packets sent from and to the AP identifier by the BSSID addr.
*/
void add_password(const address_type& addr, const std::string& password);
/**
* \brief Removes a decryption password
*
* \param addr The BSSID of the access point.
*/
void remove_password(const address_type& addr);
/**
* \brief Decrypts the provided PDU.
*
* A Dot11Data PDU is looked up inside the provided PDU chain.
* If no such PDU exists or there is no password associated
* with the Dot11 packet's BSSID, then the PDU is left intact.
*
* Otherwise, the packet is decrypted using the given password.
* If the CRC found after decrypting is invalid, false is
* returned.
*
* \return false if no decryption was performed or decryption
* failed, true otherwise.
*/
bool decrypt(PDU& pdu);
private:
typedef std::map<address_type, std::string> passwords_type;
PDU* decrypt(RawPDU& raw, const std::string& password);
passwords_type passwords_;
std::vector<uint8_t> key_buffer_;
};
#ifdef HAVE_WPA2_DECRYPTION
/**
* \brief Decrypts WPA2-encrypted traffic.
*
* This class takes valid PSK and SSID tuples, captures client handshakes,
* and decrypts their traffic afterwards.
*/
class TINS_API WPA2Decrypter {
public:
/*
* \brief The type used to store Dot11 addresses.
*/
typedef HWAddress<6> address_type;
/**
* \brief Represents a pair of mac addresses.
*
* This is used to identify a host and the access point to which
* it is connected. The first element in the pair will always de
* lower or equal than the second one, so that given any host and
* the access point it's connected to, we can uniquely identify
* it with an address pair.
*/
typedef std::pair<address_type, address_type> addr_pair;
/**
* \brief Maps an address pair to the session keys.
*
* This type associates an address pair (host, access point) with the
* session keys, as generated using the packets seen on a handshake.
*
* \sa addr_pair
*/
typedef std::map<addr_pair, WPA2::SessionKeys> keys_map;
/**
* \brief Adds an access points's information.
*
* This associates an SSID with a PSK, and allows the decryption of
* any BSSIDs that broadcast the same SSID.
*
* The decrypter will inspect beacon frames, looking for SSID tags
* that contain the given SSID.
*
* Note that using this overload, the decryption of data frames and
* handshake capturing will be disabled until any access point
* broadcasts the provided SSID(this shouldn't take long at all).
* If this is not the desired behaviour, then you should check out
* the ovther add_ap_data overload.
*
* \param psk The PSK associated with the SSID.
* \param ssid The network's SSID.
*/
void add_ap_data(const std::string& psk, const std::string& ssid);
/**
* \brief Adds a access points's information, including its BSSID.
*
* This overload can be used if the BSSID associated with this SSID is
* known beforehand. The addr parameter indicates which specific BSSID
* is associated to the SSID.
*
* Note that if any other access point broadcasts the provided SSID,
* it will be taken into account as well.
*
* \param psk The PSK associated with this SSID.
* \param ssid The network's SSID.
* \param addr The access point's BSSID.
*/
void add_ap_data(const std::string& psk,
const std::string& ssid,
const address_type& addr);
/**
* \brief Explicitly add decryption keys.
*
* This method associates a pair (host, access point) with the given decryption keys.
* All encrypted packets sent between the given addresses will be decrypted using the
* provided keys.
*
* This method shouldn't normally be required. The WPA2Decrypter will be waiting for
* handshakes and will automatically extract the session keys, decrypting all
* encrypted packets with them. You should only use this method if for some reason
* you know the actual keys being used (because you checked and stored the keys_map
* somewhere).
*
* The actual order of the addresses doesn't matter, this method will make sure
* they're sorted.
*
* \param addresses The address pair (host, access point) to associate.
* \param session_keys The keys to use when decrypting messages sent between the
* given addresses.
*/
void add_decryption_keys(const addr_pair& addresses,
const WPA2::SessionKeys& session_keys);
/**
* \brief Decrypts the provided PDU.
*
* A Dot11Data PDU is looked up inside the provided PDU chain.
* If no such PDU exists or no PSK was associated with the SSID
* broadcasted by the Dot11 packet's BSSID, or no EAPOL handshake
* was captured for the client involved in the communication,
* then the PDU is left intact.
*
* Otherwise, the packet is decrypted using the generated PTK.
* If the resulting MIC is invalid, then the packet is left intact.
*
* \return false if no decryption was performed, or the decryption
* failed, true otherwise.
*/
bool decrypt(PDU& pdu);
/**
* \brief Getter for the keys on this decrypter
*
* The returned map will be populated every time a new, complete, handshake
* is captured.
*
* \return The WPA2Decrypter keys map.
*/
const keys_map& get_keys() const;
private:
typedef std::map<std::string, WPA2::SupplicantData> pmks_map;
typedef std::map<address_type, WPA2::SupplicantData> bssids_map;
void try_add_keys(const Dot11Data& dot11, const RSNHandshake& hs);
addr_pair make_addr_pair(const address_type& addr1, const address_type& addr2) {
return (addr1 < addr2) ?
std::make_pair(addr1, addr2) :
std::make_pair(addr2, addr1);
}
addr_pair extract_addr_pair(const Dot11Data& dot11);
addr_pair extract_addr_pair_dst(const Dot11Data& dot11);
bssids_map::const_iterator find_ap(const Dot11Data& dot11);
void add_access_point(const std::string& ssid, const address_type& addr);
RSNHandshakeCapturer capturer_;
pmks_map pmks_;
bssids_map aps_;
keys_map keys_;
};
#endif // HAVE_WPA2_DECRYPTION
/**
* \brief Pluggable decrypter object which can be used to decrypt
* data on sniffing sessions.
*
* This class holds a decrypter object and a functor, and implements
* a suitable operator() to be used on BaseSniffer::sniff_loop, which
* decrypts packets and forwards them to the given functor.
*/
template<typename Functor, typename Decrypter>
class DecrypterProxy {
public:
/**
* The type of the functor object.
*/
typedef Functor functor_type;
/**
* The type of the decrypter object.
*/
typedef Decrypter decrypter_type;
/**
* \brief Constructs an object from a functor and a decrypter.
* \param func The functor to be used to forward decrypted
* packets.
* \param decrypter The decrypter which will be used to decrypt
* packets
*/
DecrypterProxy(const functor_type& func,
const decrypter_type& decr = decrypter_type());
/**
* \brief Retrieves a reference to the decrypter object.
*/
decrypter_type& decrypter();
/**
* \brief Retrieves a const reference to the decrypter object.
*/
const decrypter_type& decrypter() const;
/**
* \brief The operator() which decrypts packets and forwards
* them to the functor.
*/
bool operator() (PDU& pdu);
private:
Functor functor_;
decrypter_type decrypter_;
};
/**
* \brief Performs RC4 encription/decryption of the given byte range,
* using the provided key.
*
* The decrypted range will be copied to the OutputIterator provided.
*
* \param start The beginning of the range.
* \param start The end of the range.
* \param key The key to be used.
* \param output The iterator in which to write the output.
*/
template<typename ForwardIterator, typename OutputIterator>
void rc4(ForwardIterator start, ForwardIterator end, RC4Key& key, OutputIterator output);
/**
* \brief Wrapper function to create a DecrypterProxy using a
* WEPDecrypter as the Decrypter template parameter.
*
* \param functor The functor to be forwarded to the DecrypterProxy
* constructor.
*/
template<typename Functor>
DecrypterProxy<Functor, WEPDecrypter> make_wep_decrypter_proxy(const Functor& functor);
#ifdef HAVE_WPA2_DECRYPTION
/**
* \brief Wrapper function to create a DecrypterProxy using a
* WPA2Decrypter as the Decrypter template parameter.
*
* \param functor The functor to be forwarded to the DecrypterProxy
* constructor.
*/
template<typename Functor>
DecrypterProxy<Functor, WPA2Decrypter> make_wpa2_decrypter_proxy(const Functor& functor) {
return DecrypterProxy<Functor, WPA2Decrypter>(functor);
}
#endif // HAVE_WPA2_DECRYPTION
// Implementation section
// DecrypterProxy
template<typename Functor, typename Decrypter>
DecrypterProxy<Functor, Decrypter>::DecrypterProxy(const functor_type& func,
const decrypter_type& decr)
: functor_(func), decrypter_(decr) {
}
template<typename Functor, typename Decrypter>
typename DecrypterProxy<Functor, Decrypter>::decrypter_type &
DecrypterProxy<Functor, Decrypter>::decrypter() {
return decrypter_;
}
template<typename Functor, typename Decrypter>
const typename DecrypterProxy<Functor, Decrypter>::decrypter_type &
DecrypterProxy<Functor, Decrypter>::decrypter() const {
return decrypter_;
}
template<typename Functor, typename Decrypter>
bool DecrypterProxy<Functor, Decrypter>::operator() (PDU& pdu) {
return decrypter_.decrypt(pdu) ? functor_(pdu) : true;
}
template<typename Functor>
DecrypterProxy<Functor, WEPDecrypter> make_wep_decrypter_proxy(const Functor& functor) {
return DecrypterProxy<Functor, WEPDecrypter>(functor);
}
// RC4 stuff
template<typename ForwardIterator>
RC4Key::RC4Key(ForwardIterator start, ForwardIterator end) {
for (size_t i = 0; i < data_size; ++i) {
data[i] = static_cast<uint8_t>(i);
}
size_t j = 0;
ForwardIterator iter = start;
for (size_t i = 0; i < data_size; ++i) {
j = (j + data[i] + *iter++) % 256;
if(iter == end) {
iter = start;
}
std::swap(data[i], data[j]);
}
}
template<typename ForwardIterator, typename OutputIterator>
void rc4(ForwardIterator start, ForwardIterator end, RC4Key& key, OutputIterator output) {
size_t i = 0, j = 0;
while (start != end) {
i = (i + 1) % RC4Key::data_size;
j = (j + key.data[i]) % RC4Key::data_size;
std::swap(key.data[i], key.data[j]);
*output++ = *start++ ^ key.data[(key.data[i] + key.data[j]) % RC4Key::data_size];
}
}
} // Crypto
} // Tins
#endif // TINS_CRYPTO_H

View File

@@ -39,485 +39,488 @@
#include "cxxstd.h"
namespace Tins {
/**
* \class DHCP
* \brief Represents the DHCP PDU.
*
* This class represents a DHCP PDU. It contains helpers methods
* which make it easy to set/get specific option values.
*
* Note that when adding options, the "End" option is not added
* automatically, so you will have to add it yourself.
*
* Options can be retrieved easily from DHCP PDUs:
*
* \code
* // Sniff a packet from somewhere
* DHCP dhcp = get_dhcp_from_somewhere();
*
* // This retrieves the Domain Name Servers option and converts
* // it to a std::vector<IPv4Address>. Note that if this option
* // is not present, an option_not_found exception is thrown.
* for(const auto& address : dhcp.domain_name_servers()) {
* // address is an ip
* }
*
* \endcode
/**
* \class DHCP
* \brief Represents the DHCP PDU.
*
* This class represents a DHCP PDU. It contains helpers methods
* which make it easy to set/get specific option values.
*
* Note that when adding options, the "End" option is not added
* automatically, so you will have to add it yourself.
*
* Options can be retrieved easily from DHCP PDUs:
*
* \code
* // Sniff a packet from somewhere
* DHCP dhcp = get_dhcp_from_somewhere();
*
* // This retrieves the Domain Name Servers option and converts
* // it to a std::vector<IPv4Address>. Note that if this option
* // is not present, an option_not_found exception is thrown.
* for(const auto& address : dhcp.domain_name_servers()) {
* // address is an ip
* }
*
* \endcode
*/
class TINS_API DHCP : public BootP {
public:
/**
* This PDU's flag.
*/
class TINS_API DHCP : public BootP {
public:
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DHCP;
static const PDU::PDUType pdu_flag = PDU::DHCP;
/**
* DHCP flags.
*/
enum Flags {
DISCOVER = 1,
OFFER = 2,
REQUEST = 3,
DECLINE = 4,
ACK = 5,
NAK = 6,
RELEASE = 7,
INFORM = 8
};
/**
* DHCP flags.
*/
enum Flags {
DISCOVER = 1,
OFFER = 2,
REQUEST = 3,
DECLINE = 4,
ACK = 5,
NAK = 6,
RELEASE = 7,
INFORM = 8
};
/**
* \brief DHCP options enum.
*/
enum OptionTypes {
PAD,
SUBNET_MASK,
TIME_OFFSET,
ROUTERS,
TIME_SERVERS,
NAME_SERVERS,
DOMAIN_NAME_SERVERS,
LOG_SERVERS,
COOKIE_SERVERS,
LPR_SERVERS,
IMPRESS_SERVERS,
RESOURCE_LOCATION_SERVERS,
HOST_NAME,
BOOT_SIZE,
MERIT_DUMP,
DOMAIN_NAME,
SWAP_SERVER,
ROOT_PATH,
EXTENSIONS_PATH,
IP_FORWARDING,
NON_LOCAL_SOURCE_ROUTING,
POLICY_FILTER,
MAX_DGRAM_REASSEMBLY,
DEFAULT_IP_TTL,
PATH_MTU_AGING_TIMEOUT,
PATH_MTU_PLATEAU_TABLE,
INTERFACE_MTU,
ALL_SUBNETS_LOCAL,
BROADCAST_ADDRESS,
PERFORM_MASK_DISCOVERY,
MASK_SUPPLIER,
ROUTER_DISCOVERY,
ROUTER_SOLICITATION_ADDRESS,
STATIC_ROUTES,
TRAILER_ENCAPSULATION,
ARP_CACHE_TIMEOUT,
IEEE802_3_ENCAPSULATION,
DEFAULT_TCP_TTL,
TCP_KEEPALIVE_INTERVAL,
TCP_KEEPALIVE_GARBAGE,
NIS_DOMAIN,
NIS_SERVERS,
NTP_SERVERS,
VENDOR_ENCAPSULATED_OPTIONS,
NETBIOS_NAME_SERVERS,
NETBIOS_DD_SERVER,
NETBIOS_NODE_TYPE,
NETBIOS_SCOPE,
FONT_SERVERS,
X_DISPLAY_MANAGER,
DHCP_REQUESTED_ADDRESS,
DHCP_LEASE_TIME,
DHCP_OPTION_OVERLOAD,
DHCP_MESSAGE_TYPE,
DHCP_SERVER_IDENTIFIER,
DHCP_PARAMETER_REQUEST_LIST,
DHCP_MESSAGE,
DHCP_MAX_MESSAGE_SIZE,
DHCP_RENEWAL_TIME,
DHCP_REBINDING_TIME,
VENDOR_CLASS_IDENTIFIER,
DHCP_CLIENT_IDENTIFIER,
NWIP_DOMAIN_NAME,
NWIP_SUBOPTIONS,
USER_CLASS = 77,
FQDN = 81,
DHCP_AGENT_OPTIONS = 82,
SUBNET_SELECTION = 118,
AUTHENTICATE = 210,
END = 255
};
/**
* The DHCP option type.
*/
typedef PDUOption<uint8_t, DHCP> option;
/**
* The type used to store the DHCP options.
*/
typedef std::list<option> options_type;
/**
* \brief Creates an instance of DHCP.
*
* This sets the hwtype and hlen fields to match the ethernet
* type and length.
*/
DHCP();
/**
* \brief Constructs a DHCP object from a buffer.
*
* If there is not enough size for a BootP header, or any of
* the TLV options contains an invalid size field, then a
* malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
DHCP(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief DHCP options enum.
*/
enum OptionTypes {
PAD,
SUBNET_MASK,
TIME_OFFSET,
ROUTERS,
TIME_SERVERS,
NAME_SERVERS,
DOMAIN_NAME_SERVERS,
LOG_SERVERS,
COOKIE_SERVERS,
LPR_SERVERS,
IMPRESS_SERVERS,
RESOURCE_LOCATION_SERVERS,
HOST_NAME,
BOOT_SIZE,
MERIT_DUMP,
DOMAIN_NAME,
SWAP_SERVER,
ROOT_PATH,
EXTENSIONS_PATH,
IP_FORWARDING,
NON_LOCAL_SOURCE_ROUTING,
POLICY_FILTER,
MAX_DGRAM_REASSEMBLY,
DEFAULT_IP_TTL,
PATH_MTU_AGING_TIMEOUT,
PATH_MTU_PLATEAU_TABLE,
INTERFACE_MTU,
ALL_SUBNETS_LOCAL,
BROADCAST_ADDRESS,
PERFORM_MASK_DISCOVERY,
MASK_SUPPLIER,
ROUTER_DISCOVERY,
ROUTER_SOLICITATION_ADDRESS,
STATIC_ROUTES,
TRAILER_ENCAPSULATION,
ARP_CACHE_TIMEOUT,
IEEE802_3_ENCAPSULATION,
DEFAULT_TCP_TTL,
TCP_KEEPALIVE_INTERVAL,
TCP_KEEPALIVE_GARBAGE,
NIS_DOMAIN,
NIS_SERVERS,
NTP_SERVERS,
VENDOR_ENCAPSULATED_OPTIONS,
NETBIOS_NAME_SERVERS,
NETBIOS_DD_SERVER,
NETBIOS_NODE_TYPE,
NETBIOS_SCOPE,
FONT_SERVERS,
X_DISPLAY_MANAGER,
DHCP_REQUESTED_ADDRESS,
DHCP_LEASE_TIME,
DHCP_OPTION_OVERLOAD,
DHCP_MESSAGE_TYPE,
DHCP_SERVER_IDENTIFIER,
DHCP_PARAMETER_REQUEST_LIST,
DHCP_MESSAGE,
DHCP_MAX_MESSAGE_SIZE,
DHCP_RENEWAL_TIME,
DHCP_REBINDING_TIME,
VENDOR_CLASS_IDENTIFIER,
DHCP_CLIENT_IDENTIFIER,
NWIP_DOMAIN_NAME,
NWIP_SUBOPTIONS,
USER_CLASS = 77,
FQDN = 81,
DHCP_AGENT_OPTIONS = 82,
SUBNET_SELECTION = 118,
AUTHENTICATE = 210,
END = 255
};
/**
* The DHCP option type.
*/
typedef PDUOption<uint8_t, DHCP> option;
/**
* The type used to store the DHCP options.
*/
typedef std::list<option> options_type;
/**
* \brief Creates an instance of DHCP.
*
* This sets the hwtype and hlen fields to match the ethernet
* type and length.
*/
DHCP();
/**
* \brief Constructs a DHCP object from a buffer.
*
* If there is not enough size for a BootP header, or any of
* the TLV options contains an invalid size field, then a
* malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
DHCP(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Adds a new option to this DHCP PDU.
* \param opt The option to be added.
*/
void add_option(const option& opt);
#if TINS_IS_CXX11
/**
* \brief Adds a new option to this DHCP PDU.
*
* The option is move-constructed.
*
* \param opt The option to be added.
*/
void add_option(const option &opt);
#if TINS_IS_CXX11
/**
* \brief Adds a new option to this DHCP PDU.
*
* The option is move-constructed.
*
* \param opt The option to be added.
*/
void add_option(option &&opt) {
internal_add_option(opt);
_options.push_back(std::move(opt));
}
#endif
void add_option(option &&opt) {
internal_add_option(opt);
options_.push_back(std::move(opt));
}
#endif
/**
* \brief Removes a DHCP option.
*
* If there are multiple options of the given type, only the first one
* will be removed.
*
* \param type The type of the option to be removed.
* \return true if the option was removed, false otherwise.
*/
bool remove_option(OptionTypes type);
/**
* \brief Removes a DHCP option.
*
* If there are multiple options of the given type, only the first one
* will be removed.
*
* \param type The type of the option to be removed.
* \return true if the option was removed, false otherwise.
*/
bool remove_option(OptionTypes type);
/**
* \brief Searchs for an option that matchs the given flag.
* \param opt_flag The flag to be searched.
* \return A pointer to the option, or 0 if it was not found.
*/
const option* search_option(OptionTypes opt) const;
/**
* \brief Searchs for an option that matchs the given flag.
* \param opt_flag The flag to be searched.
* \return A pointer to the option, or 0 if it was not found.
*/
const option *search_option(OptionTypes opt) const;
/**
* \brief Adds a type option to the option list.
*
* The new option is appended at the end of the list.
*
* \param type The type of this DHCP PDU.
*/
void type(Flags type);
/**
* \brief Adds an end option to the option list.
*
* The new option is appended at the end of the list.
*
* The END option is not added automatically. You should explicitly
* add it at the end of the DHCP options for the PDU to be
* standard-compliant.
*/
void end();
/**
* \brief Adds a server identifier option.
*
* The new option is appended at the end of the list.
*
* \param ip The server's IP address.
*/
void server_identifier(ipaddress_type ip);
/**
* \brief Adds an IP address lease time option.
*
* The new option is appended at the end of the list.
*
* \param time The lease time.
*/
void lease_time(uint32_t time);
/**
* \brief Adds a lease renewal time option.
*
* The new option is appended at the end of the list.
*
* \param time The lease renew time.
*/
void renewal_time(uint32_t time);
/**
* \brief Adds a rebind time option.
*
* The new option is appended at the end of the list.
*
* \param time The lease rebind time.
*/
void rebind_time(uint32_t time);
/**
* \brief Adds a subnet mask option.
*
* The new option is appended at the end of the list.
*
* \param mask The subnet mask.
*/
void subnet_mask(ipaddress_type mask);
/**
* \brief Adds a routers option.
*
* The new option is appended at the end of the list.
*
* \param routers A list of ip addresses.
*/
void routers(const std::vector<ipaddress_type> &routers);
/**
* \brief Adds a domain name servers option.
*
* The new option is appended at the end of the list.
*
* \param dns A list of ip addresses.
*/
void domain_name_servers(const std::vector<ipaddress_type> &dns);
/**
* \brief Adds a broadcast address option.
*
* The new option is appended at the end of the list.
*
* \param addr The broadcast address.
*/
void broadcast(ipaddress_type addr);
/**
* \brief Adds a requested address option.
*
* The new option is appended at the end of the list.
*
* \param addr The requested address.
*/
void requested_ip(ipaddress_type addr);
/**
* \brief Adds a domain name option.
*
* The new option is appended at the end of the list.
*
* \param name The domain name.
*/
void domain_name(const std::string &name);
/**
* \brief Adds a type option to the option list.
*
* The new option is appended at the end of the list.
*
* \param type The type of this DHCP PDU.
*/
void type(Flags type);
/**
* \brief Adds an end option to the option list.
*
* The new option is appended at the end of the list.
*
* The END option is not added automatically. You should explicitly
* add it at the end of the DHCP options for the PDU to be
* standard-compliant.
*/
void end();
/**
* \brief Adds a server identifier option.
*
* The new option is appended at the end of the list.
*
* \param ip The server's IP address.
*/
void server_identifier(ipaddress_type ip);
/**
* \brief Adds an IP address lease time option.
*
* The new option is appended at the end of the list.
*
* \param time The lease time.
*/
void lease_time(uint32_t time);
/**
* \brief Adds a lease renewal time option.
*
* The new option is appended at the end of the list.
*
* \param time The lease renew time.
*/
void renewal_time(uint32_t time);
/**
* \brief Adds a rebind time option.
*
* The new option is appended at the end of the list.
*
* \param time The lease rebind time.
*/
void rebind_time(uint32_t time);
/**
* \brief Adds a subnet mask option.
*
* The new option is appended at the end of the list.
*
* \param mask The subnet mask.
*/
void subnet_mask(ipaddress_type mask);
/**
* \brief Adds a routers option.
*
* The new option is appended at the end of the list.
*
* \param routers A list of ip addresses.
*/
void routers(const std::vector<ipaddress_type>& routers);
/**
* \brief Adds a domain name servers option.
*
* The new option is appended at the end of the list.
*
* \param dns A list of ip addresses.
*/
void domain_name_servers(const std::vector<ipaddress_type>& dns);
/**
* \brief Adds a broadcast address option.
*
* The new option is appended at the end of the list.
*
* \param addr The broadcast address.
*/
void broadcast(ipaddress_type addr);
/**
* \brief Adds a requested address option.
*
* The new option is appended at the end of the list.
*
* \param addr The requested address.
*/
void requested_ip(ipaddress_type addr);
/**
* \brief Adds a domain name option.
*
* The new option is appended at the end of the list.
*
* \param name The domain name.
*/
void domain_name(const std::string& name);
/**
* \brief Adds a hostname option.
*
* The new option is appended at the end of the list.
*
* \param name The hostname.
*/
void hostname(const std::string &name);
// Option getters
/**
* \brief Searchs for a type option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return uint8_t containing the type option.
*/
uint8_t type() const;
/**
* \brief Searchs for a server identifier option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return ipaddress_type Containing the server identifier.
*/
ipaddress_type server_identifier() const;
/**
* \brief Searchs for a lease time option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return uint32_t Containing the lease time.
*/
uint32_t lease_time() const;
/**
* \brief Searchs for a lease renewal time option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return uint32_t Containing the renewal time.
*/
uint32_t renewal_time() const;
/**
* \brief Searchs for a rebind time option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return uint32_t Containing the rebind time.
*/
uint32_t rebind_time() const;
/**
* \brief Searchs for a subnet mask option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return ipaddress_type Containing the subnet mask.
*/
ipaddress_type subnet_mask() const;
/**
* \brief Searchs for a routers option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return std::vector<ipaddress_type> Containing the routers
* option data.
*/
std::vector<ipaddress_type> routers() const;
/**
* \brief Searchs for a dns option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return std::list<ipaddress_type> Contanining the DNS servers
* provided.
*/
std::vector<ipaddress_type> domain_name_servers() const;
/**
* \brief Searchs for a broadcast option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return ipaddress_type Containing the broadcast address.
*/
ipaddress_type broadcast() const;
/**
* \brief Searchs for a requested option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return ipaddress_type Containing the requested IP address.
*/
ipaddress_type requested_ip() const;
/**
* \brief Searchs for a domain name option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return std::string Containing the domain name.
*/
std::string domain_name() const;
/**
* \brief Adds a hostname option.
*
* The new option is appended at the end of the list.
*
* \param name The hostname.
*/
void hostname(const std::string& name);
// Option getters
/**
* \brief Searchs for a type option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return uint8_t containing the type option.
*/
uint8_t type() const;
/**
* \brief Searchs for a server identifier option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return ipaddress_type Containing the server identifier.
*/
ipaddress_type server_identifier() const;
/**
* \brief Searchs for a lease time option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return uint32_t Containing the lease time.
*/
uint32_t lease_time() const;
/**
* \brief Searchs for a lease renewal time option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return uint32_t Containing the renewal time.
*/
uint32_t renewal_time() const;
/**
* \brief Searchs for a rebind time option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return uint32_t Containing the rebind time.
*/
uint32_t rebind_time() const;
/**
* \brief Searchs for a subnet mask option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return ipaddress_type Containing the subnet mask.
*/
ipaddress_type subnet_mask() const;
/**
* \brief Searchs for a routers option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return std::vector<ipaddress_type> Containing the routers
* option data.
*/
std::vector<ipaddress_type> routers() const;
/**
* \brief Searchs for a dns option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return std::list<ipaddress_type> Contanining the DNS servers
* provided.
*/
std::vector<ipaddress_type> domain_name_servers() const;
/**
* \brief Searchs for a broadcast option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return ipaddress_type Containing the broadcast address.
*/
ipaddress_type broadcast() const;
/**
* \brief Searchs for a requested option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return ipaddress_type Containing the requested IP address.
*/
ipaddress_type requested_ip() const;
/**
* \brief Searchs for a domain name option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return std::string Containing the domain name.
*/
std::string domain_name() const;
/**
* \brief Searchs for a hostname option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return std::string Containing the hostname.
*/
std::string hostname() const;
/**
* \brief Getter for the options list.
* \return The option list.
*/
const options_type options() const { return _options; }
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Getter for the header size.
* \return Returns the BOOTP header size.
* \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \sa PDU::clone
*/
DHCP *clone() const {
return new DHCP(*this);
/**
* \brief Searchs for a hostname option.
*
* If the option is not found, an option_not_found exception
* is thrown.
*
* \return std::string Containing the hostname.
*/
std::string hostname() const;
/**
* \brief Getter for the options list.
* \return The option list.
*/
const options_type options() const { return options_; }
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Getter for the header size.
* \return Returns the BOOTP header size.
* \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \sa PDU::clone
*/
DHCP* clone() const {
return new DHCP(*this);
}
private:
static const uint32_t MAX_DHCP_SIZE;
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
template<class T>
T search_and_convert(OptionTypes opt) const {
const option* option = search_option(opt);
if (!option) {
throw option_not_found();
}
private:
static const uint32_t MAX_DHCP_SIZE;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
return option->to<T>();
}
void internal_add_option(const option& opt);
serialization_type serialize_list(const std::vector<ipaddress_type>& ip_list);
options_type::const_iterator search_option_iterator(OptionTypes opt) const;
options_type::iterator search_option_iterator(OptionTypes opt);
options_type options_;
uint32_t size_;
};
template<class T>
T search_and_convert(OptionTypes opt) const {
const option *option = search_option(opt);
if(!option)
throw option_not_found();
return option->to<T>();
}
void internal_add_option(const option &opt);
serialization_type serialize_list(const std::vector<ipaddress_type> &ip_list);
options_type::const_iterator search_option_iterator(OptionTypes opt) const;
options_type::iterator search_option_iterator(OptionTypes opt);
options_type _options;
uint32_t _size;
};
}
} // Tins
#endif // TINS_DHCP_H

View File

@@ -41,7 +41,9 @@
namespace Tins {
namespace Memory {
class OutputMemoryStream;
} // Memory
/**
@@ -187,7 +189,7 @@ public:
const options_type& options = options_type())
: id(id), t1(t1), t2(t2), options(options) {}
static ia_na_type from_option(const option &opt);
static ia_na_type from_option(const option& opt);
};
/**
@@ -204,7 +206,7 @@ public:
const options_type& options = options_type())
: id(id), options(options) {}
static ia_ta_type from_option(const option &opt);
static ia_ta_type from_option(const option& opt);
};
/**
@@ -223,7 +225,7 @@ public:
: address(address), preferred_lifetime(preferred_lifetime),
valid_lifetime(valid_lifetime), options(options) {}
static ia_address_type from_option(const option &opt);
static ia_address_type from_option(const option& opt);
};
/**
@@ -238,11 +240,11 @@ public:
authentication_type(uint8_t protocol = 0, uint8_t algorithm = 0,
uint8_t rdm = 0, uint64_t replay_detection = 0,
const auth_info_type &auth_info = auth_info_type())
const auth_info_type& auth_info = auth_info_type())
: protocol(protocol), algorithm(algorithm), rdm(rdm),
replay_detection(replay_detection), auth_info(auth_info) {}
static authentication_type from_option(const option &opt);
static authentication_type from_option(const option& opt);
};
/**
@@ -252,10 +254,10 @@ public:
uint16_t code;
std::string message;
status_code_type(uint16_t code = 0, const std::string &message = "")
status_code_type(uint16_t code = 0, const std::string& message = "")
: code(code), message(message) { }
static status_code_type from_option(const option &opt);
static status_code_type from_option(const option& opt);
};
/**
@@ -268,10 +270,10 @@ public:
data_type data;
vendor_info_type(uint32_t enterprise_number = 0,
const data_type &data = data_type())
const data_type& data = data_type())
: enterprise_number(enterprise_number), data(data) { }
static vendor_info_type from_option(const option &opt);
static vendor_info_type from_option(const option& opt);
};
@@ -288,13 +290,10 @@ public:
typedef std::vector<class_option_data_type> data_type;
data_type data;
user_class_type(const data_type &data = data_type())
: data(data)
{
user_class_type(const data_type& data = data_type())
: data(data) { }
}
static user_class_type from_option(const option &opt);
static user_class_type from_option(const option& opt);
};
/**
@@ -307,11 +306,11 @@ public:
class_data_type vendor_class_data;
vendor_class_type(uint32_t enterprise_number = 0,
const class_data_type &vendor_class_data = class_data_type())
const class_data_type& vendor_class_data = class_data_type())
: enterprise_number(enterprise_number),
vendor_class_data(vendor_class_data) { }
static vendor_class_type from_option(const option &opt);
static vendor_class_type from_option(const option& opt);
};
/**
@@ -327,12 +326,12 @@ public:
lladdress_type lladdress;
duid_llt(uint16_t hw_type = 0, uint32_t time = 0,
const lladdress_type &lladdress = lladdress_type())
const lladdress_type& lladdress = lladdress_type())
: hw_type(hw_type), time(time), lladdress(lladdress) {}
PDU::serialization_type serialize() const;
static duid_llt from_bytes(const uint8_t *buffer, uint32_t total_sz);
static duid_llt from_bytes(const uint8_t* buffer, uint32_t total_sz);
};
/**
@@ -346,12 +345,12 @@ public:
identifier_type identifier;
duid_en(uint32_t enterprise_number = 0,
const identifier_type &identifier = identifier_type())
const identifier_type& identifier = identifier_type())
: enterprise_number(enterprise_number), identifier(identifier) {}
PDU::serialization_type serialize() const;
static duid_en from_bytes(const uint8_t *buffer, uint32_t total_sz);
static duid_en from_bytes(const uint8_t* buffer, uint32_t total_sz);
};
/**
@@ -365,12 +364,12 @@ public:
lladdress_type lladdress;
duid_ll(uint16_t hw_type = 0,
const lladdress_type &lladdress = lladdress_type())
const lladdress_type& lladdress = lladdress_type())
: hw_type(hw_type), lladdress(lladdress) {}
PDU::serialization_type serialize() const;
static duid_ll from_bytes(const uint8_t *buffer, uint32_t total_sz);
static duid_ll from_bytes(const uint8_t* buffer, uint32_t total_sz);
};
/**
@@ -383,19 +382,19 @@ public:
uint16_t id;
data_type data;
duid_type(uint16_t id = 0, const data_type &data = data_type())
duid_type(uint16_t id = 0, const data_type& data = data_type())
: id(id), data(data) {}
duid_type(const duid_llt &identifier)
duid_type(const duid_llt& identifier)
: id(duid_llt::duid_id), data(identifier.serialize()) {}
duid_type(const duid_en &identifier)
duid_type(const duid_en& identifier)
: id(duid_en::duid_id), data(identifier.serialize()) {}
duid_type(const duid_ll &identifier)
duid_type(const duid_ll& identifier)
: id(duid_en::duid_id), data(identifier.serialize()) {}
static duid_type from_option(const option &opt);
static duid_type from_option(const option& opt);
};
/**
@@ -428,7 +427,7 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
DHCPv6(const uint8_t *buffer, uint32_t total_sz);
DHCPv6(const uint8_t* buffer, uint32_t total_sz);
// Getters
@@ -438,7 +437,7 @@ public:
* \return The stored message type field.
*/
MessageType msg_type() const {
return static_cast<MessageType>(header_data[0]);
return static_cast<MessageType>(header_data_[0]);
}
/**
@@ -446,7 +445,9 @@ public:
*
* \return The stored hop count field.
*/
uint8_t hop_count() const { return header_data[1]; }
uint8_t hop_count() const {
return header_data_[1];
}
/**
* \brief Getter for the transaction id field.
@@ -454,7 +455,7 @@ public:
* \return The stored transaction id field.
*/
small_uint<24> transaction_id() const {
return (header_data[1] << 16) | (header_data[2] << 8) | header_data[3];
return (header_data_[1] << 16) | (header_data_[2] << 8) | header_data_[3];
}
/**
@@ -462,21 +463,27 @@ public:
*
* \return The stored peer address field.
*/
const ipaddress_type &peer_address() const { return peer_addr; }
const ipaddress_type& peer_address() const {
return peer_addr_;
}
/**
* \brief Getter for the link address field.
*
* \return The stored link address field.
*/
const ipaddress_type &link_address() const { return link_addr; }
const ipaddress_type& link_address() const {
return link_addr_;
}
/**
* \brief Getter for the DHCPv6 options.
*
* \return The stored options.
*/
const options_type &options() const { return options_; }
const options_type& options() const {
return options_;
}
// Setters
/**
@@ -505,14 +512,14 @@ public:
*
* \param count The new peer address.
*/
void peer_address(const ipaddress_type &addr);
void peer_address(const ipaddress_type& addr);
/**
* \brief Setter for the link address field.
*
* \param count The new link address.
*/
void link_address(const ipaddress_type &addr);
void link_address(const ipaddress_type& addr);
// Option getters
@@ -678,7 +685,7 @@ public:
*
* \param value The new IA_NA option data.
*/
void ia_na(const ia_na_type &value);
void ia_na(const ia_na_type& value);
/**
* \brief Setter for the Identity Association for Temporary
@@ -686,21 +693,21 @@ public:
*
* \param value The new IA_TA option data.
*/
void ia_ta(const ia_ta_type &value);
void ia_ta(const ia_ta_type& value);
/**
* \brief Setter for the Identity Association Address option.
*
* \param value The new IA Address option data.
*/
void ia_address(const ia_address_type &value);
void ia_address(const ia_address_type& value);
/**
* \brief Setter for the Identity Association Address option.
*
* \param value The new Option Request option data.
*/
void option_request(const option_request_type &value);
void option_request(const option_request_type& value);
/**
* \brief Setter for the Preference option.
@@ -721,28 +728,28 @@ public:
*
* \param value The new Relay Message option data.
*/
void relay_message(const relay_msg_type &value);
void relay_message(const relay_msg_type& value);
/**
* \brief Setter for the Authentication option.
*
* \param value The new Authentication option data.
*/
void authentication(const authentication_type &value);
void authentication(const authentication_type& value);
/**
* \brief Setter for the Server Unicast option.
*
* \param value The new Server Unicast option data.
*/
void server_unicast(const ipaddress_type &value);
void server_unicast(const ipaddress_type& value);
/**
* \brief Setter for the Status Code option.
*
* \param value The new Status Code option data.
*/
void status_code(const status_code_type &value);
void status_code(const status_code_type& value);
/**
* \brief Adds a Rapid Commit option.
@@ -754,28 +761,28 @@ public:
*
* \param value The new User Class option data.
*/
void user_class(const user_class_type &value);
void user_class(const user_class_type& value);
/**
* \brief Setter for the Vendor Class option.
*
* \param value The new Vendor Class option data.
*/
void vendor_class(const vendor_class_type &value);
void vendor_class(const vendor_class_type& value);
/**
* \brief Setter for the Vendor-specific Information option.
*
* \param value The new Vendor-specific Information option data.
*/
void vendor_info(const vendor_info_type &value);
void vendor_info(const vendor_info_type& value);
/**
* \brief Setter for the Interface ID option.
*
* \param value The new Interface ID option data.
*/
void interface_id(const interface_id_type &value);
void interface_id(const interface_id_type& value);
/**
* \brief Setter for the Reconfigure Message option.
@@ -794,14 +801,14 @@ public:
*
* \param value The new Client Identifier option data.
*/
void client_id(const duid_type &value);
void client_id(const duid_type& value);
/**
* \brief Setter for the Server Identifier option.
*
* \param value The new Server Identifier option data.
*/
void server_id(const duid_type &value);
void server_id(const duid_type& value);
// Other stuff
@@ -818,7 +825,7 @@ public:
*
* \param opt The option to be added
*/
void add_option(const option &opt);
void add_option(const option& opt);
/**
* \brief Removes a DHCPv6 option.
@@ -840,7 +847,7 @@ public:
*
* \param type The option identifier to be searched.
*/
const option *search_option(OptionTypes type) const;
const option* search_option(OptionTypes type) const;
// PDU stuff
@@ -858,56 +865,62 @@ public:
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
bool matches_response(const uint8_t* ptr, uint32_t total_sz) const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \sa PDU::clone
*/
DHCPv6 *clone() const {
DHCPv6* clone() const {
return new DHCPv6(*this);
}
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *);
void write_option(const option &option, Memory::OutputMemoryStream& stream) const;
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *);
void write_option(const option& option, Memory::OutputMemoryStream& stream) const;
options_type::const_iterator search_option_iterator(OptionTypes type) const;
options_type::iterator search_option_iterator(OptionTypes type);
template<template <typename> class Functor>
const option *safe_search_option(OptionTypes opt, uint32_t size) const {
const option *option = search_option(opt);
if(!option || Functor<uint32_t>()(option->data_size(), size))
const option* safe_search_option(OptionTypes opt, uint32_t size) const {
const option* option = search_option(opt);
if (!option || Functor<uint32_t>()(option->data_size(), size)) {
throw option_not_found();
}
return option;
}
template<typename T>
T search_and_convert(OptionTypes opt) const {
const option *option = search_option(opt);
if(!option)
const option* option = search_option(opt);
if (!option) {
throw option_not_found();
}
return option->to<T>();
}
uint8_t header_data[4];
uint32_t options_size;
ipaddress_type link_addr, peer_addr;
uint8_t header_data_[4];
uint32_t options_size_;
ipaddress_type link_addr_, peer_addr_;
options_type options_;
};
namespace Internals {
template<typename InputIterator>
void class_option_data2option(InputIterator start, InputIterator end,
std::vector<uint8_t>& buffer, size_t start_index = 0)
{
void class_option_data2option(InputIterator start,
InputIterator end,
std::vector<uint8_t>& buffer,
size_t start_index = 0) {
size_t index = start_index;
uint16_t uint16_t_buffer;
while(start != end) {
while (start != end) {
buffer.resize(buffer.size() + sizeof(uint16_t) + start->size());
uint16_t_buffer = Endian::host_to_be(static_cast<uint16_t>(start->size()));
std::memcpy(&buffer[index], &uint16_t_buffer, sizeof(uint16_t));
@@ -920,28 +933,30 @@ void class_option_data2option(InputIterator start, InputIterator end,
}
template<typename OutputType>
OutputType option2class_option_data(const uint8_t *ptr, uint32_t total_sz)
{
OutputType option2class_option_data(const uint8_t* ptr, uint32_t total_sz) {
typedef typename OutputType::value_type value_type;
OutputType output;
size_t index = 0;
while(index + 2 < total_sz) {
while (index + 2 < total_sz) {
uint16_t size;
std::memcpy(&size, ptr + index, sizeof(uint16_t));
size = Endian::be_to_host(size);
index += sizeof(uint16_t);
if(index + size > total_sz)
if (index + size > total_sz) {
throw option_not_found();
}
output.push_back(
value_type(ptr + index, ptr + index + size)
);
index += size;
}
if(index != total_sz)
if (index != total_sz) {
throw malformed_option();
}
return output;
}
}
}
} // Internals
} // Tins
#endif // TINS_DHCPV6_H

File diff suppressed because it is too large Load Diff

View File

@@ -56,8 +56,8 @@ public:
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11Disassoc(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
Dot11Disassoc(const address_type& dst_hw_addr = address_type(),
const address_type& src_hw_addr = address_type());
/**
* \brief Constructs a Dot11Disassoc object from a buffer and
@@ -73,14 +73,16 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11Disassoc(const uint8_t *buffer, uint32_t total_sz);
Dot11Disassoc(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Getter for the reason code field.
*
* \return The stored reason code.
*/
uint16_t reason_code() const { return Endian::le_to_host(_body.reason_code); }
uint16_t reason_code() const {
return Endian::le_to_host(body_.reason_code);
}
/**
* \brief Setter for the reason code field.
@@ -101,7 +103,9 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -117,17 +121,17 @@ public:
*
* \sa PDU::clone
*/
Dot11Disassoc *clone() const {
Dot11Disassoc* clone() const {
return new Dot11Disassoc(*this);
}
private:
struct DisassocBody {
struct dot11_disassoc_body {
uint16_t reason_code;
};
void write_fixed_parameters(Memory::OutputMemoryStream& stream);
DisassocBody _body;
dot11_disassoc_body body_;
};
/**
@@ -150,8 +154,8 @@ public:
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11AssocRequest(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
Dot11AssocRequest(const address_type& dst_hw_addr = address_type(),
const address_type& src_hw_addr = address_type());
/**
* \brief Constructs a Dot11AssocRequest object from a buffer
@@ -167,7 +171,7 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11AssocRequest(const uint8_t *buffer, uint32_t total_sz);
Dot11AssocRequest(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Getter for the Capabilities Information.
@@ -175,7 +179,9 @@ public:
* \return A constant refereence to the stored Capabilities
* Information field.
*/
const capability_information& capabilities() const { return _body.capability;}
const capability_information& capabilities() const {
return body_.capability;
}
/**
* \brief Getter for the Capabilities Information.
@@ -183,14 +189,18 @@ public:
* \return A refereence to the stored Capabilities Information
* field.
*/
capability_information& capabilities() { return _body.capability;}
capability_information& capabilities() {
return body_.capability;
}
/**
* \brief Getter for the listen interval field.
*
* \return The stored listen interval field.
*/
uint16_t listen_interval() const { return Endian::le_to_host(_body.listen_interval); }
uint16_t listen_interval() const {
return Endian::le_to_host(body_.listen_interval);
}
/**
* \brief Setter for the listen interval field.
@@ -211,7 +221,9 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -227,18 +239,18 @@ public:
*
* \sa PDU::clone
*/
Dot11AssocRequest *clone() const {
Dot11AssocRequest* clone() const {
return new Dot11AssocRequest(*this);
}
private:
struct AssocReqBody {
struct dot11_assoc_request_body {
capability_information capability;
uint16_t listen_interval;
};
void write_fixed_parameters(Memory::OutputMemoryStream& stream);
AssocReqBody _body;
dot11_assoc_request_body body_;
};
/**
@@ -261,8 +273,8 @@ public:
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11AssocResponse(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
Dot11AssocResponse(const address_type& dst_hw_addr = address_type(),
const address_type& src_hw_addr = address_type());
/**
* \brief Constructor which creates a Dot11AssocResponse object
@@ -278,7 +290,7 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11AssocResponse(const uint8_t *buffer, uint32_t total_sz);
Dot11AssocResponse(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Getter for the Capabilities Information field.
@@ -286,7 +298,9 @@ public:
* \return A constant reference to the stored Capabilities
* Information field.
*/
const capability_information& capabilities() const { return _body.capability;}
const capability_information& capabilities() const {
return body_.capability;
}
/**
* \brief Getter for the Capabilities Information field.
@@ -294,21 +308,27 @@ public:
* \return A reference to the stored Capabilities
* Information field.
*/
capability_information& capabilities() { return _body.capability;}
capability_information& capabilities() {
return body_.capability;
}
/**
* \brief Getter for the status code field.
*
* \return The stored status code.
*/
uint16_t status_code() const { return Endian::le_to_host(_body.status_code); }
uint16_t status_code() const {
return Endian::le_to_host(body_.status_code);
}
/**
* \brief Getter for the AID field.
*
* \return The stored AID field.
*/
uint16_t aid() const { return Endian::le_to_host(_body.aid); }
uint16_t aid() const {
return Endian::le_to_host(body_.aid);
}
/**
* \brief Setter for the status code.
@@ -336,7 +356,9 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -352,11 +374,11 @@ public:
*
* \sa PDU::clone
*/
Dot11AssocResponse *clone() const {
Dot11AssocResponse* clone() const {
return new Dot11AssocResponse(*this);
}
private:
struct AssocRespBody {
struct dot11_assoc_response_body {
capability_information capability;
uint16_t status_code;
uint16_t aid;
@@ -364,7 +386,7 @@ private:
void write_fixed_parameters(Memory::OutputMemoryStream& stream);
AssocRespBody _body;
dot11_assoc_response_body body_;
};
/**
@@ -387,8 +409,8 @@ public:
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11ReAssocRequest(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
Dot11ReAssocRequest(const address_type& dst_hw_addr = address_type(),
const address_type& src_hw_addr = address_type());
/**
* \brief Constructs a Dot11AssocRequest object from a buffer
@@ -404,7 +426,7 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11ReAssocRequest(const uint8_t *buffer, uint32_t total_sz);
Dot11ReAssocRequest(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Getter for the Capabilities Information.
@@ -412,7 +434,9 @@ public:
* \return A constant reference to the stored Capabilities
* Information field.
*/
const capability_information& capabilities() const { return _body.capability;}
const capability_information& capabilities() const {
return body_.capability;
}
/**
* \brief Getter for the Capabilities Information.
@@ -420,21 +444,27 @@ public:
* \return A reference to the stored Capabilities Information
* field.
*/
capability_information& capabilities() { return _body.capability;}
capability_information& capabilities() {
return body_.capability;
}
/**
* \brief Getter for the listen interval field.
*
* \return The stored listen interval.
*/
uint16_t listen_interval() const { return Endian::le_to_host(_body.listen_interval); }
uint16_t listen_interval() const {
return Endian::le_to_host(body_.listen_interval);
}
/**
* \brief Getter for the current ap field.
*
* \return The current ap.
*/
address_type current_ap() const { return _body.current_ap; }
address_type current_ap() const {
return body_.current_ap;
}
/**
* \brief Setter for the listen interval field.
@@ -448,7 +478,7 @@ public:
*
* \param new_current_ap The address of the current ap.
*/
void current_ap(const address_type &new_current_ap);
void current_ap(const address_type& new_current_ap);
/**
* \brief Returns the frame's header length.
@@ -462,7 +492,9 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -478,11 +510,11 @@ public:
*
* \sa PDU::clone
*/
Dot11ReAssocRequest *clone() const {
Dot11ReAssocRequest* clone() const {
return new Dot11ReAssocRequest(*this);
}
private:
struct ReAssocReqBody {
struct dot11_reassoc_request_body {
capability_information capability;
uint16_t listen_interval;
uint8_t current_ap[address_type::address_size];
@@ -490,7 +522,7 @@ private:
void write_fixed_parameters(Memory::OutputMemoryStream& stream);
ReAssocReqBody _body;
dot11_reassoc_request_body body_;
};
/**
@@ -513,8 +545,8 @@ public:
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11ReAssocResponse(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
Dot11ReAssocResponse(const address_type& dst_hw_addr = address_type(),
const address_type& src_hw_addr = address_type());
/**
* \brief Constructs a Dot11ReAssocResponse object from a buffer
@@ -530,7 +562,7 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11ReAssocResponse(const uint8_t *buffer, uint32_t total_sz);
Dot11ReAssocResponse(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Getter for the Capabilities Information.
@@ -538,7 +570,9 @@ public:
* \return A constant reference to the stored Capabilities
* Information field.
*/
const capability_information& capabilities() const { return _body.capability;}
const capability_information& capabilities() const {
return body_.capability;
}
/**
* \brief Getter for the Capabilities Information.
@@ -546,21 +580,27 @@ public:
* \return A reference to the stored Capabilities Information
* field.
*/
capability_information& capabilities() { return _body.capability;}
capability_information& capabilities() {
return body_.capability;
}
/**
* \brief Getter for the status code field.
*
* \return The stored status code.
*/
uint16_t status_code() const { return Endian::le_to_host(_body.status_code); }
uint16_t status_code() const {
return Endian::le_to_host(body_.status_code);
}
/**
* \brief Getter for the AID field.
*
* \return The stored AID field value.
*/
uint16_t aid() const { return Endian::le_to_host(_body.aid); }
uint16_t aid() const {
return Endian::le_to_host(body_.aid);
}
/**
* \brief Setter for the status code field.
@@ -588,7 +628,9 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -604,11 +646,11 @@ public:
*
* \sa PDU::clone
*/
Dot11ReAssocResponse *clone() const {
Dot11ReAssocResponse* clone() const {
return new Dot11ReAssocResponse(*this);
}
private:
struct ReAssocRespBody {
struct dot11_reassoc_response_body {
capability_information capability;
uint16_t status_code;
uint16_t aid;
@@ -616,8 +658,9 @@ private:
void write_fixed_parameters(Memory::OutputMemoryStream& stream);
ReAssocRespBody _body;
dot11_reassoc_response_body body_;
};
} // namespace Tins
#endif // TINS_DOT11_DOT11_ASSOC_H

View File

@@ -55,8 +55,8 @@ public:
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11Authentication(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
Dot11Authentication(const address_type& dst_hw_addr = address_type(),
const address_type& src_hw_addr = address_type());
/**
* \brief Constructs a Dot11Authentication object from a buffer
@@ -72,28 +72,33 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11Authentication(const uint8_t *buffer, uint32_t total_sz);
Dot11Authentication(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Getter for the Authetication Algorithm Number field.
*
* \return The stored authentication algorithm number.
*/
uint16_t auth_algorithm() const {return Endian::le_to_host(_body.auth_algorithm); }
uint16_t auth_algorithm() const {
return Endian::le_to_host(body_.auth_algorithm); }
/**
* \brief Getter for the Authetication Sequence Number field.
*
* \return The stored authentication sequence number.
*/
uint16_t auth_seq_number() const {return Endian::le_to_host(_body.auth_seq_number); }
uint16_t auth_seq_number() const {
return Endian::le_to_host(body_.auth_seq_number);
}
/**
* \brief Getter for the status code field.
*
* \return The stored status code.
*/
uint16_t status_code() const { return Endian::le_to_host(_body.status_code); }
uint16_t status_code() const {
return Endian::le_to_host(body_.status_code);
}
/**
* \brief Setter for the Authetication Algorithm Number field.
@@ -130,7 +135,9 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -146,11 +153,11 @@ public:
*
* \sa PDU::clone
*/
Dot11Authentication *clone() const {
Dot11Authentication* clone() const {
return new Dot11Authentication(*this);
}
private:
struct AuthBody {
struct dot11_auth_body {
uint16_t auth_algorithm;
uint16_t auth_seq_number;
uint16_t status_code;
@@ -158,8 +165,7 @@ private:
void write_fixed_parameters(Memory::OutputMemoryStream& stream);
AuthBody _body;
dot11_auth_body body_;
};
/**
@@ -182,8 +188,8 @@ public:
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11Deauthentication(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
Dot11Deauthentication(const address_type& dst_hw_addr = address_type(),
const address_type& src_hw_addr = address_type());
/**
* \brief Constructs a Dot11Deauthentication object from a buffer
@@ -199,14 +205,16 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11Deauthentication(const uint8_t *buffer, uint32_t total_sz);
Dot11Deauthentication(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Getter for the reason code field.
*
* \return The reason code to be set.
*/
uint16_t reason_code() const { return Endian::le_to_host(_body.reason_code); }
uint16_t reason_code() const {
return Endian::le_to_host(body_.reason_code);
}
/**
* \brief Setter for the reason code field.
@@ -227,7 +235,9 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -243,19 +253,19 @@ public:
*
* \sa PDU::clone
*/
Dot11Deauthentication *clone() const {
Dot11Deauthentication* clone() const {
return new Dot11Deauthentication(*this);
}
private:
struct DeauthBody {
struct dot11_deauth_body {
uint16_t reason_code;
};
void write_fixed_parameters(Memory::OutputMemoryStream& stream);
DeauthBody _body;
dot11_deauth_body body_;
};
} // namespace Tins
#endif // TINS_DOT11_DOT11_AUTH_H

View File

@@ -192,7 +192,7 @@ public:
*
* \param dst_hw_addr The destination hardware address.
*/
Dot11(const address_type &dst_hw_addr = address_type());
Dot11(const address_type& dst_hw_addr = address_type());
/**
* \brief Constructs 802.11 PDU from a buffer and adds all
@@ -206,91 +206,115 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11(const uint8_t *buffer, uint32_t total_sz);
Dot11(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Getter for the protocol version field.
*
* \return The stored protocol version field.
*/
small_uint<2> protocol() const { return _header.control.protocol; }
small_uint<2> protocol() const {
return header_.control.protocol;
}
/**
* \brief Getter for the Type field.
*
* \return The stored Type field.
*/
small_uint<2> type() const { return _header.control.type; }
small_uint<2> type() const {
return header_.control.type;
}
/**
* \brief Getter for the Subtype field.
*
* \return The stored Subtype field.
*/
small_uint<4> subtype() const { return _header.control.subtype; }
small_uint<4> subtype() const {
return header_.control.subtype;
}
/**
* \brief Getter for the To-DS field.
*
* \return The stored To-DS field.
*/
small_uint<1> to_ds() const { return _header.control.to_ds; }
small_uint<1> to_ds() const {
return header_.control.to_ds;
}
/**
* \brief Getter for the From-DS field.
*
* \return The stored From-DS field.
*/
small_uint<1> from_ds() const { return _header.control.from_ds; }
small_uint<1> from_ds() const {
return header_.control.from_ds;
}
/**
* \brief Getter for the More-Frag field.
*
* \return The stored More-Frag field.
*/
small_uint<1> more_frag() const { return _header.control.more_frag; }
small_uint<1> more_frag() const {
return header_.control.more_frag;
}
/**
* \brief Getter for the Retry field.
*
* \return The stored Retry field.
*/
small_uint<1> retry() const { return _header.control.retry; }
small_uint<1> retry() const {
return header_.control.retry;
}
/**
* \brief Getter for the Power-Management field.
*
* \return The stored Power-Management field.
*/
small_uint<1> power_mgmt() const { return _header.control.power_mgmt; }
small_uint<1> power_mgmt() const {
return header_.control.power_mgmt;
}
/**
* \brief Getter for the WEP field.
*
* \return The stored WEP field.
*/
small_uint<1> wep() const { return _header.control.wep; }
small_uint<1> wep() const {
return header_.control.wep;
}
/**
* \brief Getter for the Order field.
*
* \return The stored Order field.
*/
small_uint<1> order() const { return _header.control.order; }
small_uint<1> order() const {
return header_.control.order;
}
/**
* \brief Getter for the Duration-ID field.
*
* \return The stored Duration-ID field.
*/
uint16_t duration_id() const { return Endian::le_to_host(_header.duration_id); }
uint16_t duration_id() const {
return Endian::le_to_host(header_.duration_id);
}
/**
* \brief Getter for the first address.
*
* \return The stored first address.
*/
address_type addr1() const { return _header.addr1; }
address_type addr1() const {
return header_.addr1;
}
// Setters
@@ -376,7 +400,7 @@ public:
*
* \param new_addr1 The new first address.
*/
void addr1(const address_type &new_addr1);
void addr1(const address_type& new_addr1);
/* Virtual methods */
/**
@@ -391,14 +415,14 @@ public:
/**
* \sa PDU::send()
*/
void send(PacketSender &sender, const NetworkInterface &iface);
void send(PacketSender& sender, const NetworkInterface& iface);
#endif // _WIN32
/**
* \brief Adds a new option to this Dot11 PDU.
* \param opt The option to be added.
*/
void add_option(const option &opt);
void add_option(const option& opt);
#if TINS_IS_CXX11
/**
@@ -410,7 +434,7 @@ public:
*/
void add_option(option &&opt) {
internal_add_option(opt);
_options.push_back(std::move(opt));
options_.push_back(std::move(opt));
}
#endif
@@ -433,18 +457,20 @@ public:
* \param type The option identifier.
* \return The option found, or 0 if no such option has been set.
*/
const option *search_option(OptionTypes type) const;
const option* search_option(OptionTypes type) const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \sa PDU::clone
*/
Dot11 *clone() const {
Dot11* clone() const {
return new Dot11(*this);
}
@@ -462,7 +488,9 @@ public:
*
* \return The options list.
*/
const options_type &options() const { return _options; }
const options_type& options() const {
return options_;
}
/**
* \brief Allocates an Dot11 PDU from a buffer.
@@ -478,18 +506,18 @@ public:
* \param total_sz The total size of the buffer.
* \return The allocated Dot11 PDU.
*/
static Dot11 *from_bytes(const uint8_t *buffer, uint32_t total_sz);
static Dot11* from_bytes(const uint8_t* buffer, uint32_t total_sz);
protected:
virtual void write_ext_header(Memory::OutputMemoryStream& stream) { }
virtual void write_fixed_parameters(Memory::OutputMemoryStream& stream) { }
void parse_tagged_parameters(Memory::InputMemoryStream& stream);
void add_tagged_option(OptionTypes opt, uint8_t len, const uint8_t *val);
void add_tagged_option(OptionTypes opt, uint8_t len, const uint8_t* val);
protected:
/**
* Struct that represents the 802.11 header
*/
TINS_BEGIN_PACK
struct ieee80211_header {
struct dot11_header {
TINS_BEGIN_PACK
struct {
#if TINS_IS_LITTLE_ENDIAN
@@ -523,18 +551,19 @@ protected:
} TINS_END_PACK;
private:
Dot11(const ieee80211_header *header_ptr);
Dot11(const dot11_header* header_ptr);
void internal_add_option(const option &opt);
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
void internal_add_option(const option& opt);
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
options_type::const_iterator search_option_iterator(OptionTypes type) const;
options_type::iterator search_option_iterator(OptionTypes type);
ieee80211_header _header;
uint32_t _options_size;
options_type _options;
dot11_header header_;
uint32_t options_size_;
options_type options_;
};
}
} // Tins
#endif // TINS_DOT11_DOT11_H

View File

@@ -36,132 +36,144 @@
#include "../macros.h"
namespace Tins {
/**
* \brief Represents an IEEE 802.11 Beacon.
*
*/
class TINS_API Dot11Beacon : public Dot11ManagementFrame {
public:
/**
* \brief Class representing an 802.11 Beacon.
*
* \brief This PDU's flag.
*/
class TINS_API Dot11Beacon : public Dot11ManagementFrame {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::DOT11_BEACON;
static const PDU::PDUType pdu_flag = PDU::DOT11_BEACON;
/**
* \brief Constructor for creating a 802.11 Beacon.
*
* Constructs a 802.11 Beacon taking destination and source
* hardware address.
*
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11Beacon(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructor for creating a 802.11 Beacon.
*
* Constructs a 802.11 Beacon taking destination and source
* hardware address.
*
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11Beacon(const address_type& dst_hw_addr = address_type(),
const address_type& src_hw_addr = address_type());
/**
* \brief Constructs a Dot11Beacon object from a buffer and adds
* all identifiable PDUs found in the buffer as children of this
* one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11Beacon(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Constructs a Dot11Beacon object from a buffer and adds
* all identifiable PDUs found in the buffer as children of this
* one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for the header in the buffer
* or the input data is malformed, a malformed_packet exception
* is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11Beacon(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Getter for the timestamp field.
*
* \return The stored timestamp value.
*/
uint64_t timestamp() const { return Endian::le_to_host(_body.timestamp); }
/**
* \brief Getter for the timestamp field.
*
* \return The stored timestamp value.
*/
uint64_t timestamp() const {
return Endian::le_to_host(body_.timestamp);
}
/**
* \brief Getter for the interval field.
*
* \return The stored interval value.
*/
uint16_t interval() const { return Endian::le_to_host(_body.interval); }
/**
* \brief Getter for the interval field.
*
* \return The stored interval value.
*/
uint16_t interval() const {
return Endian::le_to_host(body_.interval);
}
/**
* \brief Getter for the Capabilities Information structure.
*
* \return A constant refereence to the stored Capabilities
* Information field.
*/
const capability_information& capabilities() const { return _body.capability; }
/**
* \brief Getter for the Capabilities Information structure.
*
* \return A constant refereence to the stored Capabilities
* Information field.
*/
const capability_information& capabilities() const {
return body_.capability;
}
/**
* \brief Getter for the Capabilities Information.
*
* \return A refereence to the stored Capabilities Information
* field.
*/
capability_information& capabilities() { return _body.capability; }
/**
* \brief Getter for the Capabilities Information.
*
* \return A refereence to the stored Capabilities Information
* field.
*/
capability_information& capabilities() {
return body_.capability;
}
/**
* \brief Setter for the timestamp field.
*
* \param new_timestamp The timestamp to be set.
*/
void timestamp(uint64_t new_timestamp);
/**
* \brief Setter for the timestamp field.
*
* \param new_timestamp The timestamp to be set.
*/
void timestamp(uint64_t new_timestamp);
/**
* \brief Setter for the interval field.
*
* \param new_interval The interval to be set.
*/
void interval(uint16_t new_interval);
/**
* \brief Setter for the interval field.
*
* \param new_interval The interval to be set.
*/
void interval(uint16_t new_interval);
/**
* \brief Returns the frame's header length.
*
* \return An uint32_t with the header's size.
* \sa PDU::header_size()
*/
uint32_t header_size() const;
/**
* \brief Returns the frame's header length.
*
* \return An uint32_t with the header's size.
* \sa PDU::header_size()
*/
uint32_t header_size() const;
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11ManagementFrame::matches_flag(flag);
}
/**
* \brief Check wether this PDU matches the specified flag.
* \param flag The flag to match
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11ManagementFrame::matches_flag(flag);
}
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11Beacon *clone() const {
return new Dot11Beacon(*this);
}
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11Beacon* clone() const {
return new Dot11Beacon(*this);
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
private:
TINS_BEGIN_PACK
struct BeaconBody {
uint64_t timestamp;
uint16_t interval;
capability_information capability;
} TINS_END_PACK;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const {
return pdu_flag;
}
private:
TINS_BEGIN_PACK
struct dot11_beacon_body {
uint64_t timestamp;
uint16_t interval;
capability_information capability;
} TINS_END_PACK;
void write_fixed_parameters(Memory::OutputMemoryStream& stream);
void write_fixed_parameters(Memory::OutputMemoryStream& stream);
dot11_beacon_body body_;
};
BeaconBody _body;
};
} // namespace Tins
#endif // TINS_DOT11_DOT11_BEACON_H

View File

@@ -38,7 +38,7 @@
namespace Tins {
/**
* \brief Class that represents an 802.11 control frame.
* \brief Represents an IEEE 802.11 control frame.
*/
class TINS_API Dot11Control : public Dot11 {
public:
@@ -55,7 +55,7 @@ public:
*
* \param dst_addr The destination hardware address.
*/
Dot11Control(const address_type &dst_addr = address_type());
Dot11Control(const address_type& dst_addr = address_type());
/**
* \brief Constructs a Dot11Control object from a buffer and
@@ -71,13 +71,15 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11Control(const uint8_t *buffer, uint32_t total_sz);
Dot11Control(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::DOT11_CONTROL; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -85,7 +87,7 @@ public:
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == PDU::DOT11_CONTROL || Dot11::matches_flag(flag);
return flag == pdu_flag || Dot11::matches_flag(flag);
}
};
@@ -98,13 +100,15 @@ public:
/**
* \brief Getter for the target address field.
*/
address_type target_addr() const { return _taddr; }
address_type target_addr() const {
return taddr_;
}
/**
* \brief Setter for the target address field.
* \param addr The new target address.
*/
void target_addr(const address_type &addr);
void target_addr(const address_type& addr);
protected:
/**
* \brief Constructor for creating a 802.11 control frame TA PDU
@@ -115,8 +119,8 @@ protected:
* \param dst_addr The destination hardware address.
* \param target_addr The source hardware address.
*/
Dot11ControlTA(const address_type &dst_addr = address_type(),
const address_type &target_addr = address_type());
Dot11ControlTA(const address_type& dst_addr = address_type(),
const address_type& target_addr = address_type());
/**
* \brief Constructs a Dot11ControlTA object from a buffer and
@@ -132,7 +136,7 @@ protected:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11ControlTA(const uint8_t *buffer, uint32_t total_sz);
Dot11ControlTA(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Returns the 802.11 frame's header length.
@@ -146,13 +150,13 @@ protected:
* \brief Getter for the control ta additional fields size.
*/
uint32_t controlta_size() const {
return static_cast<uint32_t>(_taddr.size() + sizeof(ieee80211_header));
return static_cast<uint32_t>(taddr_.size() + sizeof(dot11_header));
}
void write_ext_header(Memory::OutputMemoryStream& stream);
private:
address_type _taddr;
address_type taddr_;
};
/**
@@ -174,8 +178,8 @@ public:
* \param dst_addr The destination hardware address.
* \param target_addr The source hardware address.
*/
Dot11RTS(const address_type &dst_addr = address_type(),
const address_type &target_addr = address_type());
Dot11RTS(const address_type& dst_addr = address_type(),
const address_type& target_addr = address_type());
/**
* \brief Constructs a Dot11RTS object from a buffer and adds all
@@ -190,14 +194,14 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11RTS(const uint8_t *buffer, uint32_t total_sz);
Dot11RTS(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11RTS *clone() const {
Dot11RTS* clone() const {
return new Dot11RTS(*this);
}
@@ -205,7 +209,9 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -233,8 +239,8 @@ public:
* \param dst_addr The destination hardware address.
* \param target_addr The source hardware address.
*/
Dot11PSPoll(const address_type &dst_addr = address_type(),
const address_type &target_addr = address_type());
Dot11PSPoll(const address_type& dst_addr = address_type(),
const address_type& target_addr = address_type());
/**
* \brief Constructs a Dot11PSPoll object from a buffer and
@@ -250,14 +256,14 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11PSPoll(const uint8_t *buffer, uint32_t total_sz);
Dot11PSPoll(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11PSPoll *clone() const {
Dot11PSPoll* clone() const {
return new Dot11PSPoll(*this);
}
@@ -265,7 +271,9 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -293,8 +301,8 @@ public:
* \param dst_addr The destination hardware address.
* \param target_addr The source hardware address.
*/
Dot11CFEnd(const address_type &dst_addr = address_type(),
const address_type &target_addr = address_type());
Dot11CFEnd(const address_type& dst_addr = address_type(),
const address_type& target_addr = address_type());
/**
* \brief Constructs a Dot11CFEnd object from a buffer and adds
@@ -310,14 +318,14 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11CFEnd(const uint8_t *buffer, uint32_t total_sz);
Dot11CFEnd(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11CFEnd *clone() const {
Dot11CFEnd* clone() const {
return new Dot11CFEnd(*this);
}
@@ -325,7 +333,9 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -333,7 +343,7 @@ public:
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11Control::matches_flag(flag);
return flag == pdu_flag || Dot11Control::matches_flag(flag);
}
};
@@ -353,8 +363,8 @@ public:
* \param dst_addr The destination hardware address.
* \param target_addr The source hardware address.
*/
Dot11EndCFAck(const address_type &dst_addr = address_type(),
const address_type &target_addr = address_type());
Dot11EndCFAck(const address_type& dst_addr = address_type(),
const address_type& target_addr = address_type());
/**
* \brief Constructs a Dot11EndCFAck frame object from a buffer
@@ -370,14 +380,14 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11EndCFAck(const uint8_t *buffer, uint32_t total_sz);
Dot11EndCFAck(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11EndCFAck *clone() const {
Dot11EndCFAck* clone() const {
return new Dot11EndCFAck(*this);
}
@@ -385,7 +395,9 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -393,7 +405,7 @@ public:
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11Control::matches_flag(flag);
return flag == pdu_flag || Dot11Control::matches_flag(flag);
}
};
@@ -412,7 +424,7 @@ public:
*
* \param dst_addr The destination hardware address.
*/
Dot11Ack(const address_type &dst_addr = address_type());
Dot11Ack(const address_type& dst_addr = address_type());
/**
* \brief Constructs a Dot11Ack frame object from a buffer and
@@ -428,14 +440,14 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11Ack(const uint8_t *buffer, uint32_t total_sz);
Dot11Ack(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
Dot11Ack *clone() const {
Dot11Ack* clone() const {
return new Dot11Ack(*this);
}
@@ -443,7 +455,9 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -451,7 +465,7 @@ public:
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11Control::matches_flag(flag);
return flag == pdu_flag || Dot11Control::matches_flag(flag);
}
};
@@ -474,8 +488,8 @@ public:
* \param dst_addr The destination hardware address.
* \param target_addr The source hardware address.
*/
Dot11BlockAckRequest(const address_type &dst_addr = address_type(),
const address_type &target_addr = address_type());
Dot11BlockAckRequest(const address_type& dst_addr = address_type(),
const address_type& target_addr = address_type());
/**
* \brief Constructs a Dot11BlockAckRequest object from a buffer
@@ -491,7 +505,7 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11BlockAckRequest(const uint8_t *buffer, uint32_t total_sz);
Dot11BlockAckRequest(const uint8_t* buffer, uint32_t total_sz);
/* Getter */
@@ -501,9 +515,9 @@ public:
*/
small_uint<4> bar_control() const {
#if TINS_IS_LITTLE_ENDIAN
return _bar_control & 0xf;
return bar_control_ & 0xf;
#else
return (_bar_control >> 8) & 0xf;
return (bar_control_ >> 8) & 0xf;
#endif
}
@@ -513,9 +527,9 @@ public:
*/
small_uint<12> start_sequence() const {
#if TINS_IS_LITTLE_ENDIAN
return (_start_sequence >> 4) & 0xfff;
return (start_sequence_ >> 4) & 0xfff;
#else
return (Endian::le_to_host<uint16_t>(_start_sequence) >> 4) & 0xfff;
return (Endian::le_to_host<uint16_t>(start_sequence_) >> 4) & 0xfff;
#endif
}
@@ -525,9 +539,9 @@ public:
*/
small_uint<4> fragment_number() const {
#if TINS_IS_LITTLE_ENDIAN
return _start_sequence & 0xf;
return start_sequence_ & 0xf;
#else
return (_start_sequence >> 8) & 0xf;
return (start_sequence_ >> 8) & 0xf;
#endif
}
@@ -564,7 +578,7 @@ public:
*
* \sa PDU::clone
*/
Dot11BlockAckRequest *clone() const {
Dot11BlockAckRequest* clone() const {
return new Dot11BlockAckRequest(*this);
}
@@ -572,7 +586,9 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -580,15 +596,13 @@ public:
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11Control::matches_flag(flag);
return flag == pdu_flag || Dot11Control::matches_flag(flag);
}
protected:
void write_ext_header(Memory::OutputMemoryStream& stream);
private:
void init_block_ack();
uint16_t _bar_control;
uint16_t _start_sequence;
uint16_t bar_control_;
uint16_t start_sequence_;
};
/**
@@ -615,8 +629,8 @@ public:
* \param dst_addr The destination hardware address.
* \param target_addr The source hardware address.
*/
Dot11BlockAck(const address_type &dst_addr = address_type(),
const address_type &target_addr = address_type());
Dot11BlockAck(const address_type& dst_addr = address_type(),
const address_type& target_addr = address_type());
/**
* \brief Constructs a Dot11BlockAck frame object from a buffer
@@ -632,7 +646,7 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11BlockAck(const uint8_t *buffer, uint32_t total_sz);
Dot11BlockAck(const uint8_t* buffer, uint32_t total_sz);
/* Getters */
@@ -642,9 +656,9 @@ public:
*/
small_uint<4> bar_control() const {
#if TINS_IS_LITTLE_ENDIAN
return _bar_control & 0xf;
return bar_control_ & 0xf;
#else
return (_bar_control >> 8) & 0xf;
return (bar_control_ >> 8) & 0xf;
#endif
}
@@ -654,9 +668,9 @@ public:
*/
small_uint<12> start_sequence() const {
#if TINS_IS_LITTLE_ENDIAN
return (_start_sequence >> 4) & 0xfff;
return (start_sequence_ >> 4) & 0xfff;
#else
return (Endian::le_to_host<uint16_t>(_start_sequence) >> 4) & 0xfff;
return (Endian::le_to_host<uint16_t>(start_sequence_) >> 4) & 0xfff;
#endif
}
@@ -666,9 +680,9 @@ public:
*/
small_uint<4> fragment_number() const {
#if TINS_IS_LITTLE_ENDIAN
return _start_sequence & 0xf;
return start_sequence_ & 0xf;
#else
return (_start_sequence >> 8) & 0xf;
return (start_sequence_ >> 8) & 0xf;
#endif
}
@@ -707,19 +721,23 @@ public:
*
* \return The bitmap field.
*/
const uint8_t *bitmap() const { return _bitmap; }
const uint8_t* bitmap() const {
return bitmap_;
}
/**
* \brief Setter for the bitmap field.
* \param bit The new bitmap field to be set.
*/
void bitmap(const uint8_t *bit);
void bitmap(const uint8_t* bit);
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -727,7 +745,7 @@ public:
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11Control::matches_flag(flag);
return flag == pdu_flag || Dot11Control::matches_flag(flag);
}
/**
@@ -735,15 +753,16 @@ public:
*
* \sa PDU::clone
*/
Dot11BlockAck *clone() const {
Dot11BlockAck* clone() const {
return new Dot11BlockAck(*this);
}
private:
void init_block_ack();
void write_ext_header(Memory::OutputMemoryStream& stream);
uint16_t _bar_control, _start_sequence;
uint8_t _bitmap[bitmap_size];
uint16_t bar_control_, start_sequence_;
uint8_t bitmap_[bitmap_size];
};
} // namespace Tins
#endif // TINS_DOT11_DOT11_CONTROL_H

View File

@@ -37,6 +37,9 @@
namespace Tins {
/**
* \brief Represents an IEEE 802.11 data frame
*/
class TINS_API Dot11Data : public Dot11 {
public:
/**
@@ -53,8 +56,8 @@ public:
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11Data(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
Dot11Data(const address_type& dst_hw_addr = address_type(),
const address_type& src_hw_addr = address_type());
/**
* \brief Constructs a Dot11Data object from a buffer and adds
@@ -70,21 +73,25 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11Data(const uint8_t *buffer, uint32_t total_sz);
Dot11Data(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Getter for the second address.
*
* \return The stored second address.
*/
address_type addr2() const { return _ext_header.addr2; }
address_type addr2() const {
return ext_header_.addr2;
}
/**
* \brief Getter for the third address.
*
* \return The stored third address.
*/
address_type addr3() const { return _ext_header.addr3; }
address_type addr3() const {
return ext_header_.addr3;
}
/**
* \brief Getter for the fragment number field.
@@ -93,9 +100,9 @@ public:
*/
small_uint<4> frag_num() const {
#if TINS_IS_LITTLE_ENDIAN
return _ext_header.frag_seq & 0xf;
return ext_header_.frag_seq & 0xf;
#else
return (_ext_header.frag_seq >> 8) & 0xf;
return (ext_header_.frag_seq >> 8) & 0xf;
#endif
}
@@ -106,9 +113,9 @@ public:
*/
small_uint<12> seq_num() const {
#if TINS_IS_LITTLE_ENDIAN
return (_ext_header.frag_seq >> 4) & 0xfff;
return (ext_header_.frag_seq >> 4) & 0xfff;
#else
return (Endian::le_to_host<uint16_t>(_ext_header.frag_seq) >> 4) & 0xfff;
return (Endian::le_to_host<uint16_t>(ext_header_.frag_seq) >> 4) & 0xfff;
#endif
}
@@ -117,21 +124,23 @@ public:
*
* \return The fourth address.
*/
address_type addr4() const { return _addr4; }
address_type addr4() const {
return addr4_;
}
/**
* \brief Setter for the second address.
*
* \param new_addr2 The second address to be set.
*/
void addr2(const address_type &new_addr2);
void addr2(const address_type& new_addr2);
/**
* \brief Setter for the third address.
*
* \param new_addr3 The third address to be set.
*/
void addr3(const address_type &new_addr3);
void addr3(const address_type& new_addr3);
/**
* \brief Setter for the fragment number field.
@@ -152,7 +161,7 @@ public:
*
* \param new_addr4 The fourth address to be set.
*/
void addr4(const address_type &new_addr4);
void addr4(const address_type& new_addr4);
/**
* \brief Retrieves the frame's source address.
@@ -163,10 +172,12 @@ public:
* If FromDS == ToDS == 1, the return value is not defined.
*/
address_type src_addr() const {
if(!from_ds() && !to_ds())
if (!from_ds() && !to_ds()) {
return addr2();
if(!from_ds() && to_ds())
}
if (!from_ds() && to_ds()) {
return addr2();
}
return addr3();
}
@@ -179,10 +190,12 @@ public:
* If FromDS == ToDS == 1, the return value is not defined.
*/
address_type dst_addr() const {
if(!from_ds() && !to_ds())
if (!from_ds() && !to_ds()) {
return addr1();
if(!from_ds() && to_ds())
}
if (!from_ds() && to_ds()) {
return addr3();
}
return addr1();
}
@@ -195,10 +208,12 @@ public:
* If FromDS == ToDS == 1, the return value is not defined.
*/
address_type bssid_addr() const {
if(!from_ds() && !to_ds())
if (!from_ds() && !to_ds()) {
return addr3();
if(!from_ds() && to_ds())
}
if (!from_ds() && to_ds()) {
return addr1();
}
return addr2();
}
@@ -214,7 +229,9 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -230,32 +247,25 @@ public:
*
* \sa PDU::clone
*/
Dot11Data *clone() const {
Dot11Data* clone() const {
return new Dot11Data(*this);
}
protected:
TINS_BEGIN_PACK
struct ExtendedHeader {
struct dot11_extended_header {
uint8_t addr2[address_type::address_size];
uint8_t addr3[address_type::address_size];
uint16_t frag_seq;
} TINS_END_PACK;
struct no_inner_pdu { };
Dot11Data(const uint8_t *buffer, uint32_t total_sz, no_inner_pdu);
Dot11Data(const uint8_t* buffer, uint32_t total_sz, no_inner_pdu);
uint32_t init(const uint8_t *buffer, uint32_t total_sz);
uint32_t init(const uint8_t* buffer, uint32_t total_sz);
void write_ext_header(Memory::OutputMemoryStream& stream);
uint32_t data_frame_size() {
return static_cast<uint32_t>(
Dot11::header_size() + sizeof(_ext_header) +
((from_ds() && to_ds()) ? _addr4.size() : 0)
);
}
private:
ExtendedHeader _ext_header;
address_type _addr4;
dot11_extended_header ext_header_;
address_type addr4_;
};
class TINS_API Dot11QoSData : public Dot11Data {
@@ -274,8 +284,8 @@ public:
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11QoSData(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
Dot11QoSData(const address_type& dst_hw_addr = address_type(),
const address_type& src_hw_addr = address_type());
/**
* \brief Constructors Dot11QoSData object from a buffer and adds
@@ -291,14 +301,16 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11QoSData(const uint8_t *buffer, uint32_t total_sz);
Dot11QoSData(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Getter for the QOS Control field.
*
* \return The stored QOS Control field value.
*/
uint16_t qos_control() const { return Endian::le_to_host(_qos_control); }
uint16_t qos_control() const {
return Endian::le_to_host(qos_control_);
}
/**
* \brief Setter for the QOS Control field.
@@ -320,7 +332,7 @@ public:
*
* \sa PDU::clone
*/
Dot11QoSData *clone() const {
Dot11QoSData* clone() const {
return new Dot11QoSData(*this);
}
@@ -328,7 +340,9 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::DOT11_QOS_DATA; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -336,12 +350,12 @@ public:
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == PDU::DOT11_QOS_DATA || Dot11Data::matches_flag(flag);
return flag == pdu_flag || Dot11Data::matches_flag(flag);
}
private:
void write_fixed_parameters(Memory::OutputMemoryStream& stream);
uint16_t _qos_control;
uint16_t qos_control_;
};
}

View File

@@ -40,7 +40,7 @@
namespace Tins {
/**
* \brief Abstract class that englobes all Management frames in the 802.11 protocol.
* \brief Base class for all management frames in the IEEE 802.11 protocol.
*/
class TINS_API Dot11ManagementFrame : public Dot11 {
public:
@@ -132,39 +132,39 @@ public:
class capability_information {
private:
#if TINS_IS_LITTLE_ENDIAN
uint16_t _ess:1,
_ibss:1,
_cf_poll:1,
_cf_poll_req:1,
_privacy:1,
_short_preamble:1,
_pbcc:1,
_channel_agility:1,
_spectrum_mgmt:1,
_qos:1,
_sst:1,
_apsd:1,
_radio_measurement:1,
_dsss_ofdm:1,
_delayed_block_ack:1,
_immediate_block_ack:1;
uint16_t ess_:1,
ibss_:1,
cf_poll_:1,
cf_poll_req_:1,
privacy_:1,
short_preamble_:1,
pbcc_:1,
channel_agility_:1,
spectrum_mgmt_:1,
qos_:1,
sst_:1,
apsd_:1,
radio_measurement_:1,
dsss_ofdm_:1,
delayed_block_ack_:1,
immediate_block_ack_:1;
#elif TINS_IS_BIG_ENDIAN
uint16_t _channel_agility:1,
_pbcc:1,
_short_preamble:1,
_privacy:1,
_cf_poll_req:1,
_cf_poll:1,
_ibss:1,
_ess:1,
_immediate_block_ack:1,
_delayed_block_ack:1,
_dsss_ofdm:1,
_radio_measurement:1,
_apsd:1,
_sst:1,
_qos:1,
_spectrum_mgmt:1;
uint16_t channel_agility_:1,
pbcc_:1,
short_preamble_:1,
privacy_:1,
cf_poll_req_:1,
cf_poll_:1,
ibss_:1,
ess_:1,
immediate_block_ack_:1,
delayed_block_ack_:1,
dsss_ofdm_:1,
radio_measurement_:1,
apsd_:1,
sst_:1,
qos_:1,
spectrum_mgmt_:1;
#endif
public:
/**
@@ -172,225 +172,288 @@ public:
*
* \return Bool indicating the flag's value.
*/
bool ess() const { return _ess; }
bool ess() const {
return ess_;
}
/**
* \brief Getter for the ibss flag.
*
* \return Bool indicating the flag's value.
*/
bool ibss() const { return _ibss; }
bool ibss() const {
return ibss_;
}
/**
* \brief Getter for the cf_poll flag.
*
* \return Bool indicating the flag's value.
*/
bool cf_poll() const { return _cf_poll; }
bool cf_poll() const {
return cf_poll_;
}
/**
* \brief Getter for the cf_poll_req flag.
*
* \return Bool indicating the flag's value.
*/
bool cf_poll_req() const { return _cf_poll_req; }
bool cf_poll_req() const {
return cf_poll_req_;
}
/**
* \brief Getter for the privacy flag.
*
* \return Bool indicating the flag's value.
*/
bool privacy() const { return _privacy; }
bool privacy() const {
return privacy_;
}
/**
* \brief Getter for the short_preamble flag.
*
* \return Bool indicating the flag's value.
*/
bool short_preamble() const { return _short_preamble; }
bool short_preamble() const {
return short_preamble_;
}
/**
* \brief Getter for the pbcc flag.
*
* \return Bool indicating the flag's value.
*/
bool pbcc() const { return _pbcc; }
bool pbcc() const {
return pbcc_;
}
/**
* \brief Getter for the channel_agility flag.
*
* \return Bool indicating the flag's value.
*/
bool channel_agility() const { return _channel_agility; }
bool channel_agility() const {
return channel_agility_;
}
/**
* \brief Getter for the spectrum_mgmt flag.
*
* \return Bool indicating the flag's value.
*/
bool spectrum_mgmt() const { return _spectrum_mgmt; }
bool spectrum_mgmt() const {
return spectrum_mgmt_;
}
/**
* \brief Getter for the qos flag.
*
* \return Bool indicating the flag's value.
*/
bool qos() const { return _qos; }
bool qos() const {
return qos_;
}
/**
* \brief Getter for the sst flag.
*
* \return Bool indicating the flag's value.
*/
bool sst() const { return _sst; }
bool sst() const {
return sst_;
}
/**
* \brief Getter for the apsd flag.
*
* \return Bool indicating the flag's value.
*/
bool apsd() const { return _apsd; }
bool apsd() const {
return apsd_;
}
/**
* \brief Getter for the radio measurement flag.
*
* \return Bool indicating the flag's value.
*/
bool radio_measurement() const { return _radio_measurement; }
bool radio_measurement() const {
return radio_measurement_;
}
/**
* \brief Getter for the dsss_ofdm flag.
*
* \return Bool indicating the flag's value.
*/
bool dsss_ofdm() const { return _dsss_ofdm; }
bool dsss_ofdm() const {
return dsss_ofdm_;
}
/**
* \brief Getter for the delayed_block_ack flag.
*
* \return Bool indicating the flag's value.
*/
bool delayed_block_ack() const { return _delayed_block_ack; }
bool delayed_block_ack() const {
return delayed_block_ack_;
}
/**
* \brief Getter for the immediate_block_ack flag.
*
* \return Bool indicating the flag's value.
*/
bool immediate_block_ack() const { return _immediate_block_ack; }
bool immediate_block_ack() const {
return immediate_block_ack_;
}
/**
* \brief Setter for the ess flag.
*
* \param new_value bool indicating the flag's new value.
*/
void ess(bool new_value) { _ess = new_value; }
void ess(bool new_value) {
ess_ = new_value;
}
/**
* \brief Setter for the ibss flag.
*
* \param new_value bool indicating the flag's new value.
*/
void ibss(bool new_value) { _ibss = new_value; }
void ibss(bool new_value) {
ibss_ = new_value;
}
/**
* \brief Setter for the cf_poll flag.
*
* \param new_value bool indicating the flag's new value.
*/
void cf_poll(bool new_value) { _cf_poll = new_value; }
void cf_poll(bool new_value) {
cf_poll_ = new_value;
}
/**
* \brief Setter for the cf_poll_req flag.
*
* \param new_value bool indicating the flag's new value.
*/
void cf_poll_req(bool new_value) { _cf_poll_req = new_value; }
void cf_poll_req(bool new_value) {
cf_poll_req_ = new_value;
}
/**
* \brief Setter for the privacy flag.
*
* \param new_value bool indicating the flag's new value.
*/
void privacy(bool new_value) { _privacy = new_value; }
void privacy(bool new_value) {
privacy_ = new_value;
}
/**
* \brief Setter for the short_preamble flag.
*
* \param new_value bool indicating the flag's new value.
*/
void short_preamble(bool new_value) { _short_preamble = new_value; }
void short_preamble(bool new_value) {
short_preamble_ = new_value;
}
/**
* \brief Setter for the pbcc flag.
*
* \param new_value bool indicating the flag's new value.
*/
void pbcc(bool new_value) { _pbcc = new_value; }
void pbcc(bool new_value) {
pbcc_ = new_value;
}
/**
* \brief Setter for the channel_agility flag.
*
* \param new_value bool indicating the flag's new value.
*/
void channel_agility(bool new_value) { _channel_agility = new_value; }
void channel_agility(bool new_value) {
channel_agility_ = new_value;
}
/**
* \brief Setter for the spectrum_mgmt flag.
*
* \param new_value bool indicating the flag's new value.
*/
void spectrum_mgmt(bool new_value) { _spectrum_mgmt = new_value; }
void spectrum_mgmt(bool new_value) {
spectrum_mgmt_ = new_value;
}
/**
* \brief Setter for the qos flag.
*
* \param new_value bool indicating the flag's new value.
*/
void qos(bool new_value) { _qos = new_value; }
void qos(bool new_value) {
qos_ = new_value;
}
/**
* \brief Setter for the sst flag.
*
* \param new_value bool indicating the flag's new value.
*/
void sst(bool new_value) { _sst = new_value; }
void sst(bool new_value) {
sst_ = new_value;
}
/**
* \brief Setter for the apsd flag.
*
* \param new_value bool indicating the flag's new value.
*/
void apsd(bool new_value) { _apsd = new_value; }
void apsd(bool new_value) {
apsd_ = new_value;
}
/**
* \brief Setter for the radio measurement flag.
*
* \param new_value bool indicating the flag's new value.
*/
void radio_measurement(bool new_value) { _radio_measurement = new_value; }
void radio_measurement(bool new_value) {
radio_measurement_ = new_value;
}
/**
* \brief Setter for the dsss_ofdm flag.
*
* \param new_value bool indicating the flag's new value.
*/
void dsss_ofdm(bool new_value) { _dsss_ofdm = new_value; }
void dsss_ofdm(bool new_value) {
dsss_ofdm_ = new_value;
}
/**
* \brief Setter for the delayed_block_ack flag.
*
* \param new_value bool indicating the flag's new value.
*/
void delayed_block_ack(bool new_value) { _delayed_block_ack = new_value; }
void delayed_block_ack(bool new_value) {
delayed_block_ack_ = new_value;
}
/**
* \brief Setter for the immediate_block_ack flag.
*
* \param new_value bool indicating the flag's new value.
*/
void immediate_block_ack(bool new_value) { _immediate_block_ack = new_value; }
void immediate_block_ack(bool new_value) {
immediate_block_ack_ = new_value;
}
} TINS_END_PACK;
/**
@@ -402,12 +465,14 @@ public:
fh_params_set() {}
fh_params_set(uint16_t dwell_time, uint8_t hop_set,
uint8_t hop_pattern, uint8_t hop_index)
fh_params_set(uint16_t dwell_time,
uint8_t hop_set,
uint8_t hop_pattern,
uint8_t hop_index)
: dwell_time(dwell_time), hop_set(hop_set),
hop_pattern(hop_pattern), hop_index(hop_index) {}
static fh_params_set from_option(const option &opt);
static fh_params_set from_option(const option& opt);
};
/**
@@ -419,13 +484,15 @@ public:
cf_params_set() {}
cf_params_set(uint8_t cfp_count, uint8_t cfp_period,
uint16_t cfp_max_duration, uint16_t cfp_dur_remaining)
cf_params_set(uint8_t cfp_count,
uint8_t cfp_period,
uint16_t cfp_max_duration,
uint16_t cfp_dur_remaining)
: cfp_count(cfp_count), cfp_period(cfp_period),
cfp_max_duration(cfp_max_duration),
cfp_dur_remaining(cfp_dur_remaining) {}
static cf_params_set from_option(const option &opt);
static cf_params_set from_option(const option& opt);
};
/**
@@ -440,12 +507,13 @@ public:
ibss_dfs_params() {}
ibss_dfs_params(const address_type &addr,
uint8_t recovery_interval, const channel_map_type &channel_map)
ibss_dfs_params(const address_type& addr,
uint8_t recovery_interval,
const channel_map_type& channel_map)
: dfs_owner(addr), recovery_interval(recovery_interval),
channel_map(channel_map) {}
static ibss_dfs_params from_option(const option &opt);
static ibss_dfs_params from_option(const option& opt);
};
/**
@@ -460,12 +528,14 @@ public:
country_params() {}
country_params(const std::string &country, const byte_array &first,
const byte_array &number, const byte_array &max)
country_params(const std::string& country,
const byte_array& first,
const byte_array& number,
const byte_array& max)
: country(country), first_channel(first), number_channels(number),
max_transmit_power(max) {}
static country_params from_option(const option &opt);
static country_params from_option(const option& opt);
};
/**
@@ -479,12 +549,15 @@ public:
fh_pattern_type() {}
fh_pattern_type(uint8_t flag, uint8_t sets, uint8_t modulus,
uint8_t offset, const byte_array& table)
fh_pattern_type(uint8_t flag,
uint8_t sets,
uint8_t modulus,
uint8_t offset,
const byte_array& table)
: flag(flag), number_of_sets(sets), modulus(modulus),
offset(offset), random_table(table) {}
static fh_pattern_type from_option(const option &opt);
static fh_pattern_type from_option(const option& opt);
};
/**
@@ -495,10 +568,12 @@ public:
channel_switch_type() {}
channel_switch_type(uint8_t mode, uint8_t channel, uint8_t count)
channel_switch_type(uint8_t mode,
uint8_t channel,
uint8_t count)
: switch_mode(mode), new_channel(channel), switch_count(count) { }
static channel_switch_type from_option(const option &opt);
static channel_switch_type from_option(const option& opt);
};
/**
@@ -510,12 +585,14 @@ public:
quiet_type() {}
quiet_type(uint8_t count, uint8_t period, uint16_t duration,
uint16_t offset)
quiet_type(uint8_t count,
uint8_t period,
uint16_t duration,
uint16_t offset)
: quiet_count(count), quiet_period(period),
quiet_duration(duration), quiet_offset(offset) {}
static quiet_type from_option(const option &opt);
static quiet_type from_option(const option& opt);
};
/**
@@ -528,12 +605,11 @@ public:
bss_load_type() {}
bss_load_type(uint16_t count, uint8_t utilization,
uint16_t capacity)
bss_load_type(uint16_t count, uint8_t utilization, uint16_t capacity)
: station_count(count), available_capacity(capacity),
channel_utilization(utilization) {}
static bss_load_type from_option(const option &opt);
static bss_load_type from_option(const option& opt);
};
/**
@@ -545,12 +621,14 @@ public:
tim_type() {}
tim_type(uint8_t count, uint8_t period, uint8_t control,
const byte_array &bitmap)
tim_type(uint8_t count,
uint8_t period,
uint8_t control,
const byte_array& bitmap)
: dtim_count(count), dtim_period(period), bitmap_control(control),
partial_virtual_bitmap(bitmap) {}
static tim_type from_option(const option &opt);
static tim_type from_option(const option& opt);
};
/**
@@ -562,11 +640,11 @@ public:
oui_type oui;
byte_array data;
vendor_specific_type(const oui_type &oui = oui_type(),
const byte_array &data = byte_array())
vendor_specific_type(const oui_type& oui = oui_type(),
const byte_array& data = byte_array())
: oui(oui), data(data) { }
static vendor_specific_type from_bytes(const uint8_t *buffer, uint32_t sz);
static vendor_specific_type from_bytes(const uint8_t* buffer, uint32_t sz);
};
/**
@@ -579,14 +657,18 @@ public:
*
* \return address_type containing the second address.
*/
address_type addr2() const { return _ext_header.addr2; }
address_type addr2() const {
return ext_header_.addr2;
}
/**
* \brief Getter for the third address.
*
* \return address_type containing the third address.
*/
address_type addr3() const { return _ext_header.addr3; }
address_type addr3() const {
return ext_header_.addr3;
}
/**
* \brief Getter for the fragment number.
@@ -595,9 +677,9 @@ public:
*/
small_uint<4> frag_num() const {
#if TINS_IS_LITTLE_ENDIAN
return _ext_header.frag_seq & 0xf;
return ext_header_.frag_seq & 0xf;
#else
return (_ext_header.frag_seq >> 8) & 0xf;
return (ext_header_.frag_seq >> 8) & 0xf;
#endif
}
@@ -608,9 +690,9 @@ public:
*/
small_uint<12> seq_num() const {
#if TINS_IS_LITTLE_ENDIAN
return (_ext_header.frag_seq >> 4) & 0xfff;
return (ext_header_.frag_seq >> 4) & 0xfff;
#else
return (Endian::le_to_host<uint16_t>(_ext_header.frag_seq) >> 4) & 0xfff;
return (Endian::le_to_host<uint16_t>(ext_header_.frag_seq) >> 4) & 0xfff;
#endif
}
@@ -619,21 +701,23 @@ public:
*
* \return The stored fourth address.
*/
const address_type &addr4() const { return _addr4; }
const address_type& addr4() const {
return addr4_;
}
/**
* \brief Setter for the second address.
*
* \param new_addr2 The new second address to be set.
*/
void addr2(const address_type &new_addr2);
void addr2(const address_type& new_addr2);
/**
* \brief Setter for the third address.
*
* \param new_addr3 The new third address to be set.
*/
void addr3(const address_type &new_addr3);
void addr3(const address_type& new_addr3);
/**
* \brief Setter for the fragment number.
@@ -654,7 +738,7 @@ public:
*
* \param new_addr4 The new fourth address to be set.
*/
void addr4(const address_type &new_addr4);
void addr4(const address_type& new_addr4);
// Option setter helpers
@@ -663,7 +747,7 @@ public:
*
* \param new_ssid The SSID to be set.
*/
void ssid(const std::string &new_ssid);
void ssid(const std::string& new_ssid);
/**
* \brief Helper method to set the RSN information option.
@@ -677,14 +761,14 @@ public:
*
* \param new_rates The new rates to be set.
*/
void supported_rates(const rates_type &new_rates);
void supported_rates(const rates_type& new_rates);
/**
* \brief Helper method to set the extended supported rates option.
*
* \param new_rates The new rates to be set.
*/
void extended_supported_rates(const rates_type &new_rates);
void extended_supported_rates(const rates_type& new_rates);
/**
* \brief Helper method to set the QoS capabilities option.
@@ -710,7 +794,7 @@ public:
*
* \param new_channels A list of channels to be set.
*/
void supported_channels(const channels_type &new_channels);
void supported_channels(const channels_type& new_channels);
/**
* \brief Helper method to set the EDCA Parameter Set.
@@ -734,7 +818,7 @@ public:
*
* \param fh_params The new FH parameter set value.
*/
void fh_parameter_set(const fh_params_set &fh_params);
void fh_parameter_set(const fh_params_set& fh_params);
/**
* \brief Helper method to set the DS parameter tagged option.
@@ -748,7 +832,7 @@ public:
*
* \param params The new CF parameter set value.
*/
void cf_parameter_set(const cf_params_set &params);
void cf_parameter_set(const cf_params_set& params);
/**
* \brief Helper method to set the IBSS parameter set tagged option.
@@ -762,14 +846,14 @@ public:
*
* \param params The IBSS DFS data to be set.
*/
void ibss_dfs(const ibss_dfs_params &params);
void ibss_dfs(const ibss_dfs_params& params);
/**
* \brief Helper method to set the country tagged option.
*
* \param params The data to be used for this country option.
*/
void country(const country_params &params);
void country(const country_params& params);
/**
* \brief Helper method to set the FH parameters set tagged option.
@@ -784,7 +868,7 @@ public:
*
* \param params The data to be used for this FH pattern table option.
*/
void fh_pattern_table(const fh_pattern_type &params);
void fh_pattern_table(const fh_pattern_type& params);
/**
* \brief Helper method to set the Power Constraint tagged option.
@@ -798,14 +882,14 @@ public:
*
* \param data The value of the Channel Switch option.
*/
void channel_switch(const channel_switch_type &data);
void channel_switch(const channel_switch_type& data);
/**
* \brief Helper method to set the Quiet tagged option.
*
* \param data The value of the quiet count field.
*/
void quiet(const quiet_type &data);
void quiet(const quiet_type& data);
/**
* \brief Helper method to set the TPC Report tagged option.
@@ -827,28 +911,28 @@ public:
*
* \param data The value to set in this bss load option.
*/
void bss_load(const bss_load_type &data);
void bss_load(const bss_load_type& data);
/**
* \brief Helper method to set the TIM tagged option.
*
* \brief data The value to set in this tim option.
*/
void tim(const tim_type &data);
void tim(const tim_type& data);
/**
* \brief Helper method to set the Challenge Text tagged option.
*
* \brief text The challenge text to be added.
*/
void challenge_text(const std::string &text);
void challenge_text(const std::string& text);
/**
* \brief Helper method to add a Vendor Specific tagged option.
*
* \brief text The option to be added.
*/
void vendor_specific(const vendor_specific_type &data);
void vendor_specific(const vendor_specific_type& data);
// Option searching helpers
@@ -1123,7 +1207,9 @@ public:
*
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -1135,15 +1221,15 @@ public:
}
protected:
TINS_BEGIN_PACK
struct ExtendedHeader {
struct dot11_extended_header {
uint8_t addr2[address_type::address_size];
uint8_t addr3[address_type::address_size];
uint16_t frag_seq;
} TINS_END_PACK;
Dot11ManagementFrame(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
Dot11ManagementFrame(const address_type& dst_hw_addr = address_type(),
const address_type& src_hw_addr = address_type());
/**
* \brief Constructs a Dot11ManagementFrame object from a buffer
@@ -1159,29 +1245,30 @@ protected:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11ManagementFrame(const uint8_t *buffer, uint32_t total_sz);
Dot11ManagementFrame(const uint8_t* buffer, uint32_t total_sz);
void write_ext_header(Memory::OutputMemoryStream& stream);
uint32_t management_frame_size() {
return sizeof(ieee80211_header) + sizeof(_ext_header) +
((from_ds() && to_ds()) ? address_type::address_size : 0);
return Dot11ManagementFrame::header_size();
}
private:
static uint8_t *serialize_rates(const rates_type &rates);
static rates_type deserialize_rates(const option *option);
static std::vector<uint8_t> serialize_rates(const rates_type& rates);
static rates_type deserialize_rates(const option* option);
template<typename T>
T search_and_convert(OptionTypes opt_type) const {
const option *opt = search_option(opt_type);
if(!opt)
const option* opt = search_option(opt_type);
if (!opt) {
throw option_not_found();
}
return opt->to<T>();
}
ExtendedHeader _ext_header;
address_type _addr4;
dot11_extended_header ext_header_;
address_type addr4_;
};
} // namespace Tins
#endif // TINS_DOT11_DOT11_MGMT_H

View File

@@ -57,8 +57,8 @@ public:
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11ProbeRequest(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
Dot11ProbeRequest(const address_type& dst_hw_addr = address_type(),
const address_type& src_hw_addr = address_type());
/**
* \brief Constructs a Dot11ProbeRequest object from a buffer
@@ -74,13 +74,15 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11ProbeRequest(const uint8_t *buffer, uint32_t total_sz);
Dot11ProbeRequest(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::DOT11_PROBE_REQ; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether this PDU matches the specified flag.
@@ -122,8 +124,8 @@ public:
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
*/
Dot11ProbeResponse(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
Dot11ProbeResponse(const address_type& dst_hw_addr = address_type(),
const address_type& src_hw_addr = address_type());
/**
* \brief Constructs a Dot11ProbeResponse object from a buffer
@@ -139,21 +141,25 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot11ProbeResponse(const uint8_t *buffer, uint32_t total_sz);
Dot11ProbeResponse(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Getter for the timestamp field.
*
* \return The stored timestamp value.
*/
uint64_t timestamp() const { return Endian::le_to_host(_body.timestamp); }
uint64_t timestamp() const {
return Endian::le_to_host(body_.timestamp);
}
/**
* \brief Getter for the interval field.
*
* \return The stored interval value.
*/
uint16_t interval() const { return Endian::le_to_host(_body.interval); }
uint16_t interval() const {
return Endian::le_to_host(body_.interval);
}
/**
* \brief Getter for the Capabilities Information.
@@ -161,7 +167,9 @@ public:
* \return A constant reference to the stored Capabilities
* Information field.
*/
const capability_information& capabilities() const { return _body.capability;}
const capability_information& capabilities() const {
return body_.capability;
}
/**
* \brief Getter for the Capabilities Information.
@@ -169,7 +177,9 @@ public:
* \return A reference to the stored Capabilities Information
* field.
*/
capability_information& capabilities() { return _body.capability;}
capability_information& capabilities() {
return body_.capability;
}
/**
* \brief Setter for the timestamp field.
@@ -214,21 +224,21 @@ public:
* \sa PDU::matches_flag
*/
bool matches_flag(PDUType flag) const {
return flag == pdu_flag || Dot11ManagementFrame::matches_flag(flag);
return flag == pdu_flag || Dot11ManagementFrame::matches_flag(flag);
}
protected:
private:
void write_fixed_parameters(Memory::OutputMemoryStream& stream);
TINS_BEGIN_PACK
struct ProbeResp {
struct dot11_probe_response_header {
uint64_t timestamp;
uint16_t interval;
capability_information capability;
} TINS_END_PACK;
ProbeResp _body;
void write_fixed_parameters(Memory::OutputMemoryStream& stream);
dot11_probe_response_header body_;
};
} // namespace Tins
#endif // TINS_DOT11_DOT11_PROBE_H

View File

@@ -36,6 +36,7 @@
#include "small_uint.h"
namespace Tins {
/**
* \class Dot1Q
* Represents an IEEE 802.1q PDU.
@@ -65,7 +66,7 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot1Q(const uint8_t *buffer, uint32_t total_sz);
Dot1Q(const uint8_t* buffer, uint32_t total_sz);
// Getters
@@ -87,7 +88,7 @@ public:
* \return The stored priority field value.
*/
small_uint<3> priority() const {
return _header.priority;
return header_.priority;
}
/**
@@ -95,7 +96,7 @@ public:
* \return The stored CFI field value.
*/
small_uint<1> cfi() const {
return _header.cfi;
return header_.cfi;
}
/**
@@ -104,9 +105,9 @@ public:
*/
small_uint<12> id() const {
#if TINS_IS_LITTLE_ENDIAN
return _header.idL | (_header.idH << 8);
return header_.idL | (header_.idH << 8);
#else
return _header.id;
return header_.id;
#endif
}
@@ -115,19 +116,21 @@ public:
* \return The stored type field value.
*/
uint16_t payload_type() const {
return Endian::be_to_host(_header.type);
return Endian::be_to_host(header_.type);
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \sa PDU::clone
*/
Dot1Q *clone() const {
Dot1Q* clone() const {
return new Dot1Q(*this);
}
@@ -136,7 +139,7 @@ public:
* appended at the end of this packet.
*/
bool append_padding() const {
return _append_padding;
return append_padding_;
}
// Setters
@@ -184,9 +187,9 @@ public:
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
bool matches_response(const uint8_t* ptr, uint32_t total_sz) const;
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
TINS_BEGIN_PACK
struct dot1q_hdr {
@@ -204,10 +207,10 @@ private:
#endif
} TINS_END_PACK;
static uint16_t get_id(const dot1q_hdr *hdr);
static uint16_t get_id(const dot1q_hdr* hdr);
dot1q_hdr _header;
bool _append_padding;
dot1q_hdr header_;
bool append_padding_;
};
}

View File

@@ -39,157 +39,163 @@
namespace Tins {
/**
* \class Dot3
* \brief Class representing an IEEE 802.3 PDU.
/**
* \class Dot3
* \brief Class representing an IEEE 802.3 PDU.
*/
class TINS_API Dot3 : public PDU {
public:
/**
* \brief The address type.
*/
class TINS_API Dot3 : public PDU {
public:
/**
* \brief The address type.
*/
typedef HWAddress<6> address_type;
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::IEEE802_3;
typedef HWAddress<6> address_type;
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::IEEE802_3;
/**
* \brief Represents the Dot3 broadcast address.
*/
static const address_type BROADCAST;
/**
* \brief Represents the Dot3 broadcast address.
*/
static const address_type BROADCAST;
/**
* \brief Constructor for creating an Dot3 PDU
*
* Constructor that builds an Dot3 PDU taking the interface name,
* destination's and source's MAC.
*
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
* \param child The PDU which will be set as the inner PDU.
*/
Dot3(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructor for creating an Dot3 PDU
*
* Constructor that builds an Dot3 PDU taking the interface name,
* destination's and source's MAC.
*
* \param dst_hw_addr The destination hardware address.
* \param src_hw_addr The source hardware address.
* \param child The PDU which will be set as the inner PDU.
*/
Dot3(const address_type& dst_hw_addr = address_type(),
const address_type& src_hw_addr = address_type());
/**
* \brief Constructs a Dot3 object from a buffer and adds a
* LLC object with the remaining data as the inner PDU.
*
* If there is not enough size for a Dot3 header, a
* malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot3(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Constructs a Dot3 object from a buffer and adds a
* LLC object with the remaining data as the inner PDU.
*
* If there is not enough size for a Dot3 header, a
* malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Dot3(const uint8_t* buffer, uint32_t total_sz);
/* Getters */
/**
* \brief Getter for the destination hardware address.
*
* \return The destination hardware address.
*/
address_type dst_addr() const { return _eth.dst_mac; }
/* Getters */
/**
* \brief Getter for the destination hardware address.
*
* \return The destination hardware address.
*/
address_type dst_addr() const {
return header_.dst_mac;
}
/**
* \brief Getter for the source hardware address.
*
* \return The source hardware address.
*/
address_type src_addr() const { return _eth.src_mac; }
/**
* \brief Getter for the source hardware address.
*
* \return The source hardware address.
*/
address_type src_addr() const {
return header_.src_mac;
}
/**
* \brief Getter for the length field.
* \return The length field value.
*/
uint16_t length() const { return Endian::be_to_host(_eth.length); };
/**
* \brief Getter for the length field.
* \return The length field value.
*/
uint16_t length() const {
return Endian::be_to_host(header_.length);
}
/* Setters */
/* Setters */
/**
* \brief Setter for the destination hardware address.
*
* \param new_dst_mac The new destination hardware address.
*/
void dst_addr(const address_type &new_dst_mac);
/**
* \brief Setter for the destination hardware address.
*
* \param address The new destination hardware address.
*/
void dst_addr(const address_type& address);
/**
* \brief Setter for the source hardware address.
*
* \param new_src_mac The new source hardware address.
*/
void src_addr(const address_type &new_src_mac);
/**
* \brief Setter for the source hardware address.
*
* \param address The new source hardware address.
*/
void src_addr(const address_type& address);
/**
* \brief Setter for the length field.
*
* \param new_length uint16_t with the new value of the length field.
*/
void length(uint16_t new_length);
/**
* \brief Setter for the length field.
*
* \param value The new value for the length field
*/
void length(uint16_t value);
/* Virtual methods */
/**
* \brief Returns the Dot3 frame's header length.
*
* \return An uint32_t with the header's size.
* \sa PDU::header_size()
*/
uint32_t header_size() const;
#if !defined(_WIN32) || defined(HAVE_PACKET_SENDER_PCAP_SENDPACKET)
/**
* \sa PDU::send()
*/
void send(PacketSender &sender, const NetworkInterface &iface);
#endif // !_WIN32 || HAVE_PACKET_SENDER_PCAP_SENDPACKET
// Virtual methods
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Returns the Dot3 frame's header length.
*
* \return An uint32_t with the header's size.
* \sa PDU::header_size()
*/
uint32_t header_size() const;
#if !defined(_WIN32) || defined(HAVE_PACKET_SENDER_PCAP_SENDPACKET)
/**
* \sa PDU::send()
*/
void send(PacketSender& sender, const NetworkInterface& iface);
#endif // !_WIN32 || HAVE_PACKET_SENDER_PCAP_SENDPACKET
#ifndef _WIN32
/**
* \sa PDU::recv_response
*/
PDU *recv_response(PacketSender &sender, const NetworkInterface &iface);
#endif // _WIN32
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t* ptr, uint32_t total_sz) const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
#ifndef _WIN32
/**
* \sa PDU::recv_response
*/
PDU* recv_response(PacketSender& sender, const NetworkInterface& iface);
#endif // _WIN32
/**
* \sa PDU::clone
*/
Dot3 *clone() const {
return new Dot3(*this);
}
private:
/**
* Struct that represents the Ethernet II header
*/
TINS_BEGIN_PACK
struct ethhdr {
uint8_t dst_mac[address_type::address_size];
uint8_t src_mac[address_type::address_size];
uint16_t length;
} TINS_END_PACK;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
/**
* \sa PDU::clone
*/
Dot3* clone() const {
return new Dot3(*this);
}
private:
/**
* Struct that represents the Ethernet II header
*/
TINS_BEGIN_PACK
struct dot3_header {
uint8_t dst_mac[address_type::address_size];
uint8_t src_mac[address_type::address_size];
uint16_t length;
} TINS_END_PACK;
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
ethhdr _eth;
};
}
dot3_header header_;
};
} // Tins
#endif // TINS_DOT3_H

File diff suppressed because it is too large Load Diff

View File

@@ -51,187 +51,183 @@
#define TINS_IS_BIG_ENDIAN (__BYTE_ORDER == __BIG_ENDIAN)
#endif
namespace Tins {
namespace Endian {
/**
* \brief "Changes" a 8-bit integral value's endianess. This is an
* identity function.
*
* \param data The data to convert.
*/
inline uint8_t do_change_endian(uint8_t data) {
return data;
}
/**
* \brief Changes a 16-bit integral value's endianess.
*
* \param data The data to convert.
*/
inline uint16_t do_change_endian(uint16_t data) {
return ((data & 0xff00) >> 8) | ((data & 0x00ff) << 8);
}
/**
* \brief Changes a 32-bit integral value's endianess.
*
* \param data The data to convert.
*/
inline uint32_t do_change_endian(uint32_t data) {
return (((data & 0xff000000) >> 24) | ((data & 0x00ff0000) >> 8) |
((data & 0x0000ff00) << 8) | ((data & 0x000000ff) << 24));
}
/**
* \brief Changes a 64-bit integral value's endianess.
*
* \param data The data to convert.
*/
inline uint64_t do_change_endian(uint64_t data) {
return (((uint64_t)(do_change_endian((uint32_t)(data & 0xffffffff))) << 32) |
(do_change_endian(((uint32_t)(data >> 32)))));
}
/**
* \cond
*/
// Helpers to convert
template<typename T>
struct conversion_dispatch_helper {
static T dispatch(T data) {
return do_change_endian(data);
}
};
template<size_t>
struct conversion_dispatcher;
template<>
struct conversion_dispatcher<sizeof(uint8_t)>
: public conversion_dispatch_helper<uint8_t> { };
template<>
struct conversion_dispatcher<sizeof(uint16_t)>
: public conversion_dispatch_helper<uint16_t> { };
template<>
struct conversion_dispatcher<sizeof(uint32_t)>
: public conversion_dispatch_helper<uint32_t> { };
template<>
struct conversion_dispatcher<sizeof(uint64_t)>
: public conversion_dispatch_helper<uint64_t> { };
/**
* \endcond
*/
/**
* \brief Changes an integral value's endianess.
*
* This dispatchs to the corresponding function.
*
* \param data The data to convert.
*/
template<typename T>
inline T change_endian(T data) {
return conversion_dispatcher<sizeof(T)>::dispatch(data);
}
#if TINS_IS_LITTLE_ENDIAN
/**
* \brief "Changes" a 8-bit integral value's endianess. This is an
* identity function.
* \brief Convert any integral type to big endian.
*
* \param data The data to convert.
*/
inline uint8_t do_change_endian(uint8_t data) {
return data;
template<typename T>
inline T host_to_be(T data) {
return change_endian(data);
}
/**
* \brief Changes a 16-bit integral value's endianess.
*
* \param data The data to convert.
*/
inline uint16_t do_change_endian(uint16_t data) {
return ((data & 0xff00) >> 8) | ((data & 0x00ff) << 8);
}
/**
* \brief Changes a 32-bit integral value's endianess.
* \brief Convert any integral type to little endian.
*
* On little endian platforms, the parameter is simply returned.
*
* \param data The data to convert.
*/
inline uint32_t do_change_endian(uint32_t data) {
return (((data & 0xff000000) >> 24) | ((data & 0x00ff0000) >> 8) |
((data & 0x0000ff00) << 8) | ((data & 0x000000ff) << 24));
}
/**
* \brief Changes a 64-bit integral value's endianess.
*
* \param data The data to convert.
*/
inline uint64_t do_change_endian(uint64_t data) {
return (((uint64_t)(do_change_endian((uint32_t)(data & 0xffffffff))) << 32) |
(do_change_endian(((uint32_t)(data >> 32)))));
template<typename T>
inline T host_to_le(T data) {
return data;
}
/**
* \cond
*/
// Helpers to convert
template<typename T>
struct conversion_dispatch_helper {
static T dispatch(T data) {
return do_change_endian(data);
}
};
template<size_t>
struct conversion_dispatcher;
template<>
struct conversion_dispatcher<sizeof(uint8_t)>
: public conversion_dispatch_helper<uint8_t>
{ };
template<>
struct conversion_dispatcher<sizeof(uint16_t)>
: public conversion_dispatch_helper<uint16_t>
{ };
template<>
struct conversion_dispatcher<sizeof(uint32_t)>
: public conversion_dispatch_helper<uint32_t>
{ };
template<>
struct conversion_dispatcher<sizeof(uint64_t)>
: public conversion_dispatch_helper<uint64_t>
{ };
/**
* \endcond
*/
/**
* \brief Changes an integral value's endianess.
* \brief Convert any big endian value to the host's endianess.
*
* This dispatchs to the corresponding function.
* \param data The data to convert.
*/
template<typename T>
inline T be_to_host(T data) {
return change_endian(data);
}
/**
* \brief Convert any little endian value to the host's endianess.
*
* \param data The data to convert.
*/
template<typename T>
inline T le_to_host(T data) {
return data;
}
#elif TINS_IS_BIG_ENDIAN
/**
* \brief Convert any integral type to big endian.
*
* \param data The data to convert.
*/
*/
template<typename T>
inline T host_to_be(T data) {
return data;
}
/**
* \brief Convert any integral type to little endian.
*
* On little endian platforms, the parameter is simply returned.
*
* \param data The data to convert.
*/
template<typename T>
inline T change_endian(T data) {
return conversion_dispatcher<sizeof(T)>::dispatch(data);
inline T host_to_le(T data) {
return change_endian(data);
}
#if TINS_IS_LITTLE_ENDIAN
/**
* \brief Convert any integral type to big endian.
*
* \param data The data to convert.
*/
template<typename T>
inline T host_to_be(T data) {
return change_endian(data);
}
/**
* \brief Convert any integral type to little endian.
*
* On little endian platforms, the parameter is simply returned.
*
* \param data The data to convert.
*/
template<typename T>
inline T host_to_le(T data) {
return data;
}
/**
* \brief Convert any big endian value to the host's endianess.
*
* \param data The data to convert.
*/
template<typename T>
inline T be_to_host(T data) {
return change_endian(data);
}
/**
* \brief Convert any little endian value to the host's endianess.
*
* \param data The data to convert.
*/
template<typename T>
inline T le_to_host(T data) {
return data;
}
#elif TINS_IS_BIG_ENDIAN
/**
* \brief Convert any integral type to big endian.
*
* \param data The data to convert.
*/
template<typename T>
inline T host_to_be(T data) {
return data;
}
/**
* \brief Convert any integral type to little endian.
*
* On little endian platforms, the parameter is simply returned.
*
* \param data The data to convert.
*/
template<typename T>
inline T host_to_le(T data) {
return change_endian(data);
}
/**
* \brief Convert any big endian value to the host's endianess.
*
* \param data The data to convert.
*/
template<typename T>
inline T be_to_host(T data) {
return data;
}
/**
* \brief Convert any little endian value to the host's endianess.
*
* \param data The data to convert.
*/
template<typename T>
inline T le_to_host(T data) {
return change_endian(data);
}
#endif
}
}
/**
* \brief Convert any big endian value to the host's endianess.
*
* \param data The data to convert.
*/
template<typename T>
inline T be_to_host(T data) {
return data;
}
/**
* \brief Convert any little endian value to the host's endianess.
*
* \param data The data to convert.
*/
template<typename T>
inline T le_to_host(T data) {
return change_endian(data);
}
#endif
} // Endian
} // Tins
#endif // TINS_ENDIANNESS_H

View File

@@ -39,165 +39,172 @@
namespace Tins {
/**
* \class EthernetII
* \brief Represents an Ethernet II PDU.
*/
class TINS_API EthernetII : public PDU {
public:
/**
* \class EthernetII
* \brief Represents an Ethernet II PDU.
* \brief The hardware address type.
*/
class TINS_API EthernetII : public PDU {
public:
/**
* \brief The hardware address type.
*/
typedef HWAddress<6> address_type;
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::ETHERNET_II;
typedef HWAddress<6> address_type;
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::ETHERNET_II;
/**
* \brief Represents the ethernetII broadcast address.
*/
static const address_type BROADCAST;
/**
* \brief Represents the ethernetII broadcast address.
*/
static const address_type BROADCAST;
/**
* \brief Constructs an ethernet II PDU.
*
* \param dst_hw_addr address_type containing the destination's MAC.
* \param src_hw_addr address_type containing the source's MAC.
*/
EthernetII(const address_type &dst_hw_addr = address_type(),
const address_type &src_hw_addr = address_type());
/**
* \brief Constructs an ethernet II PDU.
*
* \param dst_hw_addr address_type containing the destination's MAC.
* \param src_hw_addr address_type containing the source's MAC.
*/
EthernetII(const address_type& dst_hw_addr = address_type(),
const address_type& src_hw_addr = address_type());
/**
* \brief Constructs a EthernetII object from a buffer and adds
* all identifiable PDUs found in the buffer as children of
* this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for a EthernetII header in the
* buffer, a malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
EthernetII(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Constructs a EthernetII object from a buffer and adds
* all identifiable PDUs found in the buffer as children of
* this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for a EthernetII header in the
* buffer, a malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
EthernetII(const uint8_t* buffer, uint32_t total_sz);
/* Getters */
/**
* \brief Getter for the destination's hardware address.
*
* \return address_type containing the destination hardware
* address.
*/
address_type dst_addr() const { return _eth.dst_mac; }
/* Getters */
/**
* \brief Getter for the destination's hardware address.
*
* \return address_type containing the destination hardware
* address.
*/
address_type dst_addr() const {
return header_.dst_mac;
}
/**
* \brief Getter for the source's hardware address.
*
* \return address_type containing the source hardware address.
*/
address_type src_addr() const { return _eth.src_mac; }
/**
* \brief Getter for the source's hardware address.
*
* \return address_type containing the source hardware address.
*/
address_type src_addr() const {
return header_.src_mac;
}
/**
* \brief Getter for the payload_type
* \return The payload type.
*/
uint16_t payload_type() const { return Endian::be_to_host(_eth.payload_type); };
/**
* \brief Getter for the payload_type
* \return The payload type.
*/
uint16_t payload_type() const {
return Endian::be_to_host(header_.payload_type);
}
/* Setters */
/* Setters */
/**
* \brief Setter for the destination hardware address.
*
* \param new_dst_addr the destination hardware address to be set.
*/
void dst_addr(const address_type &new_dst_addr);
/**
* \brief Setter for the destination hardware address.
*
* \param new_dst_addr the destination hardware address to be set.
*/
void dst_addr(const address_type& new_dst_addr);
/**
* \brief Setter for the source hardware address.
*
* \param new_src_addr the source hardware address to be set.
*/
void src_addr(const address_type &new_src_addr);
/**
* \brief Setter for the source hardware address.
*
* \param new_src_addr the source hardware address to be set.
*/
void src_addr(const address_type& new_src_addr);
/**
* \brief Setter for the payload type.
*
* \param new_payload_type the new value of the payload type field.
*/
void payload_type(uint16_t new_payload_type);
/**
* \brief Setter for the payload type.
*
* \param new_payload_type the new value of the payload type field.
*/
void payload_type(uint16_t new_payload_type);
/* Virtual methods */
/**
* \brief Returns the ethernet frame's header length.
*
* \return An uint32_t with the header's size.
* \sa PDU::header_size()
*/
uint32_t header_size() const;
/**
* \brief Returns the ethernet II frame's padding.
*
* \return An uint32_t with the padding size.
* \sa PDU::trailer_size()
*/
uint32_t trailer_size() const;
/* Virtual methods */
/**
* \brief Returns the ethernet frame's header length.
*
* \return An uint32_t with the header's size.
* \sa PDU::header_size()
*/
uint32_t header_size() const;
/**
* \brief Returns the ethernet II frame's padding.
*
* \return An uint32_t with the padding size.
* \sa PDU::trailer_size()
*/
uint32_t trailer_size() const;
/**
* \sa PDU::send()
*/
void send(PacketSender &sender, const NetworkInterface &iface);
/**
* \sa PDU::send()
*/
void send(PacketSender& sender, const NetworkInterface& iface);
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t* ptr, uint32_t total_sz) const;
#ifndef _WIN32
/**
* \brief Receives a matching response for this packet.
*
* \sa PDU::recv_response
*/
PDU *recv_response(PacketSender &sender, const NetworkInterface &iface);
#endif // _WIN32
#ifndef _WIN32
/**
* \brief Receives a matching response for this packet.
*
* \sa PDU::recv_response
*/
PDU* recv_response(PacketSender& sender, const NetworkInterface& iface);
#endif // _WIN32
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::ETHERNET_II; }
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \sa PDU::clone
*/
EthernetII *clone() const {
return new EthernetII(*this);
}
private:
/**
* Struct that represents the Ethernet II header
*/
TINS_BEGIN_PACK
struct ethhdr {
uint8_t dst_mac[address_type::address_size];
uint8_t src_mac[address_type::address_size];
uint16_t payload_type;
} TINS_END_PACK;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
/**
* \sa PDU::clone
*/
EthernetII* clone() const {
return new EthernetII(*this);
}
private:
/**
* Struct that represents the Ethernet II header
*/
TINS_BEGIN_PACK
struct ethernet_header {
uint8_t dst_mac[address_type::address_size];
uint8_t src_mac[address_type::address_size];
uint16_t payload_type;
} TINS_END_PACK;
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
ethhdr _eth;
};
}
ethernet_header header_;
};
} // Tins
#endif // TINS_ETHERNET_II_H

View File

@@ -34,6 +34,7 @@
#include <stdexcept>
namespace Tins {
/**
* \brief Base class for all libtins exceptions.
*/
@@ -98,6 +99,17 @@ public:
}
};
/**
* \brief Exception thrown when an invalid string representation of an address
* is provided
*/
class invalid_address : public exception_base {
public:
const char* what() const throw() {
return "Invalid address";
}
};
/**
* \brief Exception thrown when a field is not present in frame.
*/
@@ -113,7 +125,7 @@ public:
*/
class socket_open_error : public exception_base {
public:
socket_open_error(const std::string &msg)
socket_open_error(const std::string& msg)
: exception_base(msg) { }
};
@@ -122,7 +134,7 @@ public:
*/
class socket_close_error : exception_base {
public:
socket_close_error(const std::string &msg)
socket_close_error(const std::string& msg)
: exception_base(msg) { }
};
@@ -131,7 +143,7 @@ public:
*/
class socket_write_error : public exception_base {
public:
socket_write_error(const std::string &msg)
socket_write_error(const std::string& msg)
: exception_base(msg) { }
};
@@ -141,7 +153,7 @@ public:
*/
class invalid_socket_type : public exception_base {
public:
const char *what() const throw() {
const char* what() const throw() {
return "The provided socket type is invalid";
}
};
@@ -152,7 +164,7 @@ public:
*/
class unknown_link_type : public exception_base {
public:
const char *what() const throw() {
const char* what() const throw() {
return "The sniffed link layer PDU type is unknown";
}
};
@@ -162,7 +174,7 @@ public:
*/
class malformed_option : public exception_base {
public:
const char *what() const throw() {
const char* what() const throw() {
return "Malformed option";
}
};
@@ -172,7 +184,7 @@ public:
*/
class bad_tins_cast : public exception_base {
public:
const char *what() const throw() {
const char* what() const throw() {
return "Bad Tins cast";
}
};
@@ -183,7 +195,7 @@ public:
*/
class protocol_disabled : public exception_base {
public:
const char *what() const throw() {
const char* what() const throw() {
return "Protocol disabled";
}
};
@@ -194,11 +206,63 @@ public:
*/
class option_payload_too_large : public exception_base {
public:
const char *what() const throw() {
const char* what() const throw() {
return "Option payload too large";
}
};
/**
* \brief Generic pcap error
*/
class pcap_error : public exception_base {
public:
pcap_error(const char* message) : exception_base(message) {
}
};
/**
* \brief Exception thrown when an invalid pcap filter is compiled
*/
class invalid_pcap_filter : public exception_base {
public:
invalid_pcap_filter(const char* message) : exception_base(message) {
}
};
/**
* \brief Exception thrown when serialiation of a non-serializable PDU
* is attempted
*/
class pdu_not_serializable : public exception_base {
public:
const char* what() const throw() {
return "PDU not serializable";
}
};
/**
* \brief Exception thrown when opening a pcap handle fails
*/
class pcap_open_failed : public exception_base {
public:
const char* what() const throw() {
return "Failed to create pcap handle";
}
};
/**
* \brief Exception thrown when a function not supported on the current OS
* is called
*/
class unsupported_function : public exception_base {
public:
const char* what() const throw() {
return "Function is not supported on this OS";
}
};
namespace Crypto {
namespace WPA2 {
/**
@@ -206,7 +270,7 @@ namespace WPA2 {
*/
class invalid_handshake : public exception_base {
public:
const char *what() const throw() {
const char* what() const throw() {
return "Invalid WPA2 handshake";
}
};

View File

@@ -39,132 +39,132 @@
#include "macros.h"
#include "eapol.h"
// .h
namespace Tins {
/**
* \brief Generic EAPOL handshake.
*
* Stores both the client and supplicant addresses, as well as
* all of the EAPOL packets used during the handshake.
*/
template<typename T>
class EAPOLHandshake {
public:
typedef std::vector<T> container_type;
typedef HWAddress<6> address_type;
/**
* \brief Generic EAPOL handshake.
* \brief Default constructor.
*/
EAPOLHandshake() { }
/**
* Constructs an EAPOLHandshake object.
*
* \param client_address The client address.
* \param supplicant_address The supplicant address.
* \param cont The container that holds the EAPOL packets used
* in the handshake.
*/
EAPOLHandshake(const address_type& client_address,
const address_type& supplicant_address,
const container_type& cont)
: cl_address_(client_address), suppl_address_(supplicant_address),
handshake_(cont) {
}
/**
* \return const address_type&
*/
const address_type& client_address() const {
return cl_address_;
}
/**
* \return const address_type&
*/
const address_type& supplicant_address() const {
return suppl_address_;
}
/**
* \return const container_type&
*/
const container_type& handshake() const {
return handshake_;
}
private:
address_type cl_address_, suppl_address_;
container_type handshake_;
};
/**
* The type used to store RSN handshakes.
*/
typedef EAPOLHandshake<RSNEAPOL> RSNHandshake;
/**
* Captures 802.1X RSN handshakes.
*/
class TINS_API RSNHandshakeCapturer {
public:
/**
* The type of handshakes that will be captured.
*/
typedef RSNHandshake handshake_type;
/**
* The type in which all of the captured handshakes
* will be stored.
*/
typedef std::vector<handshake_type> handshakes_type;
/**
* \brief Processes a packet.
*
* This will fetch the RSNEAPOL layer, if any, and store
* it in an intermediate storage. When a handshake is
* completed, it will be stored separately.
*
* Stores both the client and supplicant addresses, as well as
* all of the EAPOL packets used during the handshake.
* \sa RSNHandshakeCapturer::handshakes
*/
template<typename T>
class EAPOLHandshake {
public:
typedef std::vector<T> container_type;
typedef HWAddress<6> address_type;
/**
* \brief Default constructor.
*/
EAPOLHandshake() { }
bool process_packet(const PDU& pdu);
/**
* Constructs an EAPOLHandshake object.
*
* \param client_address The client address.
* \param supplicant_address The supplicant address.
* \param cont The container that holds the EAPOL packets used
* in the handshake.
*/
EAPOLHandshake(const address_type &client_address,
const address_type &supplicant_address, const container_type &cont)
: cl_address_(client_address), suppl_address_(supplicant_address),
handshake_(cont)
{
}
/**
* \return const address_type&
*/
const address_type &client_address() const {
return cl_address_;
}
/**
* \return const address_type&
*/
const address_type &supplicant_address() const {
return suppl_address_;
}
/**
* \return const container_type&
*/
const container_type &handshake() const {
return handshake_;
}
private:
address_type cl_address_, suppl_address_;
container_type handshake_;
};
/**
* The type used to store RSN handshakes.
* \brief Retrieves the completed handshakes.
*
* This will return the handshakes that have been completed
* so far. A handshake is completed when the 4-way handshake
* is captured.
*
* \sa RSNHandshakeCapturer::clear_handshakes
*/
typedef EAPOLHandshake<RSNEAPOL> RSNHandshake;
const handshakes_type& handshakes() const {
return completed_handshakes_;
}
/**
* Captures 802.1X RSN handshakes.
* \brief Clears the completed handshakes.
*
* Since completed handshakes are stored in a std::vector,
* it is advisable to remove all of them once they have been
* processed.
*/
class TINS_API RSNHandshakeCapturer {
public:
/**
* The type of handshakes that will be captured.
*/
typedef RSNHandshake handshake_type;
void clear_handshakes() {
completed_handshakes_.clear();
}
private:
typedef handshake_type::address_type address_type;
typedef handshake_type::container_type eapol_list;
typedef std::map<std::pair<address_type, address_type>, eapol_list> handshake_map;
/**
* The type in which all of the captured handshakes
* will be stored.
*/
typedef std::vector<handshake_type> handshakes_type;
/**
* \brief Processes a packet.
*
* This will fetch the RSNEAPOL layer, if any, and store
* it in an intermediate storage. When a handshake is
* completed, it will be stored separately.
*
* \sa RSNHandshakeCapturer::handshakes
*/
bool process_packet(const PDU &pdu);
bool do_insert(const handshake_map::key_type& key, const RSNEAPOL* eapol,
size_t expected);
/**
* \brief Retrieves the completed handshakes.
*
* This will return the handshakes that have been completed
* so far. A handshake is completed when the 4-way handshake
* is captured.
*
* \sa RSNHandshakeCapturer::clear_handshakes
*/
const handshakes_type &handshakes() const {
return completed_handshakes_;
}
handshake_map handshakes_;
handshakes_type completed_handshakes_;
};
/**
* \brief Clears the completed handshakes.
*
* Since completed handshakes are stored in a std::vector,
* it is advisable to remove all of them once they have been
* processed.
*/
void clear_handshakes() {
completed_handshakes_.clear();
}
private:
typedef handshake_type::address_type address_type;
typedef handshake_type::container_type eapol_list;
typedef std::map<std::pair<address_type, address_type>, eapol_list> handshake_map;
bool do_insert(const handshake_map::key_type &key, const RSNEAPOL *eapol,
size_t expected);
handshake_map handshakes_;
handshakes_type completed_handshakes_;
};
}
} // Tins
#endif // TINS_HANDSHAKE_CAPTURER_H

View File

@@ -40,6 +40,7 @@
#include "cxxstd.h"
namespace Tins {
/**
* \class HWAddress
* \brief Represents a hardware address.
@@ -107,10 +108,12 @@ public:
* \param ptr The pointer from which to construct this address.
*/
HWAddress(const storage_type* ptr = 0) {
if(ptr)
std::copy(ptr, ptr + address_size, buffer);
else
if (ptr) {
std::copy(ptr, ptr + address_size, buffer_);
}
else {
std::fill(begin(), end(), storage_type());
}
}
/**
@@ -124,15 +127,15 @@ public:
*
* \param address The hex-notation address to be parsed.
*/
HWAddress(const std::string &address) {
convert(address, buffer);
HWAddress(const std::string& address) {
convert(address, buffer_);
}
/**
* \brief Overload provided basically for string literals.
*
* This constructor takes a const char array of i elements in
* hex-notation. \sa HWAddress::HWAddress(const std::string &address)
* hex-notation. \sa HWAddress::HWAddress(const std::string& address)
*
* This is mostly used when providing string literals. If this where
* a const char*, then there would be an ambiguity when providing
@@ -143,7 +146,7 @@ public:
*/
template<size_t i>
HWAddress(const char (&address)[i]) {
convert(address, buffer);
convert(address, buffer_);
}
/**
@@ -159,7 +162,7 @@ public:
* \param rhs The HWAddress to be constructed from.
*/
template<size_t i>
HWAddress(const HWAddress<i> &rhs) {
HWAddress(const HWAddress<i>& rhs) {
// Fill extra bytes
std::fill(
// Copy as most as we can
@@ -181,7 +184,7 @@ public:
* \return iterator.
*/
iterator begin() {
return buffer;
return buffer_;
}
/**
@@ -191,7 +194,7 @@ public:
* \return const_iterator.
*/
const_iterator begin() const {
return buffer;
return buffer_;
}
/**
@@ -201,7 +204,7 @@ public:
* \return iterator.
*/
iterator end() {
return buffer + address_size;
return buffer_ + address_size;
}
/**
@@ -211,7 +214,7 @@ public:
* \return const_iterator.
*/
const_iterator end() const {
return buffer + address_size;
return buffer_ + address_size;
}
/**
@@ -221,8 +224,8 @@ public:
*
* \return bool indicating whether addresses are equal.
*/
bool operator==(const HWAddress &rhs) const {
return std::equal(begin(), end(), rhs.buffer);
bool operator==(const HWAddress& rhs) const {
return std::equal(begin(), end(), rhs.begin());
}
/**
@@ -232,7 +235,7 @@ public:
*
* \return bool indicating whether addresses are distinct.
*/
bool operator!=(const HWAddress &rhs) const {
bool operator!=(const HWAddress& rhs) const {
return !(*this == rhs);
}
@@ -243,7 +246,7 @@ public:
*
* \return bool indicating whether this address is less-than rhs.
*/
bool operator<(const HWAddress &rhs) const {
bool operator<(const HWAddress& rhs) const {
return std::lexicographical_compare(begin(), end(), rhs.begin(), rhs.end());
}
@@ -260,14 +263,14 @@ public:
* \brief Indicates whether this is a broadcast address.
*/
bool is_broadcast() const {
return *this == broadcast;
return* this == broadcast;
}
/**
* \brief Indicates whether this is a multicast address.
*/
bool is_multicast() const {
return (buffer[0] & 0x01);
return (*begin() & 0x01);
}
/**
@@ -284,7 +287,7 @@ public:
*/
std::string to_string() const {
std::ostringstream oss;
oss << *this;
oss <<* this;
return oss.str();
}
@@ -294,7 +297,7 @@ public:
* \param i The element to retrieve.
*/
storage_type operator[](size_t i) const {
return buffer[i];
return begin()[i];
}
/**
@@ -304,14 +307,14 @@ public:
* \param addr The parameter to be written.
* \return std::ostream& pointing to the os parameter.
*/
friend std::ostream &operator<<(std::ostream &os, const HWAddress &addr) {
friend std::ostream& operator<<(std::ostream& os, const HWAddress& addr) {
std::transform(
addr.begin(),
addr.end() - 1,
std::ostream_iterator<std::string>(os, ":"),
&HWAddress::storage_to_string
);
return os << storage_to_string(addr.buffer[HWAddress::address_size-1]);
return os << storage_to_string(addr.begin()[HWAddress::address_size - 1]);
}
/**
@@ -338,70 +341,91 @@ public:
}
private:
template<typename OutputIterator>
static void convert(const std::string &hw_addr, OutputIterator output);
static void convert(const std::string& hw_addr, OutputIterator output);
static HWAddress<n> make_broadcast_address() {
// Build a buffer made of n 0xff bytes
uint8_t buffer[n];
for (size_t i = 0; i < n; ++i) {
buffer[i] = 0xff;
}
return HWAddress<n>(buffer);
}
static std::string storage_to_string(storage_type element) {
std::ostringstream oss;
oss << std::hex;
if(element < 0x10)
if (element < 0x10) {
oss << '0';
}
oss << (unsigned)element;
return oss.str();
}
storage_type buffer[n];
storage_type buffer_[n];
};
template<size_t n, typename Storage>
template<typename OutputIterator>
void HWAddress<n, Storage>::convert(const std::string &hw_addr,
OutputIterator output)
{
void HWAddress<n, Storage>::convert(const std::string& hw_addr,
OutputIterator output) {
unsigned i(0);
size_t count(0);
storage_type tmp;
while(i < hw_addr.size() && count < n) {
while (i < hw_addr.size() && count < n) {
const unsigned end = i+2;
tmp = storage_type();
while(i < end) {
if(hw_addr[i] >= 'a' && hw_addr[i] <= 'f')
while (i < end) {
if (hw_addr[i] >= 'a' && hw_addr[i] <= 'f') {
tmp = (tmp << 4) | (hw_addr[i] - 'a' + 10);
else if(hw_addr[i] >= 'A' && hw_addr[i] <= 'F')
}
else if (hw_addr[i] >= 'A' && hw_addr[i] <= 'F') {
tmp = (tmp << 4) | (hw_addr[i] - 'A' + 10);
else if(hw_addr[i] >= '0' && hw_addr[i] <= '9')
}
else if (hw_addr[i] >= '0' && hw_addr[i] <= '9') {
tmp = (tmp << 4) | (hw_addr[i] - '0');
else if(hw_addr[i] == ':')
}
else if (hw_addr[i] == ':') {
break;
else
}
else {
throw std::runtime_error("Invalid byte found");
}
i++;
}
*(output++) = tmp;
count++;
if(i < hw_addr.size()) {
if(hw_addr[i] == ':')
if (i < hw_addr.size()) {
if (hw_addr[i] == ':') {
i++;
else
}
else {
throw std::runtime_error("Invalid separator");
}
}
}
while(count++ < n) {
while (count++ < n) {
*(output++) = storage_type();
}
}
template<size_t n, typename Storage>
const HWAddress<n, Storage> HWAddress<n, Storage>::broadcast("ff:ff:ff:ff:ff:ff");
const HWAddress<n, Storage> HWAddress<n, Storage>::broadcast = make_broadcast_address();
} // namespace Tins
#if TINS_IS_CXX11
namespace std
{
namespace std {
// Specialization of std::hash for HWAddress
template<size_t n>
struct hash<Tins::HWAddress<n>> {
size_t operator()(const Tins::HWAddress<n> &addr) const {
size_t operator()(const Tins::HWAddress<n>& addr) const {
return std::hash<std::string>()(addr.to_string());
}
};
} // namespace std
#endif
#endif // TINS_IS_CXX11
#endif // TINS_HWADDRESS_H

View File

@@ -50,7 +50,9 @@
namespace Tins {
namespace Memory {
class InputMemoryStream;
} // Memory
/**
@@ -109,7 +111,7 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
ICMP(const uint8_t *buffer, uint32_t total_sz);
ICMP(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Sets the code field.
@@ -262,43 +264,53 @@ public:
*
* \return The type flag for this ICMP PDU.
*/
Flags type() const { return (Flags)_icmp.type; }
Flags type() const {
return (Flags)header_.type;
}
/**
* \brief Getter for the ICMP code flag.
*
* \return The code flag for this ICMP PDU.
*/
uint8_t code() const { return _icmp.code; }
uint8_t code() const {
return header_.code;
}
/**
* \brief Getter for the checksum field.
*
* \return Returns the checksum as an unit16_t.
*/
uint16_t checksum() const { return Endian::be_to_host(_icmp.check); }
uint16_t checksum() const {
return Endian::be_to_host(header_.check);
}
/**
* \brief Getter for the echo id.
*
* \return Returns the echo id.
*/
uint16_t id() const { return Endian::be_to_host(_icmp.un.echo.id); }
uint16_t id() const {
return Endian::be_to_host(header_.un.echo.id);
}
/**
* \brief Getter for the echo sequence number.
*
* \return Returns the echo sequence number.
*/
uint16_t sequence() const { return Endian::be_to_host(_icmp.un.echo.sequence); }
uint16_t sequence() const {
return Endian::be_to_host(header_.un.echo.sequence);
}
/**
* \brief Getter for the gateway field.
*
* \return Returns the gateway field value.
*/
address_type gateway() const {
return address_type(Endian::be_to_host(_icmp.un.gateway));
address_type gateway() const {
return address_type(Endian::be_to_host(header_.un.gateway));
}
/**
@@ -306,50 +318,62 @@ public:
*
* \return Returns the pointer field value.
*/
uint8_t pointer() const { return _icmp.un.rfc4884.pointer; }
uint8_t pointer() const {
return header_.un.rfc4884.pointer;
}
/**
* \brief Getter for the length field.
*
* \return Returns the length field value.
*/
uint8_t length() const { return _icmp.un.rfc4884.length; }
uint8_t length() const {
return header_.un.rfc4884.length;
}
/**
* \brief Getter for the mtu field.
*
* \return Returns the mtu field value.
*/
uint16_t mtu() const { return Endian::be_to_host(_icmp.un.frag.mtu); }
uint16_t mtu() const {
return Endian::be_to_host(header_.un.frag.mtu);
}
/**
* \brief Getter for the original timestamp field.
*
* \return Returns the original timestamp value.
*/
uint32_t original_timestamp() const { return Endian::be_to_host(_orig_timestamp_or_address_mask); }
uint32_t original_timestamp() const {
return Endian::be_to_host(orig_timestamp_or_address_mask_);
}
/**
* \brief Getter for the receive timestamp field.
*
* \return Returns the receive timestamp value.
*/
uint32_t receive_timestamp() const { return Endian::be_to_host(_recv_timestamp); }
uint32_t receive_timestamp() const {
return Endian::be_to_host(recv_timestamp_);
}
/**
* \brief Getter for the transmit timestamp field.
*
* \return Returns the transmit timestamp value.
*/
uint32_t transmit_timestamp() const { return Endian::be_to_host(_trans_timestamp); }
uint32_t transmit_timestamp() const {
return Endian::be_to_host(trans_timestamp_);
}
/**
* \brief Getter for the address mask field.
*
* \return Returns the address mask value.
*/
address_type address_mask() const {
return address_type(Endian::be_to_host(_orig_timestamp_or_address_mask));
address_type address_mask() const {
return address_type(Endian::be_to_host(orig_timestamp_or_address_mask_));
}
/**
@@ -378,26 +402,32 @@ public:
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
bool matches_response(const uint8_t* ptr, uint32_t total_sz) const;
/**
* \brief Getter for the extensions field.
*
* \return The extensions field
*/
const ICMPExtensionsStructure& extensions() const { return extensions_; }
const ICMPExtensionsStructure& extensions() const {
return extensions_;
}
/**
* \brief Getter for the extensions field.
*
* \return The extensions field
*/
ICMPExtensionsStructure& extensions() { return extensions_; }
ICMPExtensionsStructure& extensions() {
return extensions_;
}
/**
* \brief Indicates whether this object contains ICMP extensions
*/
bool has_extensions() const { return !extensions_.extensions().empty(); }
bool has_extensions() const {
return !extensions_.extensions().empty();
}
/**
* \brief Sets whether the length field will be set for packets that use it
@@ -421,17 +451,19 @@ public:
*
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::ICMP; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \sa PDU::clone
*/
ICMP *clone() const {
ICMP* clone() const {
return new ICMP(*this);
}
private:
TINS_BEGIN_PACK
struct icmphdr {
struct icmp_header {
uint8_t type;
uint8_t code;
uint16_t check;
@@ -460,14 +492,14 @@ private:
* \param total_sz The size available in the buffer.
* \param parent The PDU that's one level below this one on the stack.
*/
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
uint32_t get_adjusted_inner_pdu_size() const;
void try_parse_extensions(Memory::InputMemoryStream& stream);
bool are_extensions_allowed() const;
icmphdr _icmp;
uint32_t _orig_timestamp_or_address_mask, _recv_timestamp, _trans_timestamp;
icmp_header header_;
uint32_t orig_timestamp_or_address_mask_, recv_timestamp_, trans_timestamp_;
ICMPExtensionsStructure extensions_;
};

View File

@@ -104,21 +104,27 @@ public:
*
* \return The extension class field value
*/
uint8_t extension_class() const { return extension_class_; }
uint8_t extension_class() const {
return extension_class_;
}
/**
* \brief Getter for the extension sub-type field
*
* \return The extension sub-type field value
*/
uint8_t extension_type() const { return extension_type_; }
uint8_t extension_type() const {
return extension_type_;
}
/**
* \brief Getter for the extension payload field
*
* \return The extension payload field value
*/
const payload_type& payload() const { return payload_; }
const payload_type& payload() const {
return payload_;
}
/**
* \brief Gets the size of this ICMP extension
@@ -206,9 +212,9 @@ public:
*
* \return The version field value
*/
small_uint<4> version() const {
small_uint<4> version() const {
uint16_t value = Endian::be_to_host(version_and_reserved_);
return (value >> 12) & 0xf;
return (value >> 12) & 0xf;
}
/**
@@ -216,7 +222,7 @@ public:
*
* \return The reserved field value
*/
small_uint<12> reserved() const {
small_uint<12> reserved() const {
uint16_t value = Endian::be_to_host(version_and_reserved_);
return value & 0xfff;
}
@@ -226,14 +232,18 @@ public:
*
* \return The checksum field value
*/
uint16_t checksum() const { return Endian::be_to_host(checksum_); }
uint16_t checksum() const {
return Endian::be_to_host(checksum_);
}
/**
* \brief Getter for the extensions stored by this structure
*
* \return The extensions stored in this structure
*/
const extensions_type& extensions() const { return extensions_; }
const extensions_type& extensions() const {
return extensions_;
}
/**
* \brief Adds an extension to this structure

View File

@@ -45,8 +45,10 @@
namespace Tins {
namespace Memory {
class InputMemoryStream;
class OutputMemoryStream;
} // memory
/**
@@ -164,13 +166,12 @@ public:
uint8_t reserved[6];
addresses_type addresses;
addr_list_type(const addresses_type &addresses = addresses_type())
: addresses(addresses)
{
addr_list_type(const addresses_type& addresses = addresses_type())
: addresses(addresses) {
std::fill(reserved, reserved + sizeof(reserved), 0);
}
static addr_list_type from_option(const option &opt);
static addr_list_type from_option(const option& opt);
};
/**
@@ -192,12 +193,11 @@ public:
uint8_t reserved[4];
naack_type(uint8_t code = 0, uint8_t status = 0)
: code(code), status(status)
{
: code(code), status(status) {
std::fill(reserved, reserved + 4, 0);
}
static naack_type from_option(const option &opt);
static naack_type from_option(const option& opt);
};
/**
@@ -216,9 +216,8 @@ public:
* \param address The address to be stored.
*/
lladdr_type(uint8_t option_code = 0,
const address_type &address = address_type())
: option_code(option_code), address(address)
{
const address_type& address = address_type())
: option_code(option_code), address(address) {
}
@@ -231,14 +230,12 @@ public:
* \param option_code The option code.
* \param address The address to be stored.
*/
lladdr_type(uint8_t option_code,
const hwaddress_type &address)
: option_code(option_code), address(address.begin(), address.end())
{
lladdr_type(uint8_t option_code, const hwaddress_type& address)
: option_code(option_code), address(address.begin(), address.end()) {
}
static lladdr_type from_option(const option &opt);
static lladdr_type from_option(const option& opt);
};
/**
@@ -252,14 +249,16 @@ public:
reserved2;
ipaddress_type prefix;
prefix_info_type(uint8_t prefix_len=0, small_uint<1> A=0, small_uint<1> L=0,
uint32_t valid_lifetime=0, uint32_t preferred_lifetime=0,
const ipaddress_type &prefix = ipaddress_type())
: prefix_len(prefix_len), A(A), L(L),
valid_lifetime(valid_lifetime), preferred_lifetime(preferred_lifetime),
prefix(prefix) { }
prefix_info_type(uint8_t prefix_len = 0,
small_uint<1> A = 0,
small_uint<1> L = 0,
uint32_t valid_lifetime = 0,
uint32_t preferred_lifetime = 0,
const ipaddress_type& prefix = ipaddress_type())
: prefix_len(prefix_len), A(A), L(L), valid_lifetime(valid_lifetime),
preferred_lifetime(preferred_lifetime), prefix(prefix) { }
static prefix_info_type from_option(const option &opt);
static prefix_info_type from_option(const option& opt);
};
/**
@@ -291,8 +290,7 @@ public:
*/
template<typename RAIterator, typename ForwardIterator>
rsa_sign_type(RAIterator hash, ForwardIterator start, ForwardIterator end)
: signature(start, end)
{
: signature(start, end) {
std::copy(hash, hash + sizeof(key_hash), key_hash);
}
@@ -309,9 +307,8 @@ public:
* \param sign The signature to be set.
*/
template<typename RAIterator>
rsa_sign_type(RAIterator hash, const signature_type &sign)
: signature(sign)
{
rsa_sign_type(RAIterator hash, const signature_type& sign)
: signature(sign) {
std::copy(hash, hash + sizeof(key_hash), key_hash);
}
@@ -320,12 +317,11 @@ public:
*
* The key_hash member will be 0-initialized.
*/
rsa_sign_type()
{
rsa_sign_type() {
std::fill(key_hash, key_hash + sizeof(key_hash), 0);
}
static rsa_sign_type from_option(const option &opt);
static rsa_sign_type from_option(const option& opt);
};
/**
@@ -335,12 +331,13 @@ public:
uint8_t option_code, prefix_len;
ipaddress_type address;
ip_prefix_type(uint8_t option_code = 0, uint8_t prefix_len = 0,
const ipaddress_type &address = ipaddress_type())
ip_prefix_type(uint8_t option_code = 0,
uint8_t prefix_len = 0,
const ipaddress_type& address = ipaddress_type())
: option_code(option_code), prefix_len(prefix_len), address(address)
{}
static ip_prefix_type from_option(const option &opt);
static ip_prefix_type from_option(const option& opt);
};
/**
@@ -352,13 +349,15 @@ public:
uint32_t valid_lifetime;
ipaddress_type address;
map_type(small_uint<4> dist = 0, small_uint<4> pref = 0,
small_uint<1> r = 0, uint32_t valid_lifetime = 0,
const ipaddress_type &address = ipaddress_type())
map_type(small_uint<4> dist = 0,
small_uint<4> pref = 0,
small_uint<1> r = 0,
uint32_t valid_lifetime = 0,
const ipaddress_type& address = ipaddress_type())
: dist(dist), pref(pref), r(r), valid_lifetime(valid_lifetime),
address(address) { }
static map_type from_option(const option &opt);
static map_type from_option(const option& opt);
};
/**
@@ -372,12 +371,14 @@ public:
uint32_t route_lifetime;
prefix_type prefix;
route_info_type(uint8_t prefix_len = 0, small_uint<2> pref = 0,
uint32_t route_lifetime = 0, const prefix_type &prefix = prefix_type())
route_info_type(uint8_t prefix_len = 0,
small_uint<2> pref = 0,
uint32_t route_lifetime = 0,
const prefix_type& prefix = prefix_type())
: prefix_len(prefix_len), pref(pref), route_lifetime(route_lifetime),
prefix(prefix) { }
static route_info_type from_option(const option &opt);
static route_info_type from_option(const option& opt);
};
/**
@@ -390,10 +391,10 @@ public:
servers_type servers;
recursive_dns_type(uint32_t lifetime = 0,
const servers_type &servers = servers_type())
const servers_type& servers = servers_type())
: lifetime(lifetime), servers(servers) {}
static recursive_dns_type from_option(const option &opt);
static recursive_dns_type from_option(const option& opt);
};
/**
@@ -406,10 +407,10 @@ public:
key_type key;
handover_key_req_type(small_uint<4> AT = 0,
const key_type &key = key_type())
const key_type& key = key_type())
: AT(AT), key(key) { }
static handover_key_req_type from_option(const option &opt);
static handover_key_req_type from_option(const option& opt);
};
/**
@@ -418,11 +419,12 @@ public:
struct handover_key_reply_type : handover_key_req_type {
uint16_t lifetime;
handover_key_reply_type(uint16_t lifetime = 0, small_uint<4> AT = 0,
const key_type &key = key_type())
handover_key_reply_type(uint16_t lifetime = 0,
small_uint<4> AT = 0,
const key_type& key = key_type())
: handover_key_req_type(AT, key), lifetime(lifetime) { }
static handover_key_reply_type from_option(const option &opt);
static handover_key_reply_type from_option(const option& opt);
};
/**
@@ -435,10 +437,10 @@ public:
hai_type hai;
handover_assist_info_type(uint8_t option_code=0,
const hai_type &hai = hai_type())
const hai_type& hai = hai_type())
: option_code(option_code), hai(hai) { }
static handover_assist_info_type from_option(const option &opt);
static handover_assist_info_type from_option(const option& opt);
};
/**
@@ -451,10 +453,10 @@ public:
mn_type mn;
mobile_node_id_type(uint8_t option_code=0,
const mn_type &mn = mn_type())
const mn_type& mn = mn_type())
: option_code(option_code), mn(mn) { }
static mobile_node_id_type from_option(const option &opt);
static mobile_node_id_type from_option(const option& opt);
};
/**
@@ -467,10 +469,10 @@ public:
domains_type domains;
dns_search_list_type(uint32_t lifetime = 0,
const domains_type &domains = domains_type())
const domains_type& domains = domains_type())
: lifetime(lifetime), domains(domains) { }
static dns_search_list_type from_option(const option &opt);
static dns_search_list_type from_option(const option& opt);
};
/**
@@ -481,12 +483,11 @@ public:
uint64_t timestamp;
timestamp_type(uint64_t timestamp = 0)
: timestamp(timestamp)
{
: timestamp(timestamp) {
std::fill(reserved, reserved + sizeof(reserved), 0);
}
static timestamp_type from_option(const option &opt);
static timestamp_type from_option(const option& opt);
};
/**
@@ -497,12 +498,11 @@ public:
uint32_t reserved2;
shortcut_limit_type(uint8_t limit = 0)
: limit(limit), reserved1(), reserved2()
{
: limit(limit), reserved1(), reserved2() {
}
static shortcut_limit_type from_option(const option &opt);
static shortcut_limit_type from_option(const option& opt);
};
/**
@@ -513,12 +513,11 @@ public:
uint32_t interval;
new_advert_interval_type(uint32_t interval = 0)
: reserved(), interval(interval)
{
: reserved(), interval(interval) {
}
static new_advert_interval_type from_option(const option &opt);
static new_advert_interval_type from_option(const option& opt);
};
/**
@@ -566,7 +565,7 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
ICMPv6(const uint8_t *buffer, uint32_t total_sz);
ICMPv6(const uint8_t* buffer, uint32_t total_sz);
// Getters
@@ -575,7 +574,7 @@ public:
* \return The stored type field value.
*/
Types type() const {
return static_cast<Types>(_header.type);
return static_cast<Types>(header_.type);
}
/**
@@ -583,7 +582,7 @@ public:
* \return The stored code field value.
*/
uint8_t code() const {
return _header.code;
return header_.code;
}
/**
@@ -591,7 +590,7 @@ public:
* \return The stored cksum field value.
*/
uint16_t checksum() const {
return Endian::be_to_host(_header.cksum);
return Endian::be_to_host(header_.cksum);
}
/**
@@ -599,7 +598,7 @@ public:
* \return The stored identifier field value.
*/
uint16_t identifier() const {
return Endian::be_to_host(_header.u_echo.identifier);
return Endian::be_to_host(header_.u_echo.identifier);
}
/**
@@ -607,7 +606,7 @@ public:
* \return The stored sequence field value.
*/
uint16_t sequence() const {
return Endian::be_to_host(_header.u_echo.sequence);
return Endian::be_to_host(header_.u_echo.sequence);
}
/**
@@ -615,7 +614,7 @@ public:
* \return The stored override field value.
*/
small_uint<1> override() const {
return _header.u_nd_advt.override;
return header_.u_nd_advt.override;
}
/**
@@ -623,7 +622,7 @@ public:
* \return The stored solicited field value.
*/
small_uint<1> solicited() const {
return _header.u_nd_advt.solicited;
return header_.u_nd_advt.solicited;
}
/**
@@ -631,7 +630,7 @@ public:
* \return The stored router field value.
*/
small_uint<1> router() const {
return _header.u_nd_advt.router;
return header_.u_nd_advt.router;
}
/**
@@ -639,7 +638,7 @@ public:
* \return The stored hop_limit field value.
*/
uint8_t hop_limit() const {
return _header.u_nd_ra.hop_limit;
return header_.u_nd_ra.hop_limit;
}
/**
@@ -647,7 +646,7 @@ public:
* \return The stored router_pref field value.
*/
small_uint<2> router_pref() const {
return _header.u_nd_ra.router_pref;
return header_.u_nd_ra.router_pref;
}
/**
@@ -655,7 +654,7 @@ public:
* \return The stored home_agent field value.
*/
small_uint<1> home_agent() const {
return _header.u_nd_ra.home_agent;
return header_.u_nd_ra.home_agent;
}
/**
@@ -663,7 +662,7 @@ public:
* \return The stored other field value.
*/
small_uint<1> other() const {
return _header.u_nd_ra.other;
return header_.u_nd_ra.other;
}
/**
@@ -671,7 +670,7 @@ public:
* \return The stored managed field value.
*/
small_uint<1> managed() const {
return _header.u_nd_ra.managed;
return header_.u_nd_ra.managed;
}
/**
@@ -679,7 +678,7 @@ public:
* \return The stored router_lifetime field value.
*/
uint16_t router_lifetime() const {
return Endian::be_to_host(_header.u_nd_ra.router_lifetime);
return Endian::be_to_host(header_.u_nd_ra.router_lifetime);
}
/**
@@ -687,7 +686,7 @@ public:
* \return The stored reachable_time field value.
*/
uint32_t reachable_time() const {
return Endian::be_to_host(reach_time);
return Endian::be_to_host(reach_time_);
}
/**
@@ -695,31 +694,31 @@ public:
* \return The stored retransmit_timer field value.
*/
uint32_t retransmit_timer() const {
return Endian::be_to_host(retrans_timer);
return Endian::be_to_host(retrans_timer_);
}
/**
* \brief Getter for the target address field.
* \return The stored target address field value.
*/
const ipaddress_type &target_addr() const {
return _target_address;
const ipaddress_type& target_addr() const {
return target_address_;
}
/**
* \brief Getter for the destination address field.
* \return The stored destination address field value.
*/
const ipaddress_type &dest_addr() const {
return _dest_address;
const ipaddress_type& dest_addr() const {
return dest_address_;
}
/**
* \brief Getter for the ICMPv6 options.
* \return The stored options.
*/
const options_type &options() const {
return _options;
const options_type& options() const {
return options_;
}
/**
@@ -728,7 +727,7 @@ public:
* \return Returns the length field value.
*/
uint8_t length() const {
return _header.rfc4884.length;
return header_.rfc4884.length;
}
/**
@@ -828,13 +827,13 @@ public:
* \brief Setter for the target address field.
* \param new_target_addr The new target address field value.
*/
void target_addr(const ipaddress_type &new_target_addr);
void target_addr(const ipaddress_type& new_target_addr);
/**
* \brief Setter for the destination address field.
* \param new_dest_addr The new destination address field value.
*/
void dest_addr(const ipaddress_type &new_dest_addr);
void dest_addr(const ipaddress_type& new_dest_addr);
/**
* \brief Setter for the reachable_time field.
@@ -869,8 +868,8 @@ public:
*/
bool has_target_addr() const {
return type() == NEIGHBOUR_SOLICIT ||
type() == NEIGHBOUR_ADVERT ||
type() == REDIRECT;
type() == NEIGHBOUR_ADVERT ||
type() == REDIRECT;
}
/**
@@ -890,7 +889,7 @@ public:
*
* \param option The option to be added
*/
void add_option(const option &option);
void add_option(const option& option);
#if TINS_IS_CXX11
/**
@@ -902,7 +901,7 @@ public:
*/
void add_option(option &&option) {
internal_add_option(option);
_options.push_back(std::move(option));
options_.push_back(std::move(option));
}
#endif
@@ -939,19 +938,25 @@ public:
*
* \return The extensions field
*/
const ICMPExtensionsStructure& extensions() const { return extensions_; }
const ICMPExtensionsStructure& extensions() const {
return extensions_;
}
/**
* \brief Getter for the extensions field.
*
* \return The extensions field
*/
ICMPExtensionsStructure& extensions() { return extensions_; }
ICMPExtensionsStructure& extensions() {
return extensions_;
}
/**
* \brief Indicates whether this object contains ICMP extensions
*/
bool has_extensions() const { return !extensions_.extensions().empty(); }
bool has_extensions() const {
return !extensions_.extensions().empty();
}
/**
* \brief Sets whether the length field will be set for packets that use it
@@ -977,7 +982,7 @@ public:
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
bool matches_response(const uint8_t* ptr, uint32_t total_sz) const;
/**
* \brief Searchs for an option that matchs the given flag.
@@ -988,12 +993,12 @@ public:
*
* \param type The option identifier to be searched.
*/
const option *search_option(OptionTypes type) const;
const option* search_option(OptionTypes type) const;
/**
* \sa PDU::clone
*/
ICMPv6 *clone() const {
ICMPv6* clone() const {
return new ICMPv6(*this);
}
@@ -1006,14 +1011,14 @@ public:
*
* \param addr The source link layer address.
*/
void source_link_layer_addr(const hwaddress_type &addr);
void source_link_layer_addr(const hwaddress_type& addr);
/**
* \brief Setter for the target link layer address option.
*
* \param addr The target link layer address.
*/
void target_link_layer_addr(const hwaddress_type &addr);
void target_link_layer_addr(const hwaddress_type& addr);
/**
* \brief Setter for the prefix information option.
@@ -1027,7 +1032,7 @@ public:
*
* \param data The redirect header option data.
*/
void redirect_header(const byte_array &data);
void redirect_header(const byte_array& data);
/**
* \brief Setter for the MTU option.
@@ -1048,56 +1053,56 @@ public:
*
* \param value The new advertisement interval option data.
*/
void new_advert_interval(const new_advert_interval_type &value);
void new_advert_interval(const new_advert_interval_type& value);
/**
* \brief Setter for the new home agent information option.
*
* \param value The new home agent information option data.
*/
void new_home_agent_info(const new_ha_info_type &value);
void new_home_agent_info(const new_ha_info_type& value);
/**
* \brief Setter for the new source address list option.
*
* \param value The new source address list option data.
*/
void source_addr_list(const addr_list_type &value);
void source_addr_list(const addr_list_type& value);
/**
* \brief Setter for the new target address list option.
*
* \param value The new target address list option data.
*/
void target_addr_list(const addr_list_type &value);
void target_addr_list(const addr_list_type& value);
/**
* \brief Setter for the new RSA signature option.
*
* \param value The new RSA signature option data.
*/
void rsa_signature(const rsa_sign_type &value);
void rsa_signature(const rsa_sign_type& value);
/**
* \brief Setter for the new timestamp option.
*
* \param value The new timestamp option data.
*/
void timestamp(const timestamp_type &value);
void timestamp(const timestamp_type& value);
/**
* \brief Setter for the new nonce option.
*
* \param value The new nonce option data.
*/
void nonce(const nonce_type &value);
void nonce(const nonce_type& value);
/**
* \brief Setter for the new IP address/prefix option.
*
* \param value The new IP address/prefix option data.
*/
void ip_prefix(const ip_prefix_type &value);
void ip_prefix(const ip_prefix_type& value);
/**
* \brief Setter for the new link layer address option.
@@ -1111,63 +1116,63 @@ public:
*
* \param value The new naack option data.
*/
void naack(const naack_type &value);
void naack(const naack_type& value);
/**
* \brief Setter for the map option.
*
* \param value The new map option data.
*/
void map(const map_type &value);
void map(const map_type& value);
/**
* \brief Setter for the route information option.
*
* \param value The new route information option data.
*/
void route_info(const route_info_type &value);
void route_info(const route_info_type& value);
/**
* \brief Setter for the recursive DNS servers option.
*
* \param value The new recursive DNS servers option data.
*/
void recursive_dns_servers(const recursive_dns_type &value);
void recursive_dns_servers(const recursive_dns_type& value);
/**
* \brief Setter for the handover key request option.
*
* \param value The new handover key request option data.
*/
void handover_key_request(const handover_key_req_type &value);
void handover_key_request(const handover_key_req_type& value);
/**
* \brief Setter for the handover key reply option.
*
* \param value The new handover key reply option data.
*/
void handover_key_reply(const handover_key_reply_type &value);
void handover_key_reply(const handover_key_reply_type& value);
/**
* \brief Setter for the handover assist info option.
*
* \param value The new handover assist info option data.
*/
void handover_assist_info(const handover_assist_info_type &value);
void handover_assist_info(const handover_assist_info_type& value);
/**
* \brief Setter for the mobile node identifier option.
*
* \param value The new mobile node identifier option data.
*/
void mobile_node_identifier(const mobile_node_id_type &value);
void mobile_node_identifier(const mobile_node_id_type& value);
/**
* \brief Setter for the DNS search list option.
*
* \param value The new DNS search list option data.
*/
void dns_search_list(const dns_search_list_type &value);
void dns_search_list(const dns_search_list_type& value);
// ****************************************************************
// Option getters
@@ -1367,7 +1372,7 @@ public:
dns_search_list_type dns_search_list() const;
private:
TINS_BEGIN_PACK
struct icmp6hdr {
struct icmp6_header {
uint8_t type;
uint8_t code;
uint16_t cksum;
@@ -1420,40 +1425,43 @@ private:
};
} TINS_END_PACK;
void internal_add_option(const option &option);
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
void internal_add_option(const option& option);
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
bool has_options() const;
void write_option(const option &opt, Memory::OutputMemoryStream& stream);
void write_option(const option& opt, Memory::OutputMemoryStream& stream);
void parse_options(Memory::InputMemoryStream& stream);
void add_addr_list(uint8_t type, const addr_list_type &value);
void add_addr_list(uint8_t type, const addr_list_type& value);
addr_list_type search_addr_list(OptionTypes type) const;
options_type::const_iterator search_option_iterator(OptionTypes type) const;
options_type::iterator search_option_iterator(OptionTypes type);
void try_parse_extensions(Memory::InputMemoryStream& stream);
bool are_extensions_allowed() const;
uint32_t get_adjusted_inner_pdu_size() const;
uint8_t get_option_padding(uint32_t data_size);
template<template <typename> class Functor>
const option *safe_search_option(OptionTypes opt, uint32_t size) const {
const option *option = search_option(opt);
if(!option || Functor<uint32_t>()(option->data_size(), size))
const option* safe_search_option(OptionTypes opt, uint32_t size) const {
const option* option = search_option(opt);
if (!option || Functor<uint32_t>()(option->data_size(), size)) {
throw option_not_found();
}
return option;
}
template<typename T>
T search_and_convert(OptionTypes type) const {
const option *opt = search_option(type);
if(!opt)
const option* opt = search_option(type);
if (!opt) {
throw option_not_found();
}
return opt->to<T>();
}
icmp6hdr _header;
ipaddress_type _target_address, _dest_address;
options_type _options;
uint32_t _options_size;
uint32_t reach_time, retrans_timer;
icmp6_header header_;
ipaddress_type target_address_, dest_address_;
options_type options_;
uint32_t options_size_;
uint32_t reach_time_, retrans_timer_;
multicast_address_records_list multicast_records_;
ICMPExtensionsStructure extensions_;
};

View File

@@ -46,6 +46,7 @@
*/
namespace Tins {
namespace Memory {
class InputMemoryStream;
} // Memory
class IPv4Address;
@@ -53,6 +54,7 @@ class IPv6Address;
class ICMPExtensionsStructure;
namespace Internals {
template<size_t n>
class byte_array {
public:
@@ -73,7 +75,7 @@ public:
std::copy(start, n, data);
}
uint8_t &operator[](size_t i) {
uint8_t& operator[](size_t i) {
return data[i];
}
@@ -104,8 +106,8 @@ private:
uint8_t data[n];
};
void skip_line(std::istream &input);
bool from_hex(const std::string &str, uint32_t &result);
void skip_line(std::istream& input);
bool from_hex(const std::string& str, uint32_t& result);
template<bool, typename T = void>
struct enable_if {
@@ -117,13 +119,13 @@ struct enable_if<false, T> {
};
PDU *pdu_from_flag(Constants::Ethernet::e flag, const uint8_t *buffer,
PDU* pdu_from_flag(Constants::Ethernet::e flag, const uint8_t* buffer,
uint32_t size, bool rawpdu_on_no_match = true);
PDU *pdu_from_flag(Constants::IP::e flag, const uint8_t *buffer,
PDU* pdu_from_flag(Constants::IP::e flag, const uint8_t* buffer,
uint32_t size, bool rawpdu_on_no_match = true);
PDU *pdu_from_dlt_flag(int flag, const uint8_t *buffer,
PDU* pdu_from_dlt_flag(int flag, const uint8_t* buffer,
uint32_t size, bool rawpdu_on_no_match = true);
PDU *pdu_from_flag(PDU::PDUType type, const uint8_t *buffer, uint32_t size);
PDU* pdu_from_flag(PDU::PDUType type, const uint8_t* buffer, uint32_t size);
Constants::Ethernet::e pdu_flag_to_ether_type(PDU::PDUType flag);
Constants::IP::e pdu_flag_to_ip_type(PDU::PDUType flag);
@@ -133,58 +135,60 @@ void try_parse_icmp_extensions(Memory::InputMemoryStream& stream,
uint32_t payload_length, ICMPExtensionsStructure& extensions);
template<typename T>
bool increment_buffer(T &addr) {
bool increment_buffer(T& addr) {
typename T::iterator it = addr.end() - 1;
while(it >= addr.begin() && *it == 0xff) {
while (it >= addr.begin() && *it == 0xff) {
*it = 0;
--it;
}
// reached end
if(it < addr.begin())
if (it < addr.begin()) {
return true;
}
(*it)++;
return false;
}
template<typename T>
bool decrement_buffer(T &addr) {
bool decrement_buffer(T& addr) {
typename T::iterator it = addr.end() - 1;
while(it >= addr.begin() && *it == 0) {
while (it >= addr.begin() && *it == 0) {
*it = 0xff;
--it;
}
// reached end
if(it < addr.begin())
if (it < addr.begin()) {
return true;
}
(*it)--;
return false;
}
bool increment(IPv4Address &addr);
bool increment(IPv6Address &addr);
bool decrement(IPv4Address &addr);
bool decrement(IPv6Address &addr);
bool increment(IPv4Address& addr);
bool increment(IPv6Address& addr);
bool decrement(IPv4Address& addr);
bool decrement(IPv6Address& addr);
template<size_t n>
bool increment(HWAddress<n> &addr) {
bool increment(HWAddress<n>& addr) {
return increment_buffer(addr);
}
template<size_t n>
bool decrement(HWAddress<n> &addr) {
bool decrement(HWAddress<n>& addr) {
return decrement_buffer(addr);
}
IPv4Address last_address_from_mask(IPv4Address addr, IPv4Address mask);
IPv6Address last_address_from_mask(IPv6Address addr, const IPv6Address &mask);
IPv6Address last_address_from_mask(IPv6Address addr, const IPv6Address& mask);
template<size_t n>
HWAddress<n> last_address_from_mask(HWAddress<n> addr, const HWAddress<n> &mask) {
HWAddress<n> last_address_from_mask(HWAddress<n> addr, const HWAddress<n>& mask) {
typename HWAddress<n>::iterator addr_iter = addr.begin();
for(typename HWAddress<n>::const_iterator it = mask.begin(); it != mask.end(); ++it, ++addr_iter) {
for (typename HWAddress<n>::const_iterator it = mask.begin(); it != mask.end(); ++it, ++addr_iter) {
*addr_iter = *addr_iter | ~*it;
}
return addr;
}
inline bool is_dot3(const uint8_t *ptr, size_t sz) {
inline bool is_dot3(const uint8_t* ptr, size_t sz) {
return (sz >= 13 && ptr[12] < 8);
}

File diff suppressed because it is too large Load Diff

View File

@@ -63,7 +63,7 @@ public:
*
* \param ip const char* containing the dotted-notation address.
*/
IPv4Address(const char *ip = 0);
IPv4Address(const char* ip = 0);
/**
* \brief Constructor taking a std::string.
@@ -72,7 +72,7 @@ public:
*
* \param ip std::string containing the dotted-notation address.
*/
IPv4Address(const std::string &ip);
IPv4Address(const std::string& ip);
/**
* \brief Constructor taking a IP address represented as a
@@ -102,8 +102,8 @@ public:
* \param rhs The address to be compared.
* \return bool indicating whether this address equals rhs.
*/
bool operator==(const IPv4Address &rhs) const {
return ip_addr == rhs.ip_addr;
bool operator==(const IPv4Address& rhs) const {
return ip_addr_ == rhs.ip_addr_;
}
/**
@@ -113,7 +113,7 @@ public:
* \return bool indicating whether this address is distinct
* from rhs.
*/
bool operator!=(const IPv4Address &rhs) const {
bool operator!=(const IPv4Address& rhs) const {
return !(*this == rhs);
}
@@ -123,8 +123,8 @@ public:
* \param rhs The address to be compared.
* \return bool indicating whether this address is less-than rhs.
*/
bool operator< (const IPv4Address &rhs) const {
return ip_addr < rhs.ip_addr;
bool operator< (const IPv4Address& rhs) const {
return ip_addr_ < rhs.ip_addr_;
}
/**
@@ -176,25 +176,27 @@ public:
* \param addr The IPv4Address to be written.
* \return std::stream& pointing to output.
*/
friend std::ostream &operator<<(std::ostream &output, const IPv4Address &addr);
friend std::ostream& operator<<(std::ostream& output, const IPv4Address& addr);
private:
uint32_t ip_to_int(const char* ip);
uint32_t ip_addr;
uint32_t ip_addr_;
};
} //namespace Tins
} // Tins
#if TINS_IS_CXX11
namespace std
{
namespace std {
template<>
struct hash<Tins::IPv4Address> {
size_t operator()(const Tins::IPv4Address &addr) const {
size_t operator()(const Tins::IPv4Address& addr) const {
return std::hash<uint32_t>()(addr);
}
};
} // namespace std
#endif
} // std
#endif // TINS_IS_CXX11
#endif // TINS_IPADDRESS_H

View File

@@ -37,6 +37,7 @@
#include "ip_address.h"
namespace Tins {
/**
* \cond
*/
@@ -49,13 +50,12 @@ public:
IPv4Fragment() : offset_() { }
template<typename T>
IPv4Fragment(T *pdu, uint16_t offset)
: payload_(pdu->serialize()), offset_(offset)
{
IPv4Fragment(T* pdu, uint16_t offset)
: payload_(pdu->serialize()), offset_(offset) {
}
const payload_type &payload() const {
const payload_type& payload() const {
return payload_;
}
@@ -71,19 +71,19 @@ class TINS_API IPv4Stream {
public:
IPv4Stream();
void add_fragment(IP *ip);
void add_fragment(IP* ip);
bool is_complete() const;
PDU *allocate_pdu() const;
PDU* allocate_pdu() const;
private:
typedef std::vector<IPv4Fragment> fragments_type;
uint16_t extract_offset(const IP *ip);
bool extract_more_frag(const IP *ip);
uint16_t extract_offset(const IP* ip);
bool extract_more_frag(const IP* ip);
fragments_type fragments;
bool received_end;
uint8_t transport_proto;
size_t received_size, total_size;
fragments_type fragments_;
bool received_end_;
uint8_t transport_proto_;
size_t received_size_, total_size_;
};
} // namespace Internals
@@ -134,7 +134,7 @@ public:
* fragmented or REASSEMBLED if the packet was fragmented
* but has now been reassembled.
*/
packet_status process(PDU &pdu);
packet_status process(PDU& pdu);
/**
* Removes all of the packets and data stored.
@@ -157,11 +157,11 @@ private:
typedef std::pair<uint16_t, address_pair> key_type;
typedef std::map<key_type, Internals::IPv4Stream> streams_type;
key_type make_key(const IP *ip) const;
key_type make_key(const IP* ip) const;
address_pair make_address_pair(IPv4Address addr1, IPv4Address addr2) const;
streams_type streams;
overlapping_technique technique;
streams_type streams_;
overlapping_technique technique_;
};
/**
@@ -176,8 +176,7 @@ public:
* \param func The functor object.
*/
IPv4ReassemblerProxy(Functor func)
: functor_(func)
{
: functor_(func) {
}
@@ -189,15 +188,15 @@ public:
* \return true if the packet wasn't forwarded, otherwise
* the value returned by the functor.
*/
bool operator()(PDU &pdu) {
bool operator()(PDU& pdu) {
// Forward it unless it's fragmented.
if(reassembler.process(pdu) != IPv4Reassembler::FRAGMENTED)
if(reassembler_.process(pdu) != IPv4Reassembler::FRAGMENTED)
return functor_(pdu);
else
return true;
}
private:
IPv4Reassembler reassembler;
IPv4Reassembler reassembler_;
Functor functor_;
};

View File

@@ -36,6 +36,7 @@
#include "small_uint.h"
namespace Tins {
/**
* \class IPSecAH
* \brief Represents an IPSec Authentication Header.
@@ -66,7 +67,7 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
IPSecAH(const uint8_t *buffer, uint32_t total_sz);
IPSecAH(const uint8_t* buffer, uint32_t total_sz);
// Getters
@@ -75,7 +76,7 @@ public:
* \return The stored Next header field value.
*/
uint8_t next_header() const {
return _header.next_header;
return header_.next_header;
}
/**
@@ -83,7 +84,7 @@ public:
* \return The stored Length field value.
*/
uint8_t length() const {
return _header.length;
return header_.length;
}
/**
@@ -91,7 +92,7 @@ public:
* \return The stored Security Parameters Index field value.
*/
uint32_t spi() const {
return Endian::be_to_host(_header.spi);
return Endian::be_to_host(header_.spi);
}
/**
@@ -99,15 +100,15 @@ public:
* \return The stored Sequence number field value.
*/
uint32_t seq_number() const {
return Endian::be_to_host(_header.seq_number);
return Endian::be_to_host(header_.seq_number);
}
/**
* \brief Getter for the ICV field.
* \return The stored ICV field value.
*/
const byte_array &icv() const {
return _icv;
const byte_array& icv() const {
return icv_;
}
// Setters
@@ -138,9 +139,9 @@ public:
/**
* \brief Setter for the ICV field.
* \param new_icv The new ICV field value.
* \param newicv_ The new ICV field value.
*/
void icv(const byte_array &new_icv);
void icv(const byte_array& newicv_);
/**
* \brief Returns the header size.
@@ -158,19 +159,19 @@ public:
/**
* \sa PDU::clone
*/
IPSecAH *clone() const {
IPSecAH* clone() const {
return new IPSecAH(*this);
}
private:
struct header {
struct ipsec_header {
uint8_t next_header, length;
uint32_t spi, seq_number;
};
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *);
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *);
header _header;
byte_array _icv;
ipsec_header header_;
byte_array icv_;
};
/**
@@ -199,7 +200,7 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
IPSecESP(const uint8_t *buffer, uint32_t total_sz);
IPSecESP(const uint8_t* buffer, uint32_t total_sz);
// Getters
@@ -208,7 +209,7 @@ public:
* \return The stored Security Parameters Index field value.
*/
uint32_t spi() const {
return Endian::be_to_host(_header.spi);
return Endian::be_to_host(header_.spi);
}
/**
@@ -216,7 +217,7 @@ public:
* \return The stored Sequence number field value.
*/
uint32_t seq_number() const {
return Endian::be_to_host(_header.seq_number);
return Endian::be_to_host(header_.seq_number);
}
// Setters
@@ -249,17 +250,17 @@ public:
/**
* \sa PDU::clone
*/
IPSecESP *clone() const {
IPSecESP* clone() const {
return new IPSecESP(*this);
}
private:
struct header {
struct ipsec_header {
uint32_t spi, seq_number;
};
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *);
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *);
header _header;
ipsec_header header_;
};
}

View File

@@ -41,7 +41,9 @@
namespace Tins {
namespace Memory {
class OutputMemoryStream;
} // Memory
class PacketSender;
@@ -96,8 +98,8 @@ public:
* for the packet being constructed(optional).
*/
IPv6(address_type ip_dst = address_type(),
address_type ip_src = address_type(),
PDU *child = 0);
address_type ip_src = address_type(),
PDU* child = 0);
/**
* \brief Constructs an IPv6 object from a buffer and adds all
@@ -109,7 +111,7 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
IPv6(const uint8_t *buffer, uint32_t total_sz);
IPv6(const uint8_t* buffer, uint32_t total_sz);
// Getters
@@ -118,7 +120,7 @@ public:
* \return The stored version field value.
*/
small_uint<4> version() const {
return _header.version;
return header_.version;
}
/**
@@ -127,10 +129,10 @@ public:
*/
uint8_t traffic_class() const {
#if TINS_IS_LITTLE_ENDIAN
return ((_header.traffic_class << 4) & 0xf0) |
((_header.flow_label[0] >> 4) & 0x0f);
return ((header_.traffic_class << 4) & 0xf0) |
((header_.flow_label[0] >> 4) & 0x0f);
#else
return _header.traffic_class;
return header_.traffic_class;
#endif
}
@@ -140,11 +142,11 @@ public:
*/
small_uint<20> flow_label() const {
#if TINS_IS_LITTLE_ENDIAN
return ((_header.flow_label[0] & 0x0f) << 16)
| (_header.flow_label[1] << 8)
| (_header.flow_label[2]);
return ((header_.flow_label[0] & 0x0f) << 16)
| (header_.flow_label[1] << 8)
| (header_.flow_label[2]);
#else
return _header.flow_label;
return header_.flow_label;
#endif
}
@@ -153,7 +155,7 @@ public:
* \return The stored payload_length field value.
*/
uint16_t payload_length() const {
return Endian::be_to_host(_header.payload_length);
return Endian::be_to_host(header_.payload_length);
}
/**
@@ -161,7 +163,7 @@ public:
* \return The stored next_header field value.
*/
uint8_t next_header() const {
return _header.next_header;
return header_.next_header;
}
/**
@@ -169,7 +171,7 @@ public:
* \return The stored hop_limit field value.
*/
uint8_t hop_limit() const {
return _header.hop_limit;
return header_.hop_limit;
}
/**
@@ -177,7 +179,7 @@ public:
* \return The stored src_addr field value.
*/
address_type src_addr() const {
return _header.src_addr;
return header_.src_addr;
}
/**
@@ -185,7 +187,7 @@ public:
* \return The stored dst_addr field value.
*/
address_type dst_addr() const {
return _header.dst_addr;
return header_.dst_addr;
}
/**
@@ -193,7 +195,7 @@ public:
* \return The stored headers.
*/
const headers_type& headers() const {
return ext_headers;
return ext_headers_;
}
// Setters
@@ -238,13 +240,13 @@ public:
* \brief Setter for the src_addr field.
* \param new_src_addr The new src_addr field value.
*/
void src_addr(const address_type &new_src_addr);
void src_addr(const address_type& new_src_addr);
/**
* \brief Setter for the dst_addr field.
* \param new_dst_addr The new dst_addr field value.
*/
void dst_addr(const address_type &new_dst_addr);
void dst_addr(const address_type& new_dst_addr);
/**
* \brief Returns the header size.
@@ -260,12 +262,12 @@ public:
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
bool matches_response(const uint8_t* ptr, uint32_t total_sz) const;
/**
* \sa PDU::clone
*/
IPv6 *clone() const {
IPv6* clone() const {
return new IPv6(*this);
}
@@ -279,7 +281,7 @@ public:
/**
* \sa PDU::send()
*/
void send(PacketSender &sender, const NetworkInterface &);
void send(PacketSender& sender, const NetworkInterface &);
#endif
/**
@@ -287,7 +289,7 @@ public:
*
* \param header The extension header to be added.
*/
void add_ext_header(const ext_header &header);
void add_ext_header(const ext_header& header);
/**
* \brief Searchs for an extension header that matchs the given
@@ -299,11 +301,11 @@ public:
*
* \param id The header identifier to be searched.
*/
const ext_header *search_header(ExtensionHeader id) const;
const ext_header* search_header(ExtensionHeader id) const;
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
void set_last_next_header(uint8_t value);
static void write_header(const ext_header &header, Memory::OutputMemoryStream& stream);
static void write_header(const ext_header& header, Memory::OutputMemoryStream& stream);
static bool is_extension_header(uint8_t header_id);
TINS_BEGIN_PACK
@@ -326,9 +328,9 @@ private:
uint8_t src_addr[16], dst_addr[16];
} TINS_END_PACK;
ipv6_header _header;
headers_type ext_headers;
uint32_t headers_size;
ipv6_header header_;
headers_type ext_headers_;
uint32_t headers_size_;
};
}

View File

@@ -43,16 +43,6 @@ namespace Tins {
*/
class TINS_API IPv6Address {
public:
/**
* The exception thrown when a malformed address is parsed.
*/
class malformed_address : public std::exception {
public:
const char *what() const throw() {
return "Malformed address";
}
};
static const size_t address_size = 16;
/**
@@ -76,14 +66,14 @@ public:
* \param addr The text representation from which to construct this
* object.
*/
IPv6Address(const char *addr);
IPv6Address(const char* addr);
/**
* \brief Constructor from a text representation std::string.
* \param addr The text representation from which to construct this
* object.
*/
IPv6Address(const std::string &addr);
IPv6Address(const std::string& addr);
/**
* \brief Constructor from a buffer.
@@ -105,21 +95,21 @@ public:
* Returns an iterator to the beginning of this address.
*/
iterator begin() {
return address;
return address_;
}
/**
* Returns a const iterator to the beginning of this address.
*/
const_iterator begin() const {
return address;
return address_;
}
/**
* Returns an iterator to the one-past-the-end element of this address.
*/
iterator end() {
return address + address_size;
return address_ + address_size;
}
/**
@@ -127,7 +117,7 @@ public:
* address.
*/
const_iterator end() const {
return address + address_size;
return address_ + address_size;
}
/**
@@ -137,8 +127,8 @@ public:
*
* \return bool indicating whether addresses are equal.
*/
bool operator==(const IPv6Address &rhs) const {
return std::equal(begin(), end(), rhs.address);
bool operator==(const IPv6Address& rhs) const {
return std::equal(begin(), end(), rhs.address_);
}
/**
@@ -148,7 +138,7 @@ public:
*
* \return bool indicating whether addresses are distinct.
*/
bool operator!=(const IPv6Address &rhs) const {
bool operator!=(const IPv6Address& rhs) const {
return !(*this == rhs);
}
@@ -159,7 +149,7 @@ public:
*
* \return bool indicating whether this address is less-than rhs.
*/
bool operator<(const IPv6Address &rhs) const {
bool operator<(const IPv6Address& rhs) const {
return std::lexicographical_compare(begin(), end(), rhs.begin(), rhs.end());
}
@@ -206,26 +196,29 @@ public:
* \param addr The parameter to be written.
* \return std::ostream& pointing to the os parameter.
*/
friend std::ostream &operator<<(std::ostream &os, const IPv6Address &addr) {
friend std::ostream& operator<<(std::ostream& os, const IPv6Address& addr) {
return os << addr.to_string();
}
private:
void init(const char *addr);
void init(const char* addr);
uint8_t address[address_size];
uint8_t address_[address_size];
};
} //namespace Tins
} // Tins
#if TINS_IS_CXX11
namespace std
{
namespace std {
template<>
struct hash<Tins::IPv6Address> {
size_t operator()(const Tins::IPv6Address &addr) const {
size_t operator()(const Tins::IPv6Address& addr) const {
return std::hash<std::string>()(addr.to_string());
}
};
} // namespace std
#endif
} // std
#endif // TINS_IS_CXX11
#endif // TINS_IPV6_ADDRESS

View File

@@ -40,366 +40,382 @@
namespace Tins {
/**
* \class LLC
* \brief Representing a LLC frame.
*
* This PDU follows the standard LLC frame described in the IEEE 802.2 specs.
*/
class TINS_API LLC : public PDU {
public:
/**
* \class LLC
* \brief Representing a LLC frame.
*
* This PDU follows the standard LLC frame described in the IEEE 802.2 specs.
* \brief This PDU's flag.
*/
class TINS_API LLC : public PDU {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::LLC;
static const PDU::PDUType pdu_flag = PDU::LLC;
/**
* \brief Represents the LLC global DSAP address.
*/
static const uint8_t GLOBAL_DSAP_ADDR;
/**
* \brief Represents the LLC NULL address.
*/
static const uint8_t NULL_ADDR;
/**
* \brief Represents the LLC global DSAP address.
*/
static const uint8_t GLOBAL_DSAP_ADDR;
/**
* \brief Represents the LLC NULL address.
*/
static const uint8_t NULL_ADDR;
/**
* \brief LLC Format flags.
*/
enum Format {
INFORMATION = 0,
SUPERVISORY = 1,
UNNUMBERED = 3
};
/**
* \brief LLC Modifier functions.
*/
enum ModifierFunctions {
UI = 0x00,
XID = 0x1D,
TEST = 0x07,
SABME = 0x1E,
DISC = 0x02,
UA = 0x06,
DM = 0x18,
FRMR = 0x11
};
/**
* \brief LLC Supervisory functions
*/
enum SupervisoryFunctions {
RECEIVE_READY = 0,
REJECT = 2,
RECEIVE_NOT_READY = 1
};
/**
* \brief Default constructor.
*/
LLC();
/**
* \brief Constructs an instance of LLC, setting the dsap and ssap.
* The control field is set to 0.
* \param dsap The dsap value to be set.
* \param ssap The ssap value to be set.
*/
LLC(uint8_t dsap, uint8_t ssap);
/**
* \brief Constructs a LLC object from a buffer and adds all
* identifiable PDUs found in the buffer as children of this one.
*
* If there is not enough size for a LLC header, a malformed_packet
* exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
LLC(const uint8_t *buffer, uint32_t total_sz);
/* Setters */
/**
* \brief Setter for the group destination bit.
* \param value The value to be set.
*/
void group(bool value);
/**
* \brief Setter for the dsap field.
* \param new_dsap The new dsap field.
*/
void dsap(uint8_t new_dsap);
/**
* \brief Setter for the response bit.
* \param value The value to be set.
*/
void response(bool value);
/**
* \brief Setter for the ssap field.
* \param new_ssap The new ssap field.
*/
void ssap(uint8_t new_ssap);
/**
* \brief Setter for the LLC frame format type.
* \param type The LLC frame format to set.
*/
void type(Format type);
/**
* \brief Setter for sender send sequence number.
* Only applied if format is INFORMATION.
* \param seq_number New sender send sequence number to be set.
*/
void send_seq_number(uint8_t seq_number);
/**
* \brief Setter for sender receive sequence number.
* Only applied if format is INFORMATION or SUPERVISORY.
* \param seq_number New sender receive sequence number to be set.
*/
void receive_seq_number(uint8_t seq_number);
/**
* \brief Setter for the poll/final flag.
* \param value Bool indicating the value of the flag.
*/
void poll_final(bool value);
/**
* \brief Setter for the supervisory function.
* Only applied if format is SUPERVISORY.
* \param new_func Value to set on the supervisory function field.
*/
void supervisory_function(SupervisoryFunctions new_func);
/**
* \brief Setter for the modifier function field.
* Only applied if format is UNNUMBERED.
* \param modifier_func Value to set on the modifier function field.
*/
void modifier_function(ModifierFunctions mod_func);
/**
* \brief Add a xid information field.
* Only applied if format is UNNUMBERED and function is XID.
* \param xid_id XID information of the MAC sublayer.
* \param llc_type_class Value to set the llc_type_class field.
* \param receive_window XID sender's receive window size.
*/
void add_xid_information(uint8_t xid_id, uint8_t llc_type_class, uint8_t receive_window);
//TODO: Add Acknowledged connectionless information
/* Getters */
/**
* \brief Getter for the group destination bit.
* \return Whether the group bit is set or not.
*/
bool group() {return _header.dsap & 0x01; }
/**
* \brief Getter for the dsap field.
* \return The dsap field value
*/
uint8_t dsap() {return _header.dsap; }
/**
* \brief Getter for the response bit.
* \return Whether the response bit is set or not.
*/
bool response() {return (_header.ssap & 0x01); }
/**
* \brief Getter for the ssap field.
* \return The ssap field.
*/
uint8_t ssap() {return _header.ssap; }
/**
* \brief Getter for the LLC frame format type.
* \return The LLC frame format.
*/
uint8_t type() {return _type; }
/**
* \brief Getter for sender send sequence number.
*
* \return The sender send sequence number if format is INFORMATION else 0.
*/
uint8_t send_seq_number() {
return (type() == INFORMATION) ? (control_field.info.send_seq_num) : 0;
}
/**
* \brief Getter for sender receive sequence number.
*
* \return The sender receive sequence number if format is
* INFORMATION or SUPERVISORY else 0.
*/
uint8_t receive_seq_number() {
switch (type()) {
case INFORMATION:
return control_field.info.recv_seq_num;
case SUPERVISORY:
return control_field.super.recv_seq_num;
case UNNUMBERED:
return 0;
default:
return 0;
}
}
/**
* \brief Getter for the poll/final flag.
* \return Whether the poll/final flag is set.
*/
bool poll_final() {
switch (type()) {
case UNNUMBERED:
return control_field.unnumbered.poll_final_bit;
case INFORMATION:
return control_field.info.poll_final_bit;
case SUPERVISORY:
return control_field.super.poll_final_bit;
default:
return false;
}
}
/**
* \brief Getter for the supervisory function.
*
* \return The supervisory function if format is SUPERVISORY else 0.
*/
uint8_t supervisory_function() {
if (type() == SUPERVISORY)
return control_field.super.supervisory_func;
return 0;
}
/**
* \brief Getter for the modifier function field.
*
* \return The modifier function if format is UNNUMBERED else 0.
*/
uint8_t modifier_function() {
if (type() == UNNUMBERED)
return (control_field.unnumbered.mod_func1 << 3) + control_field.unnumbered.mod_func2;
return 0;
}
/**
* \brief Returns the LLC frame's header length.
*
* \return The header's size.
* \sa PDU::header_size()
*/
uint32_t header_size() const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Delete all the information fields added.
*/
void clear_information_fields();
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
LLC *clone() const {
return new LLC(*this);
}
private:
TINS_BEGIN_PACK
struct llchdr {
uint8_t dsap;
uint8_t ssap;
} TINS_END_PACK;
#if TINS_IS_LITTLE_ENDIAN
TINS_BEGIN_PACK
struct info_control_field {
uint16_t
type_bit:1,
send_seq_num:7,
poll_final_bit:1,
recv_seq_num:7;
} TINS_END_PACK;
TINS_BEGIN_PACK
struct super_control_field {
uint16_t type_bit:2,
supervisory_func:2,
unused:4,
poll_final_bit:1,
recv_seq_num:7;
} TINS_END_PACK;
TINS_BEGIN_PACK
struct un_control_field {
uint8_t type_bits:2,
mod_func1:2,
poll_final_bit:1,
mod_func2:3;
} TINS_END_PACK;
#elif TINS_IS_BIG_ENDIAN
TINS_BEGIN_PACK
struct info_control_field {
uint16_t send_seq_num:7,
type_bit:1,
recv_seq_num:7,
poll_final_bit:1;
} TINS_END_PACK;
TINS_BEGIN_PACK
struct super_control_field {
uint16_t unused:4,
supervisory_func:2,
type_bit:2,
recv_seq_num:7,
poll_final_bit:1;
} TINS_END_PACK;
TINS_BEGIN_PACK
struct un_control_field {
uint8_t mod_func2:3,
poll_final_bit:1,
mod_func1:2,
type_bits:2;
} TINS_END_PACK;
#endif
typedef std::vector<uint8_t> field_type;
typedef std::list<field_type> field_list;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
llchdr _header;
uint8_t control_field_length;
union {
info_control_field info;
super_control_field super;
un_control_field unnumbered;
} control_field;
Format _type;
uint8_t information_field_length;
field_list information_fields;
/**
* \brief LLC Format flags.
*/
enum Format {
INFORMATION = 0,
SUPERVISORY = 1,
UNNUMBERED = 3
};
}
/**
* \brief LLC Modifier functions.
*/
enum ModifierFunctions {
UI = 0x00,
XID = 0x1D,
TEST = 0x07,
SABME = 0x1E,
DISC = 0x02,
UA = 0x06,
DM = 0x18,
FRMR = 0x11
};
/**
* \brief LLC Supervisory functions
*/
enum SupervisoryFunctions {
RECEIVE_READY = 0,
REJECT = 2,
RECEIVE_NOT_READY = 1
};
/**
* \brief Default constructor.
*/
LLC();
/**
* \brief Constructs an instance of LLC, setting the dsap and ssap.
* The control field is set to 0.
* \param dsap The dsap value to be set.
* \param ssap The ssap value to be set.
*/
LLC(uint8_t dsap, uint8_t ssap);
/**
* \brief Constructs a LLC object from a buffer and adds all
* identifiable PDUs found in the buffer as children of this one.
*
* If there is not enough size for a LLC header, a malformed_packet
* exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
LLC(const uint8_t* buffer, uint32_t total_sz);
/* Setters */
/**
* \brief Setter for the group destination bit.
* \param value The value to be set.
*/
void group(bool value);
/**
* \brief Setter for the dsap field.
* \param new_dsap The new dsap field.
*/
void dsap(uint8_t new_dsap);
/**
* \brief Setter for the response bit.
* \param value The value to be set.
*/
void response(bool value);
/**
* \brief Setter for the ssap field.
* \param new_ssap The new ssap field.
*/
void ssap(uint8_t new_ssap);
/**
* \brief Setter for the LLC frame format type.
* \param type The LLC frame format to set.
*/
void type(Format type);
/**
* \brief Setter for sender send sequence number.
* Only applied if format is INFORMATION.
* \param seq_number New sender send sequence number to be set.
*/
void send_seq_number(uint8_t seq_number);
/**
* \brief Setter for sender receive sequence number.
* Only applied if format is INFORMATION or SUPERVISORY.
* \param seq_number New sender receive sequence number to be set.
*/
void receive_seq_number(uint8_t seq_number);
/**
* \brief Setter for the poll/final flag.
* \param value Bool indicating the value of the flag.
*/
void poll_final(bool value);
/**
* \brief Setter for the supervisory function.
* Only applied if format is SUPERVISORY.
* \param new_func Value to set on the supervisory function field.
*/
void supervisory_function(SupervisoryFunctions new_func);
/**
* \brief Setter for the modifier function field.
* Only applied if format is UNNUMBERED.
* \param modifier_func Value to set on the modifier function field.
*/
void modifier_function(ModifierFunctions mod_func);
/**
* \brief Add a xid information field.
* Only applied if format is UNNUMBERED and function is XID.
* \param xid_id XID information of the MAC sublayer.
* \param llc_type_class Value to set the llc_type_class field.
* \param receive_window XID sender's receive window size.
*/
void add_xid_information(uint8_t xid_id,
uint8_t llc_type_class,
uint8_t receive_window);
//TODO: Add Acknowledged connectionless information
/* Getters */
/**
* \brief Getter for the group destination bit.
* \return Whether the group bit is set or not.
*/
bool group() {
return header_.dsap & 0x01;
}
/**
* \brief Getter for the dsap field.
* \return The dsap field value
*/
uint8_t dsap() {
return header_.dsap;
}
/**
* \brief Getter for the response bit.
* \return Whether the response bit is set or not.
*/
bool response() {
return (header_.ssap & 0x01);
}
/**
* \brief Getter for the ssap field.
* \return The ssap field.
*/
uint8_t ssap() {
return header_.ssap;
}
/**
* \brief Getter for the LLC frame format type.
* \return The LLC frame format.
*/
uint8_t type() {
return type_;
}
/**
* \brief Getter for sender send sequence number.
*
* \return The sender send sequence number if format is INFORMATION else 0.
*/
uint8_t send_seq_number() {
return (type() == INFORMATION) ? (control_field.info.send_seq_num) : 0;
}
/**
* \brief Getter for sender receive sequence number.
*
* \return The sender receive sequence number if format is
* INFORMATION or SUPERVISORY else 0.
*/
uint8_t receive_seq_number() {
switch (type()) {
case INFORMATION:
return control_field.info.recv_seq_num;
case SUPERVISORY:
return control_field.super.recv_seq_num;
case UNNUMBERED:
return 0;
default:
return 0;
}
}
/**
* \brief Getter for the poll/final flag.
* \return Whether the poll/final flag is set.
*/
bool poll_final() {
switch (type()) {
case UNNUMBERED:
return control_field.unnumbered.poll_final_bit;
case INFORMATION:
return control_field.info.poll_final_bit;
case SUPERVISORY:
return control_field.super.poll_final_bit;
default:
return false;
}
}
/**
* \brief Getter for the supervisory function.
*
* \return The supervisory function if format is SUPERVISORY else 0.
*/
uint8_t supervisory_function() {
if (type() == SUPERVISORY) {
return control_field.super.supervisory_func;
}
return 0;
}
/**
* \brief Getter for the modifier function field.
*
* \return The modifier function if format is UNNUMBERED else 0.
*/
uint8_t modifier_function() {
if (type() == UNNUMBERED) {
return (control_field.unnumbered.mod_func1 << 3) + control_field.unnumbered.mod_func2;
}
return 0;
}
/**
* \brief Returns the LLC frame's header length.
*
* \return The header's size.
* \sa PDU::header_size()
*/
uint32_t header_size() const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Delete all the information fields added.
*/
void clear_information_fields();
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
LLC* clone() const {
return new LLC(*this);
}
private:
TINS_BEGIN_PACK
struct llchdr {
uint8_t dsap;
uint8_t ssap;
} TINS_END_PACK;
#if TINS_IS_LITTLE_ENDIAN
TINS_BEGIN_PACK
struct info_control_field {
uint16_t
type_bit:1,
send_seq_num:7,
poll_final_bit:1,
recv_seq_num:7;
} TINS_END_PACK;
TINS_BEGIN_PACK
struct super_control_field {
uint16_t type_bit:2,
supervisory_func:2,
unused:4,
poll_final_bit:1,
recv_seq_num:7;
} TINS_END_PACK;
TINS_BEGIN_PACK
struct un_control_field {
uint8_t type_bits:2,
mod_func1:2,
poll_final_bit:1,
mod_func2:3;
} TINS_END_PACK;
#elif TINS_IS_BIG_ENDIAN
TINS_BEGIN_PACK
struct info_control_field {
uint16_t send_seq_num:7,
type_bit:1,
recv_seq_num:7,
poll_final_bit:1;
} TINS_END_PACK;
TINS_BEGIN_PACK
struct super_control_field {
uint16_t unused:4,
supervisory_func:2,
type_bit:2,
recv_seq_num:7,
poll_final_bit:1;
} TINS_END_PACK;
TINS_BEGIN_PACK
struct un_control_field {
uint8_t mod_func2:3,
poll_final_bit:1,
mod_func1:2,
type_bits:2;
} TINS_END_PACK;
#endif
typedef std::vector<uint8_t> field_type;
typedef std::list<field_type> field_list;
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
llchdr header_;
uint8_t control_field_length_;
union {
info_control_field info;
super_control_field super;
un_control_field unnumbered;
} control_field;
Format type_;
uint8_t information_field_length_;
field_list information_fields_;
};
} // Tins
#endif // TINS_IEEE8022_H

View File

@@ -34,6 +34,10 @@
#include "macros.h"
namespace Tins {
/**
* \brief Represents a Loopback PDU
*/
class TINS_API Loopback : public PDU {
public:
/**
@@ -61,13 +65,15 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
Loopback(const uint8_t *buffer, uint32_t total_sz);
Loopback(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Getter for the family identifier.
* \return The stored family identifier.
*/
uint32_t family() const { return _family; }
uint32_t family() const {
return family_;
}
/**
* \brief Setter for the family identifier.
@@ -84,7 +90,9 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Check wether ptr points to a valid response for this PDU.
@@ -93,26 +101,27 @@ public:
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
bool matches_response(const uint8_t* ptr, uint32_t total_sz) const;
/**
* \sa PDU::clone
*/
Loopback *clone() const {
Loopback* clone() const {
return new Loopback(*this);
}
// Null/Loopback can only be sent in *BSD
// Null/Loopback can only be sent in* BSD
#ifdef BSD
/**
* \sa PDU::send()
*/
void send(PacketSender &sender, const NetworkInterface &iface);
void send(PacketSender& sender, const NetworkInterface& iface);
#endif // BSD
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
uint32_t _family;
uint32_t family_;
};
}
} // Tins
#endif // TINS_LOOPBACK_H

View File

@@ -38,6 +38,7 @@
#include "ip_address.h"
#include "ipv6_address.h"
#include "hw_address.h"
#include "endianness.h"
namespace Tins {
namespace Memory {
@@ -71,6 +72,9 @@ public:
}
void skip(uint32_t size) {
if (TINS_UNLIKELY(size > size_)) {
throw malformed_packet();
}
buffer_ += size;
size_ -= size;
}
@@ -86,6 +90,16 @@ public:
return output;
}
template <typename T>
T read_le() {
return Endian::le_to_host(read<T>());
}
template <typename T>
T read_be() {
return Endian::be_to_host(read<T>());
}
template <typename T>
void read(T& value) {
if (!can_read(sizeof(value))) {
@@ -95,6 +109,14 @@ public:
skip(sizeof(value));
}
void read(std::vector<uint8_t>& value, size_t count) {
if (!can_read(count)) {
throw malformed_packet();
}
value.assign(pointer(), pointer() + count);
skip(count);
}
void read(IPv4Address& address) {
address = IPv4Address(read<uint32_t>());
}
@@ -150,7 +172,14 @@ public:
: buffer_(buffer), size_(total_sz) {
}
OutputMemoryStream(std::vector<uint8_t>& buffer)
: buffer_(&buffer[0]), size_(buffer.size()) {
}
void skip(uint32_t size) {
if (TINS_UNLIKELY(size > size_)) {
throw malformed_packet();
}
buffer_ += size;
size_ -= size;
}
@@ -164,6 +193,16 @@ public:
skip(sizeof(value));
}
template <typename T>
void write_be(const T& value) {
write(Endian::host_to_be(value));
}
template <typename T>
void write_le(const T& value) {
write(Endian::host_to_le(value));
}
template <typename ForwardIterator>
void write(ForwardIterator start, ForwardIterator end) {
const uint32_t length = std::distance(start, end);

View File

@@ -128,12 +128,14 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \sa PDU::clone
*/
MPLS *clone() const {
MPLS* clone() const {
return new MPLS(*this);
}
private:
@@ -144,7 +146,7 @@ private:
uint8_t ttl;
} TINS_END_PACK;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
mpls_header header_;
};

View File

@@ -38,6 +38,7 @@
#include "ip_address.h"
namespace Tins {
/**
* \class NetworkInterface
* \brief Abstraction of a network interface
@@ -89,14 +90,14 @@ public:
*
* \param name The name of the interface this object will abstract.
*/
NetworkInterface(const std::string &name);
NetworkInterface(const std::string& name);
/**
* \brief Constructor from const char*.
*
* \param name The name of the interface this object will abstract.
*/
NetworkInterface(const char *name);
NetworkInterface(const char* name);
/**
* \brief Constructs a NetworkInterface from an ip address.
@@ -114,7 +115,7 @@ public:
* \return id_type containing the identifier.
*/
id_type id() const {
return iface_id;
return iface_id_;
}
/**
@@ -153,7 +154,7 @@ public:
* default constructor.
*/
operator bool() const {
return iface_id != 0;
return iface_id_ != 0;
}
/**
@@ -175,8 +176,8 @@ public:
*
* \param rhs The interface being compared.
*/
bool operator==(const NetworkInterface &rhs) const {
return iface_id == rhs.iface_id;
bool operator==(const NetworkInterface& rhs) const {
return iface_id_ == rhs.iface_id_;
}
/**
@@ -184,13 +185,15 @@ public:
*
* \param rhs The interface being compared.
*/
bool operator!=(const NetworkInterface &rhs) const {
bool operator!=(const NetworkInterface& rhs) const {
return !(*this == rhs);
}
private:
id_type resolve_index(const char *name);
id_type resolve_index(const char* name);
id_type iface_id;
id_type iface_id_;
};
}
} // Tins
#endif // TINS_NETWORK_INTERFACE_H

View File

@@ -36,6 +36,7 @@
#include "macros.h"
namespace Tins {
class PDU;
/**
@@ -85,10 +86,10 @@ public:
* \param snap_len The snapshot length to use.
*/
template<typename T>
OfflinePacketFilter(const std::string& filter, const DataLinkType<T>& lt,
unsigned int snap_len = 65535)
: string_filter(filter)
{
OfflinePacketFilter(const std::string& filter,
const DataLinkType<T>& lt,
unsigned int snap_len = 65535)
: string_filter_(filter) {
init(filter, lt.get_type(), snap_len);
}
@@ -149,9 +150,9 @@ private:
unsigned int snap_len);
pcap_t* handle;
mutable bpf_program filter;
std::string string_filter;
pcap_t* handle_;
mutable bpf_program filter_;
std::string string_filter_;
};
} // Tins

View File

@@ -39,6 +39,7 @@
* \namespace Tins
*/
namespace Tins {
template<typename WrappedType, typename TimestampType>
class PacketWrapper;
@@ -101,20 +102,20 @@ public:
* This is the timestamp in which the packet was taken out of the
* network interface/pcap file.
*/
const Timestamp &timestamp() const {
const Timestamp& timestamp() const {
return ts_;
}
private:
friend class BaseSniffer;
friend class SnifferIterator;
PacketWrapper(pdu_type pdu, const Timestamp &ts)
PacketWrapper(pdu_type pdu, const Timestamp& ts)
: pdu_(pdu), ts_(ts) {}
PacketWrapper(const PacketWrapper&);
PacketWrapper& operator=(const PacketWrapper&);
void* operator new (size_t size);
void operator delete (void *p);
void operator delete (void* p);
pdu_type pdu_;
timestamp_type ts_;
@@ -149,8 +150,8 @@ public:
*
* The PDU* is cloned using PDU::clone.
*/
Packet(const PDU *apdu, const Timestamp &tstamp)
: pdu_(apdu->clone()), ts(tstamp) { }
Packet(const PDU* apdu, const Timestamp& tstamp)
: pdu_(apdu->clone()), ts_(tstamp) { }
/**
* \brief Constructs a Packet from a PDU* and a Timestamp.
@@ -160,8 +161,8 @@ public:
* will be done automatically by the Packet when it goes out
* of scope.
*/
Packet(PDU *apdu, const Timestamp &tstamp, own_pdu)
: pdu_(apdu), ts(tstamp) { }
Packet(PDU* apdu, const Timestamp& tstamp, own_pdu)
: pdu_(apdu), ts_(tstamp) { }
/**
* \brief Constructs a Packet from a const PDU&.
@@ -171,8 +172,8 @@ public:
* This calls PDU::clone on the PDU parameter.
*
*/
Packet(const PDU &rhs)
: pdu_(rhs.clone()), ts(Timestamp::current_time()) { }
Packet(const PDU& rhs)
: pdu_(rhs.clone()), ts_(Timestamp::current_time()) { }
/**
* \brief Constructs a Packet from a RefPacket.
@@ -180,21 +181,21 @@ public:
* This calls PDU::clone on the RefPacket's PDU.
*
*/
Packet(const RefPacket &pck)
: pdu_(pck.pdu().clone()), ts(pck.timestamp()) { }
Packet(const RefPacket& pck)
: pdu_(pck.pdu().clone()), ts_(pck.timestamp()) { }
/**
* \brief Constructs a Packet from a PtrPacket object.
*/
Packet(const PtrPacket &pck)
: pdu_(pck.pdu()), ts(pck.timestamp()) { }
Packet(const PtrPacket& pck)
: pdu_(pck.pdu()), ts_(pck.timestamp()) { }
/**
* \brief Copy constructor.
*
* This calls PDU::clone on the rhs's PDU* member.
*/
Packet(const Packet &rhs) : ts(rhs.timestamp()) {
Packet(const Packet& rhs) : ts_(rhs.timestamp()) {
pdu_ = rhs.pdu() ? rhs.pdu()->clone() : 0;
}
@@ -203,20 +204,20 @@ public:
*
* This calls PDU::clone on the rhs's PDU* member.
*/
Packet& operator=(const Packet &rhs) {
if(this != &rhs) {
Packet& operator=(const Packet& rhs) {
if (this != &rhs) {
delete pdu_;
ts = rhs.timestamp();
ts_ = rhs.timestamp();
pdu_ = rhs.pdu() ? rhs.pdu()->clone() : 0;
}
return *this;
return* this;
}
#if TINS_IS_CXX11
/**
* Move constructor.
*/
Packet(Packet &&rhs) TINS_NOEXCEPT : pdu_(rhs.pdu()), ts(rhs.timestamp()) {
Packet(Packet &&rhs) TINS_NOEXCEPT : pdu_(rhs.pdu()), ts_(rhs.timestamp()) {
rhs.pdu_ = nullptr;
}
@@ -224,11 +225,11 @@ public:
* Move assignment operator.
*/
Packet& operator=(Packet &&rhs) TINS_NOEXCEPT {
if(this != &rhs) {
if (this != &rhs) {
std::swap(pdu_, rhs.pdu_);
ts = rhs.timestamp();
ts_ = rhs.timestamp();
}
return *this;
return* this;
}
#endif
@@ -244,8 +245,8 @@ public:
/**
* Returns this Packet's timestamp.
*/
const Timestamp &timestamp() const {
return ts;
const Timestamp& timestamp() const {
return ts_;
}
/**
@@ -253,7 +254,7 @@ public:
*
* Caller <b>must not</b> delete the pointer. \sa Packet::release_pdu
*/
PDU *pdu() {
PDU* pdu() {
return pdu_;
}
@@ -262,7 +263,7 @@ public:
*
* Caller <b>must not</b> delete the pointer. \sa Packet::release_pdu
*/
const PDU *pdu() const {
const PDU* pdu() const {
return pdu_;
}
@@ -275,8 +276,8 @@ public:
* when Packet's destructor is called, the stored pointer will be
* deleted.
*/
PDU *release_pdu() {
PDU *some_pdu = pdu_;
PDU* release_pdu() {
PDU* some_pdu = pdu_;
pdu_ = 0;
return some_pdu;
}
@@ -298,13 +299,13 @@ public:
*
* \param rhs The PDU to be appended.
*/
Packet &operator/=(const PDU &rhs) {
Packet& operator/=(const PDU& rhs) {
pdu_ /= rhs;
return *this;
return* this;
}
private:
PDU *pdu_;
Timestamp ts;
PDU* pdu_;
Timestamp ts_;
};
}

View File

@@ -48,377 +48,382 @@ struct timeval;
struct sockaddr;
namespace Tins {
class PDU;
class PDU;
/**
* \class PacketSender
* \brief Sends packets through a network interface.
*
* This class allows sending packets through a network interface.
* It can send basically two types of packets:
*
* - Those that contain a link layer PDU (EthernetII, SLL, etc). These
* will be serialized and sent through an interface that has to be
* specified. This can be done by providing it when you call
* PacketSender::send, or set a default one using
* PacketSender::default_interface.
* - Those that don't contain a link layer PDU. In this case, the
* kernel will be responsible for picking the appropriate network interface
* based on the destination address.
*
* \par Note for Windows users:
* Sending layer 3 PDUs (without a link layer protocol) is very restricted
* on Windows (<a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms740548(v=vs.85).aspx">link</a>).
* Therefore it's recommended you always send packets which contain link layer PDUs.
* This will use Winpcap's pcap_sendpacket to inject the packets.
*
* Sending packets can be done via PacketSender::send:
*
* \code
* // Construct a packet which uses an EthernetII link layer.
* EthernetII pkt1 = ...;
*
* // Construct a packet sender, which we'll use to send packets.
* PacketSender sender;
*
* // Send it through interface eth0
* sender.send(pkt1, "eth0");
*
* // Set the default interface to eth0
* sender.default_interface("eth0");
*
* // This is now equivalent to the previous send.
* sender.send(pkt1);
*
* // Construct a packet which has no link layer protocol.
* IP ip = IP("192.168.0.1") / TCP(22, 928);
*
* // Here the kernel will figure out which interface to use and it will
* // append the appropriate link layer protocol PDU. It will also perform
* // the necessary ARP lookups in order to use the destination host's
* // hardware address.
* //
* // libtins will find which is the appropriate source IP address to use.
* // This will be done by the kernel as well, but it's required when
* // calculating checksums.
* sender.send(ip);
* \endcode
*
* PacketSender also supports sending a packet and waiting for a response.
* This can be done by using PacketSender::send_recv.
*
* This class opens sockets as it needs to, and closes them when the object
* is destructed.
*
* \sa PacketSender::send
* \sa PacketSender::send_recv
*/
class TINS_API PacketSender {
public:
/**
* The default timeout for receive actions.
*/
static const uint32_t DEFAULT_TIMEOUT;
/**
* Flags to indicate the socket type.
*/
enum SocketType {
ETHER_SOCKET,
IP_TCP_SOCKET,
IP_UDP_SOCKET,
IP_RAW_SOCKET,
ARP_SOCKET,
ICMP_SOCKET,
IPV6_SOCKET,
SOCKETS_END
};
/**
* \brief Constructor for PacketSender objects.
*
* \param iface The default interface in which to send the packets.
* \param recv_timeout The timeout which will be used when receiving responses.
*/
PacketSender(const NetworkInterface& iface = NetworkInterface(),
uint32_t recv_timeout = DEFAULT_TIMEOUT,
uint32_t usec = 0);
#if TINS_IS_CXX11
/**
* \brief Move constructor.
* \param rhs The sender to be moved.
*/
PacketSender(PacketSender &&rhs) TINS_NOEXCEPT {
*this = std::move(rhs);
}
/**
* \brief Move assignment operator.
* \param rhs The sender to be moved.
*/
PacketSender& operator=(PacketSender &&rhs) TINS_NOEXCEPT {
sockets_ = std::move(rhs.sockets_);
rhs.sockets_ = std::vector<int>(SOCKETS_END, INVALID_RAW_SOCKET);
#ifndef _WIN32
#if defined(BSD) || defined(__FreeBSD_kernel__)
ether_socket_ = std::move(rhs.ether_socket_);
#else
ether_socket_ = rhs.ether_socket_;
rhs.ether_socket_ = INVALID_RAW_SOCKET;
#endif
#endif
types_ = rhs.types_; // no move
_timeout = rhs._timeout;
timeout_usec_ = rhs.timeout_usec_;
default_iface_ = rhs.default_iface_;
return* this;
}
#endif
/**
* \brief PacketSender destructor.
*
* This gracefully closes all open sockets.
*/
~PacketSender();
#if !defined(_WIN32) || defined(HAVE_PACKET_SENDER_PCAP_SENDPACKET)
/**
* \brief Opens a layer 2 socket.
*
* If this operation fails, then a socket_open_error will be thrown.
*/
void open_l2_socket(const NetworkInterface& iface = NetworkInterface());
#endif // !_WIN32 || defined(HAVE_PACKET_SENDER_PCAP_SENDPACKET)
/**
* \brief Opens a layer 3 socket, using the corresponding protocol
* for the given flag.
*
* If this operation fails, then a socket_open_error will be thrown.
* If the provided socket type is not valid, an invalid_socket_type
* exception will be throw.
*
* \param type The type of socket which will be used to pick the protocol flag
* for this socket.
*/
void open_l3_socket(SocketType type);
/**
* \brief Closes the socket associated with the given flag.
*
* If the provided type is invalid, meaning no such open socket
* exists, an invalid_socket_type exception is thrown.
*
* If any socket close errors are encountered, a socket_close_error
* is thrown.
*
* \param type The type of the socket to be closed.
*/
void close_socket(SocketType type, const NetworkInterface& iface = NetworkInterface());
/**
* \brief Sets the default interface.
*
* The interface will be used whenever PacketSender::send(PDU&)
* is called.
*/
void default_interface(const NetworkInterface& iface);
/**
* \class PacketSender
* \brief Sends packets through a network interface.
*
* This class allows sending packets through a network interface.
* It can send basically two types of packets:
*
* - Those that contain a link layer PDU (EthernetII, SLL, etc). These
* will be serialized and sent through an interface that has to be
* specified. This can be done by providing it when you call
* PacketSender::send, or set a default one using
* PacketSender::default_interface.
* - Those that don't contain a link layer PDU. In this case, the
* kernel will be responsible for picking the appropriate network interface
* based on the destination address.
*
* \par Note for Windows users:
* Sending layer 3 PDUs (without a link layer protocol) is very restricted
* on Windows (<a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms740548(v=vs.85).aspx">link</a>).
* Therefore it's recommended you always send packets which contain link layer PDUs.
* This will use Winpcap's pcap_sendpacket to inject the packets.
*
* Sending packets can be done via PacketSender::send:
*
* \code
* // Construct a packet which uses an EthernetII link layer.
* EthernetII pkt1 = ...;
*
* // Construct a packet sender, which we'll use to send packets.
* PacketSender sender;
* \brief Gets the default interface.
*
* // Send it through interface eth0
* sender.send(pkt1, "eth0");
*
* // Set the default interface to eth0
* sender.default_interface("eth0");
*
* // This is now equivalent to the previous send.
* sender.send(pkt1);
*
* // Construct a packet which has no link layer protocol.
* IP ip = IP("192.168.0.1") / TCP(22, 928);
*
* // Here the kernel will figure out which interface to use and it will
* // append the appropriate link layer protocol PDU. It will also perform
* // the necessary ARP lookups in order to use the destination host's
* // hardware address.
* //
* // libtins will find which is the appropriate source IP address to use.
* // This will be done by the kernel as well, but it's required when
* // calculating checksums.
* sender.send(ip);
* \endcode
*
* PacketSender also supports sending a packet and waiting for a response.
* This can be done by using PacketSender::send_recv.
*
* This class opens sockets as it needs to, and closes them when the object
* is destructed.
*
* \sa PacketSender::send
* \sa PacketSender::send_recv
* \sa PacketSender::default_interface
*/
class TINS_API PacketSender {
public:
/**
* The default timeout for receive actions.
*/
static const uint32_t DEFAULT_TIMEOUT;
const NetworkInterface& default_interface() const;
/**
* \brief Sends a PDU.
*
* This method opens the appropriate socket, if it's not open yet,
* and sends the PDU on the open socket.
*
* If any send error occurs, then a socket_write_error is thrown.
*
* If the PDU contains a link layer protocol, then default_interface
* is used.
*
* \sa PacketSender::default_interface
*
* \param pdu The PDU to be sent.
*/
void send(PDU& pdu);
/**
* Flags to indicate the socket type.
*/
enum SocketType {
ETHER_SOCKET,
IP_TCP_SOCKET,
IP_UDP_SOCKET,
IP_RAW_SOCKET,
ARP_SOCKET,
ICMP_SOCKET,
IPV6_SOCKET,
SOCKETS_END
};
/**
* \brief Sends a PDU.
*
* \sa PacketSender::send
*
* This overload takes a NetworkInterface. The packet is sent
* through that interface if a link-layer PDU is present,
* otherwise this call is equivalent to send(PDU&).
*
* The interface stored in the link layer PDU(if any), is restored
* after this method ends.
*
* \param pdu The PDU to be sent.
* \param iface The network interface to use.
*/
void send(PDU& pdu, const NetworkInterface& iface);
/**
* \brief Constructor for PacketSender objects.
*
* \param iface The default interface in which to send the packets.
* \param recv_timeout The timeout which will be used when receiving responses.
*/
PacketSender(const NetworkInterface &iface = NetworkInterface(),
uint32_t recv_timeout = DEFAULT_TIMEOUT, uint32_t usec = 0);
#if TINS_IS_CXX11
/**
* \brief Move constructor.
* \param rhs The sender to be moved.
*/
PacketSender(PacketSender &&rhs) TINS_NOEXCEPT {
*this = std::move(rhs);
}
/**
* \brief Move assignment operator.
* \param rhs The sender to be moved.
*/
PacketSender& operator=(PacketSender &&rhs) TINS_NOEXCEPT {
_sockets = std::move(rhs._sockets);
rhs._sockets = std::vector<int>(SOCKETS_END, INVALID_RAW_SOCKET);
#ifndef _WIN32
#if defined(BSD) || defined(__FreeBSD_kernel__)
_ether_socket = std::move(rhs._ether_socket);
#else
_ether_socket = rhs._ether_socket;
rhs._ether_socket = INVALID_RAW_SOCKET;
#endif
#endif
_types = rhs._types; // no move
_timeout = rhs._timeout;
_timeout_usec = rhs._timeout_usec;
default_iface = rhs.default_iface;
return *this;
}
#endif
/**
* \brief PacketSender destructor.
*
* This gracefully closes all open sockets.
*/
~PacketSender();
/**
* \brief Sends a PDU and waits for its response.
*
* This method is used to send PDUs and receive their response.
* The packet is sent, and then a response is awaited.
* PDU::matches_pdu is called on the packet sent in order to
* check whether a packet received is a response.
*
* This will match every response to a packet. For example,
* if you send a TCP packet, any response matching the same
* IP addresses and ports will be taken as a response to it.
* This also happens for other protocols, such as ARP, ICMP,
* DHCP, DNS, IP, etc.
*
* If you send a packet and get an ICMP response indicating
* an error (such as host unreachable, ttl exceeded, etc),
* that packet will be considered a response.
*
* \param pdu The PDU to send.
* \return Returns the response PDU, 0 if not response was received.
*/
PDU* send_recv(PDU& pdu);
/**
* \brief Sends a PDU and waits for its response.
*
* Sends a packet and receives a response. This overload takes
* a NetworkInterface.
*
* \sa PacketSender::send_recv(PDU&);
* \param pdu The PDU to send.
* \param iface The network interface in which to send and receive.
* \return Returns the response PDU, 0 if not response was received.
*/
PDU* send_recv(PDU& pdu, const NetworkInterface& iface);
#if !defined(_WIN32) || defined(HAVE_PACKET_SENDER_PCAP_SENDPACKET)
/**
* \brief Opens a layer 2 socket.
*
* If this operation fails, then a socket_open_error will be thrown.
*/
void open_l2_socket(const NetworkInterface& iface = NetworkInterface());
#endif // !_WIN32 || defined(HAVE_PACKET_SENDER_PCAP_SENDPACKET)
#ifndef _WIN32
/**
* \brief Receives a layer 2 PDU response to a previously sent PDU.
*
* This method is used internally. You should just use PacketSender::send_recv.
*
* This PacketSender will receive data from a raw socket, open using
* the corresponding flag, according to the given type of protocol, until
* a match for the given PDU is received.
*
* \param pdu The PDU which will try to match the responses.
* \param link_addr The sockaddr struct which will be used to receive the PDU.
* \param len_addr The sockaddr struct length.
* \return Returns the response PDU. If no response is received, then 0 is returned.
*/
PDU* recv_l2(PDU& pdu, struct sockaddr* link_addr, uint32_t len_addr,
const NetworkInterface& iface = NetworkInterface());
/**
* \brief Opens a layer 3 socket, using the corresponding protocol
* for the given flag.
*
* If this operation fails, then a socket_open_error will be thrown.
* If the provided socket type is not valid, an invalid_socket_type
* exception will be throw.
*
* \param type The type of socket which will be used to pick the protocol flag
* for this socket.
*/
void open_l3_socket(SocketType type);
#endif // _WIN32
/**
* \brief Closes the socket associated with the given flag.
*
* If the provided type is invalid, meaning no such open socket
* exists, an invalid_socket_type exception is thrown.
*
* If any socket close errors are encountered, a socket_close_error
* is thrown.
*
* \param type The type of the socket to be closed.
*/
void close_socket(SocketType type, const NetworkInterface &iface = NetworkInterface());
#if !defined(_WIN32) || defined(HAVE_PACKET_SENDER_PCAP_SENDPACKET)
/**
* \brief Sends a level 2 PDU.
*
* This method is used internally. You should just use PacketSender::send.
*
* This method sends a layer 2 PDU, using a raw socket, open
* using the corresponding flag, according to the given type of
* protocol.
*
* If any socket write error occurs, a socket_write_error is thrown.
*
* \param pdu The PDU to send.
* \param link_addr The sockaddr struct which will be used to send the PDU.
* \param len_addr The sockaddr struct length.
*/
void send_l2(PDU& pdu, struct sockaddr* link_addr, uint32_t len_addr,
const NetworkInterface& iface = NetworkInterface());
#endif // !_WIN32 || HAVE_PACKET_SENDER_PCAP_SENDPACKET
/**
* \brief Sets the default interface.
*
* The interface will be used whenever PacketSender::send(PDU&)
* is called.
*/
void default_interface(const NetworkInterface &iface);
/**
* \brief Gets the default interface.
*
* \sa PacketSender::default_interface
*/
const NetworkInterface& default_interface() const;
/**
* \brief Receives a layer 3 PDU response to a previously sent PDU.
*
* This method is used internally. You should just use PacketSender::send_recv.
*
* This PacketSender will receive data from a raw socket, open using the corresponding flag,
* according to the given type of protocol, until a match for the given PDU is received.
*
* \param pdu The PDU which will try to match the responses.
* \param link_addr The sockaddr struct which will be used to receive the PDU.
* \param len_addr The sockaddr struct length.
* \param type The socket protocol type.
* \return Returns the response PDU. If no response is received, then 0 is returned.
*/
PDU* recv_l3(PDU& pdu, struct sockaddr* link_addr, uint32_t len_addr, SocketType type);
/**
* \brief Sends a PDU.
*
* This method opens the appropriate socket, if it's not open yet,
* and sends the PDU on the open socket.
*
* If any send error occurs, then a socket_write_error is thrown.
*
* If the PDU contains a link layer protocol, then default_interface
* is used.
*
* \sa PacketSender::default_interface
*
* \param pdu The PDU to be sent.
*/
void send(PDU &pdu);
/**
* \brief Sends a PDU.
*
* \sa PacketSender::send
*
* This overload takes a NetworkInterface. The packet is sent
* through that interface if a link-layer PDU is present,
* otherwise this call is equivalent to send(PDU&).
*
* The interface stored in the link layer PDU(if any), is restored
* after this method ends.
*
* \param pdu The PDU to be sent.
* \param iface The network interface to use.
*/
void send(PDU &pdu, const NetworkInterface &iface);
/**
* \brief Sends a level 3 PDU.
*
* This method is used internally. You should just use PacketSender::send.
*
* This method sends a layer 3 PDU, using a raw socket, open using the corresponding flag,
* according to the given type of protocol.
*
* If any socket write error occurs, a socket_write_error is thrown.
*
* \param pdu The PDU to send.
* \param link_addr The sockaddr struct which will be used to send the PDU.
* \param len_addr The sockaddr struct length.
* \param type The socket protocol type.
*/
void send_l3(PDU& pdu, struct sockaddr* link_addr, uint32_t len_addr, SocketType type);
private:
static const int INVALID_RAW_SOCKET;
/**
* \brief Sends a PDU and waits for its response.
*
* This method is used to send PDUs and receive their response.
* The packet is sent, and then a response is awaited.
* PDU::matches_pdu is called on the packet sent in order to
* check whether a packet received is a response.
*
* This will match every response to a packet. For example,
* if you send a TCP packet, any response matching the same
* IP addresses and ports will be taken as a response to it.
* This also happens for other protocols, such as ARP, ICMP,
* DHCP, DNS, IP, etc.
*
* If you send a packet and get an ICMP response indicating
* an error (such as host unreachable, ttl exceeded, etc),
* that packet will be considered a response.
*
* \param pdu The PDU to send.
* \return Returns the response PDU, 0 if not response was received.
*/
PDU *send_recv(PDU &pdu);
/**
* \brief Sends a PDU and waits for its response.
*
* Sends a packet and receives a response. This overload takes
* a NetworkInterface.
*
* \sa PacketSender::send_recv(PDU&);
* \param pdu The PDU to send.
* \param iface The network interface in which to send and receive.
* \return Returns the response PDU, 0 if not response was received.
*/
PDU *send_recv(PDU &pdu, const NetworkInterface &iface);
typedef std::map<SocketType, int> SocketTypeMap;
#ifndef _WIN32
/**
* \brief Receives a layer 2 PDU response to a previously sent PDU.
*
* This method is used internally. You should just use PacketSender::send_recv.
*
* This PacketSender will receive data from a raw socket, open using
* the corresponding flag, according to the given type of protocol, until
* a match for the given PDU is received.
*
* \param pdu The PDU which will try to match the responses.
* \param link_addr The sockaddr struct which will be used to receive the PDU.
* \param len_addr The sockaddr struct length.
* \return Returns the response PDU. If no response is received, then 0 is returned.
*/
PDU *recv_l2(PDU &pdu, struct sockaddr *link_addr, uint32_t len_addr,
const NetworkInterface &iface = NetworkInterface());
PacketSender(const PacketSender&);
PacketSender& operator=(const PacketSender&);
int find_type(SocketType type);
int timeval_subtract (struct timeval* result, struct timeval* x, struct timeval* y);
#ifndef _WIN32
bool ether_socket_initialized(const NetworkInterface& iface = NetworkInterface()) const;
int getether_socket_(const NetworkInterface& iface = NetworkInterface());
#endif
template<typename T>
void send(PDU& pdu, const NetworkInterface& iface) {
static_cast<T&>(pdu).send(*this, iface);
}
#ifdef HAVE_PACKET_SENDER_PCAP_SENDPACKET
pcap_t* make_pcap_handle(const NetworkInterface& iface) const;
#endif // HAVE_PACKET_SENDER_PCAP_SENDPACKET
PDU* recv_match_loop(const std::vector<int>& sockets,
PDU& pdu,
struct sockaddr* link_addr,
uint32_t addrlen);
#endif // _WIN32
#if !defined(_WIN32) || defined(HAVE_PACKET_SENDER_PCAP_SENDPACKET)
/**
* \brief Sends a level 2 PDU.
*
* This method is used internally. You should just use PacketSender::send.
*
* This method sends a layer 2 PDU, using a raw socket, open
* using the corresponding flag, according to the given type of
* protocol.
*
* If any socket write error occurs, a socket_write_error is thrown.
*
* \param pdu The PDU to send.
* \param link_addr The sockaddr struct which will be used to send the PDU.
* \param len_addr The sockaddr struct length.
*/
void send_l2(PDU &pdu, struct sockaddr* link_addr, uint32_t len_addr,
const NetworkInterface &iface = NetworkInterface());
#endif // !_WIN32 || HAVE_PACKET_SENDER_PCAP_SENDPACKET
/**
* \brief Receives a layer 3 PDU response to a previously sent PDU.
*
* This method is used internally. You should just use PacketSender::send_recv.
*
* This PacketSender will receive data from a raw socket, open using the corresponding flag,
* according to the given type of protocol, until a match for the given PDU is received.
*
* \param pdu The PDU which will try to match the responses.
* \param link_addr The sockaddr struct which will be used to receive the PDU.
* \param len_addr The sockaddr struct length.
* \param type The socket protocol type.
* \return Returns the response PDU. If no response is received, then 0 is returned.
*/
PDU *recv_l3(PDU &pdu, struct sockaddr *link_addr, uint32_t len_addr, SocketType type);
/**
* \brief Sends a level 3 PDU.
*
* This method is used internally. You should just use PacketSender::send.
*
* This method sends a layer 3 PDU, using a raw socket, open using the corresponding flag,
* according to the given type of protocol.
*
* If any socket write error occurs, a socket_write_error is thrown.
*
* \param pdu The PDU to send.
* \param link_addr The sockaddr struct which will be used to send the PDU.
* \param len_addr The sockaddr struct length.
* \param type The socket protocol type.
*/
void send_l3(PDU &pdu, struct sockaddr *link_addr, uint32_t len_addr, SocketType type);
private:
static const int INVALID_RAW_SOCKET;
typedef std::map<SocketType, int> SocketTypeMap;
PacketSender(const PacketSender&);
PacketSender& operator=(const PacketSender&);
int find_type(SocketType type);
int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y);
#ifndef _WIN32
bool ether_socket_initialized(const NetworkInterface& iface = NetworkInterface()) const;
int get_ether_socket(const NetworkInterface& iface = NetworkInterface());
#endif
template<typename T>
void send(PDU &pdu, const NetworkInterface &iface) {
static_cast<T&>(pdu).send(*this, iface);
}
#ifdef HAVE_PACKET_SENDER_PCAP_SENDPACKET
pcap_t* make_pcap_handle(const NetworkInterface& iface) const;
#endif // HAVE_PACKET_SENDER_PCAP_SENDPACKET
PDU *recv_match_loop(const std::vector<int>& sockets, PDU &pdu, struct sockaddr* link_addr,
uint32_t addrlen);
std::vector<int> _sockets;
#ifndef _WIN32
#if defined(BSD) || defined(__FreeBSD_kernel__)
typedef std::map<uint32_t, int> BSDEtherSockets;
BSDEtherSockets _ether_socket;
#else
int _ether_socket;
#endif
#endif
SocketTypeMap _types;
uint32_t _timeout, _timeout_usec;
NetworkInterface default_iface;
// In BSD we need to store the buffer size, retrieved using BIOCGBLEN
std::vector<int> sockets_;
#ifndef _WIN32
#if defined(BSD) || defined(__FreeBSD_kernel__)
int buffer_size;
#endif // BSD
#ifdef HAVE_PACKET_SENDER_PCAP_SENDPACKET
typedef std::map<NetworkInterface, pcap_t*> PcapHandleMap;
PcapHandleMap pcap_handles;
#endif // HAVE_PACKET_SENDER_PCAP_SENDPACKET
};
}
typedef std::map<uint32_t, int> BSDEtherSockets;
BSDEtherSockets ether_socket_;
#else
int ether_socket_;
#endif
#endif
SocketTypeMap types_;
uint32_t _timeout, timeout_usec_;
NetworkInterface default_iface_;
// In BSD we need to store the buffer size, retrieved using BIOCGBLEN
#if defined(BSD) || defined(__FreeBSD_kernel__)
int buffer_size_;
#endif // BSD
#ifdef HAVE_PACKET_SENDER_PCAP_SENDPACKET
typedef std::map<NetworkInterface, pcap_t*> PcapHandleMap;
PcapHandleMap pcap_handles_;
#endif // HAVE_PACKET_SENDER_PCAP_SENDPACKET
};
} // Tins
#endif // TINS_PACKET_SENDER_H

View File

@@ -115,8 +115,7 @@ public:
* \sa PcapIdentifier.
*/
template<typename T>
PacketWriter(const std::string &file_name, const DataLinkType<T>& lt)
{
PacketWriter(const std::string& file_name, const DataLinkType<T>& lt) {
init(file_name, lt.get_type());
}
@@ -130,7 +129,7 @@ public:
* \param lt The link type which will be written to this file.
* \sa LinkType.
*/
PacketWriter(const std::string &file_name, LinkType lt);
PacketWriter(const std::string& file_name, LinkType lt);
#if TINS_IS_CXX11
/**
@@ -154,11 +153,11 @@ public:
* \param rhs The PacketWriter to be moved.
*/
PacketWriter& operator=(PacketWriter &&rhs) TINS_NOEXCEPT {
handle = 0;
dumper = 0;
std::swap(handle, rhs.handle);
std::swap(dumper, rhs.dumper);
return *this;
handle_ = 0;
dumper_ = 0;
std::swap(handle_, rhs.handle_);
std::swap(dumper_, rhs.dumper_);
return* this;
}
#endif
@@ -173,7 +172,7 @@ public:
* \brief Writes a PDU to this file.
* \param pdu The PDU to be written.
*/
void write(PDU &pdu);
void write(PDU& pdu);
/**
* \brief Writes a Packet to this file.
@@ -183,7 +182,7 @@ public:
*
* \param packet The packet to be written.
*/
void write(Packet &packet);
void write(Packet& packet);
/**
* \brief Writes a PDU to this file.
@@ -193,7 +192,7 @@ public:
* raw and smart pointers.
*/
template<typename T>
void write(T &pdu) {
void write(T& pdu) {
write(Utils::dereference_until_pdu(pdu));
}
@@ -206,8 +205,9 @@ public:
*/
template<typename ForwardIterator>
void write(ForwardIterator start, ForwardIterator end) {
while(start != end)
while (start != end) {
write(Utils::dereference_until_pdu(*start++));
}
}
private:
// You shall not copy
@@ -217,8 +217,8 @@ private:
void init(const std::string& file_name, int link_type);
void write(PDU& pdu, const struct timeval& tv);
pcap_t *handle;
pcap_dumper_t *dumper;
pcap_t* handle_;
pcap_dumper_t* dumper_;
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -45,9 +45,9 @@ class IP;
class IPv6;
namespace Internals {
template<typename PDUType>
PDU *default_allocator(const uint8_t *buffer, uint32_t size)
{
PDU* default_allocator(const uint8_t* buffer, uint32_t size) {
return new PDUType(buffer, size);
}
@@ -58,25 +58,21 @@ public:
typedef PDU *(*allocator_type)(const uint8_t *, uint32_t);
template<typename PDUType>
static void register_allocator(id_type identifier)
{
static void register_allocator(id_type identifier) {
allocators[identifier] = &default_allocator<PDUType>;
pdu_types[PDUType::pdu_flag] = identifier;
}
static PDU *allocate(id_type identifier, const uint8_t *buffer, uint32_t size)
{
static PDU* allocate(id_type identifier, const uint8_t* buffer, uint32_t size) {
typename allocators_type::const_iterator it = allocators.find(identifier);
return (it == allocators.end()) ? 0 : (*it->second)(buffer, size);
}
static bool pdu_type_registered(PDU::PDUType type)
{
static bool pdu_type_registered(PDU::PDUType type) {
return pdu_types.count(type) != 0;
}
static id_type pdu_type_to_id(PDU::PDUType type)
{
static id_type pdu_type_to_id(PDU::PDUType type) {
typename pdu_map_types::const_iterator it = pdu_types.find(type);
return it->second;
}
@@ -118,26 +114,23 @@ TINS_GENERATE_TAG_MAPPER(IPv6, uint8_t)
#undef TINS_GENERATE_TAG_MAPPER
template<typename PDUType>
PDU* allocate(
typename pdu_tag_mapper<PDUType>::type::identifier_type id,
const uint8_t *buffer,
uint32_t size)
{
PDU* allocate(typename pdu_tag_mapper<PDUType>::type::identifier_type id,
const uint8_t* buffer,
uint32_t size) {
return PDUAllocator<typename pdu_tag_mapper<PDUType>::type>::allocate(id, buffer, size);
}
template<typename PDUType>
bool pdu_type_registered(PDU::PDUType type)
{
bool pdu_type_registered(PDU::PDUType type) {
return PDUAllocator<typename pdu_tag_mapper<PDUType>::type>::pdu_type_registered(type);
}
template<typename PDUType>
typename pdu_tag_mapper<PDUType>::type::identifier_type pdu_type_to_id(PDU::PDUType type)
{
typename pdu_tag_mapper<PDUType>::type::identifier_type pdu_type_to_id(PDU::PDUType type) {
return PDUAllocator<typename pdu_tag_mapper<PDUType>::type>::pdu_type_to_id(type);
}
} // namespace Interals
} // Interals
/**
* \endcond
*/
@@ -170,13 +163,13 @@ namespace Allocators {
* the same way.
*/
template<typename PDUType, typename AllocatedType>
void register_allocator(typename Internals::pdu_tag_mapper<PDUType>::type::identifier_type id)
{
void register_allocator(typename Internals::pdu_tag_mapper<PDUType>::type::identifier_type id) {
Internals::PDUAllocator<
typename Internals::pdu_tag_mapper<PDUType>::type
>::template register_allocator<AllocatedType>(id);
}
} // namespace Allocators
} // namespace Tins
} // Allocators
} // Tins
#endif // TINS_PDU_ALLOCATOR_H

View File

@@ -68,14 +68,15 @@ public:
/**
* Default constructs the cached PDU.
*/
PDUCacher() : cached_size() {}
PDUCacher()
: cached_size_() {}
/**
* Constructor from a cached_type.
* \param pdu The PDU to be copy constructed.
*/
PDUCacher(const cached_type &pdu) : cached(pdu),
cached_size() {}
PDUCacher(const cached_type& pdu)
: cached_(pdu), cached_size_() {}
/**
* Forwards the call to the cached PDU.
@@ -83,9 +84,10 @@ public:
* \sa PDU::header_size.
*/
uint32_t header_size() const {
if(cached_serialization.empty())
cached_size = cached.size();
return cached_size;
if (cached_serialization_.empty()) {
cached_size_ = cached_.size();
}
return cached_size_;
}
/**
@@ -93,7 +95,7 @@ public:
*
* \sa PDU::clone.
*/
PDUCacher *clone() const {
PDUCacher* clone() const {
return new PDUCacher<T>(*this);
}
@@ -102,8 +104,8 @@ public:
*
* \sa PDU::send.
*/
void send(PacketSender &sender, const NetworkInterface &iface) {
cached.send(sender, iface);
void send(PacketSender& sender, const NetworkInterface& iface) {
cached_.send(sender, iface);
}
/**
@@ -111,8 +113,8 @@ public:
*
* \sa PDU::recv_responde.
*/
PDU *recv_response(PacketSender &sender, const NetworkInterface &iface) {
return cached.recv_response(sender, iface);
PDU* recv_response(PacketSender& sender, const NetworkInterface& iface) {
return cached_.recv_response(sender, iface);
}
/**
@@ -120,8 +122,8 @@ public:
*
* \sa PDU::matches_response.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const {
return cached.matches_response(ptr, total_sz);
bool matches_response(const uint8_t* ptr, uint32_t total_sz) const {
return cached_.matches_response(ptr, total_sz);
}
/**
@@ -130,7 +132,7 @@ public:
* \sa PDU::matches_flag.
*/
bool matches_flag(PDUType flag) const {
return cached.matches_flag(flag);
return cached_.matches_flag(flag);
}
/**
@@ -139,19 +141,19 @@ public:
* \sa PDU::pdu_type.
*/
PDUType pdu_type() const {
return cached.pdu_type();
return cached_.pdu_type();
}
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
if(cached_serialization.size() != total_sz) {
cached_serialization = cached.serialize();
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent) {
if (cached_serialization_.size() != total_sz) {
cached_serialization_ = cached_.serialize();
}
std::copy(cached_serialization.begin(), cached_serialization.end(), buffer);
std::copy(cached_serialization_.begin(), cached_serialization_.end(), buffer);
}
cached_type cached;
PDU::serialization_type cached_serialization;
mutable uint32_t cached_size;
cached_type cached_;
PDU::serialization_type cached_serialization_;
mutable uint32_t cached_size_;
};
}

View File

@@ -54,13 +54,16 @@ class PDUOption;
namespace Internals {
template<typename T, typename X, typename PDUType>
T convert_to_integral(const PDUOption<X, PDUType> & opt) {
if(opt.data_size() != sizeof(T))
if (opt.data_size() != sizeof(T)) {
throw malformed_option();
}
T data = *(T*)opt.data_ptr();
if(PDUType::endianness == PDUType::BE)
if (PDUType::endianness == PDUType::BE) {
data = Endian::be_to_host(data);
else
}
else {
data = Endian::le_to_host(data);
}
return data;
}
@@ -76,9 +79,10 @@ namespace Internals {
struct converter<uint8_t> {
template<typename X, typename PDUType>
static uint8_t convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() != 1)
if (opt.data_size() != 1) {
throw malformed_option();
return *opt.data_ptr();
}
return* opt.data_ptr();
}
};
@@ -110,8 +114,9 @@ namespace Internals {
struct converter<HWAddress<n> > {
template<typename X, typename PDUType>
static HWAddress<n> convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() != n)
if (opt.data_size() != n) {
throw malformed_option();
}
return HWAddress<n>(opt.data_ptr());
}
};
@@ -120,13 +125,16 @@ namespace Internals {
struct converter<IPv4Address> {
template<typename X, typename PDUType>
static IPv4Address convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() != sizeof(uint32_t))
if (opt.data_size() != sizeof(uint32_t)) {
throw malformed_option();
const uint32_t *ptr = (const uint32_t*)opt.data_ptr();
if(PDUType::endianness == PDUType::BE)
}
const uint32_t* ptr = (const uint32_t*)opt.data_ptr();
if (PDUType::endianness == PDUType::BE) {
return IPv4Address(*ptr);
else
}
else {
return IPv4Address(Endian::change_endian(*ptr));
}
}
};
@@ -134,8 +142,9 @@ namespace Internals {
struct converter<IPv6Address> {
template<typename X, typename PDUType>
static IPv6Address convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() != IPv6Address::address_size)
if (opt.data_size() != IPv6Address::address_size) {
throw malformed_option();
}
return IPv6Address(opt.data_ptr());
}
};
@@ -156,8 +165,8 @@ namespace Internals {
template<typename X, typename PDUType>
static std::vector<float> convert(const PDUOption<X, PDUType>& opt) {
std::vector<float> output;
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
while(ptr != end) {
const uint8_t* ptr = opt.data_ptr(), *end = ptr + opt.data_size();
while (ptr != end) {
output.push_back(float(*(ptr++) & 0x7f) / 2);
}
return output;
@@ -168,18 +177,21 @@ namespace Internals {
struct converter<std::vector<T>, typename enable_if<is_unsigned_integral<T>::value>::type> {
template<typename X, typename PDUType>
static std::vector<T> convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() % sizeof(T) != 0)
if (opt.data_size() % sizeof(T) != 0) {
throw malformed_option();
const T *ptr = (const T*)opt.data_ptr();
const T *end = (const T*)(opt.data_ptr() + opt.data_size());
}
const T* ptr = (const T*)opt.data_ptr();
const T* end = (const T*)(opt.data_ptr() + opt.data_size());
std::vector<T> output(std::distance(ptr, end));
typename std::vector<T>::iterator it = output.begin();
while(ptr < end) {
if(PDUType::endianness == PDUType::BE)
while (ptr < end) {
if (PDUType::endianness == PDUType::BE) {
*it++ = Endian::be_to_host(*ptr++);
else
}
else {
*it++ = Endian::le_to_host(*ptr++);
}
}
return output;
}
@@ -194,18 +206,19 @@ namespace Internals {
> {
template<typename X, typename PDUType>
static std::vector<std::pair<T, U> > convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() % (sizeof(T) + sizeof(U)) != 0)
if (opt.data_size() % (sizeof(T) + sizeof(U)) != 0) {
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();
std::vector<std::pair<T, U> > output;
while(ptr < end) {
while (ptr < end) {
std::pair<T, U> data;
data.first = *(const T*)ptr;
ptr += sizeof(T);
data.second = *(const U*)ptr;
ptr += sizeof(U);
if(PDUType::endianness == PDUType::BE) {
if (PDUType::endianness == PDUType::BE) {
data.first = Endian::be_to_host(data.first);
data.second = Endian::be_to_host(data.second);
}
@@ -223,18 +236,21 @@ namespace Internals {
struct converter<std::vector<IPv4Address> > {
template<typename X, typename PDUType>
static std::vector<IPv4Address> convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() % 4 != 0)
if (opt.data_size() % 4 != 0) {
throw malformed_option();
const uint32_t *ptr = (const uint32_t*)opt.data_ptr();
const uint32_t *end = (const uint32_t*)(opt.data_ptr() + opt.data_size());
}
const uint32_t* ptr = (const uint32_t*)opt.data_ptr();
const uint32_t* end = (const uint32_t*)(opt.data_ptr() + opt.data_size());
std::vector<IPv4Address> output(std::distance(ptr, end));
std::vector<IPv4Address>::iterator it = output.begin();
while(ptr < end) {
if(PDUType::endianness == PDUType::BE)
while (ptr < end) {
if (PDUType::endianness == PDUType::BE) {
*it++ = IPv4Address(*ptr++);
else
}
else {
*it++ = IPv4Address(Endian::change_endian(*ptr++));
}
}
return output;
}
@@ -244,11 +260,12 @@ namespace Internals {
struct converter<std::vector<IPv6Address> > {
template<typename X, typename PDUType>
static std::vector<IPv6Address> convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() % IPv6Address::address_size != 0)
if (opt.data_size() % IPv6Address::address_size != 0) {
throw malformed_option();
const uint8_t *ptr = opt.data_ptr(), *end = opt.data_ptr() + opt.data_size();
}
const uint8_t* ptr = opt.data_ptr(), *end = opt.data_ptr() + opt.data_size();
std::vector<IPv6Address> output;
while(ptr < end) {
while (ptr < end) {
output.push_back(IPv6Address(ptr));
ptr += IPv6Address::address_size;
}
@@ -265,12 +282,13 @@ namespace Internals {
> {
template<typename X, typename PDUType>
static std::pair<T, U> convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() != sizeof(T) + sizeof(U))
if (opt.data_size() != sizeof(T) + sizeof(U)) {
throw malformed_option();
}
std::pair<T, U> output;
std::memcpy(&output.first, opt.data_ptr(), sizeof(T));
std::memcpy(&output.second, opt.data_ptr() + sizeof(T), sizeof(U));
if(PDUType::endianness == PDUType::BE) {
if (PDUType::endianness == PDUType::BE) {
output.first = Endian::be_to_host(output.first);
output.second = Endian::be_to_host(output.second);
}
@@ -312,7 +330,9 @@ public:
* \param length The option's data length.
* \param data The option's data(if any).
*/
PDUOption(option_type opt = option_type(), size_t length = 0, const data_type *data = 0)
PDUOption(option_type opt = option_type(),
size_t length = 0,
const data_type* data = 0)
: option_(opt), size_(static_cast<uint16_t>(length)) {
set_payload_contents(data, data + (data ? length : 0));
}
@@ -343,11 +363,11 @@ public:
PDUOption& operator=(PDUOption&& rhs) {
option_ = rhs.option_;
size_ = rhs.size_;
if(real_size_ > small_buffer_size) {
if (real_size_ > small_buffer_size) {
delete[] payload_.big_buffer_ptr;
}
real_size_ = rhs.real_size_;
if(real_size_ > small_buffer_size) {
if (real_size_ > small_buffer_size) {
payload_.big_buffer_ptr = nullptr;
std::swap(payload_.big_buffer_ptr, rhs.payload_.big_buffer_ptr);
rhs.real_size_ = 0;
@@ -359,7 +379,7 @@ public:
payload_.small_buffer
);
}
return *this;
return* this;
}
#endif // TINS_IS_CXX11
@@ -371,19 +391,19 @@ public:
PDUOption& operator=(const PDUOption& rhs) {
option_ = rhs.option_;
size_ = rhs.size_;
if(real_size_ > small_buffer_size) {
if (real_size_ > small_buffer_size) {
delete[] payload_.big_buffer_ptr;
}
real_size_ = rhs.real_size_;
set_payload_contents(rhs.data_ptr(), rhs.data_ptr() + rhs.data_size());
return *this;
return* this;
}
/**
* \brief Destructor.
*/
~PDUOption() {
if(real_size_ > small_buffer_size) {
if (real_size_ > small_buffer_size) {
delete[] payload_.big_buffer_ptr;
}
}
@@ -448,10 +468,10 @@ public:
*
* \return const data_type& containing this option's value.
*/
const data_type *data_ptr() const {
const data_type* data_ptr() const {
return real_size_ <= small_buffer_size ?
payload_.small_buffer :
payload_.big_buffer_ptr;
payload_.small_buffer :
payload_.big_buffer_ptr;
}
/**
@@ -498,7 +518,7 @@ private:
throw option_payload_too_large();
}
real_size_ = static_cast<uint16_t>(total_size);
if(real_size_ <= small_buffer_size) {
if (real_size_ <= small_buffer_size) {
std::copy(
start,
end,

View File

@@ -35,6 +35,9 @@
namespace Tins {
/**
* \brief Represents a PKTAP PDU
*/
class TINS_API PKTAP : public PDU {
public:
/**
@@ -64,7 +67,9 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Returns the header size.
@@ -77,7 +82,7 @@ public:
/**
* \sa PDU::clone
*/
PKTAP *clone() const {
PKTAP* clone() const {
return new PKTAP(*this);
}
private:
@@ -99,8 +104,7 @@ private:
uint8_t ecommand[20];
};
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
pktap_header header_;
};

View File

@@ -36,6 +36,7 @@
#include "small_uint.h"
namespace Tins {
/**
* \class PPI
* \brief Represents a Per-Packet Information PDU.
@@ -62,7 +63,7 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
PPI(const uint8_t *buffer, uint32_t total_sz);
PPI(const uint8_t* buffer, uint32_t total_sz);
// Getters
@@ -71,7 +72,7 @@ public:
* \return The stored version field value.
*/
uint8_t version() const {
return _header.version;
return header_.version;
}
/**
@@ -79,7 +80,7 @@ public:
* \return The stored flags field value.
*/
uint8_t flags() const {
return _header.flags;
return header_.flags;
}
/**
@@ -87,7 +88,7 @@ public:
* \return The stored length field value.
*/
uint16_t length() const {
return Endian::le_to_host(_header.length);
return Endian::le_to_host(header_.length);
}
/**
@@ -95,7 +96,7 @@ public:
* \return The stored Data Link Type field value.
*/
uint32_t dlt() const {
return Endian::le_to_host(_header.dlt);
return Endian::le_to_host(header_.dlt);
}
/**
@@ -109,28 +110,30 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
PPI *clone() const {
PPI* clone() const {
return new PPI(*this);
}
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *);
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *);
void parse_80211(const uint8_t* buffer, uint32_t total_sz);
struct header {
struct ppi_header {
uint8_t version, flags;
uint16_t length;
uint32_t dlt;
};
header _header;
byte_array _data;
ppi_header header_;
byte_array data_;
};
}

View File

@@ -93,10 +93,10 @@ public:
uint32_t vendor_id;
data_type data;
vendor_spec_type(uint32_t vendor_id = 0, const data_type &data = data_type())
vendor_spec_type(uint32_t vendor_id = 0, const data_type& data = data_type())
: vendor_id(vendor_id), data(data) { }
static vendor_spec_type from_option(const tag &opt);
static vendor_spec_type from_option(const tag& opt);
};
/**
@@ -120,7 +120,7 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
PPPoE(const uint8_t *buffer, uint32_t total_sz);
PPPoE(const uint8_t* buffer, uint32_t total_sz);
// Getters
@@ -129,7 +129,7 @@ public:
* \return The stored version field value.
*/
small_uint<4> version() const {
return _header.version;
return header_.version;
}
/**
@@ -137,7 +137,7 @@ public:
* \return The stored type field value.
*/
small_uint<4> type() const {
return _header.type;
return header_.type;
}
/**
@@ -145,7 +145,7 @@ public:
* \return The stored code field value.
*/
uint8_t code() const {
return _header.code;
return header_.code;
}
/**
@@ -153,7 +153,7 @@ public:
* \return The stored session_id field value.
*/
uint16_t session_id() const {
return Endian::be_to_host(_header.session_id);
return Endian::be_to_host(header_.session_id);
}
/**
@@ -161,7 +161,7 @@ public:
* \return The stored payload_length field value.
*/
uint16_t payload_length() const {
return Endian::be_to_host(_header.payload_length);
return Endian::be_to_host(header_.payload_length);
}
/**
@@ -174,18 +174,18 @@ public:
/**
* \brief Returns the list of tags.
*/
const tags_type &tags() const {
return _tags;
const tags_type& tags() const {
return tags_;
}
/**
* \sa PDU::clone
*/
PPPoE *clone() const {
PPPoE* clone() const {
return new PPPoE(*this);
}
const tag *search_tag(TagTypes identifier) const;
const tag* search_tag(TagTypes identifier) const;
/**
* \brief Getter for the PDU's type.
@@ -230,7 +230,7 @@ public:
*
* \param option The option to be added.
*/
void add_tag(const tag &option);
void add_tag(const tag& option);
#if TINS_IS_CXX11
/**
@@ -241,8 +241,8 @@ public:
* \param option The option to be added.
*/
void add_tag(tag &&option) {
_tags_size += static_cast<uint16_t>(option.data_size() + sizeof(uint16_t) * 2);
_tags.push_back(std::move(option));
tags_size_ += static_cast<uint16_t>(option.data_size() + sizeof(uint16_t) * 2);
tags_.push_back(std::move(option));
}
#endif
@@ -258,63 +258,63 @@ public:
*
* \param value The service name.
*/
void service_name(const std::string &value);
void service_name(const std::string& value);
/**
* \brief Adds a AC-name tag.
*
* \param value The AC name.
*/
void ac_name(const std::string &value);
void ac_name(const std::string& value);
/**
* \brief Adds a host-uniq tag.
*
* \param value The tag's value.
*/
void host_uniq(const byte_array &value);
void host_uniq(const byte_array& value);
/**
* \brief Adds a AC-Cookie tag.
*
* \param value The tag's value.
*/
void ac_cookie(const byte_array &value);
void ac_cookie(const byte_array& value);
/**
* \brief Adds a Vendor-Specific tag.
*
* \param value The tag's value.
*/
void vendor_specific(const vendor_spec_type &value);
void vendor_specific(const vendor_spec_type& value);
/**
* \brief Adds a Relay-Session-Id tag.
*
* \param value The tag's value.
*/
void relay_session_id(const byte_array &value);
void relay_session_id(const byte_array& value);
/**
* \brief Adds a Service-Name-Error tag.
*
* \param value The tag's value.
*/
void service_name_error(const std::string &value);
void service_name_error(const std::string& value);
/**
* \brief Adds a AC-System-Error tag.
*
* \param value The tag's value.
*/
void ac_system_error(const std::string &value);
void ac_system_error(const std::string& value);
/**
* \brief Adds a Generic-Error tag.
*
* \param value The tag's value.
*/
void generic_error(const std::string &value);
void generic_error(const std::string& value);
// Option getters
@@ -390,10 +390,10 @@ public:
*/
std::string generic_error() const;
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *);
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *);
template<typename T>
void add_tag_iterable(TagTypes id, const T &data) {
void add_tag_iterable(TagTypes id, const T& data) {
add_tag(
tag(
id,
@@ -405,14 +405,15 @@ private:
template<typename T>
T search_and_convert(TagTypes id) const {
const tag *t = search_tag(id);
if(!t)
const tag* t = search_tag(id);
if (!t) {
throw option_not_found();
}
return t->to<T>();
}
TINS_BEGIN_PACK
struct pppoe_hdr {
struct pppoe_header {
#if TINS_IS_LITTLE_ENDIAN
uint8_t version:4,
type:4;
@@ -426,9 +427,9 @@ private:
uint16_t payload_length;
} TINS_END_PACK;
pppoe_hdr _header;
tags_type _tags;
uint16_t _tags_size;
pppoe_header header_;
tags_type tags_;
uint16_t tags_size_;
};
}

View File

@@ -137,7 +137,7 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
RadioTap(const uint8_t *buffer, uint32_t total_sz);
RadioTap(const uint8_t* buffer, uint32_t total_sz);
/* Setters */
@@ -145,7 +145,7 @@ public:
/**
* \sa PDU::send()
*/
void send(PacketSender &sender, const NetworkInterface &iface);
void send(PacketSender& sender, const NetworkInterface& iface);
#endif
/**
@@ -365,8 +365,8 @@ public:
* if its corresponding bit flag is set in the present field.
*/
PresentFlags present() const {
//return (PresentFlags)*(uint32_t*)(&_radio.it_len + 1);
return (PresentFlags)Endian::le_to_host(_radio.flags_32);
//return (PresentFlags)*(uint32_t*)(&radio_.it_len + 1);
return (PresentFlags)Endian::le_to_host(radio_.flags_32);
}
/** \brief Check wether ptr points to a valid response for this PDU.
@@ -375,7 +375,7 @@ public:
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
bool matches_response(const uint8_t* ptr, uint32_t total_sz) const;
/**
* \brief Returns the RadioTap frame's header length.
@@ -394,7 +394,7 @@ public:
/**
* \sa PDU::clone
*/
RadioTap *clone() const {
RadioTap* clone() const {
return new RadioTap(*this);
}
@@ -402,7 +402,9 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::RADIOTAP; }
PDUType pdu_type() const {
return pdu_flag;
}
private:
TINS_BEGIN_PACK
#if TINS_IS_LITTLE_ENDIAN
@@ -484,13 +486,13 @@ private:
} TINS_END_PACK;
void init();
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
uint32_t find_extra_flag_fields_size(const uint8_t* buffer, uint32_t total_sz);
template <size_t n>
void align_buffer(const uint8_t* buffer_start, const uint8_t*& buffer, uint32_t& size) {
uint32_t offset = ((buffer - buffer_start) % n);
if(offset) {
if (offset) {
offset = n - offset;
if (offset > size) {
throw malformed_packet();
@@ -501,13 +503,13 @@ private:
}
radiotap_hdr _radio;
radiotap_hdr radio_;
// present fields...
uint64_t _tsft;
uint16_t _channel_type, _channel_freq, _rx_flags, _signal_quality, _tx_flags;
mcs_type _mcs;
uint8_t _antenna, _flags, _rate, _channel, _max_power, _db_signal, _data_retries;
int8_t _dbm_signal, _dbm_noise;
uint64_t tsft_;
uint16_t channel_type_, channel_freq_, rx_flags_, signal_quality_, tx_flags_;
mcs_type mcs_;
uint8_t antenna_, flags_, rate_, channel_, max_power_, db_signal_, data_retries_;
int8_t dbm_signal_, dbm_noise_;
};
}

View File

@@ -38,168 +38,174 @@
namespace Tins {
/**
* \class PDU
* \brief Represents a PDU which holds raw data.
*
* This class is a wrapper over a byte array. It can be used to hold
* the payload sent over transport layer protocols (such as TCP or UDP).
*
* While sniffing, this class is the one that will hold transport layer
* protocols' payload. You can simply convert a RawPDU into a specific
* application layer protocol using the RawPDU::to method:
*
* \code
* // Get a RawPDU from somewhere
* RawPDU raw = get_raw_pdu();
*
* // Parse it as a DHCP PDU.
* DHCP dhcp = raw.to<DHCP>();
*
* // Or parse it as DNS. Of course this will fail if the contents
* // don't look like DNS
* DNS dns = raw.to<DNS>();
* \endcode
/**
* \class PDU
* \brief Represents a PDU which holds raw data.
*
* This class is a wrapper over a byte array. It can be used to hold
* the payload sent over transport layer protocols (such as TCP or UDP).
*
* While sniffing, this class is the one that will hold transport layer
* protocols' payload. You can simply convert a RawPDU into a specific
* application layer protocol using the RawPDU::to method:
*
* \code
* // Get a RawPDU from somewhere
* RawPDU raw = get_raw_pdu();
*
* // Parse it as a DHCP PDU.
* DHCP dhcp = raw.to<DHCP>();
*
* // Or parse it as DNS. Of course this will fail if the contents
* // don't look like DNS
* DNS dns = raw.to<DNS>();
* \endcode
*/
class TINS_API RawPDU : public PDU {
public:
/**
* The type used to store the payload.
*/
class TINS_API RawPDU : public PDU {
public:
/**
* The type used to store the payload.
*/
typedef std::vector<uint8_t> payload_type;
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::RAW;
typedef std::vector<uint8_t> payload_type;
/**
* \brief Creates an instance of RawPDU.
*
* The payload is copied, therefore the original payload's memory
* must be freed by the user.
* \param pload The payload which the RawPDU will contain.
* \param size The size of the payload.
*/
RawPDU(const uint8_t *pload, uint32_t size);
/**
* \brief Constructs a RawPDU from an iterator range.
*
* The data in the iterator range is copied into the RawPDU
* internal buffer.
*
* \param start The beginning of the iterator range.
* \param end The end of the iterator range.
*/
template<typename ForwardIterator>
RawPDU(ForwardIterator start, ForwardIterator end)
: _payload(start, end) { }
/**
* This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::RAW;
#if TINS_IS_CXX11
/**
* \brief Creates an instance of RawPDU from a payload_type.
*
* The payload is moved into the RawPDU's internal buffer.
*
* \param data The payload to use.
*/
RawPDU(payload_type&& data)
: _payload(move(data)) { }
#endif // TINS_IS_CXX11
/**
* \brief Creates an instance of RawPDU.
*
* The payload is copied, therefore the original payload's memory
* must be freed by the user.
* \param pload The payload which the RawPDU will contain.
* \param size The size of the payload.
*/
RawPDU(const uint8_t* pload, uint32_t size);
/**
* \brief Constructs a RawPDU from an iterator range.
*
* The data in the iterator range is copied into the RawPDU
* internal buffer.
*
* \param start The beginning of the iterator range.
* \param end The end of the iterator range.
*/
template<typename ForwardIterator>
RawPDU(ForwardIterator start, ForwardIterator end)
: payload_(start, end) { }
#if TINS_IS_CXX11
/**
* \brief Creates an instance of RawPDU from an input string.
* \brief Creates an instance of RawPDU from a payload_type.
*
* The payload is moved into the RawPDU's internal buffer.
*
* \param data The content of the payload.
* \param data The payload to use.
*/
RawPDU(const std::string &data);
RawPDU(payload_type&& data)
: payload_(move(data)) { }
#endif // TINS_IS_CXX11
/**
* \brief Setter for the payload field
* \param pload The payload to be set.
*/
void payload(const payload_type &pload);
/**
* \brief Creates an instance of RawPDU from an input string.
*
* \param data The content of the payload.
*/
RawPDU(const std::string& data);
/**
* \brief Setter for the payload field
* \param start The start of the new payload.
* \param end The end of the new payload.
*/
template<typename ForwardIterator>
void payload(ForwardIterator start, ForwardIterator end) {
_payload.assign(start, end);
}
/**
* \brief Setter for the payload field
* \param pload The payload to be set.
*/
void payload(const payload_type& pload);
/**
* \brief Const getter for the payload.
* \return The RawPDU's payload.
*/
const payload_type &payload() const { return _payload; }
/**
* \brief Non-const getter for the payload.
* \return The RawPDU's payload.
*/
payload_type &payload() { return _payload; }
/**
* \brief Returns the header size.
*
* This returns the same as RawPDU::payload_size().
*
* This metod overrides PDU::header_size. \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Returns the payload size.
*
* \return uint32_t containing the payload size.
*/
uint32_t payload_size() const {
return static_cast<uint32_t>(_payload.size());
}
/**
* \brief Setter for the payload field
* \param start The start of the new payload.
* \param end The end of the new payload.
*/
template<typename ForwardIterator>
void payload(ForwardIterator start, ForwardIterator end) {
payload_.assign(start, end);
}
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* This always returns true, since we don't know what this
* RawPDU is holding.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Const getter for the payload.
* \return The RawPDU's payload.
*/
const payload_type& payload() const {
return payload_;
}
/**
* \brief Non-const getter for the payload.
* \return The RawPDU's payload.
*/
payload_type& payload() {
return payload_;
}
/**
* \brief Returns the header size.
*
* This returns the same as RawPDU::payload_size().
*
* This metod overrides PDU::header_size. \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Returns the payload size.
*
* \return uint32_t containing the payload size.
*/
uint32_t payload_size() const {
return static_cast<uint32_t>(payload_.size());
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::RAW; }
/**
* \brief Constructs the given PDU type from the raw data stored
* in this RawPDU.
*/
template<typename T>
T to() const {
return T(&_payload[0], static_cast<uint32_t>(_payload.size()));
}
/**
* \sa PDU::clone
*/
RawPDU *clone() const {
return new RawPDU(*this);
}
private:
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* This always returns true, since we don't know what this
* RawPDU is holding.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t* ptr, uint32_t total_sz) const;
payload_type _payload;
};
}
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Constructs the given PDU type from the raw data stored
* in this RawPDU.
*/
template<typename T>
T to() const {
return T(&payload_[0], static_cast<uint32_t>(payload_.size()));
}
/**
* \sa PDU::clone
*/
RawPDU* clone() const {
return new RawPDU(*this);
}
private:
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
payload_type payload_;
};
} // Tins
#endif // TINS_RAWPDU_H

View File

@@ -92,7 +92,7 @@ public:
*
* \param buffer The buffer from which to construct this object.
*/
RSNInformation(const serialization_type &buffer);
RSNInformation(const serialization_type& buffer);
/**
* \brief Constructs a RSNInformation from a buffer.
@@ -103,7 +103,7 @@ public:
* \param buffer The buffer from which this object will be constructed.
* \param total_sz The total size of the buffer.
*/
RSNInformation(const uint8_t *buffer, uint32_t total_sz);
RSNInformation(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief Helper function to create a WPA2-PSK RSNInformation
@@ -149,32 +149,40 @@ public:
* \return The group suite field.
*/
CypherSuites group_suite() const {
return static_cast<CypherSuites>(Endian::le_to_host<uint32_t>(_group_suite));
return static_cast<CypherSuites>(Endian::le_to_host<uint32_t>(group_suite_));
}
/**
* \brief Getter for the version field.
* \return The version field.
*/
uint16_t version() const { return Endian::le_to_host(_version); }
uint16_t version() const {
return Endian::le_to_host(version_);
}
/**
* \brief Getter for the capabilities field.
* \return The version field.
*/
uint16_t capabilities() const { return Endian::le_to_host(_capabilities); }
uint16_t capabilities() const {
return Endian::le_to_host(capabilities_);
}
/**
* \brief Getter for the pairwise cypher suite list.
* \return A list of pairwise cypher suites.
*/
const cyphers_type &pairwise_cyphers() const { return _pairwise_cyphers; }
const cyphers_type& pairwise_cyphers() const {
return pairwise_cyphers_;
}
/**
* \brief Getter for the akm suite list.
* \return A list of akm suites.
*/
const akm_type &akm_cyphers() const { return _akm_cyphers; }
const akm_type& akm_cyphers() const {
return akm_cyphers_;
}
/**
* \brief Serializes this object.
@@ -185,14 +193,14 @@ public:
/**
* Constructs an RSNInformation object from a Dot11 tagged option.
*/
static RSNInformation from_option(const PDUOption<uint8_t, Dot11> &opt);
static RSNInformation from_option(const PDUOption<uint8_t, Dot11>& opt);
private:
void init(const uint8_t *buffer, uint32_t total_sz);
void init(const uint8_t* buffer, uint32_t total_sz);
uint16_t _version, _capabilities;
CypherSuites _group_suite;
akm_type _akm_cyphers;
cyphers_type _pairwise_cyphers;
uint16_t version_, capabilities_;
CypherSuites group_suite_;
akm_type akm_cyphers_;
cyphers_type pairwise_cyphers_;
};
} // namespace Tins

View File

@@ -37,6 +37,7 @@
#include "hw_address.h"
namespace Tins {
/**
* \class SLL
* \brief Represents a Linux cooked-mode capture (SLL) PDU.
@@ -70,7 +71,7 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
SLL(const uint8_t *buffer, uint32_t total_sz);
SLL(const uint8_t* buffer, uint32_t total_sz);
// Getters
@@ -79,7 +80,7 @@ public:
* \return The stored Packet Type field value.
*/
uint16_t packet_type() const {
return Endian::be_to_host(_header.packet_type);
return Endian::be_to_host(header_.packet_type);
}
/**
@@ -87,7 +88,7 @@ public:
* \return The stored LLADDR Type field value.
*/
uint16_t lladdr_type() const {
return Endian::be_to_host(_header.lladdr_type);
return Endian::be_to_host(header_.lladdr_type);
}
/**
@@ -95,7 +96,7 @@ public:
* \return The stored LLADDR Length field value.
*/
uint16_t lladdr_len() const {
return Endian::be_to_host(_header.lladdr_len);
return Endian::be_to_host(header_.lladdr_len);
}
/**
@@ -103,7 +104,7 @@ public:
* \return The stored Address field value.
*/
address_type address() const {
return _header.address;
return header_.address;
}
/**
@@ -111,7 +112,7 @@ public:
* \return The stored Protocol field value.
*/
uint16_t protocol() const {
return Endian::be_to_host(_header.protocol);
return Endian::be_to_host(header_.protocol);
}
/**
@@ -144,7 +145,7 @@ public:
* \brief Setter for the Address field.
* \param new_address The new Address field value.
*/
void address(const address_type &new_address);
void address(const address_type& new_address);
/**
* \brief Setter for the Protocol field.
@@ -162,20 +163,20 @@ public:
/**
* \sa PDU::clone
*/
SLL *clone() const {
SLL* clone() const {
return new SLL(*this);
}
private:
TINS_BEGIN_PACK
struct sllhdr {
struct sll_header {
uint16_t packet_type, lladdr_type, lladdr_len;
uint8_t address[8];
uint16_t protocol;
} TINS_END_PACK;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *);
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU *);
sllhdr _header;
sll_header header_;
};
}

View File

@@ -36,7 +36,7 @@
namespace Tins {
class value_too_large : public std::exception {
public:
const char *what() const throw() {
const char* what() const throw() {
return "Value is too large";
}
};
@@ -112,8 +112,9 @@ public:
* \param val The parameter from which to copy construct.
*/
small_uint(repr_type val) {
if(val > max_value)
if (val > max_value) {
throw value_too_large();
}
value = val;
}
@@ -127,5 +128,6 @@ private:
repr_type value;
};
} // namespace Tins
} // Tins
#endif // TINS_SMALL_UINT_H

View File

@@ -39,140 +39,149 @@
namespace Tins {
/**
* \class SNAP
* \brief Represents a SNAP frame.
*
* Note that this PDU contains the 802.3 LLC structure + SNAP frame.
* So far only unnumbered information structure is supported.
*/
class TINS_API SNAP : public PDU {
public:
/**
* \class SNAP
* \brief Represents a SNAP frame.
*
* Note that this PDU contains the 802.3 LLC structure + SNAP frame.
* So far only unnumbered information structure is supported.
* \brief This PDU's flag.
*/
class TINS_API SNAP : public PDU {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::SNAP;
static const PDU::PDUType pdu_flag = PDU::SNAP;
/**
* \brief Creates an instance of SNAP
* This constructor sets the dsap and ssap fields to 0xaa, and
* the id field to 3.
*/
SNAP();
/**
* \brief Creates an instance of SNAP
* This constructor sets the dsap and ssap fields to 0xaa, and
* the id field to 3.
*/
SNAP();
/**
* \brief Constructs a SNAP object from a buffer and adds all
* identifiable PDUs found in the buffer as children of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for a SNAP header in the
* buffer, a malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
SNAP(const uint8_t *buffer, uint32_t total_sz);
/* Setters */
/**
* \brief Setter for the Control field.
* \param new_id The new Control to be set.
*/
void control(uint8_t new_control);
/**
* \brief Setter for the Organization Code field.
* \param new_org The new Organization Code to be set.
*/
void org_code(small_uint<24> new_org);
/**
* \brief Setter for the Ethernet Type field.
* \param new_eth The new Ethernet Type to be set.
*/
void eth_type(uint16_t new_eth);
/* Getters */
/**
* \brief Getter for the DSAP field.
* \return The DSAP field.
*/
uint8_t dsap() const { return _snap.dsap; }
/**
* \brief Getter for the SSAP field.
* \return The SSAP field.
*/
uint8_t ssap() const { return _snap.ssap; }
/**
* \brief Getter for the Control field.
* \return The Control field.
*/
uint8_t control() const {
#if TINS_IS_LITTLE_ENDIAN
return (_snap.control_org) & 0xff;
#else
return (_snap.control_org >> 24) & 0xff;
#endif
}
/**
* \brief Getter for the Organization Code field.
* \return The Organization Code field.
*/
small_uint<24> org_code() const {
#if TINS_IS_LITTLE_ENDIAN
return Endian::be_to_host<uint32_t>(_snap.control_org & 0xffffff00);
#else
return _snap.control_org & 0xffffff;
#endif
}
/**
* \brief Getter for the Ethernet Type field.
* \return The Ethernet Type field.
*/
uint16_t eth_type() const { return Endian::be_to_host(_snap.eth_type); }
/**
* \brief Returns the SNAP frame's header length.
*
* \return The header's size.
* \sa PDU::header_size()
*/
uint32_t header_size() const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
SNAP *clone() const {
return new SNAP(*this);
}
private:
TINS_BEGIN_PACK
struct snaphdr {
uint8_t dsap;
uint8_t ssap;
uint32_t control_org;
uint16_t eth_type;
} TINS_END_PACK;
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
snaphdr _snap;
};
}
/**
* \brief Constructs a SNAP object from a buffer and adds all
* identifiable PDUs found in the buffer as children of this one.
*
* If the next PDU is not recognized, then a RawPDU is used.
*
* If there is not enough size for a SNAP header in the
* buffer, a malformed_packet exception is thrown.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
SNAP(const uint8_t* buffer, uint32_t total_sz);
/* Setters */
/**
* \brief Setter for the Control field.
* \param new_id The new Control to be set.
*/
void control(uint8_t new_control);
/**
* \brief Setter for the Organization Code field.
* \param new_org The new Organization Code to be set.
*/
void org_code(small_uint<24> new_org);
/**
* \brief Setter for the Ethernet Type field.
* \param new_eth The new Ethernet Type to be set.
*/
void eth_type(uint16_t new_eth);
/* Getters */
/**
* \brief Getter for the DSAP field.
* \return The DSAP field.
*/
uint8_t dsap() const {
return snap_.dsap;
}
/**
* \brief Getter for the SSAP field.
* \return The SSAP field.
*/
uint8_t ssap() const {
return snap_.ssap;
}
/**
* \brief Getter for the Control field.
* \return The Control field.
*/
uint8_t control() const {
#if TINS_IS_LITTLE_ENDIAN
return (snap_.control_org) & 0xff;
#else
return (snap_.control_org >> 24) & 0xff;
#endif
}
/**
* \brief Getter for the Organization Code field.
* \return The Organization Code field.
*/
small_uint<24> org_code() const {
#if TINS_IS_LITTLE_ENDIAN
return Endian::be_to_host<uint32_t>(snap_.control_org & 0xffffff00);
#else
return snap_.control_org & 0xffffff;
#endif
}
/**
* \brief Getter for the Ethernet Type field.
* \return The Ethernet Type field.
*/
uint16_t eth_type() const {
return Endian::be_to_host(snap_.eth_type);
}
/**
* \brief Returns the SNAP frame's header length.
*
* \return The header's size.
* \sa PDU::header_size()
*/
uint32_t header_size() const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \brief Clones this PDU.
*
* \sa PDU::clone
*/
SNAP* clone() const {
return new SNAP(*this);
}
private:
TINS_BEGIN_PACK
struct snap_header {
uint8_t dsap;
uint8_t ssap;
uint32_t control_org;
uint16_t eth_type;
} TINS_END_PACK;
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
snap_header snap_;
};
} // Tins
#endif // TINS_SNAP_H

File diff suppressed because it is too large Load Diff

View File

@@ -80,7 +80,7 @@ public:
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
STP(const uint8_t *buffer, uint32_t total_sz);
STP(const uint8_t* buffer, uint32_t total_sz);
// Getters
@@ -89,7 +89,7 @@ public:
* \return The stored Protocol ID field value.
*/
uint16_t proto_id() const {
return Endian::be_to_host(_header.proto_id);
return Endian::be_to_host(header_.proto_id);
}
/**
@@ -97,7 +97,7 @@ public:
* \return The stored Protocol Version field value.
*/
uint8_t proto_version() const {
return _header.proto_version;
return header_.proto_version;
}
/**
@@ -105,7 +105,7 @@ public:
* \return The stored BDU Type field value.
*/
uint8_t bpdu_type() const {
return _header.bpdu_type;
return header_.bpdu_type;
}
/**
@@ -113,7 +113,7 @@ public:
* \return The stored BDU Flags field value.
*/
uint8_t bpdu_flags() const {
return _header.bpdu_flags;
return header_.bpdu_flags;
}
/**
@@ -121,7 +121,7 @@ public:
* \return The stored Root Path Cost field value.
*/
uint32_t root_path_cost() const {
return Endian::be_to_host(_header.root_path_cost);
return Endian::be_to_host(header_.root_path_cost);
}
/**
@@ -129,7 +129,7 @@ public:
* \return The stored Port ID field value.
*/
uint16_t port_id() const {
return Endian::be_to_host(_header.port_id);
return Endian::be_to_host(header_.port_id);
}
/**
@@ -137,7 +137,7 @@ public:
* \return The stored Message Age field value.
*/
uint16_t msg_age() const {
return Endian::be_to_host(_header.msg_age) / 256;
return Endian::be_to_host(header_.msg_age) / 256;
}
/**
@@ -145,7 +145,7 @@ public:
* \return The stored Maximum Age field value.
*/
uint16_t max_age() const {
return Endian::be_to_host(_header.max_age) / 256;
return Endian::be_to_host(header_.max_age) / 256;
}
/**
@@ -153,7 +153,7 @@ public:
* \return The stored Hello Time field value.
*/
uint16_t hello_time() const {
return Endian::be_to_host(_header.hello_time) / 256;
return Endian::be_to_host(header_.hello_time) / 256;
}
/**
@@ -161,7 +161,7 @@ public:
* \return The stored Forward Delay field value.
*/
uint16_t fwd_delay() const {
return Endian::be_to_host(_header.fwd_delay) / 256;
return Endian::be_to_host(header_.fwd_delay) / 256;
}
/**
@@ -180,12 +180,14 @@ public:
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
PDUType pdu_type() const {
return pdu_flag;
}
/**
* \sa PDU::clone
*/
STP *clone() const {
STP* clone() const {
return new STP(*this);
}
@@ -262,13 +264,13 @@ public:
* \brief Setter for the Root ID field.
* \param new_fwd_delay The new Root ID field value.
*/
void root_id(const bpdu_id_type &id);
void root_id(const bpdu_id_type& id);
/**
* \brief Setter for the Bridge ID field.
* \param new_fwd_delay The new Bridge ID field value.
*/
void bridge_id(const bpdu_id_type &id);
void bridge_id(const bpdu_id_type& id);
private:
TINS_BEGIN_PACK
struct pvt_bpdu_id {
@@ -285,7 +287,7 @@ private:
} TINS_END_PACK;
TINS_BEGIN_PACK
struct stphdr {
struct stp_header {
uint16_t proto_id;
uint8_t proto_version;
uint8_t bpdu_type;
@@ -300,12 +302,12 @@ private:
uint16_t fwd_delay;
} TINS_END_PACK;
static bpdu_id_type convert(const pvt_bpdu_id &id);
static pvt_bpdu_id convert(const bpdu_id_type &id);
static bpdu_id_type convert(const pvt_bpdu_id& id);
static pvt_bpdu_id convert(const bpdu_id_type& id);
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
stphdr _header;
stp_header header_;
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -65,7 +65,7 @@ public:
StreamInfo(IPv4Address client, IPv4Address server,
uint16_t cport, uint16_t sport);
bool operator<(const StreamInfo &rhs) const;
bool operator<(const StreamInfo& rhs) const;
};
/**
@@ -79,17 +79,17 @@ public:
* \param tcp The TCP PDU from which to take the initial parameters.
* \param identifier This stream's identifier number
*/
TCPStream(IP *ip, TCP *tcp, uint64_t identifier);
TCPStream(IP* ip, TCP* tcp, uint64_t identifier);
/**
* Copy constructor.
*/
TCPStream(const TCPStream &rhs);
TCPStream(const TCPStream& rhs);
/**
* Copy assignment operator.
*/
TCPStream& operator=(const TCPStream &rhs);
TCPStream& operator=(const TCPStream& rhs);
/**
* Destructor.
@@ -103,7 +103,7 @@ public:
*
* \return const payload_type& containing the payload.
*/
const payload_type &client_payload() const {
const payload_type& client_payload() const {
return client_payload_;
}
@@ -114,7 +114,7 @@ public:
*
* \return payload_type& containing the payload.
*/
payload_type &client_payload() {
payload_type& client_payload() {
return client_payload_;
}
@@ -125,7 +125,7 @@ public:
*
* \return const payload_type& containing the payload.
*/
const payload_type &server_payload() const {
const payload_type& server_payload() const {
return server_payload_;
}
@@ -136,7 +136,7 @@ public:
*
* \return payload_type& containing the payload.
*/
payload_type &server_payload() {
payload_type& server_payload() {
return server_payload_;
}
@@ -145,15 +145,15 @@ public:
* \return uint64_t containing the identification number.
*/
uint64_t id() const {
return identifier;
return identifier_;
}
/**
* \brief Retrieves the stream information.
* \return const StreamInfo& containing the stream information.
*/
const StreamInfo &stream_info() const {
return info;
const StreamInfo& stream_info() const {
return info_;
}
/**
@@ -165,7 +165,7 @@ public:
* \return bool indicating whether the stream is finished.
*/
bool is_finished() const {
return fin_sent;
return fin_sent_;
}
/**
@@ -178,25 +178,25 @@ public:
* \return bool indicating whether any changes have been done to
* any of the stored payloads.
*/
bool update(IP *ip, TCP *tcp);
bool update(IP* ip, TCP* tcp);
private:
typedef std::map<uint32_t, RawPDU*> fragments_type;
static void free_fragments(fragments_type &frags);
static fragments_type clone_fragments(const fragments_type &frags);
static void free_fragments(fragments_type& frags);
static fragments_type clone_fragments(const fragments_type& frags);
bool generic_process(uint32_t &my_seq, uint32_t &other_seq,
payload_type &pload, fragments_type &frags, TCP *tcp);
bool generic_process(uint32_t& my_seq, uint32_t& other_seq,
payload_type& pload, fragments_type& frags, TCP* tcp);
void safe_insert(fragments_type &frags, uint32_t seq, RawPDU *raw);
void safe_insert(fragments_type& frags, uint32_t seq, RawPDU* raw);
uint32_t client_seq, server_seq;
StreamInfo info;
uint64_t identifier;
uint32_t client_seq_, server_seq_;
StreamInfo info_;
uint64_t identifier_;
payload_type client_payload_, server_payload_;
fragments_type client_frags, server_frags;
bool syn_ack_sent, fin_sent;
fragments_type client_frags_, server_frags_;
bool syn_ack_sent_, fin_sent_;
};
@@ -224,7 +224,7 @@ public:
* closed.
*/
template<typename DataFunctor, typename EndFunctor>
void follow_streams(BaseSniffer &sniffer, DataFunctor data_fun, EndFunctor end_fun);
void follow_streams(BaseSniffer& sniffer, DataFunctor data_fun, EndFunctor end_fun);
/**
* \brief Starts following TCP streams.
@@ -263,7 +263,7 @@ public:
* closed.
*/
template<typename DataFunctor>
void follow_streams(BaseSniffer &sniffer, DataFunctor data_fun);
void follow_streams(BaseSniffer& sniffer, DataFunctor data_fun);
/**
* \brief Starts following TCP streams.
@@ -292,89 +292,97 @@ private:
template<typename DataFunctor, typename EndFunctor>
struct proxy_caller {
bool callback(PDU &pdu) {
bool callback(PDU& pdu) {
return stream->callback(pdu, data_fun, end_fun);
}
TCPStreamFollower *stream;
TCPStreamFollower* stream;
DataFunctor data_fun;
EndFunctor end_fun;
};
template<typename DataFunctor, typename EndFunctor>
bool callback(PDU &pdu, const DataFunctor &fun, const EndFunctor &end_fun);
bool callback(PDU& pdu, const DataFunctor& fun, const EndFunctor& end_fun);
static void dummy_function(TCPStream&) { }
sessions_type sessions;
uint64_t last_identifier;
sessions_type sessions_;
uint64_t last_identifier_;
};
template<typename DataFunctor, typename EndFunctor>
void TCPStreamFollower::follow_streams(BaseSniffer &sniffer, DataFunctor data_fun, EndFunctor end_fun) {
void TCPStreamFollower::follow_streams(BaseSniffer& sniffer,
DataFunctor data_fun,
EndFunctor end_fun) {
typedef proxy_caller<DataFunctor, EndFunctor> proxy_type;
proxy_type proxy = { this, data_fun, end_fun };
sniffer.sniff_loop(make_sniffer_handler(&proxy, &proxy_type::callback));
}
template<typename ForwardIterator, typename DataFunctor, typename EndFunctor>
void TCPStreamFollower::follow_streams(ForwardIterator start, ForwardIterator end,
DataFunctor data_fun, EndFunctor end_fun)
{
void TCPStreamFollower::follow_streams(ForwardIterator start,
ForwardIterator end,
DataFunctor data_fun,
EndFunctor end_fun) {
while(start != end) {
if(!callback(Utils::dereference_until_pdu(start), data_fun, end_fun))
if (!callback(Utils::dereference_until_pdu(start), data_fun, end_fun)) {
return;
}
start++;
}
}
template<typename DataFunctor>
void TCPStreamFollower::follow_streams(BaseSniffer &sniffer, DataFunctor data_fun) {
void TCPStreamFollower::follow_streams(BaseSniffer& sniffer, DataFunctor data_fun) {
return follow_streams(sniffer, data_fun, dummy_function);
}
template<typename ForwardIterator, typename DataFunctor>
void TCPStreamFollower::follow_streams(ForwardIterator start, ForwardIterator end,
DataFunctor data_fun)
{
void TCPStreamFollower::follow_streams(ForwardIterator start,
ForwardIterator end,
DataFunctor data_fun) {
follow_streams(start, end, data_fun, dummy_function);
}
template<typename DataFunctor, typename EndFunctor>
bool TCPStreamFollower::callback(PDU &pdu, const DataFunctor &data_fun, const EndFunctor &end_fun) {
IP *ip = pdu.find_pdu<IP>();
TCP *tcp = pdu.find_pdu<TCP>();
if(!ip || !tcp) {
bool TCPStreamFollower::callback(PDU& pdu,
const DataFunctor& data_fun,
const EndFunctor& end_fun) {
IP* ip = pdu.find_pdu<IP>();
TCP* tcp = pdu.find_pdu<TCP>();
if (!ip || !tcp) {
return true;
}
TCPStream::StreamInfo info(
ip->src_addr(), ip->dst_addr(),
tcp->sport(), tcp->dport()
);
sessions_type::iterator it = sessions.find(info);
if(it == sessions.end()) {
sessions_type::iterator it = sessions_.find(info);
if (it == sessions_.end()) {
std::swap(info.client_addr, info.server_addr);
std::swap(info.client_port, info.server_port);
if((it = sessions.find(info)) == sessions.end()) {
if(tcp->get_flag(TCP::SYN) && !tcp->get_flag(TCP::ACK)) {
sessions.insert(
if ((it = sessions_.find(info)) == sessions_.end()) {
if (tcp->get_flag(TCP::SYN) && !tcp->get_flag(TCP::ACK)) {
sessions_.insert(
std::make_pair(
info,
TCPStream(ip, tcp, last_identifier++)
TCPStream(ip, tcp, last_identifier_++)
)
);
}
return true;
}
}
if(it->second.update(ip, tcp))
if (it->second.update(ip, tcp)) {
data_fun(it->second);
}
// We're done with this stream
if(it->second.is_finished()) {
if (it->second.is_finished()) {
end_fun(it->second);
sessions.erase(it);
sessions_.erase(it);
}
return true;
}
}
} // Tins
#endif // TINS_TCP_STREAM_H

View File

@@ -93,7 +93,7 @@ public:
* Constructs a timestamp from a timeval object.
* \param time_val The timeval object.
*/
Timestamp(const timeval &time_val) : tv(time_val) {}
Timestamp(const timeval& time_val) : tv(time_val) {}
/**
* Returns the amount of seconds in this timestamp.
@@ -121,6 +121,7 @@ public:
private:
timeval tv;
};
}
} // Tins
#endif // TINS_TIMESTAMP_H

View File

@@ -36,150 +36,159 @@
namespace Tins {
/**
* \class UDP
* \brief Represents an UDP PDU.
*
* This class represents an UDP PDU.
*
* While sniffing, the payload sent in each packet will be wrapped
* in a RawPDU, which is set as the UDP object's inner_pdu. Therefore,
* if you are sniffing and want to see the UDP packet's payload,
* you need to do the following:
*
* \code
* // Get a packet from somewhere.
* UDP udp = ...;
*
* // Extract the RawPDU object.
* const RawPDU& raw = udp.rfind_pdu<RawPDU>();
*
* // Finally, take the payload (this is a vector<uint8_t>)
* const RawPDU::payload_type& payload = raw.payload();
* \endcode
*
* \sa RawPDU
/**
* \class UDP
* \brief Represents an UDP PDU.
*
* This class represents an UDP PDU.
*
* While sniffing, the payload sent in each packet will be wrapped
* in a RawPDU, which is set as the UDP object's inner_pdu. Therefore,
* if you are sniffing and want to see the UDP packet's payload,
* you need to do the following:
*
* \code
* // Get a packet from somewhere.
* UDP udp = ...;
*
* // Extract the RawPDU object.
* const RawPDU& raw = udp.rfind_pdu<RawPDU>();
*
* // Finally, take the payload (this is a vector<uint8_t>)
* const RawPDU::payload_type& payload = raw.payload();
* \endcode
*
* \sa RawPDU
*/
class UDP : public PDU {
public:
/**
* \brief This PDU's flag.
*/
class UDP : public PDU {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::UDP;
static const PDU::PDUType pdu_flag = PDU::UDP;
/**
* \brief UDP constructor.
*
* Constructs an instance of UDP. The destination and source
* port can be provided, otherwise both of them will be 0.
*
* \param dport Destination port.
* \param sport Source port.
* */
UDP(uint16_t dport = 0, uint16_t sport = 0);
/**
* \brief Constructs an UDP object from a buffer.
*
* If there is not enough size for a UDP header a malformed_packet
* exception is thrown.
*
* Any extra data will be stored in a RawPDU.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
UDP(const uint8_t* buffer, uint32_t total_sz);
/**
* \brief UDP constructor.
*
* Constructs an instance of UDP. The destination and source
* port can be provided, otherwise both of them will be 0.
*
* \param dport Destination port.
* \param sport Source port.
* */
UDP(uint16_t dport = 0, uint16_t sport = 0);
/**
* \brief Getter for the destination port.
* \return The datagram's destination port.
*/
uint16_t dport() const {
return Endian::be_to_host(header_.dport);
}
/**
* \brief Constructs an UDP object from a buffer.
*
* If there is not enough size for a UDP header a malformed_packet
* exception is thrown.
*
* Any extra data will be stored in a RawPDU.
*
* \param buffer The buffer from which this PDU will be constructed.
* \param total_sz The total size of the buffer.
*/
UDP(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Getter for the destination port.
* \return The datagram's destination port.
*/
uint16_t dport() const { return Endian::be_to_host(_udp.dport); }
/**
* \brief Getter for the source port.
* \return The datagram's source port.
*/
uint16_t sport() const {
return Endian::be_to_host(header_.sport);
}
/**
* \brief Getter for the length of the datagram.
* \return The length of the datagram.
*/
uint16_t length() const {
return Endian::be_to_host(header_.len);
}
/**
* \brief Getter for the checksum of the datagram.
* \return The datagram's checksum.
*/
uint16_t checksum() const {
return Endian::be_to_host(header_.check);
}
/**
* \brief Getter for the source port.
* \return The datagram's source port.
*/
uint16_t sport() const { return Endian::be_to_host(_udp.sport); }
/**
* \brief Getter for the length of the datagram.
* \return The length of the datagram.
*/
uint16_t length() const { return Endian::be_to_host(_udp.len); }
/**
* \brief Getter for the checksum of the datagram.
* \return The datagram's checksum.
*/
uint16_t checksum() const { return Endian::be_to_host(_udp.check); }
/**
* \brief Set the destination port.
* \param new_dport The new destination port.
*/
void dport(uint16_t new_dport);
/**
* \brief Set the destination port.
* \param new_dport The new destination port.
*/
void dport(uint16_t new_dport);
/**
* \brief Set the source port.
*
* \param new_sport The new source port.
*/
void sport(uint16_t new_sport);
/**
* \brief Getter for the length field.
* \param new_len The new length field.
* \return The length field.
*/
void length(uint16_t new_len);
/**
* \brief Set the source port.
*
* \param new_sport The new source port.
*/
void sport(uint16_t new_sport);
/**
* \brief Getter for the length field.
* \param new_len The new length field.
* \return The length field.
*/
void length(uint16_t new_len);
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* This compares the source and destination ports in the provided
* response with those stored in this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t* ptr, uint32_t total_sz) const;
/**
* \brief Check wether ptr points to a valid response for this PDU.
*
* This compares the source and destination ports in the provided
* response with those stored in this PDU.
*
* \sa PDU::matches_response
* \param ptr The pointer to the buffer.
* \param total_sz The size of the buffer.
*/
bool matches_response(const uint8_t *ptr, uint32_t total_sz) const;
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. This size includes the
* payload and options size. \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::UDP; }
/**
* \sa PDU::clone
*/
UDP* clone() const {
return new UDP(*this);
}
private:
TINS_BEGIN_PACK
struct udp_header {
uint16_t sport;
uint16_t dport;
uint16_t len;
uint16_t check;
} TINS_END_PACK;
/**
* \brief Returns the header size.
*
* This metod overrides PDU::header_size. This size includes the
* payload and options size. \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return PDU::UDP; }
/**
* \sa PDU::clone
*/
UDP *clone() const {
return new UDP(*this);
}
private:
TINS_BEGIN_PACK
struct udphdr {
uint16_t sport;
uint16_t dport;
uint16_t len;
uint16_t check;
} TINS_END_PACK;
void write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* parent);
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
udp_header header_;
};
udphdr _udp;
};
}
} // Tins
#endif // TINS_UDP_H

View File

@@ -59,335 +59,351 @@
#include "internals.h"
namespace Tins {
class NetworkInterface;
class PacketSender;
class PDU;
/**
* \brief Network utils namespace.
*
* This namespace provides utils to convert between integer IP addresses
* and dotted notation strings, "net to host" integer conversions,
* interface listing, etc.
class NetworkInterface;
class PacketSender;
class PDU;
/**
* \brief Network utils namespace.
*
* This namespace provides utils to convert between integer IP addresses
* and dotted notation strings, "net to host" integer conversions,
* interface listing, etc.
*/
namespace Utils {
/**
* Struct that represents an entry in /proc/net/route
*/
struct RouteEntry {
/**
* This interface's name.
*/
namespace Utils {
/**
* Struct that represents an entry in /proc/net/route
*/
struct RouteEntry {
/**
* This interface's name.
*/
std::string interface;
/**
* This route entry's destination.
*/
IPv4Address destination;
/**
* This route entry's gateway.
*/
IPv4Address gateway;
/**
* This route entry's subnet mask.
*/
IPv4Address mask;
std::string interface;
/**
* This route entry's destination.
*/
IPv4Address destination;
/**
* This route entry's gateway.
*/
IPv4Address gateway;
/**
* This route entry's subnet mask.
*/
IPv4Address mask;
/**
* This route entry's metric.
*/
int metric;
};
/**
* \brief Resolves a domain name and returns its corresponding ip address.
*
* If an ip address is given, its integer representation is returned.
* Otherwise, the domain name is resolved and its ip address is returned.
*
* \param to_resolve The domain name/ip address to resolve.
*/
IPv4Address resolve_domain(const std::string &to_resolve);
/**
* \brief Resolves a domain name and returns its corresponding ip address.
*
* If an ip address is given, its integer representation is returned.
* Otherwise, the domain name is resolved and its ip address is returned.
*
* \param to_resolve The domain name/ip address to resolve.
*/
IPv6Address resolve_domain6(const std::string &to_resolve);
/**
* \brief Resolves the hardware address for a given ip.
*
* If the address can't be resolved, a std::runtime_error
* exception is thrown.
*
* \param iface The interface in which the packet will be sent.
* \param ip The ip to resolve, in integer format.
* \param sender The sender to use to send and receive the ARP requests.
* \return HWAddress<6> containing the resolved hardware address.
*/
HWAddress<6> resolve_hwaddr(const NetworkInterface &iface,
IPv4Address ip, PacketSender &sender);
/**
* \brief Resolves the hardware address for a given ip.
*
* If the address can't be resolved, a std::runtime_error
* exception is thrown.
*
* This method sends and receives the packet through
* PacketSender::default_interface.
*
* \param ip The ip to resolve, in integer format.
* \param sender The sender to use to send and receive the ARP requests.
* \return HWAddress<6> containing the resolved hardware address.
*/
HWAddress<6> resolve_hwaddr(IPv4Address ip, PacketSender &sender);
/**
* This route entry's metric.
*/
int metric;
};
/** \brief List all network interfaces.
*
* Returns a set of strings, each of them representing the name
* of a network interface. These names can be used as the input
* interface for Utils::interface_ip, Utils::interface_hwaddr, etc.
*/
std::set<std::string> network_interfaces();
/**
* \brief Finds the gateway's IP address for the given IP
* address.
*
* \param ip The IP address for which the default gateway will
* be searched.
* \param gw_addr This parameter will contain the gateway's IP
* address in case it is found.
*
* \return bool indicating wether the lookup was successfull.
*/
bool gateway_from_ip(IPv4Address ip, IPv4Address &gw_addr);
/**
* \brief Retrieves entries in the routing table.
*
* \brief output ForwardIterator in which entries will be stored.
*/
template<class ForwardIterator>
void route_entries(ForwardIterator output);
/**
* \brief Resolves a domain name and returns its corresponding ip address.
*
* If an ip address is given, its integer representation is returned.
* Otherwise, the domain name is resolved and its ip address is returned.
*
* \param to_resolve The domain name/ip address to resolve.
*/
TINS_API IPv4Address resolve_domain(const std::string& to_resolve);
/**
* \brief Retrieves entries in the routing table.
*
* \return a vector which contains all of the route entries.
*/
std::vector<RouteEntry> route_entries();
/**
* \brief Resolves a domain name and returns its corresponding ip address.
*
* If an ip address is given, its integer representation is returned.
* Otherwise, the domain name is resolved and its ip address is returned.
*
* \param to_resolve The domain name/ip address to resolve.
*/
TINS_API IPv6Address resolve_domain6(const std::string& to_resolve);
/** \brief Returns the 32 bit crc of the given buffer.
*
* \param data The input buffer.
* \param data_size The size of the input buffer.
*/
uint32_t crc32(const uint8_t* data, uint32_t data_size);
/**
* \brief Resolves the hardware address for a given ip.
*
* If the address can't be resolved, a std::runtime_error
* exception is thrown.
*
* \param iface The interface in which the packet will be sent.
* \param ip The ip to resolve, in integer format.
* \param sender The sender to use to send and receive the ARP requests.
* \return HWAddress<6> containing the resolved hardware address.
*/
TINS_API HWAddress<6> resolve_hwaddr(const NetworkInterface& iface,
IPv4Address ip,
PacketSender& sender);
/**
* \brief Converts a channel number to its mhz representation.
* \param channel The channel number.
* \return The channel's mhz representation.
*/
uint16_t channel_to_mhz(uint16_t channel);
/**
* \brief Converts mhz units to the appropriate channel number.
* \param mhz The mhz units to be converted.
* \return The channel number.
*/
uint16_t mhz_to_channel(uint16_t mhz);
/**
* \brief Converts a PDUType to a string.
* \param pduType The PDUType to be converted.
* \return A string representation, for example "DOT11_QOS_DATA".
*/
std::string to_string(PDU::PDUType pduType);
/**
* \brief Resolves the hardware address for a given ip.
*
* If the address can't be resolved, a std::runtime_error
* exception is thrown.
*
* This method sends and receives the packet through
* PacketSender::default_interface.
*
* \param ip The ip to resolve, in integer format.
* \param sender The sender to use to send and receive the ARP requests.
* \return HWAddress<6> containing the resolved hardware address.
*/
TINS_API HWAddress<6> resolve_hwaddr(IPv4Address ip, PacketSender& sender);
/**
* \brief Does the 16 bits sum of all 2 bytes elements between start and end.
*
* This is the checksum used by IP, UDP and TCP. If there's and odd number of
* bytes, the last one is padded and added to the checksum.
* \param start The pointer to the start of the buffer.
* \param end The pointer to the end of the buffer(excluding the last element).
* \return Returns the checksum between start and end (non inclusive)
* in network endian
*/
uint32_t do_checksum(const uint8_t *start, const uint8_t *end);
/** \brief List all network interfaces.
*
* Returns a set of strings, each of them representing the name
* of a network interface. These names can be used as the input
* interface for Utils::interface_ip, Utils::interface_hwaddr, etc.
*/
TINS_API std::set<std::string> network_interfaces();
/**
* \brief Computes the 16 bit sum of the input buffer.
*
* If there's and odd number of bytes in the buffer, the last one is padded and
* added to the checksum.
* \param start The pointer to the start of the buffer.
* \param end The pointer to the end of the buffer(excluding the last element).
* \return Returns the checksum between start and end (non inclusive)
* in network endian
*/
uint16_t sum_range(const uint8_t *start, const uint8_t *end);
/**
* \brief Finds the gateway's IP address for the given IP
* address.
*
* \param ip The IP address for which the default gateway will
* be searched.
* \param gw_addr This parameter will contain the gateway's IP
* address in case it is found.
*
* \return bool indicating wether the lookup was successfull.
*/
TINS_API bool gateway_from_ip(IPv4Address ip, IPv4Address& gw_addr);
/** \brief Performs the pseudo header checksum used in TCP and UDP PDUs.
*
* \param source_ip The source ip address.
* \param dest_ip The destination ip address.
* \param len The length to be included in the pseudo header.
* \param flag The flag to use in the protocol field of the pseudo header.
* \return The pseudo header checksum.
*/
uint32_t pseudoheader_checksum(IPv4Address source_ip, IPv4Address dest_ip, uint16_t len, uint16_t flag);
/** \brief Performs the pseudo header checksum used in TCP and UDP PDUs.
*
* \param source_ip The source ip address.
* \param dest_ip The destination ip address.
* \param len The length to be included in the pseudo header.
* \param flag The flag to use in the protocol field of the pseudo header.
* \return The pseudo header checksum.
*/
uint32_t pseudoheader_checksum(IPv6Address source_ip, IPv6Address dest_ip, uint16_t len, uint16_t flag);
/** \brief Generic function to iterate through interface and collect
* data.
*
* The parameter is applied to every interface found, allowing
* the object to collect data from them.
* \param functor An instance of an class which implements operator(struct ifaddrs*).
*/
#ifndef _WIN32
template<class Functor>
void generic_iface_loop(Functor &functor) {
struct ifaddrs *ifaddrs = 0;
struct ifaddrs *if_it = 0;
getifaddrs(&ifaddrs);
for(if_it = ifaddrs; if_it; if_it = if_it->ifa_next) {
if(functor(if_it))
break;
}
if(ifaddrs)
freeifaddrs(ifaddrs);
/**
* \brief Retrieves entries in the routing table.
*
* \brief output ForwardIterator in which entries will be stored.
*/
template<class ForwardIterator>
void route_entries(ForwardIterator output);
/**
* \brief Retrieves entries in the routing table.
*
* \return a vector which contains all of the route entries.
*/
TINS_API std::vector<RouteEntry> route_entries();
/** \brief Returns the 32 bit crc of the given buffer.
*
* \param data The input buffer.
* \param data_size The size of the input buffer.
*/
TINS_API uint32_t crc32(const uint8_t* data, uint32_t data_size);
/**
* \brief Converts a channel number to its mhz representation.
* \param channel The channel number.
* \return The channel's mhz representation.
*/
TINS_API uint16_t channel_to_mhz(uint16_t channel);
/**
* \brief Converts mhz units to the appropriate channel number.
* \param mhz The mhz units to be converted.
* \return The channel number.
*/
TINS_API uint16_t mhz_to_channel(uint16_t mhz);
/**
* \brief Converts a PDUType to a string.
* \param pduType The PDUType to be converted.
* \return A string representation, for example "DOT11_QOS_DATA".
*/
TINS_API std::string to_string(PDU::PDUType pduType);
/**
* \brief Does the 16 bits sum of all 2 bytes elements between start and end.
*
* This is the checksum used by IP, UDP and TCP. If there's and odd number of
* bytes, the last one is padded and added to the checksum.
* \param start The pointer to the start of the buffer.
* \param end The pointer to the end of the buffer(excluding the last element).
* \return Returns the checksum between start and end (non inclusive)
* in network endian
*/
TINS_API uint32_t do_checksum(const uint8_t* start, const uint8_t* end);
/**
* \brief Computes the 16 bit sum of the input buffer.
*
* If there's and odd number of bytes in the buffer, the last one is padded and
* added to the checksum.
* \param start The pointer to the start of the buffer.
* \param end The pointer to the end of the buffer(excluding the last element).
* \return Returns the checksum between start and end (non inclusive)
* in network endian
*/
TINS_API uint16_t sum_range(const uint8_t* start, const uint8_t* end);
/** \brief Performs the pseudo header checksum used in TCP and UDP PDUs.
*
* \param source_ip The source ip address.
* \param dest_ip The destination ip address.
* \param len The length to be included in the pseudo header.
* \param flag The flag to use in the protocol field of the pseudo header.
* \return The pseudo header checksum.
*/
TINS_API uint32_t pseudoheader_checksum(IPv4Address source_ip,
IPv4Address dest_ip,
uint16_t len,
uint16_t flag);
/** \brief Performs the pseudo header checksum used in TCP and UDP PDUs.
*
* \param source_ip The source ip address.
* \param dest_ip The destination ip address.
* \param len The length to be included in the pseudo header.
* \param flag The flag to use in the protocol field of the pseudo header.
* \return The pseudo header checksum.
*/
TINS_API uint32_t pseudoheader_checksum(IPv6Address source_ip,
IPv6Address dest_ip,
uint16_t len,
uint16_t flag);
/** \brief Generic function to iterate through interface and collect
* data.
*
* The parameter is applied to every interface found, allowing
* the object to collect data from them.
* \param functor An instance of an class which implements operator(struct ifaddrs*).
*/
#ifndef _WIN32
template<class Functor>
void generic_iface_loop(Functor& functor) {
struct ifaddrs* ifaddrs = 0;
struct ifaddrs* if_it = 0;
getifaddrs(&ifaddrs);
for (if_it = ifaddrs; if_it; if_it = if_it->ifa_next) {
if (functor(if_it)) {
break;
}
#else // _WIN32
template<class Functor>
void generic_iface_loop(Functor &functor) {
ULONG size;
::GetAdaptersAddresses(AF_INET, 0, 0, 0, &size);
std::vector<uint8_t> buffer(size);
if (::GetAdaptersAddresses(AF_INET, 0, 0, (IP_ADAPTER_ADDRESSES *)&buffer[0], &size) == ERROR_SUCCESS) {
PIP_ADAPTER_ADDRESSES iface = (IP_ADAPTER_ADDRESSES *)&buffer[0];
while(iface) {
if(functor(iface))
break;
iface = iface->Next;
}
}
}
#endif // _WIN32
template <typename T>
struct is_pdu {
template <typename U>
static char test(typename U::PDUType*);
template <typename U>
static long test(...);
static const bool value = sizeof(test<T>(0)) == 1;
};
/**
* Returns the argument.
*/
inline PDU& dereference_until_pdu(PDU &pdu) {
return pdu;
}
/**
* \brief Dereferences the parameter until a PDU is found.
*
* This function dereferences the parameter until a PDU object
* is found. When it's found, it is returned.
*
* \param value The parameter to be dereferenced.
*/
template<typename T>
inline typename Internals::enable_if<!is_pdu<T>::value, PDU&>::type
dereference_until_pdu(T &value) {
return dereference_until_pdu(*value);
}
#if defined(BSD) || defined(__FreeBSD_kernel__)
inline std::vector<char> query_route_table() {
int mib[6];
std::vector<char> buf;
size_t len;
mib[0] = CTL_NET;
mib[1] = AF_ROUTE;
mib[2] = 0;
mib[3] = AF_INET;
mib[4] = NET_RT_DUMP;
mib[5] = 0;
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
throw std::runtime_error("sysctl failed");
buf.resize(len);
if (sysctl(mib, 6, &buf[0], &len, NULL, 0) < 0) {
throw std::runtime_error("sysctl failed");
}
return buf;
}
template<typename ForwardIterator>
void parse_header(struct rt_msghdr *rtm, ForwardIterator iter)
{
char *ptr = (char *)(rtm + 1);
sockaddr *sa = 0;
for (int i = 0; i < RTAX_MAX; i++) {
if (rtm->rtm_addrs & (1 << i)) {
sa = (struct sockaddr *)ptr;
ptr += sa->sa_len;
if (sa->sa_family == 0)
sa = 0;
}
*iter++ = sa;
}
}
#endif
}
if (ifaddrs) {
freeifaddrs(ifaddrs);
}
}
#else // _WIN32
template<class Functor>
void generic_iface_loop(Functor& functor) {
ULONG size;
::GetAdaptersAddresses(AF_INET, 0, 0, 0, &size);
std::vector<uint8_t> buffer(size);
if (::GetAdaptersAddresses(AF_INET, 0, 0, (IP_ADAPTER_ADDRESSES *)&buffer[0], &size) == ERROR_SUCCESS) {
PIP_ADAPTER_ADDRESSES iface = (IP_ADAPTER_ADDRESSES *)&buffer[0];
while (iface) {
if (functor(iface)) {
break;
}
iface = iface->Next;
}
}
}
#endif // _WIN32
template <typename T>
struct is_pdu {
template <typename U>
static char test(typename U::PDUType*);
template <typename U>
static long test(...);
static const bool value = sizeof(test<T>(0)) == 1;
};
/**
* Returns the argument.
*/
inline PDU& dereference_until_pdu(PDU& pdu) {
return pdu;
}
/**
* \brief Dereferences the parameter until a PDU is found.
*
* This function dereferences the parameter until a PDU object
* is found. When it's found, it is returned.
*
* \param value The parameter to be dereferenced.
*/
template<typename T>
inline typename Internals::enable_if<!is_pdu<T>::value, PDU&>::type
dereference_until_pdu(T& value) {
return dereference_until_pdu(*value);
}
#if defined(BSD) || defined(__FreeBSD_kernel__)
inline std::vector<char> query_route_table() {
int mib[6];
std::vector<char> buf;
size_t len;
mib[0] = CTL_NET;
mib[1] = AF_ROUTE;
mib[2] = 0;
mib[3] = AF_INET;
mib[4] = NET_RT_DUMP;
mib[5] = 0;
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
throw std::runtime_error("sysctl failed");
}
buf.resize(len);
if (sysctl(mib, 6, &buf[0], &len, NULL, 0) < 0) {
throw std::runtime_error("sysctl failed");
}
return buf;
}
template<typename ForwardIterator>
void parse_header(struct rt_msghdr* rtm, ForwardIterator iter) {
char* ptr = (char *)(rtm + 1);
sockaddr* sa = 0;
for (int i = 0; i < RTAX_MAX; i++) {
if (rtm->rtm_addrs & (1 << i)) {
sa = (struct sockaddr *)ptr;
ptr += sa->sa_len;
if (sa->sa_family == 0) {
sa = 0;
}
}
*iter++ = sa;
}
}
#endif
} // Utils
} // Tins
#if defined(BSD) || defined(__FreeBSD_kernel__)
template<class ForwardIterator>
void Tins::Utils::route_entries(ForwardIterator output) {
std::vector<char> buffer = query_route_table();
char *next = &buffer[0], *end = &buffer[buffer.size()];
rt_msghdr *rtm;
char* next = &buffer[0], *end = &buffer[buffer.size()];
rt_msghdr* rtm;
std::vector<sockaddr*> sa(RTAX_MAX);
char iface_name[IF_NAMESIZE];
while(next < end) {
while (next < end) {
rtm = (rt_msghdr*)next;
parse_header(rtm, sa.begin());
if (sa[RTAX_DST] && sa[RTAX_GATEWAY] && if_indextoname(rtm->rtm_index, iface_name)) {
RouteEntry entry;
entry.destination = IPv4Address(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr.s_addr);
entry.gateway = IPv4Address(((struct sockaddr_in *)sa[RTAX_GATEWAY])->sin_addr.s_addr);
if(sa[RTAX_GENMASK])
if (sa[RTAX_GENMASK]) {
entry.mask = IPv4Address(((struct sockaddr_in *)sa[RTAX_GENMASK])->sin_addr.s_addr);
else
}
else {
entry.mask = IPv4Address(uint32_t());
}
entry.interface = iface_name;
entry.metric = 0;
*output++ = entry;
@@ -398,7 +414,7 @@ void Tins::Utils::route_entries(ForwardIterator output) {
#elif defined(_WIN32)
template<class ForwardIterator>
void Tins::Utils::route_entries(ForwardIterator output) {
MIB_IPFORWARDTABLE *table;
MIB_IPFORWARDTABLE* table;
ULONG size = 0;
GetIpForwardTable(0, &size, 0);
std::vector<uint8_t> buffer(size);
@@ -406,9 +422,9 @@ void Tins::Utils::route_entries(ForwardIterator output) {
GetIpForwardTable(table, &size, 0);
for (DWORD i = 0; i < table->dwNumEntries; i++) {
MIB_IPFORWARDROW *row = &table->table[i];
if(row->dwForwardType == MIB_IPROUTE_TYPE_INDIRECT ||
row->dwForwardType == MIB_IPROUTE_TYPE_DIRECT) {
MIB_IPFORWARDROW* row = &table->table[i];
if (row->dwForwardType == MIB_IPROUTE_TYPE_INDIRECT ||
row->dwForwardType == MIB_IPROUTE_TYPE_DIRECT) {
RouteEntry entry;
entry.interface = NetworkInterface::from_index(row->dwForwardIfIndex).name();
entry.destination = IPv4Address(row->dwForwardDest);
@@ -428,9 +444,10 @@ void Tins::Utils::route_entries(ForwardIterator output) {
uint32_t dummy;
skip_line(input);
RouteEntry entry;
while(input >> entry.interface >> destination >> gw) {
for(unsigned i(0); i < 4; ++i)
while (input >> entry.interface >> destination >> gw) {
for (unsigned i(0); i < 4; ++i) {
input >> metric;
}
input >> mask;
from_hex(destination, dummy);
entry.destination = IPv4Address(dummy);

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 &sections) {
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 &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) {
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 &section_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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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, &current_channel);
}
void Dot11ManagementFrame::cf_parameter_set(const cf_params_set &params) {
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 &params) {
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 &params) {
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 &params) {
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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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));
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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

Some files were not shown because too many files have changed in this diff Show More