Skip to content

Commit 0124728

Browse files
AdamZvarasedmicha
authored andcommitted
ASN: session process and ASN lookup
1 parent e73cf1f commit 0124728

File tree

1 file changed

+256
-5
lines changed
  • src/plugins/intermediate/asn

1 file changed

+256
-5
lines changed

src/plugins/intermediate/asn/asn.c

Lines changed: 256 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444

4545
#include "config.h"
4646

47+
#define ASN_LOOKUP_STRING "autonomous_system_number"
48+
4749
/** Plugin description */
4850
IPX_API struct ipx_plugin_info ipx_plugin_info = {
4951
// Plugin type
@@ -81,6 +83,234 @@ struct ipx_modifier_field asn_fields[] = {
8183
[ASN_DST] = {.id = 17, .length = 4, .en = 0} // bgpDestinationASNumber
8284
};
8385

86+
/**
87+
* \brief Get the autonomous system (AS) number from database
88+
*
89+
* Function takes IP address, tries to find it in ASN database and return AS number.
90+
* If number is not found, 0 is returned. If any error occurs, \p err is set to non-zero value.
91+
* \param[in] db ASN database
92+
* \param[in] address IP address to search for
93+
* \param[out] err MMDB error code
94+
* \return AS number if successful
95+
* \return 0 (reserved AS number) if number was not found
96+
*/
97+
static uint32_t
98+
mmdb_lookup(MMDB_s *db, struct sockaddr *address, int *err)
99+
{
100+
assert(db != NULL && address != NULL && err != NULL);
101+
102+
int rc = MMDB_SUCCESS;
103+
MMDB_lookup_result_s result;
104+
105+
// Search for address
106+
result = MMDB_lookup_sockaddr(db, address, &rc);
107+
if (rc) {
108+
*err = rc;
109+
return 0;
110+
}
111+
112+
// IP address not found
113+
if (!result.found_entry) {
114+
return 0;
115+
}
116+
117+
// Found address, look for AS number
118+
MMDB_entry_data_s data;
119+
rc = MMDB_get_value(&(result.entry), &data, ASN_LOOKUP_STRING, NULL);
120+
if (rc) {
121+
*err = rc;
122+
return 0;
123+
}
124+
125+
// Address was not found
126+
if (!data.has_data) {
127+
return 0;
128+
}
129+
130+
return data.uint32;
131+
}
132+
133+
/**
134+
* \brief Fill output buffer with AS number from ASN databse
135+
*
136+
* \param[in] db ASN database
137+
* \param[in] address IP address
138+
* \param[in] length Length of address (4 or 16)
139+
* \return #IPX_OK if successful
140+
* \return #IPX_ERR_ARG if argument was not valid IP address
141+
* \return #IPX_ERR_DENIED if MMDB error occured
142+
*/
143+
static int
144+
get_asn(MMDB_s *db, struct ipx_modifier_output *out, uint8_t *address, size_t length)
145+
{
146+
int rc;
147+
uint32_t asn;
148+
struct sockaddr *addr;
149+
150+
if (length == 4) {
151+
// IPv4 address
152+
struct sockaddr_in addr_4 = {
153+
.sin_family = AF_INET,
154+
.sin_addr.s_addr = *((uint32_t *)address)
155+
};
156+
addr = (struct sockaddr *) &addr_4;
157+
} else if (length == 6) {
158+
// IPv6 address
159+
struct sockaddr_in6 addr_6 = {
160+
.sin6_family = AF_INET6
161+
};
162+
memcpy(&(addr_6.sin6_addr), address, 16);
163+
addr = (struct sockaddr *) &addr_6;
164+
} else {
165+
// Unknown address format
166+
return IPX_ERR_ARG;
167+
}
168+
169+
asn = mmdb_lookup(db, addr, &rc);
170+
if (rc) {
171+
// MMDB error
172+
return IPX_ERR_DENIED;
173+
}
174+
175+
int len = 4;
176+
memcpy(out->raw, &asn, len);
177+
out->length = len;
178+
}
179+
180+
181+
/**
182+
* \brief Set output buffers with autonomous system numbers
183+
*
184+
* Output buffers are then used in modifier to modify given record with filled values.
185+
* Unknown AS numbers are skipped, indicated by negative length in output buffer item.
186+
* \param[in] rec Data record from IPFIX message
187+
* \param[out] output Output buffers
188+
* \param[in] data Callback data
189+
* \return #IPX_OK on success
190+
*/
191+
int
192+
modifier_asn_callback(const struct fds_drec *rec, struct ipx_modifier_output output[], void *data)
193+
{
194+
int rc;
195+
MMDB_s *db = (MMDB_s *) data;
196+
197+
// Source address
198+
struct fds_drec_field field;
199+
if (fds_drec_find((struct fds_drec *)rec, 0, 8, &field) != FDS_EOC) {
200+
// IPv4
201+
assert(field.size == 4);
202+
rc = get_asn(db, &output[ASN_SRC], field.data, 4);
203+
} else if (fds_drec_find((struct fds_drec *)rec, 0, 27, &field) != FDS_EOC) {
204+
// IPv6
205+
assert(field.size == 16);
206+
rc = get_asn(db, &output[ASN_SRC], field.data, 16);
207+
}
208+
209+
if (rc) {
210+
return rc;
211+
}
212+
213+
// Destination address
214+
if (fds_drec_find((struct fds_drec *)rec, 0, 12, &field) != FDS_EOC) {
215+
// IPv4
216+
assert(field.size == 4);
217+
get_asn(db, &output[ASN_DST], field.data, 4);
218+
} else if (fds_drec_find((struct fds_drec *)rec, 0, 28, &field) != FDS_EOC) {
219+
// IPv6
220+
assert(field.size == 16);
221+
get_asn(db, &output[ASN_DST], field.data, 16);
222+
}
223+
224+
if (rc) {
225+
return rc;
226+
}
227+
}
228+
229+
/**
230+
* \brief Process session message
231+
*
232+
* In the event of closing session, information about the particular
233+
* Transport Session will be removed.
234+
* \param[in] ctx Plugin context
235+
* \param[in] modifier Modifier component
236+
* \param[in] msg Transport session message
237+
* \return Always #IPX_OK
238+
*/
239+
static int
240+
process_session(ipx_ctx_t *ctx, ipx_modifier_t *modifier, ipx_msg_session_t *msg)
241+
{
242+
// Only process session close events
243+
if (ipx_msg_session_get_event(msg) != IPX_MSG_SESSION_CLOSE) {
244+
ipx_ctx_msg_pass(ctx, ipx_msg_session2base(msg));
245+
return IPX_OK;
246+
}
247+
248+
int rc;
249+
const struct ipx_session *session = ipx_msg_session_get_session(msg);
250+
251+
ipx_msg_garbage_t *garbage;
252+
if ((rc = ipx_modifier_remove_session(modifier, session, &garbage)) == IPX_OK) {
253+
// No error occured, pass the original message
254+
ipx_ctx_msg_pass(ctx, ipx_msg_session2base(msg));
255+
256+
/* Send garbage after session message because other plugins might have references to
257+
templates linked to that session */
258+
if (garbage == NULL) {
259+
IPX_CTX_WARNING(ctx, "A memory allocation failed (%s:%d).", __FILE__, __LINE__);
260+
return IPX_OK;
261+
}
262+
263+
ipx_ctx_msg_pass(ctx, ipx_msg_garbage2base(garbage));
264+
return IPX_OK;
265+
}
266+
267+
// Possible internal errors
268+
switch (rc) {
269+
case IPX_ERR_NOTFOUND:
270+
IPX_CTX_ERROR(ctx, "Received an event about closing of unknown Transport Session '%s'.",
271+
session->ident);
272+
break;
273+
default:
274+
IPX_CTX_ERROR(ctx, "ipx_modifier_session_remove() returned an unexpected value (%s:%d, "
275+
"code: %d).", __FILE__, __LINE__, rc);
276+
break;
277+
}
278+
279+
return IPX_OK;
280+
}
281+
282+
/**
283+
* \brief Process IPFIX message
284+
*
285+
* Iterate through all data records in message and modify them, store modified records
286+
* in new message which is passed instead of original message.
287+
* \param[in] ctx Plugin context
288+
* \param[in] modifier Modifier component
289+
* \param[in] builder Message builder
290+
* \param[in] msg IPFIX message
291+
* \return
292+
*/
293+
static int
294+
process_ipfix(ipx_ctx_t *ctx, ipx_modifier_t *modifier, ipx_msg_builder_t *builder,
295+
ipx_msg_ipfix_t *msg)
296+
{
297+
298+
ipx_msg_garbage_t *session_garbage;
299+
ipx_modifier_add_session(modifier, msg, &session_garbage);
300+
301+
uint32_t rec_cnt = ipx_msg_ipfix_get_drec_cnt(msg);
302+
303+
struct ipx_ipfix_record *rec;
304+
ipx_msg_garbage_t *ipfix_garbage;
305+
for (uint32_t i = 0; i < rec_cnt; i++) {
306+
rec = ipx_msg_ipfix_get_drec(msg, i);
307+
308+
ipx_modifier_modify(modifier, &(rec->rec), &ipfix_garbage);
309+
}
310+
311+
return IPX_OK;
312+
}
313+
84314
// -------------------------------------------------------------------------------------------------
85315

86316
int
@@ -111,7 +341,7 @@ ipx_plugin_init(ipx_ctx_t *ctx, const char *params)
111341
const char *ident = ipx_ctx_name_get(ctx);
112342
size_t fsize = sizeof(asn_fields) / sizeof(*asn_fields);
113343

114-
data->modifier = ipx_modifier_create(asn_fields, fsize, NULL, iemgr, &verb, ident);
344+
data->modifier = ipx_modifier_create(asn_fields, fsize, &(data->database), iemgr, &verb, ident);
115345
if (!data->modifier) {
116346
config_destroy(data->config);
117347
MMDB_close(&(data->database));
@@ -137,6 +367,9 @@ ipx_plugin_init(ipx_ctx_t *ctx, const char *params)
137367
return IPX_ERR_DENIED;
138368
}
139369

370+
// Set adder callback
371+
ipx_modifier_set_adder_cb(data->modifier, &modifier_asn_callback);
372+
140373
return IPX_OK;
141374
}
142375

@@ -146,7 +379,7 @@ ipx_plugin_destroy(ipx_ctx_t *ctx, void *cfg)
146379
(void) ctx; // Suppress warnings
147380
struct instance_data *data = (struct instance_data *) cfg;
148381

149-
/* Create garbage message when destroying modifier because orher plugins might be
382+
/* Create garbage message when destroying modifier because other plugins might be
150383
referencing templates in modifier */
151384

152385
ipx_msg_garbage_cb cb = (ipx_msg_garbage_cb) &ipx_modifier_destroy;
@@ -155,7 +388,7 @@ ipx_plugin_destroy(ipx_ctx_t *ctx, void *cfg)
155388
ipx_ctx_msg_pass(ctx, ipx_msg_garbage2base(gb_msg));
156389
} else {
157390
/* If creating garbage message fails, don't destroy modifier (memory leak) because
158-
of possible segfault */
391+
of possible segfault */
159392
IPX_CTX_WARNING(ctx, "Could not destroy modifier (%s)", ipx_ctx_name_get(ctx));
160393
}
161394

@@ -169,8 +402,26 @@ int
169402
ipx_plugin_process(ipx_ctx_t *ctx, void *cfg, ipx_msg_t *msg)
170403
{
171404
struct instance_data *data = (struct instance_data *) cfg;
405+
int rc;
406+
407+
// Get message type, call appropriate functions for message type
408+
enum ipx_msg_type type = ipx_msg_get_type(msg);
409+
switch (type) {
410+
case IPX_MSG_SESSION:
411+
rc = process_session(ctx, data->modifier, ipx_msg_base2session(msg));
412+
break;
413+
case IPX_MSG_IPFIX:
414+
rc = process_ipfix(ctx, data->modifier, data->builder, ipx_msg_base2ipfix(msg));
415+
break;
416+
default:
417+
// Should not reach
418+
assert(false);
419+
}
420+
421+
if (rc) {
422+
// Any problem occured in processing message
423+
return IPX_ERR_DENIED;
424+
}
172425

173-
// Always pass the message
174-
ipx_ctx_msg_pass(ctx, msg);
175426
return IPX_OK;
176427
}

0 commit comments

Comments
 (0)