1 /*
2 pmacct (Promiscuous mode IP Accounting package)
3 pmacct is Copyright (C) 2003-2020 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 "pmacct-dlt.h"
25 #include "addr.h"
26 #include "isis.h"
27 #include "thread_pool.h"
28
29 #include "stream.h"
30 #include "hash.h"
31 #include "prefix.h"
32
33 #include "dict.h"
34 #include "thread.h"
35 #include "iso.h"
36 #include "table.h"
37 #include "isis_constants.h"
38 #include "isis_common.h"
39 #include "isis_adjacency.h"
40 #include "isis_circuit.h"
41 #include "isis_network.h"
42 #include "isis_misc.h"
43 #include "isis_flags.h"
44 #include "isis_tlv.h"
45 #include "isisd.h"
46 #include "isis_dynhn.h"
47 #include "isis_lsp.h"
48 #include "isis_pdu.h"
49 #include "iso_checksum.h"
50 #include "isis_csm.h"
51 #include "isis_events.h"
52 #include "isis_spf.h"
53 #include "isis_route.h"
54
55 /* variables to be exported away */
56 thread_pool_t *isis_pool;
57
58 /* Functions */
nfacctd_isis_wrapper()59 void nfacctd_isis_wrapper()
60 {
61 /* initialize threads pool */
62 isis_pool = allocate_thread_pool(1);
63 assert(isis_pool);
64 Log(LOG_DEBUG, "DEBUG ( %s/core/ISIS ): %d thread(s) initialized\n", config.name, 1);
65
66 /* giving a kick to the BGP thread */
67 send_to_pool(isis_pool, skinny_isis_daemon, NULL);
68 }
69
skinny_isis_daemon()70 void skinny_isis_daemon()
71 {
72 char errbuf[PCAP_ERRBUF_SIZE];
73 struct pm_pcap_device device;
74 struct pm_pcap_isis_callback_data cb_data;
75 struct host_addr addr;
76 struct prefix_ipv4 *ipv4;
77 struct plugin_requests req;
78 int index, ret;
79
80 char area_tag[] = "default";
81 struct isis_area *area;
82 struct isis_circuit *circuit;
83 struct interface interface;
84
85 memset(&device, 0, sizeof(struct pm_pcap_device));
86 memset(&cb_data, 0, sizeof(cb_data));
87 memset(&interface, 0, sizeof(interface));
88 memset(&isis_spf_deadline, 0, sizeof(isis_spf_deadline));
89
90 memset(&ime, 0, sizeof(ime));
91 memset(&req, 0, sizeof(req));
92 reload_map = FALSE;
93 glob_isis_seq_num = 0;
94
95 /* initializing IS-IS structures */
96 isis = NULL;
97 isis_init();
98 dyn_cache_init();
99
100 /* thread master */
101 master = thread_master_create();
102
103 if (!config.nfacctd_isis_iface && !config.igp_daemon_map) {
104 Log(LOG_ERR, "ERROR ( %s/core/ISIS ): No 'isis_daemon_iface' and 'igp_daemon_map' values specified. Terminating thread.\n", config.name);
105 exit_gracefully(1);
106 }
107 else if (config.nfacctd_isis_iface && config.igp_daemon_map) {
108 Log(LOG_ERR, "ERROR ( %s/core/ISIS ): 'isis_daemon_iface' and 'igp_daemon_map' are mutually exclusive. Terminating thread.\n", config.name);
109 exit_gracefully(1);
110 }
111
112 if (config.nfacctd_isis_iface) {
113 if ((device.dev_desc = pcap_open_live(config.nfacctd_isis_iface, 65535, 0, 1000, errbuf)) == NULL) {
114 Log(LOG_ERR, "ERROR ( %s/core/ISIS ): pcap_open_live(): %s\n", config.name, errbuf);
115 exit_gracefully(1);
116 }
117
118 device.link_type = pcap_datalink(device.dev_desc);
119 for (index = 0; _isis_devices[index].link_type != -1; index++) {
120 if (device.link_type == _isis_devices[index].link_type)
121 device.data = &_isis_devices[index];
122 }
123
124 if (device.data == NULL) {
125 Log(LOG_ERR, "ERROR ( %s/core/ISIS ): data link not supported: %d\n", config.name, device.link_type);
126 return;
127 }
128 else {
129 Log(LOG_INFO, "OK ( %s/core/ISIS ): link type is: %d\n", config.name, device.link_type);
130 cb_data.device = &device;
131 }
132 }
133
134 if (config.igp_daemon_map) {
135 int igp_map_allocated = FALSE;
136
137 glob_isis_seq_num++;
138 req.key_value_table = (void *) &ime;
139 memset(&sysid_fragment_table, 0, sizeof(sysid_fragment_table));
140 load_id_file(MAP_IGP, config.igp_daemon_map, NULL, &req, &igp_map_allocated);
141 }
142
143 area = isis_area_create();
144 area->area_tag = area_tag;
145 area->is_type = IS_LEVEL_2;
146 area->newmetric = TRUE;
147 pm_listnode_add(isis->area_list, area);
148 Log(LOG_DEBUG, "DEBUG ( %s/core/ISIS ): New IS-IS area instance %s\n", config.name, area->area_tag);
149 if (config.nfacctd_isis_net) area_net_title(area, config.nfacctd_isis_net);
150 else {
151 Log(LOG_ERR, "ERROR ( %s/core/ISIS ): 'isis_daemon_net' value is not specified. Terminating thread.\n", config.name);
152 exit_gracefully(1);
153 }
154
155 circuit = isis_circuit_new();
156 circuit->circ_type = CIRCUIT_T_P2P;
157 if (config.nfacctd_isis_iface) {
158 circuit->fd = pcap_fileno(device.dev_desc);
159 circuit->tx = isis_send_pdu_p2p;
160 }
161 else {
162 circuit->fd = 0;
163 circuit->tx = NULL;
164 }
165 circuit->interface = &interface;
166 circuit->state = C_STATE_UP;
167
168 if (config.nfacctd_isis_ip) {
169 trim_spaces(config.nfacctd_isis_ip);
170 ret = str_to_addr(config.nfacctd_isis_ip, &addr);
171 if (!ret) {
172 Log(LOG_ERR, "ERROR ( %s/core/ISIS ): 'isis_daemon_ip' value is not a valid IPv4/IPv6 address. Terminating thread.\n", config.name);
173 exit_gracefully(1);
174 }
175 }
176 else {
177 Log(LOG_ERR, "ERROR ( %s/core/ISIS ): 'isis_daemon_ip' value is not specified. Terminating thread.\n", config.name);
178 exit_gracefully(1);
179 }
180
181 circuit->ip_router = addr.address.ipv4.s_addr;
182 ipv4 = isis_prefix_ipv4_new();
183 ipv4->prefixlen = 32;
184 ipv4->prefix.s_addr = addr.address.ipv4.s_addr;
185 circuit->ip_addrs = pm_list_new();
186 pm_listnode_add(circuit->ip_addrs, ipv4);
187
188 circuit_update_nlpids(circuit);
189 isis_circuit_configure(circuit, area);
190 cb_data.circuit = circuit;
191
192 area->ip_circuits = 1;
193 if (config.nfacctd_isis_iface) {
194 memcpy(circuit->interface->name, config.nfacctd_isis_iface, strlen(config.nfacctd_isis_iface));
195 circuit->interface->ifindex = if_nametoindex(config.nfacctd_isis_iface);
196 }
197 else {
198 // XXX
199 }
200
201 if (!config.nfacctd_isis_mtu) config.nfacctd_isis_mtu = SNAPLEN_ISIS_DEFAULT;
202
203 if (config.nfacctd_isis_iface) {
204 for (;;) {
205 /* XXX: should get a select() here at some stage? */
206 pcap_loop(device.dev_desc, -1, isis_pdu_runner, (u_char *) &cb_data);
207
208 break;
209 }
210
211 pcap_close(device.dev_desc);
212 }
213 else if (config.igp_daemon_map) {
214 for (;;) {
215 sleep(3);
216
217 if (reload_map) {
218 int igp_map_allocated = FALSE;
219
220 glob_isis_seq_num++;
221 memset(&sysid_fragment_table, 0, sizeof(sysid_fragment_table));
222 load_id_file(MAP_IGP, config.igp_daemon_map, NULL, &req, &igp_map_allocated);
223 reload_map = FALSE;
224 }
225 }
226 }
227 }
228
isis_pdu_runner(u_char * user,const struct pcap_pkthdr * pkthdr,const u_char * buf)229 void isis_pdu_runner(u_char *user, const struct pcap_pkthdr *pkthdr, const u_char *buf)
230 {
231 struct pm_pcap_isis_callback_data *cb_data = (struct pm_pcap_isis_callback_data *) user;
232 struct pm_pcap_device *device = cb_data->device;
233 struct isis_circuit *circuit = cb_data->circuit;
234 struct packet_ptrs pptrs;
235 int ret;
236
237 struct stream stm;
238 u_char *ssnpa;
239
240 /* Let's export a time reference */
241 memcpy(&isis_now, &pkthdr->ts, sizeof(struct timeval));
242
243 /* check if we have to expire adjacency first */
244 if (circuit && circuit->u.p2p.neighbor) {
245 if (timeval_cmp(&isis_now, &circuit->u.p2p.neighbor->expire) >= 0)
246 isis_adj_expire(circuit->u.p2p.neighbor);
247 }
248
249 memset(&pptrs, 0, sizeof(pptrs));
250 memset(&stm, 0, sizeof(stm));
251
252 if (buf) {
253 pptrs.pkthdr = (struct pcap_pkthdr *) pkthdr;
254 pptrs.packet_ptr = (u_char *) buf;
255
256 (*device->data->handler)(pkthdr, &pptrs);
257 if (pptrs.iph_ptr) {
258 if ((*pptrs.l3_handler)(&pptrs)) {
259
260 /*assembling handover to isis_handle_pdu() */
261 stm.data = pptrs.iph_ptr;
262 stm.getp = 0;
263 stm.endp = pkthdr->caplen - (pptrs.iph_ptr - pptrs.packet_ptr);
264 stm.size = pkthdr->caplen - (pptrs.iph_ptr - pptrs.packet_ptr);
265 ssnpa = pptrs.packet_ptr;
266 circuit->rcv_stream = &stm;
267 circuit->interface->mtu = config.nfacctd_isis_mtu;
268
269 /* process IS-IS packet */
270 isis_handle_pdu (circuit, ssnpa);
271 }
272 }
273 }
274
275 /* check if it's time to run SPF */
276 if (timeval_cmp(&isis_now, &isis_spf_deadline) >= 0) {
277 if (circuit->area->is_type & IS_LEVEL_1) {
278 if (circuit->area->ip_circuits) {
279 ret = isis_run_spf(circuit->area, 1, AF_INET);
280 isis_route_validate_table (circuit->area, circuit->area->route_table[0]);
281 }
282 /* XXX: IPv6 handled here */
283 }
284
285 if (circuit->area->is_type & IS_LEVEL_2) {
286 if (circuit->area->ip_circuits) {
287 ret = isis_run_spf(circuit->area, 2, AF_INET);
288 (void)ret; //TODO treat error
289 isis_route_validate_table (circuit->area, circuit->area->route_table[1]);
290 }
291 /* XXX: IPv6 handled here */
292 }
293
294 isis_route_validate_merge (circuit->area, AF_INET);
295
296 dyn_cache_cleanup();
297
298 isis_spf_deadline.tv_sec = isis_now.tv_sec + isis_jitter(PERIODIC_SPF_INTERVAL, 10);
299 isis_spf_deadline.tv_usec = 0;
300 }
301
302 if (timeval_cmp(&isis_now, &isis_psnp_deadline) >= 0) {
303 send_psnp(1, circuit);
304 send_psnp(2, circuit);
305
306 isis_psnp_deadline.tv_sec = isis_now.tv_sec + isis_jitter(PSNP_INTERVAL, PSNP_JITTER);
307 isis_psnp_deadline.tv_usec = 0;
308 }
309 }
310
isis_sll_handler(const struct pcap_pkthdr * h,register struct packet_ptrs * pptrs)311 void isis_sll_handler(const struct pcap_pkthdr *h, register struct packet_ptrs *pptrs)
312 {
313 register const struct sll_header *sllp;
314 u_int caplen = h->caplen;
315 u_int16_t etype, nl;
316 u_char *p;
317
318 if (caplen < SLL_HDR_LEN) {
319 pptrs->iph_ptr = NULL;
320 return;
321 }
322
323 p = pptrs->packet_ptr;
324 (void)p; //TODO treat error
325
326 sllp = (const struct sll_header *) pptrs->packet_ptr;
327 etype = ntohs(sllp->sll_protocol);
328 nl = SLL_HDR_LEN;
329
330 if (etype == ETHERTYPE_GRE_ISO) {
331 pptrs->l3_proto = ETHERTYPE_GRE_ISO;
332 pptrs->l3_handler = iso_handler;
333 pptrs->iph_ptr = (u_char *)(pptrs->packet_ptr + nl);
334 return;
335 }
336
337 pptrs->l3_proto = 0;
338 pptrs->l3_handler = NULL;
339 pptrs->iph_ptr = NULL;
340 }
341
iso_handler(register struct packet_ptrs * pptrs)342 int iso_handler(register struct packet_ptrs *pptrs)
343 {
344 return FALSE;
345 }
346
isis_srcdst_lookup(struct packet_ptrs * pptrs)347 void isis_srcdst_lookup(struct packet_ptrs *pptrs)
348 {
349 struct route_node *result;
350 struct isis_area *area;
351 char area_tag[] = "default";
352 int level;
353 struct in_addr pref4;
354 struct in6_addr pref6;
355
356 pptrs->igp_src = NULL;
357 pptrs->igp_dst = NULL;
358 pptrs->igp_src_info = NULL;
359 pptrs->igp_dst_info = NULL;
360
361 area = isis_area_lookup(area_tag);
362
363 if (area) {
364 level = MAX(area->is_type, 2);
365
366 if (pptrs->l3_proto == ETHERTYPE_IP) {
367 if (!pptrs->igp_src) {
368 memcpy(&pref4, &((struct pm_iphdr *)pptrs->iph_ptr)->ip_src, sizeof(struct in_addr));
369 result = route_node_match_ipv4(area->route_table[level-1], &pref4);
370
371 if (result) {
372 pptrs->igp_src = (char *) &result->p;
373 pptrs->igp_src_info = (char *) result->info;
374 if (result->p.prefixlen > pptrs->lm_mask_src) {
375 pptrs->lm_mask_src = result->p.prefixlen;
376 pptrs->lm_method_src = NF_NET_IGP;
377 }
378 }
379 }
380
381 if (!pptrs->igp_dst) {
382 memcpy(&pref4, &((struct pm_iphdr *)pptrs->iph_ptr)->ip_dst, sizeof(struct in_addr));
383 result = route_node_match_ipv4(area->route_table[level-1], &pref4);
384
385 if (result) {
386 pptrs->igp_dst = (char *) &result->p;
387 pptrs->igp_dst_info = (char *) result->info;
388 if (result->p.prefixlen > pptrs->lm_mask_dst) {
389 pptrs->lm_mask_dst = result->p.prefixlen;
390 pptrs->lm_method_dst = NF_NET_IGP;
391 }
392 }
393 }
394 }
395 else if (area && pptrs->l3_proto == ETHERTYPE_IPV6) {
396 if (!pptrs->igp_src) {
397 memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_src, sizeof(struct in6_addr));
398 result = route_node_match_ipv6(area->route_table6[level-1], &pref6);
399
400 if (result) {
401 pptrs->igp_src = (char *) &result->p;
402 pptrs->igp_src_info = (char *) result->info;
403 if (result->p.prefixlen > pptrs->lm_mask_src) {
404 pptrs->lm_mask_src = result->p.prefixlen;
405 pptrs->lm_method_src = NF_NET_IGP;
406 }
407 }
408 }
409
410 if (!pptrs->igp_dst) {
411 memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_dst, sizeof(struct in6_addr));
412 result = route_node_match_ipv6(area->route_table6[level-1], &pref6);
413
414 if (result) {
415 pptrs->igp_dst = (char *) &result->p;
416 pptrs->igp_dst_info = (char *) result->info;
417 if (result->p.prefixlen > pptrs->lm_mask_dst) {
418 pptrs->lm_mask_dst = result->p.prefixlen;
419 pptrs->lm_method_dst = NF_NET_IGP;
420 }
421 }
422 }
423 }
424 }
425 }
426
igp_daemon_map_node_handler(char * filename,struct id_entry * e,char * value,struct plugin_requests * req,int acct_type)427 int igp_daemon_map_node_handler(char *filename, struct id_entry *e, char *value, struct plugin_requests *req, int acct_type)
428 {
429 struct igp_map_entry *entry = (struct igp_map_entry *) req->key_value_table;
430
431 if (!str_to_addr(value, &entry->node) || entry->node.family != AF_INET) {
432 Log(LOG_ERR, "ERROR ( %s ): Bad IPv4 address '%s'. ", filename, value);
433 return TRUE;
434 }
435
436 return FALSE;
437 }
438
igp_daemon_map_area_id_handler(char * filename,struct id_entry * e,char * value,struct plugin_requests * req,int acct_type)439 int igp_daemon_map_area_id_handler(char *filename, struct id_entry *e, char *value, struct plugin_requests *req, int acct_type)
440 {
441 struct igp_map_entry *entry = (struct igp_map_entry *) req->key_value_table;
442 int x = 0, j, len;
443
444 len = strlen(value);
445
446 while (x < len) {
447 if (!isdigit(value[x])) {
448 Log(LOG_ERR, "ERROR ( %s ): Bad 'area_id' value: '%s'. ", filename, value);
449 return TRUE;
450 }
451 x++;
452 }
453
454 j = atoi(value);
455 if (j < 0 || j > 65535) {
456 Log(LOG_ERR, "ERROR ( %s ): Bad 'area_id' value (range: 0 >= value > 65536). ", filename);
457 return TRUE;
458 }
459
460 entry->area_id = j;
461
462 return FALSE;
463 }
464
igp_daemon_map_adj_metric_handler(char * filename,struct id_entry * e,char * value,struct plugin_requests * req,int acct_type)465 int igp_daemon_map_adj_metric_handler(char *filename, struct id_entry *e, char *value, struct plugin_requests *req, int acct_type)
466 {
467 struct igp_map_entry *entry = (struct igp_map_entry *) req->key_value_table;
468 char *str_ptr, *token, *sep, *ip_str, *metric_str, *endptr;
469 int idx = 0;
470
471 str_ptr = strdup(value);
472 if (!str_ptr) {
473 Log(LOG_ERR, "ERROR ( %s ): not enough memory to strdup(). ", filename);
474 return TRUE;
475 }
476
477 while ((token = extract_token(&str_ptr, ';'))) {
478 if (idx >= MAX_IGP_MAP_ELEM) {
479 Log(LOG_ERR, "ERROR ( %s ): maximum number of elements (%u) per adj_metric violated. ", filename, MAX_IGP_MAP_ELEM);
480 return TRUE;
481 }
482
483 sep = strchr(token, ',');
484 if (!sep) {
485 Log(LOG_WARNING, "WARN ( %s ): missing adj_metric entry separator '%s'.\n", filename, token);
486 continue;
487 }
488
489 ip_str = token;
490 metric_str = sep+1;
491 *sep = '\0';
492
493 if (!isis_str2prefix(ip_str, &entry->adj_metric[idx].prefix) || entry->adj_metric[idx].prefix.family != AF_INET) {
494 Log(LOG_WARNING, "WARN ( %s ): Bad IPv4 address '%s'.\n", filename, ip_str);
495 continue;
496 }
497
498 entry->adj_metric[idx].metric = strtoull(metric_str, &endptr, 10);
499 if (!entry->adj_metric[idx].metric) {
500 Log(LOG_WARNING, "WARN ( %s ): Bad metric '%s'.\n", filename, metric_str);
501 continue;
502 }
503
504 idx++;
505 }
506
507 if (!idx) {
508 Log(LOG_ERR, "ERROR ( %s ): invalid or empty adj_metric entry '%s'. ", filename, value);
509 return TRUE;
510 }
511 else entry->adj_metric_num = idx;
512
513 return FALSE;
514 }
515
igp_daemon_map_reach_metric_handler(char * filename,struct id_entry * e,char * value,struct plugin_requests * req,int acct_type)516 int igp_daemon_map_reach_metric_handler(char *filename, struct id_entry *e, char *value, struct plugin_requests *req, int acct_type)
517 {
518 struct igp_map_entry *entry = (struct igp_map_entry *) req->key_value_table;
519 char *str_ptr, *token, *sep, *ip_str, *metric_str, *endptr;
520 int idx = 0;
521
522 str_ptr = strdup(value);
523 if (!str_ptr) {
524 Log(LOG_ERR, "ERROR ( %s ): not enough memory to strdup(). ", filename);
525 return TRUE;
526 }
527
528 while ((token = extract_token(&str_ptr, ';'))) {
529 if (idx >= MAX_IGP_MAP_ELEM) {
530 Log(LOG_ERR, "ERROR ( %s ): maximum number of elements (%u) per reach_metric violated. ", filename, MAX_IGP_MAP_ELEM);
531 return TRUE;
532 }
533
534 sep = strchr(token, ',');
535 if (!sep) {
536 Log(LOG_WARNING, "WARN ( %s ): missing reach_metric entry separator '%s'.\n", filename, token);
537 continue;
538 }
539
540 ip_str = token;
541 metric_str = sep+1;
542 *sep = '\0';
543
544 if (!isis_str2prefix(ip_str, &entry->reach_metric[idx].prefix) || entry->reach_metric[idx].prefix.family != AF_INET) {
545 Log(LOG_WARNING, "WARN ( %s ): Bad IPv4 address '%s'.\n", filename, ip_str);
546 continue;
547 }
548
549 entry->reach_metric[idx].metric = strtoull(metric_str, &endptr, 10);
550 if (!entry->reach_metric[idx].metric) {
551 Log(LOG_WARNING, "WARN ( %s ): Bad metric '%s'.\n", filename, metric_str);
552 continue;
553 }
554
555 idx++;
556 }
557
558 if (!idx) {
559 Log(LOG_ERR, "ERROR ( %s ): invalid or empty reach_metric entry '%s'. ", filename, value);
560 return TRUE;
561 }
562 else entry->reach_metric_num = idx;
563
564 return FALSE;
565 }
566
igp_daemon_map_reach6_metric_handler(char * filename,struct id_entry * e,char * value,struct plugin_requests * req,int acct_type)567 int igp_daemon_map_reach6_metric_handler(char *filename, struct id_entry *e, char *value, struct plugin_requests *req, int acct_type)
568 {
569 struct igp_map_entry *entry = (struct igp_map_entry *) req->key_value_table;
570 char *str_ptr, *token, *sep, *ip_str, *metric_str, *endptr;
571 int idx = 0;
572
573 str_ptr = strdup(value);
574 if (!str_ptr) {
575 Log(LOG_ERR, "ERROR ( %s ): not enough memory to strdup(). ", filename);
576 return TRUE;
577 }
578
579 while ((token = extract_token(&str_ptr, ';'))) {
580 if (idx >= MAX_IGP_MAP_ELEM) {
581 Log(LOG_ERR, "ERROR ( %s ): maximum number of elements (%u) per reach6_metric violated. ", filename, MAX_IGP_MAP_ELEM);
582 return TRUE;
583 }
584
585 sep = strchr(token, ',');
586 if (!sep) {
587 Log(LOG_WARNING, "WARN ( %s ): missing reach6_metric entry separator '%s'.\n", filename, token);
588 continue;
589 }
590
591 ip_str = token;
592 metric_str = sep+1;
593 *sep = '\0';
594
595 if (!isis_str2prefix(ip_str, &entry->reach6_metric[idx].prefix) || entry->reach6_metric[idx].prefix.family != AF_INET6) {
596 Log(LOG_WARNING, "WARN ( %s ): Bad IPv6 address '%s'.\n", filename, ip_str);
597 continue;
598 }
599
600 entry->reach6_metric[idx].metric = strtoull(metric_str, &endptr, 10);
601 if (!entry->reach6_metric[idx].metric) {
602 Log(LOG_WARNING, "WARN ( %s ): Bad metric '%s'.\n", filename, metric_str);
603 continue;
604 }
605
606 idx++;
607 }
608
609 if (!idx) {
610 Log(LOG_ERR, "ERROR ( %s ): invalid or empty reach6_metric entry '%s'. ", filename, value);
611 return TRUE;
612 }
613 else entry->reach6_metric_num = idx;
614
615 return FALSE;
616 }
617
igp_daemon_map_validate(char * filename,struct plugin_requests * req)618 void igp_daemon_map_validate(char *filename, struct plugin_requests *req)
619 {
620 struct igp_map_entry *entry = (struct igp_map_entry *) req->key_value_table;
621 struct pcap_pkthdr phdr;
622
623 if (entry) {
624 if (entry->node.family && entry->area_id && (entry->adj_metric_num || entry->reach_metric_num || entry->reach6_metric_num)) {
625 u_char isis_dgram[RECEIVE_LSP_BUFFER_SIZE+sizeof(struct chdlc_header)+sizeof(struct isis_fixed_hdr)];
626 u_char *isis_dgram_ptr = isis_dgram;
627 struct chdlc_header *chdlc_hdr;
628 struct isis_fixed_hdr *isis_hdr;
629 struct isis_link_state_hdr *lsp_hdr;
630 struct idrp_info *adj_hdr, *reach_v4_hdr, *reach_v6_hdr, *proto_supported_hdr, *area_address_hdr;
631 struct is_neigh *adj;
632 struct ipv4_reachability *reach_v4;
633 struct ipv6_reachability *reach_v6;
634 struct area_address *area_addr;
635 int rem_len = sizeof(isis_dgram), cnt, tlvs_cnt = 0, pdu_len = 0;
636
637 memset(isis_dgram, 0, sizeof(isis_dgram));
638
639 /* can't use DLT_RAW for IS-IS, let's use DLT_CHDLC */
640 chdlc_hdr = (struct chdlc_header *) isis_dgram_ptr;
641 chdlc_hdr->address = CHDLC_MCAST_ADDR;
642 chdlc_hdr->control = CHDLC_FIXED_CONTROL;
643 chdlc_hdr->protocol = ETHERTYPE_ISO;
644
645 isis_dgram_ptr += sizeof(struct chdlc_header);
646 if (igp_daemon_map_handle_len(&rem_len, sizeof(struct chdlc_header), req, filename)) return;
647
648 isis_hdr = (struct isis_fixed_hdr *) isis_dgram_ptr;
649 isis_hdr->idrp = ISO10589_ISIS;
650 isis_hdr->length = 27; /* fixed: IS-IS header + LSP header */
651 isis_hdr->version1 = TRUE;
652 isis_hdr->pdu_type = 0x14;
653 isis_hdr->version2 = TRUE;
654
655 isis_dgram_ptr += sizeof(struct isis_fixed_hdr);
656 if (igp_daemon_map_handle_len(&rem_len, sizeof(struct isis_fixed_hdr), req, filename)) return;
657
658 lsp_hdr = (struct isis_link_state_hdr *) isis_dgram_ptr;
659 lsp_hdr->pdu_len = 0; /* updated later */
660 if (igp_daemon_map_handle_lsp_id(lsp_hdr->lsp_id, &entry->node)) return;
661 lsp_hdr->seq_num = htonl(glob_isis_seq_num);
662 lsp_hdr->rem_lifetime = htons(-1); /* maximum lifetime possible */
663 lsp_hdr->lsp_bits = 0x03; /* IS Type = L2 */
664
665 isis_dgram_ptr += sizeof(struct isis_link_state_hdr);
666 if (igp_daemon_map_handle_len(&rem_len, sizeof(struct isis_link_state_hdr), req, filename)) return;
667
668 proto_supported_hdr = (struct idrp_info *) isis_dgram_ptr;
669 proto_supported_hdr->value = PROTOCOLS_SUPPORTED;
670
671 isis_dgram_ptr += sizeof(struct idrp_info);
672 if (igp_daemon_map_handle_len(&rem_len, sizeof(struct idrp_info), req, filename)) return;
673
674 *isis_dgram_ptr = (u_char) 0xCC;
675 isis_dgram_ptr++;
676 proto_supported_hdr->len++;
677 *isis_dgram_ptr = (u_char) 0x8E;
678 isis_dgram_ptr++;
679 proto_supported_hdr->len++;
680 if (igp_daemon_map_handle_len(&rem_len, proto_supported_hdr->len, req, filename)) return;
681 pdu_len += proto_supported_hdr->len;
682 tlvs_cnt++;
683
684 area_address_hdr = (struct idrp_info *) isis_dgram_ptr;
685 area_address_hdr->value = AREA_ADDRESSES;
686 area_address_hdr->len = sizeof(struct area_address);
687
688 isis_dgram_ptr += sizeof(struct idrp_info);
689 if (igp_daemon_map_handle_len(&rem_len, sizeof(struct idrp_info), req, filename)) return;
690
691 area_addr = (struct area_address *) isis_dgram_ptr;
692 area_addr->len = 3;
693 area_addr->afi = 0x49;
694 area_addr->area_id = htons(entry->area_id);
695
696 isis_dgram_ptr += area_address_hdr->len;
697 if (igp_daemon_map_handle_len(&rem_len, area_address_hdr->len, req, filename)) return;
698 pdu_len += area_address_hdr->len;
699 tlvs_cnt++;
700
701 if (entry->adj_metric_num) {
702 adj_hdr = (struct idrp_info *) isis_dgram_ptr;
703 adj_hdr->value = IS_NEIGHBOURS;
704 adj_hdr->len = (11 * entry->adj_metric_num) + 1;
705 pdu_len += adj_hdr->len;
706
707 isis_dgram_ptr += sizeof(struct idrp_info);
708 if (igp_daemon_map_handle_len(&rem_len, sizeof(struct idrp_info), req, filename)) return;
709
710 for (cnt = 0; cnt < entry->adj_metric_num; cnt++) {
711 if (!cnt) {
712 /* reserved space must be zero */
713 isis_dgram_ptr++;
714 if (igp_daemon_map_handle_len(&rem_len, 1, req, filename)) return;
715 }
716
717 adj = (struct is_neigh *) isis_dgram_ptr;
718 adj->metrics.metric_default = entry->adj_metric[cnt].metric;
719 adj->metrics.metric_error = 0x80;
720 adj->metrics.metric_expense = 0x80;
721 adj->metrics.metric_delay = 0x80;
722 memcpy(adj->neigh_id, &entry->adj_metric[cnt].prefix.u.prefix4, 4);
723
724 isis_dgram_ptr += sizeof(struct is_neigh);
725 if (igp_daemon_map_handle_len(&rem_len, sizeof(struct is_neigh), req, filename)) return;
726 }
727
728 tlvs_cnt++;
729 }
730
731 if (entry->reach_metric_num) {
732 reach_v4_hdr = (struct idrp_info *) isis_dgram_ptr;
733 reach_v4_hdr->value = IPV4_INT_REACHABILITY;
734 reach_v4_hdr->len = (IPV4_REACH_LEN * entry->reach_metric_num);
735 pdu_len += reach_v4_hdr->len;
736
737 isis_dgram_ptr += sizeof(struct idrp_info);
738 if (igp_daemon_map_handle_len(&rem_len, sizeof(struct idrp_info), req, filename)) return;
739
740 for (cnt = 0; cnt < entry->reach_metric_num; cnt++) {
741 reach_v4 = (struct ipv4_reachability *) isis_dgram_ptr;
742 reach_v4->metrics.metric_default = entry->reach_metric[cnt].metric;
743 reach_v4->metrics.metric_error = 0x80;
744 reach_v4->metrics.metric_expense = 0x80;
745 reach_v4->metrics.metric_delay = 0x80;
746 memcpy(&reach_v4->prefix, &entry->reach_metric[cnt].prefix.u.prefix4, 4);
747 reach_v4->mask.s_addr = htonl((entry->reach_metric[cnt].prefix.prefixlen == 32) ? 0xffffffffUL :
748 ~(0xffffffffUL >> entry->reach_metric[cnt].prefix.prefixlen));
749
750 isis_dgram_ptr += sizeof(struct ipv4_reachability);
751 if (igp_daemon_map_handle_len(&rem_len, sizeof(struct ipv4_reachability), req, filename)) return;
752 }
753
754 tlvs_cnt++;
755 }
756
757 if (entry->reach6_metric_num) {
758 int prefix_len = 0;
759
760 reach_v6_hdr = (struct idrp_info *) isis_dgram_ptr;
761 reach_v6_hdr->value = IPV6_REACHABILITY;
762 reach_v6_hdr->len = 0;
763
764 isis_dgram_ptr += sizeof(struct idrp_info);
765 if (igp_daemon_map_handle_len(&rem_len, sizeof(struct idrp_info), req, filename)) return;
766
767 for (cnt = 0; cnt < entry->reach6_metric_num; cnt++) {
768 reach_v6 = (struct ipv6_reachability *) isis_dgram_ptr;
769 reach_v6->metric = htonl(entry->reach6_metric[cnt].metric);
770 reach_v6->control_info = 0;
771 reach_v6->prefix_len = entry->reach6_metric[cnt].prefix.prefixlen;
772 prefix_len = reach_v6->prefix_len / 8;
773 memcpy(&reach_v6->prefix, &entry->reach6_metric[cnt].prefix.u.prefix6, prefix_len);
774
775 reach_v6_hdr->len += 6 + prefix_len;
776 isis_dgram_ptr += 6 + prefix_len;
777 if (igp_daemon_map_handle_len(&rem_len, 6 + prefix_len, req, filename)) return;
778 }
779
780 pdu_len += reach_v6_hdr->len;
781
782 tlvs_cnt++;
783 }
784
785 /* wrapping up: fix lsp length */
786 pdu_len += sizeof(struct isis_fixed_hdr)+ISIS_LSP_HDR_LEN+(ISIS_TLV_HDR_LEN*tlvs_cnt);
787 lsp_hdr->pdu_len = htons(pdu_len);
788
789 if (config.debug && config.igp_daemon_map_msglog) {
790 memset(&phdr, 0, sizeof(phdr));
791 phdr.len = phdr.caplen = sizeof(isis_dgram)-rem_len;
792 pcap_dump((u_char *) idmm_fd, &phdr, isis_dgram);
793 }
794 }
795 else {
796 Log(LOG_ERR, "ERROR ( %s/core/ISIS ): required key missing at line %d in map '%s'. Required keys are:\n",
797 config.name, req->line_num, filename);
798 Log(LOG_ERR, "ERROR ( %s/core/ISIS ): node, area_id, adj_metric or reach_metric or reach6_metric.\n", config.name);
799 }
800 }
801 else Log(LOG_ERR, "ERROR ( %s ): Invalid pointer to entry. ", filename);
802 }
803
igp_daemon_map_initialize(char * filename,struct plugin_requests * req)804 void igp_daemon_map_initialize(char *filename, struct plugin_requests *req)
805 {
806 pcap_t *p;
807
808 if (config.debug && config.igp_daemon_map_msglog) {
809 p = pcap_open_dead(DLT_CHDLC, RECEIVE_LSP_BUFFER_SIZE+sizeof(struct chdlc_header)+sizeof(struct isis_fixed_hdr));
810
811 if ((idmm_fd = pcap_dump_open(p, config.igp_daemon_map_msglog)) == NULL) {
812 Log(LOG_ERR, "ERROR ( %s/core/ISIS ): Can not open igp_daemon_map_msglog '%s' (%s).\n",
813 config.name, config.igp_daemon_map_msglog, pcap_geterr(p));
814 exit_gracefully(1);
815 }
816 }
817 }
818
igp_daemon_map_finalize(char * filename,struct plugin_requests * req)819 void igp_daemon_map_finalize(char *filename, struct plugin_requests *req)
820 {
821 if (config.debug && config.igp_daemon_map_msglog) pcap_dump_close(idmm_fd);
822 }
823
igp_daemon_map_handle_len(int * rem_len,int len,struct plugin_requests * req,char * filename)824 int igp_daemon_map_handle_len(int *rem_len, int len, struct plugin_requests *req, char *filename)
825 {
826 *rem_len -= len;
827 if (*rem_len < 0) {
828 Log(LOG_ERR, "ERROR ( %s/core/ISIS ): Resulting LSP longer than %u. Ignoring line %d in map '%s'.\n",
829 config.name, RECEIVE_LSP_BUFFER_SIZE, req->line_num, filename);
830 return TRUE;
831 }
832
833 return FALSE;
834 }
835
igp_daemon_map_handle_lsp_id(u_char * lsp_id,struct host_addr * addr)836 int igp_daemon_map_handle_lsp_id(u_char *lsp_id, struct host_addr *addr)
837 {
838 u_char sysid[ISIS_SYS_ID_LEN];
839 int idx;
840
841 memset(sysid, 0, sizeof(sysid));
842 memcpy(sysid, &addr->address.ipv4, 4);
843
844 for (idx = 0; idx < MAX_IGP_MAP_NODES && sysid_fragment_table[idx].valid; idx++) {
845 if (!memcmp(sysid, sysid_fragment_table[idx].sysid, ISIS_SYS_ID_LEN)) {
846 /* check if maximum segment number reached */
847 if (sysid_fragment_table[idx].frag_num == 255) {
848 Log(LOG_WARNING, "WARN ( %s/core/ISIS ): Maximum segment number (255) reached for sysid: '%s'\n", config.name, sysid);
849 memset(lsp_id, 0, ISIS_SYS_ID_LEN + 2);
850
851 return TRUE;
852 }
853 else {
854 memcpy(lsp_id, sysid_fragment_table[idx].sysid, 4);
855 memcpy(lsp_id + ISIS_SYS_ID_LEN + 1, &sysid_fragment_table[idx].frag_num, 1);
856 sysid_fragment_table[idx].frag_num++;
857
858 return FALSE;
859 }
860 }
861 }
862
863 /* sys id not found: let's insert it */
864 if (idx < MAX_IGP_MAP_NODES) {
865 memcpy(sysid_fragment_table[idx].sysid, sysid, ISIS_SYS_ID_LEN);
866 sysid_fragment_table[idx].frag_num = 0;
867 sysid_fragment_table[idx].valid = TRUE;
868
869 memcpy(lsp_id, sysid_fragment_table[idx].sysid, 4);
870 memcpy(lsp_id + ISIS_SYS_ID_LEN + 1, &sysid_fragment_table[idx].frag_num, 1);
871 sysid_fragment_table[idx].frag_num++;
872
873 return FALSE;
874 }
875 else {
876 Log(LOG_WARNING, "WARN ( %s/core/ISIS ): Maximum number of nodes (%u) reached in igp_daemon_map\n", config.name, MAX_IGP_MAP_NODES);
877 memset(lsp_id, 0, ISIS_SYS_ID_LEN + 2);
878
879 return TRUE;
880 }
881 }
882