From 0db45b7c6ef91a1697b18b8966f012c917e1b348 Mon Sep 17 00:00:00 2001 From: Damir Zainullin Date: Mon, 2 Dec 2024 00:42:47 +0100 Subject: [PATCH 1/2] Top 10 ports - Introduce TopPorts class --- input/topPorts.hpp | 83 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 input/topPorts.hpp diff --git a/input/topPorts.hpp b/input/topPorts.hpp new file mode 100644 index 00000000..4ed1b7d9 --- /dev/null +++ b/input/topPorts.hpp @@ -0,0 +1,83 @@ +/** + * \file topPorts.hpp + * \brief Template class implementing the most popular ports. + * \author Damir Zainullin + * \date 2024 + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ipxp { +/** + * \brief Top ports counter. + * \tparam TopPortsCount Number of the most popular ports to store. + */ +template +class TopPorts { +public: + /** + * \brief Insert a port into the top ports. + * \param port Port to insert. + */ + void insert(uint16_t port) noexcept + { + m_port_frequencies[port]++; + + if (m_ports_present.size() < TopPortsCount) { + m_ports_present.insert(port); + m_least_popuplar_top_port = find_least_popular_top_port(); + return; + } + + if (auto it = m_ports_present.find(port); it == m_ports_present.end() + && m_port_frequencies[port] > m_port_frequencies[m_least_popuplar_top_port]) { + m_ports_present.erase(m_least_popuplar_top_port); + m_least_popuplar_top_port = port; + m_ports_present.insert(port); + } else if (port == m_least_popuplar_top_port) { + m_least_popuplar_top_port = find_least_popular_top_port(); + } + } + + /** + * \brief Get the top ports. + * \return Pair of the top ports array and their count. + */ + std::pair, TopPortsCount>, size_t> + get_top_ports() const noexcept + { + std::array, TopPortsCount> res; + std::transform( + m_ports_present.begin(), + m_ports_present.end(), + res.begin(), + [this](uint16_t port) { return std::make_pair(port, m_port_frequencies[port]); }); + std::sort(res.begin(), res.begin() + m_ports_present.size(), [] (const std::pair& port1, const std::pair& port2){ return port1.second > port2.second;}); + return {res, m_ports_present.size()}; + } + +private: + uint16_t find_least_popular_top_port() const noexcept + { + return *std::min_element( + m_ports_present.begin(), + m_ports_present.end(), + [this](uint16_t port1, uint16_t port2) { + return m_port_frequencies[port1] < m_port_frequencies[port2]; + }); + } + + std::array m_port_frequencies {}; + uint16_t m_least_popuplar_top_port {0}; + std::unordered_set m_ports_present; +}; + +} // namespace ipxp From 8eaa5fa072c4e66afc3d27b03d84dc101c7362c6 Mon Sep 17 00:00:00 2001 From: Damir Zainullin Date: Mon, 2 Dec 2024 01:00:25 +0100 Subject: [PATCH 2/2] Top 10 ports - Adjust parser --- include/ipfixprobe/parser-stats.hpp | 4 ++++ input/input.cpp | 15 +++++++++++++++ input/parser.cpp | 18 ++++++++++++++---- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/include/ipfixprobe/parser-stats.hpp b/include/ipfixprobe/parser-stats.hpp index 3c5c7777..a3362326 100644 --- a/include/ipfixprobe/parser-stats.hpp +++ b/include/ipfixprobe/parser-stats.hpp @@ -25,7 +25,9 @@ #pragma once +#include "../../input/topPorts.hpp" #include +#include namespace ipxp { @@ -46,6 +48,8 @@ struct ParserStats { uint64_t seen_packets; uint64_t unknown_packets; + + TopPorts<10> top_ports; }; } // namespace ipxp diff --git a/input/input.cpp b/input/input.cpp index 105615bb..611963ef 100644 --- a/input/input.cpp +++ b/input/input.cpp @@ -24,6 +24,10 @@ */ #include +#include +#include +#include +#include namespace ipxp { @@ -52,6 +56,17 @@ static telemetry::Content get_parser_stats_content(const ParserStats& parserStat dict["seen_packets"] = parserStats.seen_packets; dict["unknown_packets"] = parserStats.unknown_packets; + const auto& [ports, size] = parserStats.top_ports.get_top_ports(); + if (size == 0) { + dict["top_10_ports"] = ""; + } else { + std::string top_ports = std::to_string(ports[0].first) + ": " + std::to_string(ports[0].second); + dict["top_10_ports"] = std::accumulate(ports.begin() + 1, ports.begin() + size, top_ports, + [](std::string& acc, const std::pair& portFrequency) { + return acc + ", " + std::to_string(portFrequency.first) + ": " + std::to_string(portFrequency.second); + }); + } + return dict; } diff --git a/input/parser.cpp b/input/parser.cpp index 61b696cb..c031df94 100644 --- a/input/parser.cpp +++ b/input/parser.cpp @@ -37,6 +37,10 @@ #include "headers.hpp" #include +#include +#include +#include +#include namespace ipxp { //#define DEBUG_PARSER @@ -454,7 +458,7 @@ inline uint16_t parse_ipv6_hdr(const u_char *data_ptr, uint16_t data_len, Packet * \param [out] pkt Pointer to Packet structure where parsed fields will be stored. * \return Size of header in bytes. */ -inline uint16_t parse_tcp_hdr(const u_char *data_ptr, uint16_t data_len, Packet *pkt) +inline uint16_t parse_tcp_hdr(ParserStats& stats, const u_char *data_ptr, uint16_t data_len, Packet *pkt) { struct tcphdr *tcp = (struct tcphdr *) data_ptr; if (sizeof(struct tcphdr) > data_len) { @@ -469,6 +473,9 @@ inline uint16_t parse_tcp_hdr(const u_char *data_ptr, uint16_t data_len, Packet pkt->tcp_flags = (uint8_t) *(data_ptr + 13) & 0xFF; pkt->tcp_window = ntohs(tcp->window); + stats.top_ports.insert(pkt->src_port); + stats.top_ports.insert(pkt->dst_port); + DEBUG_MSG("TCP header:\n"); DEBUG_MSG("\tSrc port:\t%u\n", ntohs(tcp->source)); DEBUG_MSG("\tDest port:\t%u\n", ntohs(tcp->dest)); @@ -529,7 +536,7 @@ inline uint16_t parse_tcp_hdr(const u_char *data_ptr, uint16_t data_len, Packet * \param [out] pkt Pointer to Packet structure where parsed fields will be stored. * \return Size of header in bytes. */ -inline uint16_t parse_udp_hdr(const u_char *data_ptr, uint16_t data_len, Packet *pkt) +inline uint16_t parse_udp_hdr(ParserStats& stats, const u_char *data_ptr, uint16_t data_len, Packet *pkt) { struct udphdr *udp = (struct udphdr *) data_ptr; if (sizeof(struct udphdr) > data_len) { @@ -539,6 +546,9 @@ inline uint16_t parse_udp_hdr(const u_char *data_ptr, uint16_t data_len, Packet pkt->src_port = ntohs(udp->source); pkt->dst_port = ntohs(udp->dest); + stats.top_ports.insert(pkt->src_port); + stats.top_ports.insert(pkt->dst_port); + DEBUG_MSG("UDP header:\n"); DEBUG_MSG("\tSrc port:\t%u\n", ntohs(udp->source)); DEBUG_MSG("\tDest port:\t%u\n", ntohs(udp->dest)); @@ -727,10 +737,10 @@ void parse_packet(parser_opt_t *opt, ParserStats& stats, struct timeval ts, cons l4_hdr_offset = data_offset; if (pkt->ip_proto == IPPROTO_TCP) { - data_offset += parse_tcp_hdr(data + data_offset, caplen - data_offset, pkt); + data_offset += parse_tcp_hdr(stats, data + data_offset, caplen - data_offset, pkt); stats.tcp_packets++; } else if (pkt->ip_proto == IPPROTO_UDP) { - data_offset += parse_udp_hdr(data + data_offset, caplen - data_offset, pkt); + data_offset += parse_udp_hdr(stats, data + data_offset, caplen - data_offset, pkt); stats.udp_packets++; } } catch (const char *err) {