1 /*
2 pmacct (Promiscuous mode IP Accounting package)
3 pmacct is Copyright (C) 2003-2019 by Paolo Lucente
4 */
5
6 /*
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21
22 /* includes */
23 #include "pmacct.h"
24 #include "addr.h"
25 #include "nfacctd.h"
26 #include "pmacct-data.h"
27
handle_template(struct template_hdr_v9 * hdr,struct packet_ptrs * pptrs,u_int16_t tpl_type,u_int32_t sid,u_int16_t * pens,u_int16_t len,u_int32_t seq)28 struct template_cache_entry *handle_template(struct template_hdr_v9 *hdr, struct packet_ptrs *pptrs, u_int16_t tpl_type,
29 u_int32_t sid, u_int16_t *pens, u_int16_t len, u_int32_t seq)
30 {
31 struct template_cache_entry *tpl = NULL;
32 u_int8_t version = 0;
33
34 if (pens) *pens = FALSE;
35
36 if (tpl_type == 0 || tpl_type == 1) version = 9;
37 else if (tpl_type == 2 || tpl_type == 3) version = 10;
38
39 /* 0 NetFlow v9, 2 IPFIX */
40 if (tpl_type == 0 || tpl_type == 2) {
41 if ((tpl = find_template(hdr->template_id, (struct sockaddr *) pptrs->f_agent, tpl_type, sid)))
42 tpl = refresh_template(hdr, tpl, pptrs, tpl_type, sid, pens, version, len, seq);
43 else tpl = insert_template(hdr, pptrs, tpl_type, sid, pens, version, len, seq);
44 }
45 /* 1 NetFlow v9, 3 IPFIX */
46 else if (tpl_type == 1 || tpl_type == 3) {
47 if ((tpl = find_template(hdr->template_id, (struct sockaddr *) pptrs->f_agent, tpl_type, sid)))
48 tpl = refresh_opt_template(hdr, tpl, pptrs, tpl_type, sid, pens, version, len, seq);
49 else tpl = insert_opt_template(hdr, pptrs, tpl_type, sid, pens, version, len, seq);
50 }
51
52 return tpl;
53 }
54
modulo_template(u_int16_t template_id,struct sockaddr * agent,u_int16_t buckets)55 u_int16_t modulo_template(u_int16_t template_id, struct sockaddr *agent, u_int16_t buckets)
56 {
57 return hash_status_table(ntohs(template_id), agent, buckets);
58 }
59
find_template(u_int16_t id,struct sockaddr * agent,u_int16_t tpl_type,u_int32_t sid)60 struct template_cache_entry *find_template(u_int16_t id, struct sockaddr *agent, u_int16_t tpl_type, u_int32_t sid)
61 {
62 struct template_cache_entry *ptr;
63 u_int16_t modulo = modulo_template(id, agent, tpl_cache.num);
64
65 ptr = tpl_cache.c[modulo];
66
67 while (ptr) {
68 if ((ptr->template_id == id) && (!sa_addr_cmp((struct sockaddr *)agent, &ptr->agent)) &&
69 (ptr->source_id == sid))
70 return ptr;
71 else ptr = ptr->next;
72 }
73
74 return NULL;
75 }
76
insert_template(struct template_hdr_v9 * hdr,struct packet_ptrs * pptrs,u_int16_t tpl_type,u_int32_t sid,u_int16_t * pens,u_int8_t version,u_int16_t len,u_int32_t seq)77 struct template_cache_entry *insert_template(struct template_hdr_v9 *hdr, struct packet_ptrs *pptrs, u_int16_t tpl_type,
78 u_int32_t sid, u_int16_t *pens, u_int8_t version, u_int16_t len, u_int32_t seq)
79 {
80 struct template_cache_entry *ptr, *prevptr = NULL;
81 struct template_field_v9 *field;
82 u_int16_t modulo = modulo_template(hdr->template_id, (struct sockaddr *) pptrs->f_agent, tpl_cache.num);
83 u_int16_t num = ntohs(hdr->num), type, port, off, count;
84 u_int32_t *pen;
85 u_int8_t ipfix_ebit;
86 u_char *tpl;
87
88 ptr = tpl_cache.c[modulo];
89
90 while (ptr) {
91 prevptr = ptr;
92 ptr = ptr->next;
93 }
94
95 ptr = malloc(sizeof(struct template_cache_entry));
96 if (!ptr) {
97 Log(LOG_ERR, "ERROR ( %s/core ): insert_template(): unable to allocate new Data Template Cache Entry.\n", config.name);
98 return NULL;
99 }
100
101 memset(ptr, 0, sizeof(struct template_cache_entry));
102 sa_to_addr((struct sockaddr *)pptrs->f_agent, &ptr->agent, &port);
103 ptr->source_id = sid;
104 ptr->template_id = hdr->template_id;
105 ptr->template_type = 0;
106 ptr->num = num;
107
108 log_template_header(ptr, pptrs, tpl_type, sid, version);
109
110 count = off = 0;
111 tpl = (u_char *) hdr;
112 tpl += NfTplHdrV9Sz;
113 off += NfTplHdrV9Sz;
114 field = (struct template_field_v9 *)tpl;
115
116 while (count < num) {
117 if (count >= TPL_LIST_ENTRIES) {
118 notify_malf_packet(LOG_INFO, "INFO", "insert_template(): unable to read Data Template (too long)",
119 (struct sockaddr *) pptrs->f_agent, seq);
120 xflow_tot_bad_datagrams++;
121 free(ptr);
122 return NULL;
123 }
124
125 if (off >= len) {
126 notify_malf_packet(LOG_INFO, "INFO", "insert_template(): unable to read Data Template (malformed)",
127 (struct sockaddr *) pptrs->f_agent, seq);
128 xflow_tot_bad_datagrams++;
129 free(ptr);
130 return NULL;
131 }
132
133 pen = NULL;
134 ipfix_ebit = FALSE;
135 type = ntohs(field->type);
136
137 if (type & IPFIX_TPL_EBIT && version == 10) {
138 ipfix_ebit = TRUE;
139 type ^= IPFIX_TPL_EBIT;
140 if (pens) (*pens)++;
141 pen = (u_int32_t *) field;
142 pen++;
143 }
144
145 log_template_field(ptr->vlen, pen, type, ptr->len, ntohs(field->len), version);
146
147 /* Let's determine if we use legacy template registry or the
148 new template database (ie. if we have a PEN or high field
149 value, >= 384) */
150 if (type < NF9_MAX_DEFINED_FIELD && !pen) {
151 ptr->tpl[type].off = ptr->len;
152 ptr->tpl[type].tpl_len = ntohs(field->len);
153
154 if (ptr->vlen) ptr->tpl[type].off = 0;
155
156 if (ptr->tpl[type].tpl_len == IPFIX_VARIABLE_LENGTH) {
157 ptr->tpl[type].len = 0;
158 ptr->vlen = TRUE;
159 ptr->len = 0;
160 }
161 else {
162 ptr->tpl[type].len = ptr->tpl[type].tpl_len;
163 if (!ptr->vlen) ptr->len += ptr->tpl[type].len;
164 }
165 ptr->list[count].ptr = (char *) &ptr->tpl[type];
166 ptr->list[count].type = TPL_TYPE_LEGACY;
167 }
168 else {
169 u_int8_t repeat_id = 0;
170 struct utpl_field *ext_db_ptr = ext_db_get_next_ie(ptr, type, &repeat_id);
171
172 if (ext_db_ptr) {
173 if (pen) ext_db_ptr->pen = ntohl(*pen);
174 ext_db_ptr->type = type;
175 ext_db_ptr->off = ptr->len;
176 ext_db_ptr->tpl_len = ntohs(field->len);
177 ext_db_ptr->repeat_id = repeat_id;
178
179 if (ptr->vlen) ext_db_ptr->off = 0;
180
181 if (ext_db_ptr->tpl_len == IPFIX_VARIABLE_LENGTH) {
182 ext_db_ptr->len = 0;
183 ptr->vlen = TRUE;
184 ptr->len = 0;
185 }
186 else {
187 ext_db_ptr->len = ext_db_ptr->tpl_len;
188 if (!ptr->vlen) ptr->len += ext_db_ptr->len;
189 }
190 }
191 ptr->list[count].ptr = (char *) ext_db_ptr;
192 ptr->list[count].type = TPL_TYPE_EXT_DB;
193 }
194
195 count++;
196 off += NfTplFieldV9Sz;
197 if (ipfix_ebit) {
198 field++; /* skip 32-bits ahead */
199 off += sizeof(u_int32_t);
200 }
201 field++;
202 }
203
204 if (prevptr) prevptr->next = ptr;
205 else tpl_cache.c[modulo] = ptr;
206
207 log_template_footer(ptr, ptr->len, version);
208
209 #ifdef WITH_JANSSON
210 if (config.nfacctd_templates_file)
211 save_template(ptr, config.nfacctd_templates_file);
212 #endif
213
214 return ptr;
215 }
216
217 #ifdef WITH_JANSSON
load_templates_from_file(char * path)218 void load_templates_from_file(char *path)
219 {
220 struct template_cache_entry *tpl, *prev_ptr = NULL, *ptr = NULL;
221 FILE *tmp_file = fopen(path, "r");
222 char errbuf[SRVBUFLEN], tmpbuf[LARGEBUFLEN];
223 int line = 1;
224 u_int16_t modulo;
225
226 struct sockaddr_storage agent;
227
228 if (!tmp_file) {
229 Log(LOG_ERR, "ERROR ( %s/core ): [%s] load_templates_from_file(): unable to fopen(). File skipped.\n", config.name, path);
230 return;
231 }
232
233 while (fgets(tmpbuf, LARGEBUFLEN, tmp_file)) {
234 tpl = nfacctd_offline_read_json_template(tmpbuf, errbuf, SRVBUFLEN);
235
236 if (tpl == NULL) {
237 Log(LOG_WARNING, "WARN ( %s/core ): [%s:%u] %s\n", config.name, path, line, errbuf);
238 }
239 else {
240 addr_to_sa((struct sockaddr *) &agent, &tpl->agent, 0);
241
242 /* We assume the cache is empty when templates are loaded */
243 if (find_template(tpl->template_id, (struct sockaddr *) &agent, tpl->template_type, tpl->source_id)) {
244 Log(LOG_WARNING, "WARN ( %s/core ): load_templates_from_file(): template %u already cached. Skipping.\n",
245 config.name, tpl->template_id);
246 }
247 else {
248 modulo = modulo_template(tpl->template_id, (struct sockaddr *) &agent, tpl_cache.num);
249 ptr = tpl_cache.c[modulo];
250
251 while (ptr) {
252 prev_ptr = ptr;
253 ptr = ptr->next;
254 }
255
256 if (prev_ptr) prev_ptr->next = tpl;
257 else tpl_cache.c[modulo] = tpl;
258
259 Log(LOG_DEBUG, "DEBUG ( %s/core ): load_templates_from_file(): loaded template %u into cache.\n",
260 config.name, tpl->template_id);
261 }
262 }
263
264 prev_ptr = NULL;
265 line++;
266 }
267
268 fclose(tmp_file);
269 }
270
update_template_in_file(struct template_cache_entry * tpl,char * path)271 void update_template_in_file(struct template_cache_entry *tpl, char *path)
272 {
273 FILE *tmp_file = fopen(path, "r");
274 char tmpbuf[LARGEBUFLEN], tpl_agent_str[INET6_ADDRSTRLEN];
275 const char *addr;
276 int line = 0, tpl_found = 0;
277 u_int16_t tpl_id, tpl_type;
278 u_int32_t src_id;
279
280 if (!tmp_file) {
281 Log(LOG_WARNING, "WARN ( %s/core ): [%s] update_template_in_file(): unable to fopen(). File skipped.\n",
282 config.name, path);
283 return;
284 }
285
286 /* Find line where our template is stored */
287 while (fgets(tmpbuf, LARGEBUFLEN, tmp_file)) {
288 json_error_t json_err;
289 json_t *json_obj;
290
291 json_obj = json_loads(tmpbuf, 0, &json_err);
292
293 if (!json_obj) {
294 Log(LOG_WARNING, "WARN ( %s/core ): [%s] update_template_in_file(): json_loads() error: %s. Line skipped.\n",
295 config.name, path, json_err.text);
296 continue;
297 }
298 else {
299 if (!json_is_object(json_obj)) {
300 Log(LOG_WARNING, "WARN ( %s/core ): [%s] update_template_in_file(): json_is_object() failed. Line skipped.\n",
301 config.name, path);
302 goto next_line;
303 }
304 else {
305 json_t *json_tpl_id = json_object_get(json_obj, "template_id");
306 if (json_tpl_id == NULL) {
307 Log(LOG_WARNING, "WARN ( %s/core ): [%s] update_template_in_file(): template ID null. Line skipped.\n",
308 config.name, path);
309 goto next_line;
310 }
311 else tpl_id = json_integer_value(json_tpl_id);
312
313 json_t *json_agent = json_object_get(json_obj, "agent");
314 if (json_agent == NULL) {
315 Log(LOG_WARNING, "WARN ( %s/core ): [%s] update_template_in_file(): agent null. Line skipped.\n",
316 config.name, path);
317 goto next_line;
318 }
319 else addr = json_string_value(json_agent);
320
321 json_t *json_src_id = json_object_get(json_obj, "source_id");
322 if (json_src_id == NULL) {
323 Log(LOG_WARNING, "WARN ( %s/core ): [%s] update_template_in_file(): source ID null. Line skipped.\n",
324 config.name, path);
325 goto next_line;
326 }
327 else src_id = json_integer_value(json_src_id);
328
329 json_t *json_tpl_type = json_object_get(json_obj, "template_type");
330 if (json_tpl_type == NULL) {
331 Log(LOG_WARNING, "WARN ( %s/core ): [%s] update_template_in_file(): template type null. Line skipped.\n",
332 config.name, path);
333 goto next_line;
334 }
335 else tpl_type = json_integer_value(json_tpl_type);
336 }
337
338 addr_to_str(tpl_agent_str, &tpl->agent);
339 if (tpl_id == tpl->template_id && tpl_type == tpl->template_type
340 && src_id == tpl->source_id && !strcmp(addr, tpl_agent_str)) {
341 tpl_found = TRUE;
342 json_decref(json_obj);
343 break;
344 }
345 }
346
347 next_line:
348 json_decref(json_obj);
349 line++;
350 }
351
352 if (!tpl_found)
353 Log(LOG_WARNING, "WARN ( %s/core ): [%s] update_template_in_file(): Template %u not found.\n",
354 config.name, path, tpl->template_id);
355 else {
356 if (delete_line_from_file(line, path) != 0) {
357 Log(LOG_WARNING, "WARN ( %s/core ): [%s] update_template_in_file(): Error deleting old template. New version not saved.\n",
358 config.name, path);
359 }
360 else {
361 save_template(tpl, path);
362 }
363 }
364
365 fclose(tmp_file);
366 }
367
save_template(struct template_cache_entry * tpl,char * file)368 void save_template(struct template_cache_entry *tpl, char *file)
369 {
370 FILE *tpl_file = open_output_file(config.nfacctd_templates_file, "a", TRUE);
371 u_int16_t field_idx;
372 char ip_addr[INET6_ADDRSTRLEN];
373 json_t *root = json_object();
374 json_t *list_array, *tpl_array;
375
376 addr_to_str(ip_addr, &tpl->agent);
377 json_object_set_new_nocheck(root, "agent", json_string(ip_addr));
378
379 json_object_set_new_nocheck(root, "source_id", json_integer(tpl->source_id));
380
381 json_object_set_new_nocheck(root, "template_id", json_integer(tpl->template_id));
382
383 json_object_set_new_nocheck(root, "template_type", json_integer(tpl->template_type));
384
385 json_object_set_new_nocheck(root, "num", json_integer(tpl->num));
386
387 json_object_set_new_nocheck(root, "len", json_integer(tpl->len));
388
389 /* Data template */
390 if (tpl->template_type == 0) {
391 json_object_set_new_nocheck(root, "vlen", json_integer(tpl->vlen));
392
393 list_array = json_array();
394 for (field_idx = 0; field_idx < tpl->num; field_idx++) {
395 json_t *json_tfl_field = json_object();
396
397 json_object_set_new_nocheck(json_tfl_field, "type", json_integer(tpl->list[field_idx].type));
398
399 /* idea: depending on tpl->list[field_idx].type,
400 serialize either an otpl_field (if TPL_TYPE_LEGACY) or
401 an utpl_field (if TPL_TYPE_EXT_DB) */
402 if (tpl->list[field_idx].type == TPL_TYPE_LEGACY){
403 struct otpl_field *otpl_field = (struct otpl_field *) tpl->list[field_idx].ptr;
404 /* Where in tpl->tpl to insert the otpl_field
405 when deserializing */
406 int tpl_index = (otpl_field - tpl->tpl);
407 json_t *json_otpl_field = json_object();
408
409 json_object_set_new_nocheck(json_otpl_field, "off", json_integer(otpl_field->off));
410
411 json_object_set_new_nocheck(json_otpl_field, "len", json_integer(otpl_field->len));
412
413 json_object_set_new_nocheck(json_otpl_field, "tpl_len", json_integer(otpl_field->tpl_len));
414
415 json_object_set_new_nocheck(json_otpl_field, "tpl_index", json_integer(tpl_index));
416
417 json_object_set_new(json_tfl_field, "otpl", json_otpl_field);
418 }
419 else if (tpl->list[field_idx].type == TPL_TYPE_EXT_DB) {
420 struct utpl_field *ext_db_ptr = (struct utpl_field *) tpl->list[field_idx].ptr;
421 u_int16_t ext_db_modulo = (ext_db_ptr->type % TPL_EXT_DB_ENTRIES);
422
423 /* Where in tpl->ext_db[ext_db_modulo].ie
424 to insert the utpl_field when deserializing */
425 int ie_idx = (ext_db_ptr - tpl->ext_db[ext_db_modulo].ie);
426 json_t *json_utpl_field = json_object();
427
428 json_object_set_new_nocheck(json_utpl_field, "pen", json_integer(ext_db_ptr->pen));
429
430 json_object_set_new_nocheck(json_utpl_field, "type", json_integer(ext_db_ptr->type));
431
432 json_object_set_new_nocheck(json_utpl_field, "off", json_integer(ext_db_ptr->off));
433
434 json_object_set_new_nocheck(json_utpl_field, "len", json_integer(ext_db_ptr->len));
435
436 json_object_set_new_nocheck(json_utpl_field, "tpl_len", json_integer(ext_db_ptr->tpl_len));
437
438 json_object_set_new_nocheck(json_utpl_field, "repeat_id", json_integer(ext_db_ptr->repeat_id));
439
440 json_object_set_new_nocheck(json_utpl_field, "ie_idx", json_integer(ie_idx));
441
442 json_object_set_new(json_tfl_field, "utpl", json_utpl_field);
443 }
444
445 json_array_append_new(list_array, json_tfl_field);
446 }
447 json_object_set_new(root, "list", list_array);
448 }
449 /* Options template */
450 else {
451 tpl_array = json_array();
452 /* Fields with type >= NF9_MAX_DEFINED_FIELD are not serialized
453 since they don't appear to be taken into account when receiving
454 the template. */
455 for (field_idx = 0; field_idx < NF9_MAX_DEFINED_FIELD; field_idx++) {
456 if (tpl->tpl[field_idx].off == 0 && tpl->tpl[field_idx].len == 0) continue;
457
458 json_t *json_tpl_field = json_object();
459
460 json_object_set_new_nocheck(json_tpl_field, "type", json_integer(field_idx));
461
462 json_object_set_new_nocheck(json_tpl_field, "off", json_integer(tpl->tpl[field_idx].off));
463
464 json_object_set_new_nocheck(json_tpl_field, "len", json_integer(tpl->tpl[field_idx].len));
465
466 json_array_append_new(tpl_array, json_tpl_field);
467 }
468
469 json_object_set_new(root, "tpl", tpl_array);
470 }
471
472 /* NB: member `next` is willingly excluded from serialisation, since
473 it would make more sense for it to be computed when de-serializing,
474 to prevent the template cache from being corrupted. */
475
476 if (root) {
477 write_and_free_json(tpl_file, root);
478 Log(LOG_DEBUG, "DEBUG ( %s/core ): save_template(): saved template %u into file.\n", config.name, tpl->template_id);
479 }
480
481 close_output_file(tpl_file);
482 }
483
nfacctd_offline_read_json_template(char * buf,char * errbuf,int errlen)484 struct template_cache_entry *nfacctd_offline_read_json_template(char *buf, char *errbuf, int errlen)
485 {
486 struct template_cache_entry *ret = NULL;
487
488 json_error_t json_err;
489 json_t *json_obj = NULL, *json_tpl_id = NULL, *json_src_id = NULL, *json_tpl_type = NULL;
490 json_t *json_num = NULL, *json_len = NULL, *json_agent = NULL, *json_list = NULL;
491 const char *agent_str;
492
493 json_obj = json_loads(buf, 0, &json_err);
494
495 if (!json_obj) {
496 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): json_loads() error: %s. Line skipped.\n", json_err.text);
497 }
498 else {
499 if (!json_is_object(json_obj)) {
500 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): json_is_object() failed. Line skipped.\n");
501 }
502 else {
503 ret = malloc(sizeof(struct template_cache_entry));
504 if (!ret) {
505 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): Unable to allocate enough memory for a new Template Cache Entry.\n");
506 goto exit_lane;
507 }
508
509 memset(ret, 0, sizeof(struct template_cache_entry));
510
511 json_tpl_id = json_object_get(json_obj, "template_id");
512 if (json_tpl_id == NULL) {
513 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): template ID null. Line skipped.\n");
514 goto exit_lane;
515 }
516 else ret->template_id = json_integer_value(json_tpl_id);
517
518 json_src_id = json_object_get(json_obj, "source_id");
519 if (json_src_id == NULL) {
520 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): source ID null. Line skipped.\n");
521 goto exit_lane;
522 }
523 else ret->source_id = json_integer_value(json_src_id);
524
525 json_tpl_type = json_object_get(json_obj, "template_type");
526 if (json_tpl_type == NULL) {
527 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): template type null. Line skipped.\n");
528 goto exit_lane;
529 }
530 else ret->template_type = json_integer_value(json_tpl_type);
531
532 json_num = json_object_get(json_obj, "num");
533 if (json_num == NULL) {
534 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): num null. Line skipped.\n");
535 goto exit_lane;
536 }
537 else ret->num = json_integer_value(json_num);
538
539 json_len = json_object_get(json_obj, "len");
540 if (json_len == NULL) {
541 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): len null. Line skipped.\n");
542 goto exit_lane;
543 }
544 else ret->len = json_integer_value(json_len);
545
546 json_agent = json_object_get(json_obj, "agent");
547 agent_str = json_string_value(json_agent);
548 if (!str_to_addr(agent_str, &ret->agent)) {
549 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): error creating agent.\n");
550 goto exit_lane;
551 }
552
553 /* Data template */
554 if (ret->template_type == 0) {
555 json_t *json_vlen = json_object_get(json_obj, "vlen");
556
557 if (json_vlen == NULL) {
558 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): vlen null. Line skipped.\n");
559 goto exit_lane;
560 }
561 else ret->vlen = json_integer_value(json_vlen);
562
563 json_list = json_object_get(json_obj, "list");
564 if (!json_is_array(json_list)) {
565 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): error parsing template fields list.\n");
566 }
567 else {
568 size_t key;
569 json_t *value;
570 int idx = 0;
571
572 json_array_foreach(json_list, key, value) {
573 if (json_integer_value(json_object_get(value, "type")) == TPL_TYPE_LEGACY) {
574 json_t *json_otpl = NULL, *json_otpl_member = NULL;
575 struct otpl_field otpl;
576 int tpl_index = 0;
577
578 ret->list[idx].type = TPL_TYPE_LEGACY;
579
580 memset(&otpl, 0, sizeof (struct otpl_field));
581
582 json_otpl = json_object_get(value, "otpl");
583 if (json_otpl == NULL) {
584 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): otpl null. Line skipped.\n");
585 goto exit_lane;
586 }
587
588 json_otpl_member = json_object_get(json_otpl, "off");
589 if (json_otpl_member == NULL) {
590 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): off null. Line skipped.\n");
591 goto exit_lane;
592 }
593 else otpl.off = json_integer_value(json_otpl_member);
594
595 json_otpl_member = json_object_get(json_otpl, "len");
596 if (json_otpl_member == NULL) {
597 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): len null. Line skipped.\n");
598 goto exit_lane;
599 }
600 else otpl.len = json_integer_value(json_otpl_member);
601
602 json_otpl_member = json_object_get(json_otpl, "tpl_len");
603 if (json_otpl_member == NULL) {
604 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): tpl_len null. Line skipped.\n");
605 goto exit_lane;
606 }
607 else otpl.tpl_len = json_integer_value(json_otpl_member);
608
609 json_otpl_member = json_object_get(json_otpl, "tpl_index");
610 if (json_otpl_member == NULL) {
611 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): tpl_index null. Line skipped.\n");
612 goto exit_lane;
613 }
614 else tpl_index = json_integer_value(json_otpl_member);
615
616 memcpy(&ret->tpl[tpl_index], &otpl, sizeof(struct otpl_field));
617 ret->list[idx].ptr = (char *) &ret->tpl[tpl_index];
618 }
619 else if (json_integer_value(json_object_get(value, "type")) == TPL_TYPE_EXT_DB) {
620 json_t *json_utpl = NULL, *json_utpl_member = NULL;
621 struct utpl_field utpl;
622 int ie_idx = 0, modulo = 0;
623
624 ret->list[idx].type = TPL_TYPE_EXT_DB;
625
626 memset(&utpl, 0, sizeof(struct utpl_field));
627
628 json_utpl = json_object_get(value, "utpl");
629 if (json_utpl == NULL) {
630 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): utpl null. Line skipped.\n");
631 goto exit_lane;
632 }
633
634 json_utpl_member = json_object_get(json_utpl, "pen");
635 if (json_utpl_member == NULL) {
636 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): pen null. Line skipped.\n");
637 goto exit_lane;
638 }
639 else utpl.pen = json_integer_value(json_utpl_member);
640
641 json_utpl_member = json_object_get(json_utpl, "type");
642 if (json_utpl_member == NULL) {
643 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): type null. Line skipped.\n");
644 goto exit_lane;
645 }
646 else utpl.type = json_integer_value(json_utpl_member);
647
648 json_utpl_member = json_object_get(json_utpl, "off");
649 if (json_utpl_member == NULL) {
650 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): off null. Line skipped.\n");
651 goto exit_lane;
652 }
653 else utpl.off = json_integer_value(json_utpl_member);
654
655 json_utpl_member = json_object_get(json_utpl, "len");
656 if (json_utpl_member == NULL) {
657 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): len null. Line skipped.\n");
658 goto exit_lane;
659 }
660 else utpl.len = json_integer_value(json_utpl_member);
661
662 json_utpl_member = json_object_get(json_utpl, "tpl_len");
663 if (json_utpl_member == NULL) {
664 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): tpl_len null. Line skipped.\n");
665 goto exit_lane;
666 }
667 else utpl.tpl_len = json_integer_value(json_utpl_member);
668
669 json_utpl_member = json_object_get(json_utpl, "repeat_id");
670 if (json_utpl_member == NULL) {
671 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): repeat_id null. Line skipped.\n");
672 goto exit_lane;
673 }
674 else utpl.repeat_id = json_integer_value(json_utpl_member);
675
676 json_utpl_member = json_object_get(json_utpl, "ie_idx");
677 if (json_utpl_member == NULL) {
678 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): ie_idx null. Line skipped.\n");
679 goto exit_lane;
680 }
681 else ie_idx = json_integer_value(json_utpl_member);
682
683 modulo = (utpl.type % TPL_EXT_DB_ENTRIES);
684 memcpy(&ret->ext_db[modulo].ie[ie_idx], &utpl, sizeof(struct utpl_field));
685 ret->list[idx].ptr = (char *) &ret->ext_db[modulo].ie[ie_idx];
686 }
687 else {
688 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): incorrect field type. Line skipped.\n");
689 goto exit_lane;
690 }
691
692 idx++;
693 }
694 }
695 }
696 /* Options template */
697 else {
698 json_t *json_tpl = json_object_get(json_obj, "tpl");
699
700 if (!json_is_array(json_tpl)) {
701 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): error parsing template fields list.\n");
702 }
703 else {
704 size_t key;
705 json_t *value;
706 int tpl_idx = 0;
707
708 json_array_foreach(json_tpl, key, value) {
709 struct otpl_field otpl;
710
711 memset(&otpl, 0, sizeof (struct otpl_field));
712
713 json_t *json_otpl_member = json_object_get(value, "type");
714 if (json_otpl_member == NULL) {
715 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): type null. Line skipped.\n");
716 goto exit_lane;
717 }
718 else tpl_idx = json_integer_value(json_otpl_member);
719
720 json_otpl_member = json_object_get(value, "off");
721 if (json_otpl_member == NULL) {
722 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): off null. Line skipped.\n");
723 goto exit_lane;
724 }
725 else otpl.off = json_integer_value(json_otpl_member);
726
727 json_otpl_member = json_object_get(value, "len");
728 if (json_otpl_member == NULL) {
729 snprintf(errbuf, errlen, "nfacctd_offline_read_json_template(): len null. Line skipped.\n");
730 goto exit_lane;
731 }
732 else otpl.len = json_integer_value(json_otpl_member);
733
734 memcpy(&ret->tpl[tpl_idx], &otpl, sizeof(struct otpl_field));
735 }
736 }
737 }
738 }
739
740 json_decref(json_obj);
741 }
742
743 return ret;
744
745 exit_lane:
746 json_decref(json_obj);
747 if (ret) free(ret);
748
749 return NULL;
750 }
751 #else
load_templates_from_file(char * path)752 void load_templates_from_file(char *path)
753 {
754 if (config.debug) Log(LOG_DEBUG, "DEBUG ( %s/core ): load_templates_from_file(): JSON object not created due to missing --enable-jansson\n", config.name);
755 }
756
update_template_in_file(struct template_cache_entry * tpl,char * path)757 void update_template_in_file(struct template_cache_entry *tpl, char *path)
758 {
759 if (config.debug) Log(LOG_DEBUG, "DEBUG ( %s/core ): update_template_in_file(): JSON object not created due to missing --enable-jansson\n", config.name);
760 }
761
save_template(struct template_cache_entry * tpl,char * file)762 void save_template(struct template_cache_entry *tpl, char *file)
763 {
764 if (config.debug) Log(LOG_DEBUG, "DEBUG ( %s/core ): save_template(): JSON object not created due to missing --enable-jansson\n", config.name);
765 }
766
nfacctd_offline_read_json_template(char * buf,char * errbuf,int errlen)767 struct template_cache_entry *nfacctd_offline_read_json_template(char *buf, char *errbuf, int errlen)
768 {
769 if (config.debug) Log(LOG_DEBUG, "DEBUG ( %s/core ): nfacctd_offline_read_json_template(): JSON object not created due to missing --enable-jansson\n", config.name);
770
771 return NULL;
772 }
773 #endif
774
refresh_template(struct template_hdr_v9 * hdr,struct template_cache_entry * tpl,struct packet_ptrs * pptrs,u_int16_t tpl_type,u_int32_t sid,u_int16_t * pens,u_int8_t version,u_int16_t len,u_int32_t seq)775 struct template_cache_entry *refresh_template(struct template_hdr_v9 *hdr, struct template_cache_entry *tpl, struct packet_ptrs *pptrs, u_int16_t tpl_type,
776 u_int32_t sid, u_int16_t *pens, u_int8_t version, u_int16_t len, u_int32_t seq)
777 {
778 struct template_cache_entry backup, *next;
779 struct template_field_v9 *field;
780 u_int16_t count, num = ntohs(hdr->num), type, port, off;
781 u_int32_t *pen;
782 u_int8_t ipfix_ebit;
783 u_char *ptr;
784
785 next = tpl->next;
786 memcpy(&backup, tpl, sizeof(struct template_cache_entry));
787 memset(tpl, 0, sizeof(struct template_cache_entry));
788 sa_to_addr((struct sockaddr *)pptrs->f_agent, &tpl->agent, &port);
789 tpl->source_id = sid;
790 tpl->template_id = hdr->template_id;
791 tpl->template_type = 0;
792 tpl->num = num;
793 tpl->next = next;
794
795 log_template_header(tpl, pptrs, tpl_type, sid, version);
796
797 count = off = 0;
798 ptr = (u_char *) hdr;
799 ptr += NfTplHdrV9Sz;
800 off += NfTplHdrV9Sz;
801 field = (struct template_field_v9 *)ptr;
802
803 while (count < num) {
804 if (count >= TPL_LIST_ENTRIES) {
805 notify_malf_packet(LOG_INFO, "INFO", "refresh_template(): unable to read Data Template (too long)",
806 (struct sockaddr *) pptrs->f_agent, seq);
807 xflow_tot_bad_datagrams++;
808 return NULL;
809 }
810
811 if (off >= len) {
812 notify_malf_packet(LOG_INFO, "INFO", "refresh_template(): unable to read Data Template (malformed)",
813 (struct sockaddr *) pptrs->f_agent, seq);
814 xflow_tot_bad_datagrams++;
815 memcpy(tpl, &backup, sizeof(struct template_cache_entry));
816 return NULL;
817 }
818
819 pen = NULL;
820 ipfix_ebit = FALSE;
821 type = ntohs(field->type);
822
823 if (type & IPFIX_TPL_EBIT && version == 10) {
824 ipfix_ebit = TRUE;
825 type ^= IPFIX_TPL_EBIT;
826 if (pens) (*pens)++;
827 pen = (u_int32_t *) field; pen++;
828 }
829 log_template_field(tpl->vlen, pen, type, tpl->len, ntohs(field->len), version);
830
831 if (type < NF9_MAX_DEFINED_FIELD && !pen) {
832 tpl->tpl[type].off = tpl->len;
833 tpl->tpl[type].tpl_len = ntohs(field->len);
834
835 if (tpl->vlen) tpl->tpl[type].off = 0;
836
837 if (tpl->tpl[type].tpl_len == IPFIX_VARIABLE_LENGTH) {
838 tpl->tpl[type].len = 0;
839 tpl->vlen = TRUE;
840 tpl->len = 0;
841 }
842 else {
843 tpl->tpl[type].len = tpl->tpl[type].tpl_len;
844 if (!tpl->vlen) tpl->len += tpl->tpl[type].len;
845 }
846 tpl->list[count].ptr = (char *) &tpl->tpl[type];
847 tpl->list[count].type = TPL_TYPE_LEGACY;
848 }
849 else {
850 u_int8_t repeat_id = 0;
851 struct utpl_field *ext_db_ptr = ext_db_get_next_ie(tpl, type, &repeat_id);
852
853 if (ext_db_ptr) {
854 if (pen) ext_db_ptr->pen = ntohl(*pen);
855 ext_db_ptr->type = type;
856 ext_db_ptr->off = tpl->len;
857 ext_db_ptr->tpl_len = ntohs(field->len);
858 ext_db_ptr->repeat_id = repeat_id;
859
860 if (tpl->vlen) ext_db_ptr->off = 0;
861
862 if (ext_db_ptr->tpl_len == IPFIX_VARIABLE_LENGTH) {
863 ext_db_ptr->len = 0;
864 tpl->vlen = TRUE;
865 tpl->len = 0;
866 }
867 else {
868 ext_db_ptr->len = ext_db_ptr->tpl_len;
869 if (!tpl->vlen) tpl->len += ext_db_ptr->len;
870 }
871 }
872 tpl->list[count].ptr = (char *) ext_db_ptr;
873 tpl->list[count].type = TPL_TYPE_EXT_DB;
874 }
875
876 count++;
877 off += NfTplFieldV9Sz;
878 if (ipfix_ebit) {
879 field++; /* skip 32-bits ahead */
880 off += sizeof(u_int32_t);
881 }
882 field++;
883 }
884
885 log_template_footer(tpl, tpl->len, version);
886
887 #ifdef WITH_JANSSON
888 if (config.nfacctd_templates_file)
889 update_template_in_file(tpl, config.nfacctd_templates_file);
890 #endif
891
892 return tpl;
893 }
894
log_template_header(struct template_cache_entry * tpl,struct packet_ptrs * pptrs,u_int16_t tpl_type,u_int32_t sid,u_int8_t version)895 void log_template_header(struct template_cache_entry *tpl, struct packet_ptrs *pptrs, u_int16_t tpl_type, u_int32_t sid, u_int8_t version)
896 {
897 struct host_addr a;
898 char agent_addr[50];
899 u_int16_t agent_port;
900
901 sa_to_addr((struct sockaddr *)pptrs->f_agent, &a, &agent_port);
902 addr_to_str(agent_addr, &a);
903
904 Log(LOG_DEBUG, "DEBUG ( %s/core ): NfV%u agent : %s:%u\n", config.name, version, agent_addr, sid);
905 Log(LOG_DEBUG, "DEBUG ( %s/core ): NfV%u template type : %s\n", config.name, version, ( tpl->template_type == 0 || tpl->template_type == 2 ) ? "flow" : "options");
906 Log(LOG_DEBUG, "DEBUG ( %s/core ): NfV%u template ID : %u\n", config.name, version, ntohs(tpl->template_id));
907
908 Log(LOG_DEBUG, "DEBUG ( %s/core ): -------------------------------------------------------------\n", config.name);
909 Log(LOG_DEBUG, "DEBUG ( %s/core ): | pen | field type | offset | size |\n", config.name);
910 }
911
log_template_field(u_int8_t vlen,u_int32_t * pen,u_int16_t type,u_int16_t off,u_int16_t len,u_int8_t version)912 void log_template_field(u_int8_t vlen, u_int32_t *pen, u_int16_t type, u_int16_t off, u_int16_t len, u_int8_t version)
913 {
914 if (!pen) {
915 if (type <= MAX_TPL_DESC_LIST && strlen(tpl_desc_list[type])) {
916 if (!off && vlen)
917 Log(LOG_DEBUG, "DEBUG ( %s/core ): | %-10u | %-18s [%-5u] | %6s | %6u |\n", config.name, 0, tpl_desc_list[type], type, "tbd", len);
918 else
919 Log(LOG_DEBUG, "DEBUG ( %s/core ): | %-10u | %-18s [%-5u] | %6u | %6u |\n", config.name, 0, tpl_desc_list[type], type, off, len);
920 }
921 else {
922 if (!off && vlen)
923 Log(LOG_DEBUG, "DEBUG ( %s/core ): | %-10u | %-18u [%-5u] | %6s | %6u |\n", config.name, 0, type, type, "tbd", len);
924 else
925 Log(LOG_DEBUG, "DEBUG ( %s/core ): | %-10u | %-18u [%-5u] | %6u | %6u |\n", config.name, 0, type, type, off, len);
926 }
927 }
928 else {
929 if (!off && vlen)
930 Log(LOG_DEBUG, "DEBUG ( %s/core ): | %-10u | %-18u [%-5u] | %6s | %6u |\n", config.name, ntohl(*pen), type, type, "tbd", len);
931 else
932 Log(LOG_DEBUG, "DEBUG ( %s/core ): | %-10u | %-18u [%-5u] | %6u | %6u |\n", config.name, ntohl(*pen), type, type, off, len);
933 }
934 }
935
log_opt_template_field(u_int8_t vlen,u_int32_t * pen,u_int16_t type,u_int16_t off,u_int16_t len,u_int8_t version)936 void log_opt_template_field(u_int8_t vlen, u_int32_t *pen, u_int16_t type, u_int16_t off, u_int16_t len, u_int8_t version)
937 {
938 if (!pen) {
939 if (type <= MAX_OPT_TPL_DESC_LIST && strlen(opt_tpl_desc_list[type]))
940 Log(LOG_DEBUG, "DEBUG ( %s/core ): | %-10u | %-18s [%-5u] | %6u | %6u |\n", config.name, 0, opt_tpl_desc_list[type], type, off, len);
941 else
942 Log(LOG_DEBUG, "DEBUG ( %s/core ): | %-10u | %-18u [%-5u] | %6u | %6u |\n", config.name, 0, type, type, off, len);
943 }
944 else Log(LOG_DEBUG, "DEBUG ( %s/core ): | %-10u | %-18u [%-5u] | %6u | %6u |\n", config.name, ntohl(*pen), type, type, off, len);
945 }
946
log_template_footer(struct template_cache_entry * tpl,u_int16_t size,u_int8_t version)947 void log_template_footer(struct template_cache_entry *tpl, u_int16_t size, u_int8_t version)
948 {
949 Log(LOG_DEBUG, "DEBUG ( %s/core ): -------------------------------------------------------------\n", config.name);
950
951 if (!size)
952 Log(LOG_DEBUG, "DEBUG ( %s/core ): Netflow V9/IPFIX record size : %s\n", config.name, "tbd");
953 else
954 Log(LOG_DEBUG, "DEBUG ( %s/core ): Netflow V9/IPFIX record size : %u\n", config.name, size);
955 Log(LOG_DEBUG, "DEBUG ( %s/core ): \n", config.name);
956 }
957
insert_opt_template(void * hdr,struct packet_ptrs * pptrs,u_int16_t tpl_type,u_int32_t sid,u_int16_t * pens,u_int8_t version,u_int16_t len,u_int32_t seq)958 struct template_cache_entry *insert_opt_template(void *hdr, struct packet_ptrs *pptrs, u_int16_t tpl_type,
959 u_int32_t sid, u_int16_t *pens, u_int8_t version, u_int16_t len, u_int32_t seq)
960 {
961 struct options_template_hdr_v9 *hdr_v9 = (struct options_template_hdr_v9 *) hdr;
962 struct options_template_hdr_ipfix *hdr_v10 = (struct options_template_hdr_ipfix *) hdr;
963 struct template_cache_entry *ptr, *prevptr = NULL;
964 struct template_field_v9 *field;
965 u_int16_t modulo, count, slen, olen, type, port, tid, off;
966 u_int32_t *pen;
967 u_int8_t ipfix_ebit;
968 u_char *tpl;
969
970 /* NetFlow v9 */
971 if (tpl_type == 1) {
972 modulo = modulo_template(hdr_v9->template_id, (struct sockaddr *) pptrs->f_agent, tpl_cache.num);
973 tid = hdr_v9->template_id;
974 slen = ntohs(hdr_v9->scope_len)/sizeof(struct template_field_v9);
975 olen = ntohs(hdr_v9->option_len)/sizeof(struct template_field_v9);
976 }
977 /* IPFIX */
978 else if (tpl_type == 3) {
979 modulo = modulo_template(hdr_v10->template_id, (struct sockaddr *) pptrs->f_agent, tpl_cache.num);
980 tid = hdr_v10->template_id;
981 slen = ntohs(hdr_v10->scope_count);
982 olen = ntohs(hdr_v10->option_count)-slen;
983 }
984 else {
985 Log(LOG_ERR, "ERROR ( %s/core ): Unknown template type (%u).\n", config.name, tpl_type);
986 return NULL;
987 }
988
989 ptr = tpl_cache.c[modulo];
990
991 while (ptr) {
992 prevptr = ptr;
993 ptr = ptr->next;
994 }
995
996 ptr = malloc(sizeof(struct template_cache_entry));
997 if (!ptr) {
998 Log(LOG_ERR, "ERROR ( %s/core ): insert_opt_template(): unable to allocate new Options Template Cache Entry.\n", config.name);
999 return NULL;
1000 }
1001
1002 memset(ptr, 0, sizeof(struct template_cache_entry));
1003 sa_to_addr((struct sockaddr *)pptrs->f_agent, &ptr->agent, &port);
1004 ptr->source_id = sid;
1005 ptr->template_id = tid;
1006 ptr->template_type = 1;
1007 ptr->num = olen+slen;
1008
1009 log_template_header(ptr, pptrs, tpl_type, sid, version);
1010
1011 off = 0;
1012 count = ptr->num;
1013 tpl = (u_char *) hdr;
1014 tpl += NfOptTplHdrV9Sz;
1015 off += NfOptTplHdrV9Sz;
1016 field = (struct template_field_v9 *)tpl;
1017
1018 while (count) {
1019 if (off >= len) {
1020 notify_malf_packet(LOG_INFO, "INFO", "insert_opt_template(): unable to read Options Template Flowset (malformed)",
1021 (struct sockaddr *) pptrs->f_agent, seq);
1022 xflow_tot_bad_datagrams++;
1023 free(ptr);
1024 return NULL;
1025 }
1026
1027 pen = NULL;
1028 ipfix_ebit = FALSE;
1029 type = ntohs(field->type);
1030
1031 if (type & IPFIX_TPL_EBIT && version == 10) {
1032 ipfix_ebit = TRUE;
1033 type ^= IPFIX_TPL_EBIT;
1034 if (pens) (*pens)++;
1035 pen = (u_int32_t *) field;
1036 pen++;
1037 }
1038
1039 log_opt_template_field(FALSE, pen, type, ptr->len, ntohs(field->len), version);
1040 if (type < NF9_MAX_DEFINED_FIELD && !pen) {
1041 ptr->tpl[type].off = ptr->len;
1042 ptr->tpl[type].len = ntohs(field->len);
1043 ptr->len += ptr->tpl[type].len;
1044 }
1045 else {
1046 u_int8_t repeat_id = 0;
1047 struct utpl_field *ext_db_ptr = ext_db_get_next_ie(ptr, type, &repeat_id);
1048
1049 if (ext_db_ptr) {
1050 if (pen) ext_db_ptr->pen = ntohl(*pen);
1051 ext_db_ptr->type = type;
1052 ext_db_ptr->off = ptr->len;
1053 ext_db_ptr->tpl_len = ntohs(field->len);
1054 ext_db_ptr->repeat_id = repeat_id;
1055 ext_db_ptr->len = ext_db_ptr->tpl_len;
1056 }
1057
1058 if (count >= TPL_LIST_ENTRIES) {
1059 notify_malf_packet(LOG_INFO, "INFO", "insert_opt_template(): unable to read Options Template (too long)",
1060 (struct sockaddr *) pptrs->f_agent, seq);
1061 xflow_tot_bad_datagrams++;
1062 free(ptr);
1063 return NULL;
1064 }
1065
1066 ptr->list[count].ptr = (char *) ext_db_ptr;
1067 ptr->list[count].type = TPL_TYPE_EXT_DB;
1068 ptr->len += ext_db_ptr->len;
1069 }
1070
1071 count--;
1072 off += NfTplFieldV9Sz;
1073 if (ipfix_ebit) {
1074 field++; /* skip 32-bits ahead */
1075 off += sizeof(u_int32_t);
1076 }
1077 field++;
1078 }
1079
1080 if (prevptr) prevptr->next = ptr;
1081 else tpl_cache.c[modulo] = ptr;
1082
1083 log_template_footer(ptr, ptr->len, version);
1084
1085 #ifdef WITH_JANSSON
1086 if (config.nfacctd_templates_file)
1087 save_template(ptr, config.nfacctd_templates_file);
1088 #endif
1089
1090 return ptr;
1091 }
1092
refresh_opt_template(void * hdr,struct template_cache_entry * tpl,struct packet_ptrs * pptrs,u_int16_t tpl_type,u_int32_t sid,u_int16_t * pens,u_int8_t version,u_int16_t len,u_int32_t seq)1093 struct template_cache_entry *refresh_opt_template(void *hdr, struct template_cache_entry *tpl, struct packet_ptrs *pptrs, u_int16_t tpl_type,
1094 u_int32_t sid, u_int16_t *pens, u_int8_t version, u_int16_t len, u_int32_t seq)
1095 {
1096 struct options_template_hdr_v9 *hdr_v9 = (struct options_template_hdr_v9 *) hdr;
1097 struct options_template_hdr_ipfix *hdr_v10 = (struct options_template_hdr_ipfix *) hdr;
1098 struct template_cache_entry backup, *next;
1099 struct template_field_v9 *field;
1100 u_int16_t slen, olen, count, type, port, tid, off;
1101 u_int32_t *pen;
1102 u_int8_t ipfix_ebit;
1103 u_char *ptr;
1104
1105 /* NetFlow v9 */
1106 if (tpl_type == 1) {
1107 tid = hdr_v9->template_id;
1108 slen = ntohs(hdr_v9->scope_len)/sizeof(struct template_field_v9);
1109 olen = ntohs(hdr_v9->option_len)/sizeof(struct template_field_v9);
1110 }
1111 /* IPFIX */
1112 else if (tpl_type == 3) {
1113 tid = hdr_v10->template_id;
1114 slen = ntohs(hdr_v10->scope_count);
1115 olen = ntohs(hdr_v10->option_count)-slen;
1116 }
1117 else {
1118 Log(LOG_ERR, "ERROR ( %s/core ): Unknown template type (%u).\n", config.name, tpl_type);
1119 return NULL;
1120 }
1121
1122 next = tpl->next;
1123 memcpy(&backup, tpl, sizeof(struct template_cache_entry));
1124 memset(tpl, 0, sizeof(struct template_cache_entry));
1125 sa_to_addr((struct sockaddr *)pptrs->f_agent, &tpl->agent, &port);
1126 tpl->source_id = sid;
1127 tpl->template_id = tid;
1128 tpl->template_type = 1;
1129 tpl->num = olen+slen;
1130 tpl->next = next;
1131
1132 log_template_header(tpl, pptrs, tpl_type, sid, version);
1133
1134 off = 0;
1135 count = tpl->num;
1136 ptr = (u_char *) hdr;
1137 ptr += NfOptTplHdrV9Sz;
1138 off += NfOptTplHdrV9Sz;
1139 field = (struct template_field_v9 *)ptr;
1140
1141 while (count) {
1142 if (off >= len) {
1143 notify_malf_packet(LOG_INFO, "INFO", "refresh_opt_template(): unable to read Options Template Flowset (malformed)",
1144 (struct sockaddr *) pptrs->f_agent, seq);
1145 xflow_tot_bad_datagrams++;
1146 memcpy(tpl, &backup, sizeof(struct template_cache_entry));
1147 return NULL;
1148 }
1149
1150 pen = NULL;
1151 ipfix_ebit = FALSE;
1152 type = ntohs(field->type);
1153
1154 if (type & IPFIX_TPL_EBIT && version == 10) {
1155 ipfix_ebit = TRUE;
1156 type ^= IPFIX_TPL_EBIT;
1157 if (pens) (*pens)++;
1158 pen = (u_int32_t *) field; pen++;
1159 }
1160
1161 log_opt_template_field(FALSE, pen, type, tpl->len, ntohs(field->len), version);
1162 if (type < NF9_MAX_DEFINED_FIELD && !pen) {
1163 tpl->tpl[type].off = tpl->len;
1164 tpl->tpl[type].len = ntohs(field->len);
1165 tpl->len += tpl->tpl[type].len;
1166 }
1167 else {
1168 u_int8_t repeat_id = 0;
1169 struct utpl_field *ext_db_ptr = ext_db_get_next_ie(tpl, type, &repeat_id);
1170
1171 if (ext_db_ptr) {
1172 if (pen) ext_db_ptr->pen = ntohl(*pen);
1173 ext_db_ptr->type = type;
1174 ext_db_ptr->off = tpl->len;
1175 ext_db_ptr->tpl_len = ntohs(field->len);
1176 ext_db_ptr->repeat_id = repeat_id;
1177 ext_db_ptr->len = ext_db_ptr->tpl_len;
1178 }
1179
1180 if (count >= TPL_LIST_ENTRIES) {
1181 notify_malf_packet(LOG_INFO, "INFO", "refresh_opt_template: unable to read Options Template (too long)",
1182 (struct sockaddr *) pptrs->f_agent, seq);
1183 xflow_tot_bad_datagrams++;
1184 return NULL;
1185 }
1186
1187 tpl->list[count].ptr = (char *) ext_db_ptr;
1188 tpl->list[count].type = TPL_TYPE_EXT_DB;
1189 tpl->len += ext_db_ptr->len;
1190 }
1191
1192 count--;
1193 off += NfTplFieldV9Sz;
1194 if (ipfix_ebit) {
1195 field++; /* skip 32-bits ahead */
1196 off += sizeof(u_int32_t);
1197 }
1198 field++;
1199 }
1200
1201 log_template_footer(tpl, tpl->len, version);
1202
1203 #ifdef WITH_JANSSON
1204 if (config.nfacctd_templates_file)
1205 update_template_in_file(tpl, config.nfacctd_templates_file);
1206 #endif
1207
1208 return tpl;
1209 }
1210
resolve_vlen_template(u_char * ptr,u_int16_t remlen,struct template_cache_entry * tpl)1211 int resolve_vlen_template(u_char *ptr, u_int16_t remlen, struct template_cache_entry *tpl)
1212 {
1213 struct otpl_field *otpl_ptr;
1214 struct utpl_field *utpl_ptr;
1215 u_int16_t idx = 0, len = 0;
1216 u_int8_t vlen = 0, add_len;
1217 int ret;
1218
1219 while (idx < tpl->num) {
1220 add_len = 0;
1221
1222 if (tpl->list[idx].type == TPL_TYPE_LEGACY) {
1223 otpl_ptr = (struct otpl_field *) tpl->list[idx].ptr;
1224 if (vlen) otpl_ptr->off = len;
1225
1226 if (otpl_ptr->tpl_len == IPFIX_VARIABLE_LENGTH) {
1227 vlen = TRUE;
1228
1229 ret = get_ipfix_vlen(ptr+len, remlen - len, &otpl_ptr->len);
1230 if (ret > 0) add_len = ret;
1231 else return ERR;
1232
1233 otpl_ptr->off = (len + add_len);
1234 }
1235
1236 len += (otpl_ptr->len + add_len);
1237 }
1238 else if (tpl->list[idx].type == TPL_TYPE_EXT_DB) {
1239 utpl_ptr = (struct utpl_field *) tpl->list[idx].ptr;
1240 if (vlen) utpl_ptr->off = len;
1241
1242 if (utpl_ptr->tpl_len == IPFIX_VARIABLE_LENGTH) {
1243 vlen = TRUE;
1244
1245 ret = get_ipfix_vlen(ptr+len, remlen - len, &utpl_ptr->len);
1246 if (ret > 0) add_len = ret;
1247 else return ERR;
1248
1249 utpl_ptr->off = (len + add_len);
1250 }
1251
1252 len += (utpl_ptr->len + add_len);
1253 }
1254
1255 /* if len is invalid (ie. greater than flowsetlen), we stop here */
1256 if (len > remlen) return ERR;
1257
1258 idx++;
1259 }
1260
1261 tpl->len = len;
1262
1263 return SUCCESS;
1264 }
1265
get_ipfix_vlen(u_char * base,u_int16_t remlen,u_int16_t * len)1266 int get_ipfix_vlen(u_char *base, u_int16_t remlen, u_int16_t *len)
1267 {
1268 u_char *ptr = base;
1269 u_int8_t *len8, ret = 0;
1270 u_int16_t *len16;
1271
1272 if (ptr && len) {
1273 if (remlen >= 1) {
1274 len8 = (u_int8_t *) ptr;
1275
1276 if ((*len8) < 255) {
1277 ret = 1;
1278 (*len) = (*len8);
1279 }
1280 else {
1281 if (remlen >= 3) {
1282 ptr++;
1283 len16 = (u_int16_t *) ptr;
1284 ret = 3;
1285 (*len) = ntohs(*len16);
1286 }
1287 else ret = ERR;
1288 }
1289 }
1290 else ret = ERR;
1291 }
1292
1293 return ret;
1294 }
1295
ext_db_get_ie(struct template_cache_entry * ptr,u_int32_t pen,u_int16_t type,u_int8_t repeat_id)1296 struct utpl_field *ext_db_get_ie(struct template_cache_entry *ptr, u_int32_t pen, u_int16_t type, u_int8_t repeat_id)
1297 {
1298 u_int16_t ie_idx, ext_db_modulo = (type % TPL_EXT_DB_ENTRIES);
1299 struct utpl_field *ext_db_ptr = NULL;
1300
1301 for (ie_idx = 0; ie_idx < IES_PER_TPL_EXT_DB_ENTRY; ie_idx++) {
1302 if (ptr->ext_db[ext_db_modulo].ie[ie_idx].type == type &&
1303 ptr->ext_db[ext_db_modulo].ie[ie_idx].pen == pen &&
1304 ptr->ext_db[ext_db_modulo].ie[ie_idx].repeat_id == repeat_id) {
1305 ext_db_ptr = &ptr->ext_db[ext_db_modulo].ie[ie_idx];
1306 break;
1307 }
1308 }
1309
1310 return ext_db_ptr;
1311 }
1312
ext_db_get_next_ie(struct template_cache_entry * ptr,u_int16_t type,u_int8_t * repeat_id)1313 struct utpl_field *ext_db_get_next_ie(struct template_cache_entry *ptr, u_int16_t type, u_int8_t *repeat_id)
1314 {
1315 u_int16_t ie_idx, ext_db_modulo = (type % TPL_EXT_DB_ENTRIES);
1316 struct utpl_field *ext_db_ptr = NULL;
1317
1318 (*repeat_id) = 0;
1319
1320 for (ie_idx = 0; ie_idx < IES_PER_TPL_EXT_DB_ENTRY; ie_idx++) {
1321 if (ptr->ext_db[ext_db_modulo].ie[ie_idx].type == type) (*repeat_id)++;
1322
1323 if (ptr->ext_db[ext_db_modulo].ie[ie_idx].type == 0) {
1324 ext_db_ptr = &ptr->ext_db[ext_db_modulo].ie[ie_idx];
1325 break;
1326 }
1327 }
1328
1329 return ext_db_ptr;
1330 }
1331