Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Top 10 ports #238

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/ipfixprobe/parser-stats.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@

#pragma once

#include "../../input/topPorts.hpp"
#include <cstdint>
#include <array>

namespace ipxp {

Expand All @@ -46,6 +48,8 @@ struct ParserStats {

uint64_t seen_packets;
uint64_t unknown_packets;

TopPorts<10> top_ports;
};

} // namespace ipxp
15 changes: 15 additions & 0 deletions input/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
*/

#include <ipfixprobe/input.hpp>
#include <iterator>
#include <string>
#include <sstream>
#include <numeric>

namespace ipxp {

Expand Down Expand Up @@ -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<uint16_t, size_t>& portFrequency) {
return acc + ", " + std::to_string(portFrequency.first) + ": " + std::to_string(portFrequency.second);
});
}

return dict;
}

Expand Down
18 changes: 14 additions & 4 deletions input/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
#include "headers.hpp"
#include <ipfixprobe/packet.hpp>

#include <iterator>
#include <string>
#include <sstream>
#include <numeric>
namespace ipxp {

//#define DEBUG_PARSER
Expand Down Expand Up @@ -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) {
Expand All @@ -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));
Expand Down Expand Up @@ -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) {
Expand All @@ -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));
Expand Down Expand Up @@ -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) {
Expand Down
83 changes: 83 additions & 0 deletions input/topPorts.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* \file topPorts.hpp
* \brief Template class implementing the most popular ports.
* \author Damir Zainullin <[email protected]>
* \date 2024
*/
#pragma once

#include <array>
#include <cmath>
#include <cstdint>
#include <functional>
#include <limits>
#include <queue>
#include <unordered_map>
#include <unordered_set>

namespace ipxp {
/**
* \brief Top ports counter.
* \tparam TopPortsCount Number of the most popular ports to store.
*/
template<std::size_t TopPortsCount>
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<std::array<std::pair<uint16_t, size_t>, TopPortsCount>, size_t>
get_top_ports() const noexcept
{
std::array<std::pair<uint16_t, size_t>, 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<uint16_t, size_t>& port1, const std::pair<uint16_t, size_t>& 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<std::size_t, 65536> m_port_frequencies {};
uint16_t m_least_popuplar_top_port {0};
std::unordered_set<uint16_t> m_ports_present;
};

} // namespace ipxp
Loading