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