Skip to content

Commit af893b1

Browse files
Zainullin DamirZainullin Damir
authored andcommitted
++
1 parent 915d0fe commit af893b1

32 files changed

+613
-434
lines changed

src/plugins/process/dnssd/README.md

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,8 @@ The **DNSSD Plugin** extends flow records with DNS-SD (DNS Service Discovery) qu
1616

1717
| Field Name | Data Type | Description |
1818
|-----------------|-----------|----------------------------------------|
19-
| `DNS_ID`| `uint16_t` | Unique identifier of the processed DNS query |
20-
| `DNS_ANSWERS`| `uint16_t` | Number of answers in the processed DNS response |
21-
| `DNS_RCODE`| `uint8_t` | Response code of the processed DNS response |
22-
| `DNS_QTYPE`| `uint16_t` | Type of the DNS query |
23-
| `DNS_CLASS`| `uint16_t` | Class of the DNS query |
24-
| `DNS_NAME`| `string` | Domain name in the DNS query |
25-
| `DNS_RR_TTL`| `uint32_t` | Time-to-live of the first DNS response |
26-
| `DNS_RLENGTH`| `uint16_t` | Length of the first DNS response |
27-
| `DNS_RDATA`| `bytes` | Data of the first DNS response |
28-
| `DNS_PSIZE`| `uint16_t` | Length of the first DNS additional record from response |
29-
| `DNS_DO`| `uint8_t` | DNSSEC OK flag of the first DNS additional record from response |
19+
| `DNSSD_QUERIES`| `string` | Concatenated list of requested services |
20+
| `DNSSD_RESPONSES`| `string` | Concatenated list of processed DNS responses: name, src port, cpu, operating system, TXT record content |
3021

3122
## Usage
3223

@@ -36,11 +27,13 @@ Add the plugin to your ipfixprobe YAML configuration:
3627

3728
```yaml
3829
process_plugins:
39-
- dns
30+
- dnssd
4031
```
4132
4233
### CLI Usage
4334
4435
You can also enable the plugin directly from the command line:
4536
46-
```ipfixprobe -p dns ...```
37+
```ipfixprobe -p dnssd ...```
38+
```ipfixprobe -p "dnssd;txt" ...```
39+
```ipfixprobe -p "dnssd;txt=<path_to_file>" ...```
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# FlowHash Plugin
2+
3+
The **FlowHash Plugin** extends flow records with flow hashing information.
4+
5+
## Features
6+
7+
- Extracts and exports flow hash that ipfixprobe storage plugin assigned to given flow.
8+
9+
## Output Fields
10+
11+
| Field Name | Data Type | Description |
12+
|-----------------|-----------|----------------------------------------|
13+
| `FLOW_ID`| `uint64_t` | Assigned flow hash |
14+
15+
## Usage
16+
17+
### YAML Configuration
18+
19+
Add the plugin to your ipfixprobe YAML configuration:
20+
21+
```yaml
22+
process_plugins:
23+
- flowhash
24+
```
25+
26+
### CLI Usage
27+
28+
You can also enable the plugin directly from the command line:
29+
30+
```ipfixprobe -p flowhash ...```

src/plugins/process/http/README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# HTTP Plugin
2+
3+
Plugin enables detailed analysis of HTTP traffic by extracting key fields from HTTP headers.
4+
5+
## Features
6+
7+
- Extracts and exports HTTP request and response fields if flow contains HTTP information.
8+
- Terminates the flow if both HTTP request or response have been parsed.
9+
- Reinserts the flow if the second request or response is detected.
10+
11+
## Output Fields
12+
13+
| Field Name | Data Type | Description |
14+
|-----------------|-----------|----------------------------------------|
15+
| `HTTP_REQUEST_METHOD`| `string` | HTTP request method (e.g., GET, POST) |
16+
| `HTTP_REQUEST_HOST`| `string` | Requested HTTP host |
17+
| `HTTP_REQUEST_URL`| `string` | Requested URL |
18+
| `HTTP_REQUEST_AGENT`| `string` | User agent of the requester |
19+
| `HTTP_REQUEST_REFERER`| `string` | HTTP request referer |
20+
| `HTTP_RESPONSE_STATUS_CODE`| `uint16_t` | Response status code |
21+
| `HTTP_RESPONSE_CONTENT_TYPE`| `string` | Response content type |
22+
| `HTTP_RESPONSE_SERVER`| `string` | Response server |
23+
| `HTTP_RESPONSE_SET_COOKIE_NAMES`| `string` | Concatenated names of cookies that were set |
24+
25+
## Usage
26+
27+
### YAML Configuration
28+
29+
Add the plugin to your ipfixprobe YAML configuration:
30+
31+
```yaml
32+
process_plugins:
33+
- http
34+
```
35+
36+
### CLI Usage
37+
38+
You can also enable the plugin directly from the command line:
39+
40+
```ipfixprobe -p http ...```

src/plugins/process/http/src/http.cpp

Lines changed: 93 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,17 @@
1414

1515
#include "http.hpp"
1616

17-
#include <pluginManifest.hpp>
18-
#include <pluginRegistrar.hpp>
19-
#include <pluginFactory.hpp>
17+
#include <ranges>
18+
2019
#include <fieldGroup.hpp>
2120
#include <fieldManager.hpp>
21+
#include <ipfixprobe/options.hpp>
22+
#include <pluginFactory.hpp>
23+
#include <pluginManifest.hpp>
24+
#include <pluginRegistrar.hpp>
2225
#include <utils.hpp>
23-
#include <ranges>
24-
#include <utils/stringViewUtils.hpp>
2526
#include <utils/spanUtils.hpp>
26-
#include <ipfixprobe/options.hpp>
27-
27+
#include <utils/stringViewUtils.hpp>
2828

2929
namespace ipxp {
3030

@@ -44,108 +44,119 @@ static FieldGroup createHTTPSchema(FieldManager& fieldManager, FieldHandlers<HTT
4444
{
4545
FieldGroup schema = fieldManager.createFieldGroup("http");
4646

47-
handlers.insert(HTTPFields::HTTP_REQUEST_METHOD, schema.addScalarField(
48-
"HTTP_REQUEST_METHOD",
49-
[](const void* context) { return toStringView(reinterpret_cast<const HTTPData*>(context)->method); }
50-
));
51-
handlers.insert(HTTPFields::HTTP_REQUEST_HOST, schema.addScalarField(
52-
"HTTP_REQUEST_HOST",
53-
[](const void* context) { return toStringView(reinterpret_cast<const HTTPData*>(context)->host); }
54-
));
55-
handlers.insert(HTTPFields::HTTP_REQUEST_URL, schema.addScalarField(
56-
"HTTP_REQUEST_URL",
57-
[](const void* context) { return toStringView(reinterpret_cast<const HTTPData*>(context)->uri); }
58-
));
59-
handlers.insert(HTTPFields::HTTP_REQUEST_AGENT, schema.addScalarField(
60-
"HTTP_REQUEST_AGENT",
61-
[](const void* context) { return toStringView(reinterpret_cast<const HTTPData*>(context)->userAgent); }
62-
));
63-
handlers.insert(HTTPFields::HTTP_REQUEST_REFERER, schema.addScalarField(
64-
"HTTP_REQUEST_REFERER",
65-
[](const void* context) { return toStringView(reinterpret_cast<const HTTPData*>(context)->referer); }
66-
));
67-
handlers.insert(HTTPFields::HTTP_RESPONSE_STATUS_CODE, schema.addScalarField(
68-
"HTTP_RESPONSE_STATUS_CODE",
69-
[](const void* context) { return reinterpret_cast<const HTTPData*>(context)->statusCode; }
70-
));
71-
handlers.insert(HTTPFields::HTTP_RESPONSE_CONTENT_TYPE, schema.addScalarField(
72-
"HTTP_RESPONSE_CONTENT_TYPE",
73-
[](const void* context) { return toStringView(reinterpret_cast<const HTTPData*>(context)->contentType); }
74-
));
75-
handlers.insert(HTTPFields::HTTP_RESPONSE_SERVER, schema.addScalarField(
76-
"HTTP_RESPONSE_SERVER",
77-
[](const void* context) { return toStringView(reinterpret_cast<const HTTPData*>(context)->server); }
78-
));
79-
handlers.insert(HTTPFields::HTTP_RESPONSE_SET_COOKIE_NAMES, schema.addScalarField(
80-
"HTTP_RESPONSE_SET_COOKIE_NAMES",
81-
[](const void* context) { return toStringView(reinterpret_cast<const HTTPData*>(context)->cookies); }
82-
));
47+
handlers.insert(
48+
HTTPFields::HTTP_REQUEST_METHOD,
49+
schema.addScalarField("HTTP_REQUEST_METHOD", [](const void* context) {
50+
return toStringView(reinterpret_cast<const HTTPData*>(context)->method);
51+
}));
52+
handlers.insert(
53+
HTTPFields::HTTP_REQUEST_HOST,
54+
schema.addScalarField("HTTP_REQUEST_HOST", [](const void* context) {
55+
return toStringView(reinterpret_cast<const HTTPData*>(context)->host);
56+
}));
57+
handlers.insert(
58+
HTTPFields::HTTP_REQUEST_URL,
59+
schema.addScalarField("HTTP_REQUEST_URL", [](const void* context) {
60+
return toStringView(reinterpret_cast<const HTTPData*>(context)->uri);
61+
}));
62+
handlers.insert(
63+
HTTPFields::HTTP_REQUEST_AGENT,
64+
schema.addScalarField("HTTP_REQUEST_AGENT", [](const void* context) {
65+
return toStringView(reinterpret_cast<const HTTPData*>(context)->userAgent);
66+
}));
67+
handlers.insert(
68+
HTTPFields::HTTP_REQUEST_REFERER,
69+
schema.addScalarField("HTTP_REQUEST_REFERER", [](const void* context) {
70+
return toStringView(reinterpret_cast<const HTTPData*>(context)->referer);
71+
}));
72+
handlers.insert(
73+
HTTPFields::HTTP_RESPONSE_STATUS_CODE,
74+
schema.addScalarField("HTTP_RESPONSE_STATUS_CODE", [](const void* context) {
75+
return reinterpret_cast<const HTTPData*>(context)->statusCode;
76+
}));
77+
handlers.insert(
78+
HTTPFields::HTTP_RESPONSE_CONTENT_TYPE,
79+
schema.addScalarField("HTTP_RESPONSE_CONTENT_TYPE", [](const void* context) {
80+
return toStringView(reinterpret_cast<const HTTPData*>(context)->contentType);
81+
}));
82+
handlers.insert(
83+
HTTPFields::HTTP_RESPONSE_SERVER,
84+
schema.addScalarField("HTTP_RESPONSE_SERVER", [](const void* context) {
85+
return toStringView(reinterpret_cast<const HTTPData*>(context)->server);
86+
}));
87+
handlers.insert(
88+
HTTPFields::HTTP_RESPONSE_SET_COOKIE_NAMES,
89+
schema.addScalarField("HTTP_RESPONSE_SET_COOKIE_NAMES", [](const void* context) {
90+
return toStringView(reinterpret_cast<const HTTPData*>(context)->cookies);
91+
}));
8392

8493
return schema;
8594
}
8695

87-
HTTPPlugin::HTTPPlugin([[maybe_unused]]const std::string& params, FieldManager& manager)
96+
HTTPPlugin::HTTPPlugin([[maybe_unused]] const std::string& params, FieldManager& manager)
8897
{
8998
createHTTPSchema(manager, m_fieldHandlers);
9099
}
91100

92-
void HTTPPlugin::saveParsedValues(const HTTPParser& parser, FlowRecord& flowRecord, HTTPData& httpData) noexcept
101+
void HTTPPlugin::saveParsedValues(
102+
const HTTPParser& parser,
103+
FlowRecord& flowRecord,
104+
HTTPData& httpData) noexcept
93105
{
94106
httpData.requestParsed |= parser.requestParsed;
95107
httpData.responseParsed |= parser.responseParsed;
96108

97109
if (parser.method.has_value()) {
98-
std::ranges::copy(*parser.method |
99-
std::views::take(httpData.method.capacity()),
100-
std::back_inserter(httpData.method));
110+
std::ranges::copy(
111+
*parser.method | std::views::take(httpData.method.capacity()),
112+
std::back_inserter(httpData.method));
101113
m_fieldHandlers[HTTPFields::HTTP_REQUEST_METHOD].setAsAvailable(flowRecord);
102114
}
103115
if (parser.uri.has_value()) {
104-
std::ranges::copy(*parser.uri |
105-
std::views::take(httpData.uri.capacity()),
106-
std::back_inserter(httpData.uri));
116+
std::ranges::copy(
117+
*parser.uri | std::views::take(httpData.uri.capacity()),
118+
std::back_inserter(httpData.uri));
107119
m_fieldHandlers[HTTPFields::HTTP_REQUEST_URL].setAsAvailable(flowRecord);
108120
}
109121
if (parser.host.has_value()) {
110-
std::ranges::copy(*parser.host |
111-
std::views::take(httpData.host.capacity()),
112-
std::back_inserter(httpData.host));
122+
std::ranges::copy(
123+
*parser.host | std::views::take(httpData.host.capacity()),
124+
std::back_inserter(httpData.host));
113125
m_fieldHandlers[HTTPFields::HTTP_REQUEST_HOST].setAsAvailable(flowRecord);
114126
}
115127
if (parser.userAgent.has_value()) {
116-
std::ranges::copy(*parser.userAgent |
117-
std::views::take(httpData.userAgent.capacity()),
118-
std::back_inserter(httpData.userAgent));
128+
std::ranges::copy(
129+
*parser.userAgent | std::views::take(httpData.userAgent.capacity()),
130+
std::back_inserter(httpData.userAgent));
119131
m_fieldHandlers[HTTPFields::HTTP_REQUEST_AGENT].setAsAvailable(flowRecord);
120132
}
121133
if (parser.referer.has_value()) {
122-
std::ranges::copy(*parser.referer |
123-
std::views::take(httpData.referer.capacity()),
124-
std::back_inserter(httpData.referer));
134+
std::ranges::copy(
135+
*parser.referer | std::views::take(httpData.referer.capacity()),
136+
std::back_inserter(httpData.referer));
125137
m_fieldHandlers[HTTPFields::HTTP_REQUEST_REFERER].setAsAvailable(flowRecord);
126138
}
127139
if (parser.statusCode.has_value()) {
128140
httpData.statusCode = *parser.statusCode;
129141
m_fieldHandlers[HTTPFields::HTTP_RESPONSE_STATUS_CODE].setAsAvailable(flowRecord);
130142
}
131143
if (parser.contentType.has_value()) {
132-
std::ranges::copy(*parser.contentType |
133-
std::views::take(httpData.contentType.capacity()),
134-
std::back_inserter(httpData.contentType));
144+
std::ranges::copy(
145+
*parser.contentType | std::views::take(httpData.contentType.capacity()),
146+
std::back_inserter(httpData.contentType));
135147
m_fieldHandlers[HTTPFields::HTTP_RESPONSE_CONTENT_TYPE].setAsAvailable(flowRecord);
136148
}
137149
if (parser.server.has_value()) {
138-
std::ranges::copy(*parser.server |
139-
std::views::take(httpData.server.capacity()),
140-
std::back_inserter(httpData.server));
150+
std::ranges::copy(
151+
*parser.server | std::views::take(httpData.server.capacity()),
152+
std::back_inserter(httpData.server));
141153
m_fieldHandlers[HTTPFields::HTTP_RESPONSE_SERVER].setAsAvailable(flowRecord);
142154
}
143155
if (parser.cookies.has_value()) {
144156
std::ranges::for_each(*parser.cookies, [&](std::string_view cookie) {
145-
std::ranges::copy(cookie |
146-
std::views::take(
147-
httpData.cookies.capacity() - httpData.cookies.size()),
148-
std::back_inserter(httpData.cookies));
157+
std::ranges::copy(
158+
cookie | std::views::take(httpData.cookies.capacity() - httpData.cookies.size()),
159+
std::back_inserter(httpData.cookies));
149160
if (httpData.cookies.size() != httpData.cookies.capacity()) {
150161
httpData.cookies.push_back(';');
151162
}
@@ -166,7 +177,7 @@ void HTTPPlugin::saveParsedValues(const HTTPParser& parser, FlowRecord& flowReco
166177
.flowAction = FlowAction::RemovePlugin,
167178
};
168179
}
169-
180+
170181
if (parser.requestParsed && httpData.requestParsed) {
171182
// Must be flush and reinsert ????
172183
return {
@@ -199,7 +210,8 @@ void HTTPPlugin::saveParsedValues(const HTTPParser& parser, FlowRecord& flowReco
199210
PluginInitResult HTTPPlugin::onInit(const FlowContext& flowContext, void* pluginContext)
200211
{
201212
HTTPParser parser;
202-
parser.parse(toSpan<const std::byte>(flowContext.packet.payload, flowContext.packet.payload_len));
213+
parser.parse(
214+
toSpan<const std::byte>(flowContext.packet.payload, flowContext.packet.payload_len));
203215
if (!parser.method.has_value()) {
204216
return {
205217
.constructionState = ConstructionState::NotConstructed,
@@ -211,15 +223,15 @@ PluginInitResult HTTPPlugin::onInit(const FlowContext& flowContext, void* plugin
211223
auto* pluginData = std::construct_at(reinterpret_cast<HTTPData*>(pluginContext));
212224
saveParsedValues(parser, flowContext.flowRecord, *pluginData);
213225
/*auto [updateRequirement, flowAction] = parseHTTP(
214-
toSpan<const std::byte>(flowContext.packet.payload, flowContext.packet.payload_len), flowContext.flowRecord, *pluginData);*/
226+
toSpan<const std::byte>(flowContext.packet.payload, flowContext.packet.payload_len),
227+
flowContext.flowRecord, *pluginData);*/
215228
return {
216229
.constructionState = ConstructionState::Constructed,
217230
.updateRequirement = UpdateRequirement::RequiresUpdate,
218231
.flowAction = FlowAction::NoAction,
219232
};
220233
}
221234

222-
223235
PluginUpdateResult HTTPPlugin::beforeUpdate(const FlowContext& flowContext, void* pluginContext)
224236
{
225237
auto* pluginData = reinterpret_cast<HTTPData*>(pluginContext);
@@ -240,21 +252,22 @@ PluginUpdateResult HTTPPlugin::onUpdate(const FlowContext& flowContext, void* pl
240252
{
241253
auto* pluginData = reinterpret_cast<HTTPData*>(pluginContext);
242254
HTTPParser parser;
243-
parser.parse(toSpan<const std::byte>(flowContext.packet.payload, flowContext.packet.payload_len));
255+
parser.parse(
256+
toSpan<const std::byte>(flowContext.packet.payload, flowContext.packet.payload_len));
244257
if (pluginData->requestParsed && pluginData->responseParsed) {
245258
return {
246259
.updateRequirement = UpdateRequirement::NoUpdateNeeded,
247260
.flowAction = FlowAction::NoAction,
248261
};
249262
}
250-
263+
251264
return {
252265
.updateRequirement = UpdateRequirement::RequiresUpdate,
253266
.flowAction = FlowAction::NoAction,
254267
};
255268
}
256269

257-
void HTTPPlugin::onDestroy(void* pluginContext)
270+
void HTTPPlugin::onDestroy(void* pluginContext)
258271
{
259272
std::destroy_at(reinterpret_cast<HTTPData*>(pluginContext));
260273
}
@@ -267,7 +280,9 @@ PluginDataMemoryLayout HTTPPlugin::getDataMemoryLayout() const noexcept
267280
};
268281
}
269282

270-
static const PluginRegistrar<HTTPPlugin, PluginFactory<ProcessPlugin, const std::string&, FieldManager&>>
283+
static const PluginRegistrar<
284+
HTTPPlugin,
285+
PluginFactory<ProcessPlugin, const std::string&, FieldManager&>>
271286
httpPluginRegistrar(httpPluginManifest);
272287

273288
} // namespace ipxp

0 commit comments

Comments
 (0)