diff --git a/Examples/HttpAnalyzer/HttpStatsCollector.h b/Examples/HttpAnalyzer/HttpStatsCollector.h index 46faefbca6..cf45af7629 100644 --- a/Examples/HttpAnalyzer/HttpStatsCollector.h +++ b/Examples/HttpAnalyzer/HttpStatsCollector.h @@ -1,6 +1,8 @@ #pragma once -#include +#include + +#include #include #include "HttpLayer.h" #include "TcpLayer.h" @@ -89,10 +91,10 @@ struct HttpMessageStats */ struct HttpRequestStats : HttpMessageStats { - std::map methodCount; // a map for counting the different HTTP methods seen in traffic - std::map hostnameCount; // a map for counting the hostnames seen in traffic + std::unordered_map > methodCount; // a map for counting the different HTTP methods seen in traffic + std::unordered_map hostnameCount; // a map for counting the hostnames seen in traffic - void clear() + void clear() override { HttpMessageStats::clear(); methodCount.clear(); @@ -106,13 +108,13 @@ struct HttpRequestStats : HttpMessageStats */ struct HttpResponseStats : HttpMessageStats { - std::map statusCodeCount; // a map for counting the different status codes seen in traffic - std::map contentTypeCount; // a map for counting the content-types seen in traffic + std::unordered_map statusCodeCount; // a map for counting the different status codes seen in traffic + std::unordered_map contentTypeCount; // a map for counting the content-types seen in traffic int numOfMessagesWithContentLength; // total number of responses containing the "content-length" field int totalContentLengthSize; // total body size extracted by responses containing "content-length" field double averageContentLengthSize; // average body size - void clear() + void clear() override { HttpMessageStats::clear(); numOfMessagesWithContentLength = 0; @@ -461,7 +463,7 @@ class HttpStatsCollector HttpResponseStats m_ResponseStats; HttpResponseStats m_PrevResponseStats; - std::map m_FlowTable; + std::unordered_map m_FlowTable; double m_LastCalcRateTime; double m_StartTime; diff --git a/Examples/HttpAnalyzer/main.cpp b/Examples/HttpAnalyzer/main.cpp index 4a21c429a1..c4240ee888 100644 --- a/Examples/HttpAnalyzer/main.cpp +++ b/Examples/HttpAnalyzer/main.cpp @@ -31,7 +31,6 @@ #include #include - #define EXIT_WITH_ERROR(reason) do { \ printUsage(); \ std::cout << std::endl << "ERROR: " << reason << std::endl << std::endl; \ @@ -123,12 +122,11 @@ void printAppVersion() */ void listInterfaces() { - const std::vector& devList = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList(); + const std::vector& liveDevices = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDevicesList(); std::cout << std::endl << "Network interfaces:" << std::endl; - for (std::vector::const_iterator iter = devList.begin(); iter != devList.end(); iter++) - { - std::cout << " -> Name: '" << (*iter)->getName() << "' IP address: " << (*iter)->getIPv4Address().toString() << std::endl; + for(const auto& device : liveDevices){ + std::cout << " -> Name: '" << device->getName() << "' IP address: " << device->getIPv4Address().toString() << std::endl; } exit(0); } @@ -136,13 +134,7 @@ void listInterfaces() void printStatsHeadline(const std::string &description) { - std::string underline; - for (size_t i = 0; i < description.length(); i++) - { - underline += "-"; - } - - std::cout << std::endl << description << std::endl << underline << std::endl << std::endl; + std::cout << std::endl << description << std::endl << std::string(description.length(),'-') << std::endl << std::endl; } @@ -169,81 +161,70 @@ void httpPacketArrive(pcpp::RawPacket* packet, pcpp::PcapLiveDevice* dev, void* /** * Print the method count table */ -void printMethods(HttpRequestStats& reqStatscollector) +void printMethods(const HttpRequestStats& reqStatscollector) { // create the table - std::vector columnNames; - columnNames.push_back("Method"); - columnNames.push_back("Count"); - std::vector columnsWidths; - columnsWidths.push_back(9); - columnsWidths.push_back(5); + std::vector columnNames = {"Method", "Count"}; + std::vector columnsWidths = {9, 5}; pcpp::TablePrinter printer(columnNames, columnsWidths); + // Copy elements to a vector + std::vector> map2vec(reqStatscollector.methodCount.begin(), reqStatscollector.methodCount.end()); + std::sort(map2vec.begin(), map2vec.end(), + [](const std::pair& left, + const std::pair& right) { return left.second > right.second; }); - // go over the method count table and print each method and count - for(std::map::iterator iter = reqStatscollector.methodCount.begin(); - iter != reqStatscollector.methodCount.end(); - iter++) + // go over the method count table, print each method and the aggregated figure + for (auto iter : map2vec) { std::stringstream values; - switch (iter->first) + switch (iter.first) { case pcpp::HttpRequestLayer::HttpGET: - values << "GET" << "|" << reqStatscollector.methodCount[pcpp::HttpRequestLayer::HttpGET]; - printer.printRow(values.str(), '|'); + values << "GET" << "|" << reqStatscollector.methodCount.at(pcpp::HttpRequestLayer::HttpGET); break; case pcpp::HttpRequestLayer::HttpPOST: - values << "POST" << "|" << reqStatscollector.methodCount[pcpp::HttpRequestLayer::HttpPOST]; - printer.printRow(values.str(), '|'); + values << "POST" << "|" << reqStatscollector.methodCount.at(pcpp::HttpRequestLayer::HttpPOST); break; case pcpp::HttpRequestLayer::HttpCONNECT: - values << "CONNECT" << "|" << reqStatscollector.methodCount[pcpp::HttpRequestLayer::HttpCONNECT]; - printer.printRow(values.str(), '|'); + values << "CONNECT" << "|" << reqStatscollector.methodCount.at(pcpp::HttpRequestLayer::HttpCONNECT); break; case pcpp::HttpRequestLayer::HttpDELETE: - values << "DELETE" << "|" << reqStatscollector.methodCount[pcpp::HttpRequestLayer::HttpDELETE]; - printer.printRow(values.str(), '|'); + values << "DELETE" << "|" << reqStatscollector.methodCount.at(pcpp::HttpRequestLayer::HttpDELETE); break; case pcpp::HttpRequestLayer::HttpHEAD: - values << "HEAD" << "|" << reqStatscollector.methodCount[pcpp::HttpRequestLayer::HttpHEAD]; - printer.printRow(values.str(), '|'); + values << "HEAD" << "|" << reqStatscollector.methodCount.at(pcpp::HttpRequestLayer::HttpHEAD); break; case pcpp::HttpRequestLayer::HttpOPTIONS: - values << "OPTIONS" << "|" << reqStatscollector.methodCount[pcpp::HttpRequestLayer::HttpOPTIONS]; - printer.printRow(values.str(), '|'); + values << "OPTIONS" << "|" << reqStatscollector.methodCount.at(pcpp::HttpRequestLayer::HttpOPTIONS); break; case pcpp::HttpRequestLayer::HttpPATCH: - values << "PATCH" << "|" << reqStatscollector.methodCount[pcpp::HttpRequestLayer::HttpPATCH]; - printer.printRow(values.str(), '|'); + values << "PATCH" << "|" << reqStatscollector.methodCount.at(pcpp::HttpRequestLayer::HttpPATCH); break; case pcpp::HttpRequestLayer::HttpPUT: - values << "PUT" << "|" << reqStatscollector.methodCount[pcpp::HttpRequestLayer::HttpPUT]; - printer.printRow(values.str(), '|'); + values << "PUT" << "|" << reqStatscollector.methodCount.at(pcpp::HttpRequestLayer::HttpPUT); break; case pcpp::HttpRequestLayer::HttpTRACE: - values << "TRACE" << "|" << reqStatscollector.methodCount[pcpp::HttpRequestLayer::HttpTRACE]; - printer.printRow(values.str(), '|'); + values << "TRACE" << "|" << reqStatscollector.methodCount.at(pcpp::HttpRequestLayer::HttpTRACE); break; default: break; } + if(iter.first != pcpp::HttpRequestLayer::HttpMethod::HttpMethodUnknown) + { + printer.printRow(values.str(), '|'); + } } } - /** * An auxiliary method for sorting the hostname count map. Used only in printHostnames() */ -bool hostnameComparer(const std::pair& first, const std::pair& second) +bool hostnameComparer(const std::pair& leftHost, const std::pair& rightHost) { - if (first.second == second.second) - { - return first.first > second.first; - } - return first.second > second.second; + return leftHost.second > rightHost.second || (leftHost.second == rightHost.second && leftHost.first > rightHost.first); } /** @@ -252,26 +233,21 @@ bool hostnameComparer(const std::pair& first, const std::pair< void printHostnames(HttpRequestStats& reqStatscollector) { // create the table - std::vector columnNames; - columnNames.push_back("Hostname"); - columnNames.push_back("Count"); - std::vector columnsWidths; - columnsWidths.push_back(40); - columnsWidths.push_back(5); + std::vector columnNames = {"Hostname", "Count"}; + std::vector columnsWidths = {40, 5}; + pcpp::TablePrinter printer(columnNames, columnsWidths); // sort the hostname count map so the most popular hostnames will be first // since it's not possible to sort a std::map you must copy it to a std::vector and sort it then std::vector > map2vec(reqStatscollector.hostnameCount.begin(), reqStatscollector.hostnameCount.end()); - std::sort(map2vec.begin(),map2vec.end(), &hostnameComparer); + std::sort(map2vec.begin(), map2vec.end(), &hostnameComparer); // go over all items (hostname + count) in the sorted vector and print them - for(std::vector >::iterator iter = map2vec.begin(); - iter != map2vec.end(); - iter++) + for(const auto& hostname : map2vec) { std::stringstream values; - values << iter->first << "|" << iter->second; + values << hostname.first << "|" << hostname.second; printer.printRow(values.str(), '|'); } } @@ -280,24 +256,20 @@ void printHostnames(HttpRequestStats& reqStatscollector) /** * Print the status code count table */ -void printStatusCodes(HttpResponseStats& resStatscollector) +void printStatusCodes(const HttpResponseStats& resStatscollector) { // create the table - std::vector columnNames; - columnNames.push_back("Status Code"); - columnNames.push_back("Count"); - std::vector columnsWidths; - columnsWidths.push_back(28); - columnsWidths.push_back(5); + std::vector columnNames = {"Status Code", "Count"}; + std::vector columnsWidths = {28, 5}; pcpp::TablePrinter printer(columnNames, columnsWidths); - // go over the status code map and print each item - for(std::map::iterator iter = resStatscollector.statusCodeCount.begin(); - iter != resStatscollector.statusCodeCount.end(); - iter++) + // prints the status codes in lexical order + std::vector> map2vec(resStatscollector.statusCodeCount.begin(), resStatscollector.statusCodeCount.end()); + std::sort(map2vec.begin(), map2vec.end(), [](const std::pair& left, const std::pair& right) { return left.first < right.first; }); + for(const auto& statusCodeStat : map2vec) { std::stringstream values; - values << iter->first << "|" << iter->second; + values << statusCodeStat.first << "|" << statusCodeStat.second; printer.printRow(values.str(), '|'); } } @@ -306,24 +278,20 @@ void printStatusCodes(HttpResponseStats& resStatscollector) /** * Print the content-type count table */ -void printContentTypes(HttpResponseStats& resStatscollector) +void printContentTypes(const HttpResponseStats& resStatscollector) { // create the table - std::vector columnNames; - columnNames.push_back("Content-type"); - columnNames.push_back("Count"); - std::vector columnsWidths; - columnsWidths.push_back(30); - columnsWidths.push_back(5); + std::vector columnNames = {"Content-type", "Count"}; + std::vector columnsWidths = {30, 5}; pcpp::TablePrinter printer(columnNames, columnsWidths); - // go over the status code map and print each item - for(std::map::iterator iter = resStatscollector.contentTypeCount.begin(); - iter != resStatscollector.contentTypeCount.end(); - iter++) + // prints the content-types in lexical order + std::vector> map2vec(resStatscollector.contentTypeCount.begin(), resStatscollector.contentTypeCount.end()); + std::sort(map2vec.begin(), map2vec.end(), [](const std::pair& left, const std::pair& right) { return left.first < right.first; }); + for(const auto &contentTypeStat : map2vec) { std::stringstream values; - values << iter->first << "|" << iter->second; + values << contentTypeStat.first << "|" << contentTypeStat.second; printer.printRow(values.str(), '|'); } } diff --git a/Examples/PcapSplitter/ConnectionSplitters.h b/Examples/PcapSplitter/ConnectionSplitters.h index 997a50a936..0c326f91ae 100644 --- a/Examples/PcapSplitter/ConnectionSplitters.h +++ b/Examples/PcapSplitter/ConnectionSplitters.h @@ -145,4 +145,72 @@ class FiveTupleSplitter : public ValueBasedSplitter return m_FlowTable[hash]; } + + void updateStringStream(std::ostringstream & sstream, const std::string & srcIp, uint16_t srcPort, const std::string & dstIp, uint16_t dstPort) + { + sstream << hyphenIP(srcIp) + << "_" + << srcPort + << "-" + << hyphenIP(dstIp) + << "_" + << dstPort; + } + + /** + * Re-implement Splitter's getFileName() method, this time with the IPs/Ports/protocol value + */ + std::string getFileName(pcpp::Packet& packet, const std::string &outputPcapBasePath, int fileNumber) + { + std::ostringstream sstream; + + // if it's not a TCP or UDP packet, put it in file #0 + if (!packet.isPacketOfType(pcpp::TCP) && !packet.isPacketOfType(pcpp::UDP)) + { + return Splitter::getFileName(packet, outputPcapBasePath, fileNumber); + } + + sstream << "connection-"; + + if (packet.isPacketOfType(pcpp::TCP)) + { + // extract TCP layer + pcpp::TcpLayer* tcpLayer = packet.getLayerOfType(); + if (tcpLayer != nullptr) + { + uint16_t srcPort = tcpLayer->getSrcPort(); + uint16_t dstPort = tcpLayer->getDstPort(); + + sstream << "tcp_"; + + if ((tcpLayer->getTcpHeader()->synFlag == 1) && (tcpLayer->getTcpHeader()->ackFlag == 0)) + { + updateStringStream(sstream, getSrcIPString(packet), srcPort, getDstIPString(packet), dstPort); + } else if (((tcpLayer->getTcpHeader()->synFlag == 1) && + (tcpLayer->getTcpHeader()->ackFlag == 1) + ) || (srcPort < dstPort) ) + { + updateStringStream(sstream, getDstIPString(packet), dstPort, getSrcIPString(packet), srcPort); + } else + { + updateStringStream(sstream, getSrcIPString(packet), srcPort, getDstIPString(packet), dstPort); + } + return outputPcapBasePath + sstream.str(); + } + } + else if (packet.isPacketOfType(pcpp::UDP)) + { + // for UDP packets, decide the server port by the lower port + pcpp::UdpLayer* udpLayer = packet.getLayerOfType(); + if (udpLayer != nullptr) + { + sstream << "udp_"; + updateStringStream(sstream, getSrcIPString(packet), udpLayer->getSrcPort(), getDstIPString(packet), udpLayer->getDstPort()); + return outputPcapBasePath + sstream.str(); + } + } + + // if reached here, return 'miscellaneous' + return outputPcapBasePath + "miscellaneous"; + } }; diff --git a/Examples/PcapSplitter/IPPortSplitters.h b/Examples/PcapSplitter/IPPortSplitters.h index 7b7e2fee6e..6a8d23d0cb 100644 --- a/Examples/PcapSplitter/IPPortSplitters.h +++ b/Examples/PcapSplitter/IPPortSplitters.h @@ -213,26 +213,6 @@ class IPPortSplitter : public ValueBasedSplitter return 0; } - /** - * An auxiliary method for extracting packet's IPv4/IPv6 source address as string - */ - std::string getSrcIPString(pcpp::Packet& packet) - { - if (packet.isPacketOfType(pcpp::IP)) - return packet.getLayerOfType()->getSrcIPAddress().toString(); - return "miscellaneous"; - } - - /** - * An auxiliary method for extracting packet's IPv4/IPv6 dest address string - */ - std::string getDstIPString(pcpp::Packet& packet) - { - if (packet.isPacketOfType(pcpp::IP)) - return packet.getLayerOfType()->getDstIPAddress().toString(); - return "miscellaneous"; - } - /** * An auxiliary method to indicate whether an IPv4/IPv6 source address is multicast or not */ @@ -252,30 +232,6 @@ class IPPortSplitter : public ValueBasedSplitter return packet.getLayerOfType()->getDstIPAddress().isMulticast(); return false; } - - /** - * An auxiliary method for replacing '.' and ':' in IPv4/IPv6 addresses with '-' - */ - std::string hyphenIP(std::string ipVal) - { - // for IPv4 - replace '.' with '-' - int loc = ipVal.find("."); - while (loc >= 0) - { - ipVal.replace(loc, 1, "-"); - loc = ipVal.find("."); - } - - // for IPv6 - replace ':' with '-' - loc = ipVal.find(":"); - while (loc >= 0) - { - ipVal.replace(loc, 1, "-"); - loc = ipVal.find(":"); - } - - return ipVal; - } }; diff --git a/Examples/PcapSplitter/Splitters.h b/Examples/PcapSplitter/Splitters.h index a981ded88f..e4ae645dc8 100644 --- a/Examples/PcapSplitter/Splitters.h +++ b/Examples/PcapSplitter/Splitters.h @@ -194,3 +194,47 @@ class ValueBasedSplitter : public SplitterWithMaxFiles return m_ValueToFileTable[value]; } }; + +/** + * An auxiliary method for extracting packet's IPv4/IPv6 source address as string + */ +std::string getSrcIPString(pcpp::Packet& packet) +{ + if (packet.isPacketOfType(pcpp::IP)) + return packet.getLayerOfType()->getSrcIPAddress().toString(); + return "miscellaneous"; +} + +/** + * An auxiliary method for extracting packet's IPv4/IPv6 dest address string + */ +std::string getDstIPString(pcpp::Packet& packet) +{ + if (packet.isPacketOfType(pcpp::IP)) + return packet.getLayerOfType()->getDstIPAddress().toString(); + return "miscellaneous"; +} + +/** + * An auxiliary method for replacing '.' and ':' in IPv4/IPv6 addresses with '-' + */ +std::string hyphenIP(std::string ipVal) +{ + // for IPv4 - replace '.' with '-' + int loc = ipVal.find("."); + while (loc >= 0) + { + ipVal.replace(loc, 1, "-"); + loc = ipVal.find("."); + } + + // for IPv6 - replace ':' with '-' + loc = ipVal.find(":"); + while (loc >= 0) + { + ipVal.replace(loc, 1, "-"); + loc = ipVal.find(":"); + } + + return ipVal; +}