Skip to content

Commit c6beba2

Browse files
author
Pavel Siska
committed
icmp
1 parent 7d8030a commit c6beba2

File tree

2 files changed

+253
-0
lines changed

2 files changed

+253
-0
lines changed

new-process-api/icmp.cpp

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#include "fieldSchema.hpp"
2+
#include "icmp.hpp"
3+
4+
#include <functional>
5+
6+
#include <netinet/icmp6.h>
7+
#include <netinet/ip_icmp.h>
8+
9+
namespace ipxp {
10+
11+
using AddHandler = std::function<void(const FieldHandler&, IcmpFields)>;
12+
13+
static void registerIcmpTypeField(FieldSchema& schema, AddHandler addHandler)
14+
{
15+
const auto getterFunction = [](const void* context) {
16+
return reinterpret_cast<const IcmpPluginData*>(context)->type;
17+
};
18+
19+
const FieldHandler icmpTypeHandler = schema.addScalarField("ICMP_TYPE", getterFunction);
20+
21+
addHandler(icmpTypeHandler, IcmpFields::ICMP_TYPE);
22+
}
23+
24+
static void registerIcmpCodeField(FieldSchema& schema, AddHandler addHandler)
25+
{
26+
const auto getterFunction = [](const void* context) {
27+
return reinterpret_cast<const IcmpPluginData*>(context)->code;
28+
};
29+
30+
const FieldHandler icmpCodeHandler = schema.addScalarField("ICMP_CODE", getterFunction);
31+
32+
addHandler(icmpCodeHandler, IcmpFields::ICMP_CODE);
33+
}
34+
35+
static void registerIcmpTypeCodeField(FieldSchema& schema, AddHandler addHandler)
36+
{
37+
const auto getterFunction = [](const void* context) {
38+
const auto* icmpPluginData = reinterpret_cast<const IcmpPluginData*>(context);
39+
return static_cast<uint16_t>(icmpPluginData->type) << 8 | icmpPluginData->code;
40+
};
41+
42+
const FieldHandler icmpTypeCodeHandler
43+
= schema.addScalarField("ICMP_TYPE_CODE", getterFunction);
44+
45+
addHandler(icmpTypeCodeHandler, IcmpFields::ICMP_TYPE_CODE);
46+
}
47+
48+
inline AddHandler createAddHandlerFunction(FieldHandlers<IcmpFields>& handlers)
49+
{
50+
return [&handlers](const FieldHandler& handler, IcmpFields field) {
51+
handlers.insert(field, handler);
52+
};
53+
}
54+
55+
void createFieldSchema(FieldManager& fieldManager, FieldHandlers<IcmpFields>& handlers)
56+
{
57+
FieldSchema fieldSchema = fieldManager.createFieldSchema("icmp");
58+
59+
const auto addHandlerFunction = createAddHandlerFunction(handlers);
60+
61+
registerIcmpTypeField(fieldSchema, addHandlerFunction);
62+
registerIcmpCodeField(fieldSchema, addHandlerFunction);
63+
registerIcmpTypeCodeField(fieldSchema, addHandlerFunction);
64+
}
65+
66+
IcmpPlugin::IcmpPlugin(const std::string& parameters, FieldManager& fieldManager)
67+
{
68+
(void) parameters;
69+
70+
createFieldSchema(fieldManager, m_fieldHandlers);
71+
}
72+
73+
template<typename T>
74+
static void parseTypeCode(const Packet& packet, IcmpPluginData& pluginData)
75+
{
76+
const auto* icmpHeader = reinterpret_cast<const T*>(packet.payload);
77+
pluginData.type = icmpHeader->type;
78+
pluginData.code = icmpHeader->code;
79+
}
80+
81+
void IcmpPlugin::parseIcmp(
82+
const FlowRecord& flowRecord,
83+
const Packet& packet,
84+
IcmpPluginData& pluginData)
85+
{
86+
// if (packet.ipVersion == IPV4) {
87+
// parseTypeCode<icmphdr>(packet, pluginData);
88+
// } else {
89+
// parseTypeCode<icmp6_hdr>(packet, pluginData);
90+
// }
91+
92+
m_fieldHandlers[IcmpFields::ICMP_TYPE].setAsAvailable(flowRecord);
93+
m_fieldHandlers[IcmpFields::ICMP_CODE].setAsAvailable(flowRecord);
94+
m_fieldHandlers[IcmpFields::ICMP_TYPE_CODE].setAsAvailable(flowRecord);
95+
}
96+
97+
static bool isIcmpPacket(const Packet& packet) noexcept
98+
{
99+
/*
100+
if (packet.l4Protocol != ICMP_V4 && packet.l4Protocol != ICMP_V6) {
101+
return false;
102+
}
103+
104+
// TODO porovnat s velikosti cele ICMP header?
105+
constexpr std::size_t MIN_PAYLOAD_LENGTH = 16;
106+
if (packet.payload_len < MIN_PAYLOAD_LENGTH) {
107+
return false;
108+
}
109+
*/
110+
111+
return true;
112+
}
113+
114+
PluginInitResult IcmpPlugin::onInit(const FlowContext& flowContext, void* pluginContext)
115+
{
116+
assert(pluginContext != nullptr && "Icmp: Plugin context must not be null");
117+
118+
if (!isIcmpPacket(flowContext.packet)) {
119+
return {
120+
.constructionState = ConstructionState::NotConstructed,
121+
.updateRequirement = UpdateRequirement::NoUpdateNeeded,
122+
.flowAction = FlowAction::NoAction,
123+
};
124+
}
125+
126+
IcmpPluginData* pluginData
127+
= std::construct_at(reinterpret_cast<IcmpPluginData*>(pluginContext));
128+
129+
parseIcmp(flowContext.flowRecord, flowContext.packet, *pluginData);
130+
131+
return {
132+
.constructionState = ConstructionState::Constructed,
133+
.updateRequirement = UpdateRequirement::NoUpdateNeeded,
134+
.flowAction = FlowAction::NoAction,
135+
};
136+
}
137+
138+
void IcmpPlugin::onDestroy(void* pluginContext)
139+
{
140+
assert(pluginContext != nullptr && "Icmp: Plugin context must not be null");
141+
142+
std::destroy_at(reinterpret_cast<IcmpPluginData*>(pluginContext));
143+
}
144+
145+
PluginDataMemoryLayout IcmpPlugin::getDataMemoryLayout() const noexcept
146+
{
147+
return {
148+
.size = sizeof(IcmpPluginData),
149+
.alignment = alignof(IcmpPluginData),
150+
};
151+
}
152+
153+
} // namespace ipxp

new-process-api/icmp.hpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/**
2+
* @file
3+
* @author Pavel Siska <[email protected]>
4+
* @brief ICMP plugin for FlowRecord processing.
5+
*
6+
* Provides a plugin that extracts ICMP type and code from IPv4 and IPv6 packets,
7+
* stores them in per-flow plugin data, and exposes fields via FieldManager.
8+
*
9+
* @copyright Copyright (c) 2025 CESNET, z.s.p.o.
10+
*/
11+
12+
#pragma once
13+
14+
#include "fieldHandlersEnum.hpp"
15+
#include "fieldManager.hpp"
16+
#include "packet.hpp"
17+
#include "processPlugin.hpp"
18+
19+
#include <cstdint>
20+
#include <string>
21+
22+
namespace ipxp {
23+
24+
/**
25+
* @struct IcmpPluginData
26+
* @brief Stores ICMP-specific data for a flow.
27+
*
28+
* This structure is used as the per-flow plugin context for ICMP packets.
29+
*/
30+
struct IcmpPluginData {
31+
uint8_t type; /**< ICMP type field from the packet */
32+
uint8_t code; /**< ICMP code field from the packet */
33+
};
34+
35+
/**
36+
* @enum IcmpFields
37+
* @brief Enumerates the fields exported by the ICMP plugin.
38+
*
39+
* These enum values are used to index field handlers for this plugin.
40+
*/
41+
enum class IcmpFields : uint8_t {
42+
ICMP_TYPE = 0,
43+
ICMP_CODE,
44+
ICMP_TYPE_CODE,
45+
FIELDS_SIZE,
46+
};
47+
48+
/**
49+
* @class IcmpPlugin
50+
* @brief Plugin for extracting ICMP packet information into FlowRecords.
51+
*
52+
* This plugin extracts ICMP type and code from packet.
53+
*/
54+
class IcmpPlugin : public ProcessPlugin {
55+
public:
56+
/**
57+
* @brief Constructs the ICMP plugin.
58+
*
59+
* @param parameters Plugin parameters as a string (currently unused).
60+
* @param fieldManager Reference to the FieldManager for field registration.
61+
*/
62+
IcmpPlugin(const std::string& parameters, FieldManager& fieldManager);
63+
64+
/**
65+
* @brief Initializes plugin data for a new flow.
66+
*
67+
* Constructs `IcmpPluginData` in `pluginContext` if the packet is ICMP,
68+
* extracts type and code, and returns the plugin state.
69+
*
70+
* @param flowContext Flow processing context.
71+
* @param pluginContext Pointer to pre-allocated plugin data memory.
72+
* @return PluginInitResult containing initialization results.
73+
*/
74+
PluginInitResult onInit(const FlowContext& flowContext, void* pluginContext) override;
75+
76+
/**
77+
* @brief Called when a flow is being destroyed.
78+
*
79+
* Cleans up plugin context using proper destruction.
80+
*
81+
* @param pluginContext Pointer to memory containing per-flow plugin data.
82+
*/
83+
void onDestroy(void* pluginContext) override;
84+
85+
/**
86+
* @brief Returns memory layout requirements for the plugin's data.
87+
*
88+
* Used by the framework to allocate per-flow plugin storage.
89+
*
90+
* @return PluginDataMemoryLayout containing size and alignment.
91+
*/
92+
PluginDataMemoryLayout getDataMemoryLayout() const noexcept override;
93+
94+
private:
95+
void parseIcmp(const FlowRecord& flowRecord, const Packet& packet, IcmpPluginData& pluginData);
96+
97+
FieldHandlers<IcmpFields> m_fieldHandlers;
98+
};
99+
100+
} // namespace ipxp

0 commit comments

Comments
 (0)