diff --git a/examples/arpmonitor.cpp b/examples/arpmonitor.cpp index 16655ff..6caa2df 100644 --- a/examples/arpmonitor.cpp +++ b/examples/arpmonitor.cpp @@ -32,21 +32,25 @@ #include #include +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> addresses; + map> 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(); + const ARP& arp = pdu.rfind_pdu(); // 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 << " \n"; + cout << "Usage: " <<* argv << " " << endl; return 1; } arp_monitor monitor; diff --git a/examples/arpspoofing.cpp b/examples/arpspoofing.cpp index 879fcf1..543ca54 100644 --- a/examples/arpspoofing.cpp +++ b/examples/arpspoofing.cpp @@ -44,13 +44,17 @@ #include #include -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 << " \n") +int main(int argc, char* argv[]) { + if (argc != 3) { + cout << "Usage: " <<* argv << " " << 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; } } diff --git a/examples/beacon_display.cpp b/examples/beacon_display.cpp index 042d7a0..eb99a30 100644 --- a/examples/beacon_display.cpp +++ b/examples/beacon_display.cpp @@ -32,21 +32,27 @@ #include #include +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 ssids_type; + typedef set 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(); + const Dot11Beacon& beacon = pdu.rfind_pdu(); // 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 << " " << endl; + return 1; + } + string interface = argv[1]; BeaconSniffer sniffer; sniffer.run(interface); } diff --git a/examples/dns_queries.cpp b/examples/dns_queries.cpp index 05d9412..f3d914f 100644 --- a/examples/dns_queries.cpp +++ b/examples/dns_queries.cpp @@ -30,10 +30,12 @@ #include #include +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().to(); // 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 << " " << std::endl; + cout << "Usage: " <<* argv << " " << endl; return 1; } // Sniff on the provided interface in promiscuos mode diff --git a/examples/dns_spoof.cpp b/examples/dns_spoof.cpp index ace62af..0ea4fa4 100644 --- a/examples/dns_spoof.cpp +++ b/examples/dns_spoof.cpp @@ -30,11 +30,14 @@ #include #include +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().to(); // 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 << " " << std::endl; + cout << "Usage: " <<* argv << " " << endl; return 1; } // Sniff on the provided interface in promiscuos mode diff --git a/examples/dns_stats.cpp b/examples/dns_stats.cpp index c467d4f..0d4bda5 100644 --- a/examples/dns_stats.cpp +++ b/examples/dns_stats.cpp @@ -39,6 +39,25 @@ #include #include +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 class statistics { public: using duration_type = Duration; - using locker_type = std::lock_guard; + using locker_type = lock_guard; 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; @@ -99,21 +117,21 @@ public: return m_stats; } private: - using packet_info = std::tuple; - using clock_type = std::chrono::system_clock; + using packet_info = tuple; + 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 m_packet_info; + map 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().to(); 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(now - iter->second) + duration_cast(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(); - 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; } } diff --git a/examples/icmp_responses.cpp b/examples/icmp_responses.cpp index 50ace8a..aa65a88 100644 --- a/examples/icmp_responses.cpp +++ b/examples/icmp_responses.cpp @@ -33,7 +33,13 @@ #include #include -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(); - IP& received_ip = pdu.rfind_pdu(); + // Generates an ICMP response given a packet. + EthernetII generate_response(PDU& pdu) { + // Find Ethernet and IP headers. + EthernetII& received_eth = pdu.rfind_pdu(); + IP& received_ip = pdu.rfind_pdu(); - // 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(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(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] << " " << 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] << " " << 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; + } } \ No newline at end of file diff --git a/examples/interfaces_info.cpp b/examples/interfaces_info.cpp index 14bb7a2..e5d23be 100644 --- a/examples/interfaces_info.cpp +++ b/examples/interfaces_info.cpp @@ -31,28 +31,31 @@ #include #include +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; + } } \ No newline at end of file diff --git a/examples/portscan.cpp b/examples/portscan.cpp index e2fb687..7b23e52 100644 --- a/examples/portscan.cpp +++ b/examples/portscan.cpp @@ -44,22 +44,30 @@ #include #include +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_data; +typedef pair sniffer_data; class Scanner { public: - Scanner(const NetworkInterface& interface, const IPv4Address& address, - const vector& ports); + Scanner(const NetworkInterface& interface, + const IPv4Address& address, + const vector& 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& ports) -: iface(interface), host_to_scan(address), sniffer(interface.name()) -{ +Scanner::Scanner(const NetworkInterface& interface, + const IPv4Address& address, + const vector& 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(); - const TCP &tcp = pdu.rfind_pdu(); + const IP& ip = pdu.rfind_pdu(); + const TCP& tcp = pdu.rfind_pdu(); // 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 = ip.rfind_pdu(); // Set the SYN flag on. tcp.set_flag(TCP::SYN, 1); // Just some random port. tcp.sport(1337); cout << "Sending SYNs..." << endl; - for(set::const_iterator it = ports_to_scan.begin(); it != ports_to_scan.end(); ++it) { + for (set::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 << " [port2] [port3]\n") +int main(int argc, char* argv[]) { + if (argc < 3) { + cout << "Usage: " <<* argv << " [port2] [port3]" << endl; return 1; + } try { scan(argc, argv); } - catch(std::runtime_error &ex) { + catch(runtime_error& ex) { cout << "Error - " << ex.what() << endl; } } diff --git a/examples/route_table.cpp b/examples/route_table.cpp index 1e3e2ae..49f22be 100644 --- a/examples/route_table.cpp +++ b/examples/route_table.cpp @@ -32,17 +32,21 @@ #include #include -using namespace std; +using std::cout; +using std::endl; +using std::setw; +using std::vector; + using namespace Tins; int main() { - vector 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 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; + } } \ No newline at end of file diff --git a/examples/traceroute.cpp b/examples/traceroute.cpp index 1aa1da7..d8f0bae 100644 --- a/examples/traceroute.cpp +++ b/examples/traceroute.cpp @@ -43,6 +43,25 @@ #include #include +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 result_type; Traceroute(NetworkInterface interface, IPv4Address address) - : iface(interface), addr(address), lowest_dest_ttl(std::numeric_limits::max()) { - sequence = std::random_device()(); + : iface(interface), addr(address), lowest_dest_ttl(numeric_limits::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::max()) { + if (lowest_dest_ttl != numeric_limits::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 ttl_map; + typedef map 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.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 _(lock); + lock_guard _(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(); - const ICMP &icmp = pdu.rfind_pdu(); + const IP& ip = pdu.rfind_pdu(); + const ICMP& icmp = pdu.rfind_pdu(); // 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(icmp.id())); + lowest_dest_ttl = min(lowest_dest_ttl, static_cast(icmp.id())); } return running; } NetworkInterface iface; IPv4Address addr; - std::atomic running; + atomic 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 << " \n") + if (argc <= 1) { + cout << "Usage: " <<* argv << " " << 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; } } diff --git a/examples/wps_detect.cpp b/examples/wps_detect.cpp index c87d435..8731aa7 100644 --- a/examples/wps_detect.cpp +++ b/examples/wps_detect.cpp @@ -41,11 +41,11 @@ std::set> addrs; const HWAddress<3> expected_oui("00:50:F2"); bool handler(const PDU& pdu) { - const Dot11Beacon &beacon = pdu.rfind_pdu(); + const Dot11Beacon& beacon = pdu.rfind_pdu(); // 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 << " \n"; + std::cout << "Usage: " <<* argv << " \n"; return 1; } // Only sniff beacons diff --git a/include/tins/address_range.h b/include/tins/address_range.h index 77ee05a..17803a4 100644 --- a/include/tins/address_range.h +++ b/include/tins/address_range.h @@ -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 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( 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 IPv6Range; * \param mask The bit-length of the prefix. */ template -AddressRange > operator/(const HWAddress &addr, int mask) { - if(mask > 48) +AddressRange > operator/(const HWAddress& addr, int mask) { + if (mask > 48) { throw std::logic_error("Prefix length cannot exceed 48"); + } HWAddress last_addr; typename HWAddress::iterator it = last_addr.begin(); - while(mask > 8) { + while (mask > 8) { *it = 0xff; ++it; mask -= 8; @@ -318,14 +321,14 @@ AddressRange > operator/(const HWAddress &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 diff --git a/include/tins/arp.h b/include/tins/arp.h index 1f7cf4c..a2c633a 100644 --- a/include/tins/arp.h +++ b/include/tins/arp.h @@ -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 diff --git a/include/tins/bootp.h b/include/tins/bootp.h index fa28546..e1be4cb 100644 --- a/include/tins/bootp.h +++ b/include/tins/bootp.h @@ -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 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 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 - void chaddr(const HWAddress &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 + void chaddr(const HWAddress& 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 diff --git a/include/tins/constants.h b/include/tins/constants.h index d71fd22..a20cd0a 100644 --- a/include/tins/constants.h +++ b/include/tins/constants.h @@ -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 diff --git a/include/tins/crypto.h b/include/tins/crypto.h index 8c538dc..1ada146 100644 --- a/include/tins/crypto.h +++ b/include/tins/crypto.h @@ -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 ptk_type; - - /** - * The type used to hold the PMK (this has to be PMK_SIZE bytes long). - */ - typedef std::vector 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 - 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 passwords_type; - - PDU *decrypt(RawPDU &raw, const std::string &password); - - passwords_type passwords; - std::vector 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 ptk_type; + + /** + * The type used to hold the PMK (this has to be PMK_SIZE bytes long). + */ + typedef std::vector 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 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 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 pmks_map; - typedef std::map 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 - 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 - 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 - DecrypterProxy 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 - DecrypterProxy make_wpa2_decrypter_proxy(const Functor &functor) { - return DecrypterProxy(functor); - } - #endif // HAVE_WPA2_DECRYPTION - - // Implementation section - - // DecrypterProxy - - template - DecrypterProxy::DecrypterProxy( - const functor_type &func, const decrypter_type& decr) - : functor_(func), decrypter_(decr) - { - - } + const pmk_type& pmk() const; +private: + pmk_type pmk_; +}; - template - typename DecrypterProxy::decrypter_type & - DecrypterProxy::decrypter() - { - return decrypter_; - } +} // WPA2 +#endif // HAVE_WPA2_DECRYPTION - template - const typename DecrypterProxy::decrypter_type & - DecrypterProxy::decrypter() const - { - return decrypter_; - } +/** + * \brief RC4 Key abstraction. + */ +struct RC4Key { + static const size_t data_size = 256; - template - bool DecrypterProxy::operator() (PDU &pdu) - { - return decrypter_.decrypt(pdu) ? functor_(pdu) : true; - } - - template - DecrypterProxy make_wep_decrypter_proxy(const Functor &functor) - { - return DecrypterProxy(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 - RC4Key::RC4Key(ForwardIterator start, ForwardIterator end) { - for(size_t i = 0; i < data_size; ++i) { - data[i] = static_cast(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 - 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 passwords_type; + + PDU* decrypt(RawPDU& raw, const std::string& password); + + passwords_type passwords_; + std::vector 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 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 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 pmks_map; + typedef std::map 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 +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 +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 +DecrypterProxy 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 +DecrypterProxy make_wpa2_decrypter_proxy(const Functor& functor) { + return DecrypterProxy(functor); +} +#endif // HAVE_WPA2_DECRYPTION + +// Implementation section + +// DecrypterProxy + +template +DecrypterProxy::DecrypterProxy(const functor_type& func, + const decrypter_type& decr) +: functor_(func), decrypter_(decr) { + +} + +template +typename DecrypterProxy::decrypter_type & + DecrypterProxy::decrypter() { + return decrypter_; +} + +template +const typename DecrypterProxy::decrypter_type & + DecrypterProxy::decrypter() const { + return decrypter_; +} + +template +bool DecrypterProxy::operator() (PDU& pdu) { + return decrypter_.decrypt(pdu) ? functor_(pdu) : true; +} + +template +DecrypterProxy make_wep_decrypter_proxy(const Functor& functor) { + return DecrypterProxy(functor); +} + +// RC4 stuff + +template +RC4Key::RC4Key(ForwardIterator start, ForwardIterator end) { + for (size_t i = 0; i < data_size; ++i) { + data[i] = static_cast(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 +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 diff --git a/include/tins/dhcp.h b/include/tins/dhcp.h index 4b4c636..4d5c897 100644 --- a/include/tins/dhcp.h +++ b/include/tins/dhcp.h @@ -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. 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. 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 option; - - /** - * The type used to store the DHCP options. - */ - typedef std::list