Skip to content
New issue

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

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

Already on GitHub? # to your account

Top 10 ports #238

Open
wants to merge 3 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: 3 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ ipfixprobe_input_src=\
input/benchmark.hpp \
input/parser.cpp \
input/parser.hpp \
input/headers.hpp
input/headers.hpp \
input/topPorts.hpp \
input/topPorts.cpp

# How to create loadable example.so plugin:
#pkglib_LTLIBRARIES=example.la
Expand Down
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 top_ports{10};
};

} // namespace ipxp
14 changes: 14 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,16 @@ static telemetry::Content get_parser_stats_content(const ParserStats& parserStat
dict["seen_packets"] = parserStats.seen_packets;
dict["unknown_packets"] = parserStats.unknown_packets;

const std::vector<TopPorts::PortStats>& ports = parserStats.top_ports.get_top_ports();
if (ports.empty()) {
dict["top_10_ports"] = "";
} else {
std::string top_ports = ports[0].to_string();
dict["top_10_ports"] = std::accumulate(ports.begin() + 1, ports.end(), top_ports,
[](std::string& acc, const TopPorts::PortStats& port_frequency) {
return acc + ", " + port_frequency.to_string();
});
}
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.increment_tcp_frequency(pkt->src_port);
stats.top_ports.increment_tcp_frequency(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.increment_udp_frequency(pkt->src_port);
stats.top_ports.increment_udp_frequency(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 @@ -731,10 +741,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
71 changes: 71 additions & 0 deletions input/topPorts.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* \file topPorts.cpp
* \brief TopPorts class implementation.
* \author Damir Zainullin <zaidamilda@gmail.com>
* \date 2024
*/

#include "topPorts.hpp"

#include <functional>
#include <algorithm>
#include <array>
#include <cstdint>
#include <limits>
#include <vector>
#include <string>

namespace ipxp {

TopPorts::TopPorts(size_t top_ports_count) noexcept
: m_top_ports_count(top_ports_count)
{
}

void TopPorts::increment_tcp_frequency(uint16_t port) noexcept
{
m_tcp_port_frequencies[port]++;
}

void TopPorts::increment_udp_frequency(uint16_t port) noexcept
{
m_udp_port_frequencies[port]++;
}

std::string TopPorts::PortStats::to_string() const noexcept
{
return std::to_string(port) + "[" +
(protocol == Protocol::TCP ? "TCP" : "UDP") + "] - " + std::to_string(frequency);
}

std::vector<TopPorts::PortStats> TopPorts::get_top_ports() const noexcept
{
std::vector<PortStats> port_buffer(10);
size_t ports_inserted = 0;

auto callback = [&, port = uint16_t{0}](size_t frequency, PortStats::Protocol protocol) mutable {
auto port_pos = std::lower_bound(port_buffer.begin(), port_buffer.end(), frequency,
[](const PortStats& port_frequency, size_t count) {
return port_frequency.frequency >= count;
});

if (port_pos != port_buffer.end()) {
std::copy_backward(port_pos, std::prev(port_buffer.end()), port_buffer.end());
*port_pos = PortStats{port, frequency, protocol};
ports_inserted = std::min<size_t>(m_top_ports_count, ports_inserted + 1);
}
port++;
};

std::for_each(m_tcp_port_frequencies.begin(), m_tcp_port_frequencies.end(), [callback](size_t frequency) mutable {
callback(frequency, PortStats::Protocol::TCP);
});
std::for_each(m_udp_port_frequencies.begin(), m_udp_port_frequencies.end(), [callback](size_t frequency) mutable{
callback(frequency, PortStats::Protocol::UDP);
});

port_buffer.resize(std::min(m_top_ports_count, ports_inserted));
return port_buffer;
}

} // namespace ipxp
75 changes: 75 additions & 0 deletions input/topPorts.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* \file topPorts.hpp
* \brief TopPorts class declaration implementing the most popular ports.
* \author Damir Zainullin <zaidamilda@gmail.com>
* \date 2024
*/
#pragma once

#include <array>
#include <cstdint>
#include <limits>
#include <vector>
#include <string>

namespace ipxp {
/**
* \brief Top ports counter.
*/
class TopPorts {
public:

/**
* \brief Constructor.
* \param top_ports_count Number of the most popular ports to store.
*/
TopPorts(size_t top_ports_count) noexcept;

/**
* \brief Increments number of times given tcp port has been seen.
* \param port Port to increment its frequency.
*/
void increment_tcp_frequency(uint16_t port) noexcept;

/**
* \brief Increments number of times given udp port has been seen.
* \param port Port to increment its frequency.
*/
void increment_udp_frequency(uint16_t port) noexcept;

/**
* \brief Port frequency and protocol to which it belongs.
*/
struct PortStats {
/**
* \brief Protocol type.
*/
enum class Protocol {
TCP,
UDP
};

uint16_t port; /**< Port number. */
size_t frequency; /**< Number of times the port has been seen. */
Protocol protocol; /**< Protocol to which the port belongs. */

/**
* \brief Convert the port stats to string.
* \return String representation of the port stats.
*/
std::string to_string() const noexcept;
};

/**
* \brief Get the top ports.
* \return Vector of the most popular ports.
*/
std::vector<TopPorts::PortStats> get_top_ports() const noexcept;

private:
std::array<std::size_t, std::numeric_limits<uint16_t>::max() + 1> m_tcp_port_frequencies {};
std::array<std::size_t, std::numeric_limits<uint16_t>::max() + 1> m_udp_port_frequencies {};
const size_t m_top_ports_count;
};

} // namespace ipxp
Loading