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 "addr.h"
25 #include "pmacct-data.h"
26 #include "addr.h"
27 #include "bgp.h"
28 #include "thread_pool.h"
29 #if defined WITH_RABBITMQ
30 #include "amqp_common.h"
31 #endif
32 #ifdef WITH_KAFKA
33 #include "kafka_common.h"
34 #endif
35
36 /* BGP Address Famiy Identifier to UNIX Address Family converter. */
bgp_afi2family(int afi)37 int bgp_afi2family (int afi)
38 {
39 if (afi == AFI_IP)
40 return AF_INET;
41 else if (afi == AFI_IP6)
42 return AF_INET6;
43 return SUCCESS;
44 }
45
bgp_rd_ntoh(rd_t * rd)46 int bgp_rd_ntoh(rd_t *rd)
47 {
48 struct rd_ip *rdi;
49 struct rd_as *rda;
50 struct rd_as4 *rda4;
51
52 if (!rd) return ERR;
53
54 rd->type = ntohs(rd->type);
55
56 switch(rd->type) {
57 case RD_TYPE_AS:
58 rda = (struct rd_as *) rd;
59 rda->as = ntohs(rda->as);
60 rda->val = ntohl(rda->val);
61 break;
62 case RD_TYPE_IP:
63 rdi = (struct rd_ip *) rd;
64 rdi->val = ntohs(rdi->val);
65 break;
66 case RD_TYPE_AS4:
67 rda4 = (struct rd_as4 *) rd;
68 rda4->as = ntohl(rda4->as);
69 rda4->val = ntohs(rda4->val);
70 break;
71 default:
72 return ERR;
73 break;
74 }
75
76 return SUCCESS;
77 }
78
bgp_rd2str(char * str,rd_t * rd)79 int bgp_rd2str(char *str, rd_t *rd)
80 {
81 struct rd_ip *rdi;
82 struct rd_as *rda;
83 struct rd_as4 *rda4;
84 struct host_addr a;
85 char ip_address[INET6_ADDRSTRLEN];
86
87 switch (rd->type) {
88 case RD_TYPE_AS:
89 rda = (struct rd_as *) rd;
90 sprintf(str, "%u:%u:%u", rda->type, rda->as, rda->val);
91 break;
92 case RD_TYPE_IP:
93 rdi = (struct rd_ip *) rd;
94 a.family = AF_INET;
95 a.address.ipv4.s_addr = rdi->ip.s_addr;
96 addr_to_str(ip_address, &a);
97 sprintf(str, "%u:%s:%u", rdi->type, ip_address, rdi->val);
98 break;
99 case RD_TYPE_AS4:
100 rda4 = (struct rd_as4 *) rd;
101 sprintf(str, "%u:%u:%u", rda4->type, rda4->as, rda4->val);
102 break;
103 case RD_TYPE_VRFID:
104 rda = (struct rd_as *) rd;
105 sprintf(str, "vrfid:%u", rda->val);
106 break;
107 default:
108 sprintf(str, "unknown");
109 break;
110 }
111
112 return TRUE;
113 }
114
bgp_str2rd(rd_t * output,char * value)115 int bgp_str2rd(rd_t *output, char *value)
116 {
117 struct host_addr a;
118 char *endptr, *token;
119 u_int32_t tmp32;
120 struct rd_ip *rdi;
121 struct rd_as *rda;
122 struct rd_as4 *rda4;
123 int idx = 0;
124 rd_t rd;
125
126 memset(&a, 0, sizeof(a));
127 memset(&rd, 0, sizeof(rd));
128
129 /* type:RD_subfield1:RD_subfield2 */
130 while ( (token = extract_token(&value, ':')) && idx < 3) {
131 if (idx == 0) {
132 tmp32 = strtoul(token, &endptr, 10);
133 rd.type = tmp32;
134 switch (rd.type) {
135 case RD_TYPE_AS:
136 rda = (struct rd_as *) &rd;
137 break;
138 case RD_TYPE_IP:
139 rdi = (struct rd_ip *) &rd;
140 break;
141 case RD_TYPE_AS4:
142 rda4 = (struct rd_as4 *) &rd;
143 break;
144 default:
145 printf("ERROR: Invalid RD type specified\n");
146 return FALSE;
147 }
148 }
149 if (idx == 1) {
150 switch (rd.type) {
151 case RD_TYPE_AS:
152 tmp32 = strtoul(token, &endptr, 10);
153 rda->as = tmp32;
154 break;
155 case RD_TYPE_IP:
156 memset(&a, 0, sizeof(a));
157 str_to_addr(token, &a);
158 if (a.family == AF_INET) rdi->ip.s_addr = a.address.ipv4.s_addr;
159 break;
160 case RD_TYPE_AS4:
161 tmp32 = strtoul(token, &endptr, 10);
162 rda4->as = tmp32;
163 break;
164 }
165 }
166 if (idx == 2) {
167 switch (rd.type) {
168 case RD_TYPE_AS:
169 tmp32 = strtoul(token, &endptr, 10);
170 rda->val = tmp32;
171 break;
172 case RD_TYPE_IP:
173 tmp32 = strtoul(token, &endptr, 10);
174 rdi->val = tmp32;
175 break;
176 case RD_TYPE_AS4:
177 tmp32 = strtoul(token, &endptr, 10);
178 rda4->val = tmp32;
179 break;
180 }
181 }
182
183 idx++;
184 }
185
186 memcpy(output, &rd, sizeof(rd));
187
188 return TRUE;
189 }
190
bgp_label2str(char * str,u_char * label)191 int bgp_label2str(char *str, u_char *label)
192 {
193 unsigned long int tmp;
194 char *endp;
195
196 snprintf(str, 10, "0x%02x%02x%01x",
197 (unsigned)(unsigned char)label[0],
198 (unsigned)(unsigned char)label[1],
199 (unsigned)(unsigned char)(label[2] >> 4));
200
201 tmp = strtoul(str, &endp, 16);
202 snprintf(str, 8, "%lu", tmp);
203
204 return TRUE;
205 }
206
207 /* Allocate bgp_info_extra */
bgp_info_extra_new(struct bgp_info * ri)208 struct bgp_info_extra *bgp_info_extra_new(struct bgp_info *ri)
209 {
210 struct bgp_misc_structs *bms;
211 struct bgp_info_extra *new;
212
213 if (!ri || !ri->peer) return NULL;
214
215 bms = bgp_select_misc_db(ri->peer->type);
216
217 if (!bms) return NULL;
218
219 new = malloc(sizeof(struct bgp_info_extra));
220 if (!new) {
221 Log(LOG_ERR, "ERROR ( %s/%s ): malloc() failed (bgp_info_extra_new). Exiting ..\n", config.name, bms->log_str);
222 exit_gracefully(1);
223 }
224 else memset(new, 0, sizeof (struct bgp_info_extra));
225
226 return new;
227 }
228
bgp_info_extra_free(struct bgp_peer * peer,struct bgp_info_extra ** extra)229 void bgp_info_extra_free(struct bgp_peer *peer, struct bgp_info_extra **extra)
230 {
231 struct bgp_misc_structs *bms;
232
233 bms = bgp_select_misc_db(peer->type);
234
235 if (!bms) return;
236
237 if (extra && *extra) {
238 if ((*extra)->bmed.id && bms->bgp_extra_data_free) (*bms->bgp_extra_data_free)(&(*extra)->bmed);
239
240 free(*extra);
241 *extra = NULL;
242 }
243 }
244
245 /* Get bgp_info extra information for the given bgp_info */
bgp_info_extra_get(struct bgp_info * ri)246 struct bgp_info_extra *bgp_info_extra_get(struct bgp_info *ri)
247 {
248 if (!ri->extra)
249 ri->extra = bgp_info_extra_new(ri);
250
251 return ri->extra;
252 }
253
bgp_info_extra_process(struct bgp_peer * peer,struct bgp_info * ri,safi_t safi,path_id_t * path_id,rd_t * rd,u_char * label)254 struct bgp_info_extra *bgp_info_extra_process(struct bgp_peer *peer, struct bgp_info *ri, safi_t safi,
255 path_id_t *path_id, rd_t *rd, u_char *label)
256 {
257 struct bgp_info_extra *rie = NULL;
258
259 /* Install/update MPLS stuff if required */
260 if (safi == SAFI_MPLS_LABEL || safi == SAFI_MPLS_VPN) {
261 if (!rie) rie = bgp_info_extra_get(ri);
262
263 if (rie) {
264 if (safi == SAFI_MPLS_VPN) memcpy(&rie->rd, rd, sizeof(rd_t));
265 memcpy(&rie->label, label, 3);
266 }
267 }
268
269 /* Install/update BGP ADD-PATHs stuff if required */
270 if (peer->cap_add_paths && path_id && *path_id) {
271 if (!rie) rie = bgp_info_extra_get(ri);
272 if (rie) memcpy(&rie->path_id, path_id, sizeof(path_id_t));
273 }
274
275 return rie;
276 }
277
278 /* Allocate new bgp info structure. */
bgp_info_new(struct bgp_peer * peer)279 struct bgp_info *bgp_info_new(struct bgp_peer *peer)
280 {
281 struct bgp_misc_structs *bms;
282 struct bgp_info *new;
283
284 if (!peer) return NULL;
285
286 bms = bgp_select_misc_db(peer->type);
287
288 if (!bms) return NULL;
289
290 new = malloc(sizeof(struct bgp_info));
291 if (!new) {
292 Log(LOG_ERR, "ERROR ( %s/%s ): malloc() failed (bgp_info_new). Exiting ..\n", config.name, bms->log_str);
293 exit_gracefully(1);
294 }
295 else memset(new, 0, sizeof (struct bgp_info));
296
297 return new;
298 }
299
bgp_info_add(struct bgp_peer * peer,struct bgp_node * rn,struct bgp_info * ri,u_int32_t modulo)300 void bgp_info_add(struct bgp_peer *peer, struct bgp_node *rn, struct bgp_info *ri, u_int32_t modulo)
301 {
302 struct bgp_info *top;
303
304 top = rn->info[modulo];
305
306 ri->next = rn->info[modulo];
307 ri->prev = NULL;
308 if (top)
309 top->prev = ri;
310 rn->info[modulo] = ri;
311
312 bgp_lock_node(peer, rn);
313 ri->peer->lock++;
314 }
315
bgp_info_delete(struct bgp_peer * peer,struct bgp_node * rn,struct bgp_info * ri,u_int32_t modulo)316 void bgp_info_delete(struct bgp_peer *peer, struct bgp_node *rn, struct bgp_info *ri, u_int32_t modulo)
317 {
318 if (ri->next)
319 ri->next->prev = ri->prev;
320 if (ri->prev)
321 ri->prev->next = ri->next;
322 else
323 rn->info[modulo] = ri->next;
324
325 bgp_info_free(peer, ri);
326
327 bgp_unlock_node(peer, rn);
328 }
329
330 /* Free bgp route information. */
bgp_info_free(struct bgp_peer * peer,struct bgp_info * ri)331 void bgp_info_free(struct bgp_peer *peer, struct bgp_info *ri)
332 {
333 if (ri->attr)
334 bgp_attr_unintern(peer, ri->attr);
335
336 bgp_info_extra_free(peer, &ri->extra);
337
338 ri->peer->lock--;
339 free(ri);
340 }
341
342 /* Initialization of attributes */
bgp_attr_init(int buckets,struct bgp_rt_structs * inter_domain_routing_db)343 void bgp_attr_init(int buckets, struct bgp_rt_structs *inter_domain_routing_db)
344 {
345 aspath_init(buckets, &inter_domain_routing_db->ashash);
346 attrhash_init(buckets, &inter_domain_routing_db->attrhash);
347 community_init(buckets, &inter_domain_routing_db->comhash);
348 ecommunity_init(buckets, &inter_domain_routing_db->ecomhash);
349 lcommunity_init(buckets, &inter_domain_routing_db->lcomhash);
350 }
351
attrhash_key_make(void * p)352 unsigned int attrhash_key_make(void *p)
353 {
354 struct bgp_attr *attr = (struct bgp_attr *) p;
355 unsigned int key = 0;
356
357 key += attr->origin;
358 key += attr->nexthop.s_addr;
359 key += attr->med;
360 key += attr->local_pref;
361
362 if (attr->aspath)
363 key += aspath_key_make(attr->aspath);
364 if (attr->community)
365 key += community_hash_make(attr->community);
366 if (attr->ecommunity)
367 key += ecommunity_hash_make(attr->ecommunity);
368 if (attr->lcommunity)
369 key += lcommunity_hash_make(attr->lcommunity);
370
371 /* XXX: add mp_nexthop to key */
372
373 return key;
374 }
375
attrhash_cmp(const void * p1,const void * p2)376 int attrhash_cmp(const void *p1, const void *p2)
377 {
378 const struct bgp_attr *attr1 = (const struct bgp_attr *)p1;
379 const struct bgp_attr *attr2 = (const struct bgp_attr *)p2;
380
381 if (attr1->flag == attr2->flag
382 && attr1->origin == attr2->origin
383 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
384 && attr1->aspath == attr2->aspath
385 && attr1->community == attr2->community
386 && attr1->ecommunity == attr2->ecommunity
387 && attr1->lcommunity == attr2->lcommunity
388 && attr1->med == attr2->med
389 && attr1->local_pref == attr2->local_pref
390 && !host_addr_cmp2((struct host_addr *)&attr1->mp_nexthop, (struct host_addr *)&attr2->mp_nexthop))
391 return TRUE;
392
393 return FALSE;
394 }
395
attrhash_init(int buckets,struct hash ** loc_attrhash)396 void attrhash_init(int buckets, struct hash **loc_attrhash)
397 {
398 (*loc_attrhash) = (struct hash *) hash_create(buckets, attrhash_key_make, attrhash_cmp);
399 }
400
401 /* Internet argument attribute. */
bgp_attr_intern(struct bgp_peer * peer,struct bgp_attr * attr)402 struct bgp_attr *bgp_attr_intern(struct bgp_peer *peer, struct bgp_attr *attr)
403 {
404 struct bgp_rt_structs *inter_domain_routing_db;
405 struct bgp_attr *find;
406
407 if (!peer) return NULL;
408
409 inter_domain_routing_db = bgp_select_routing_db(peer->type);
410
411 if (!inter_domain_routing_db) return NULL;
412
413 /* Intern referenced strucutre. */
414 if (attr->aspath) {
415 if (! attr->aspath->refcnt)
416 attr->aspath = aspath_intern(peer, attr->aspath);
417 else
418 attr->aspath->refcnt++;
419 }
420 if (attr->community) {
421 if (! attr->community->refcnt)
422 attr->community = community_intern(peer, attr->community);
423 else
424 attr->community->refcnt++;
425 }
426 if (attr->ecommunity) {
427 if (!attr->ecommunity->refcnt)
428 attr->ecommunity = ecommunity_intern(peer, attr->ecommunity);
429 else
430 attr->ecommunity->refcnt++;
431 }
432 if (attr->lcommunity) {
433 if (!attr->lcommunity->refcnt)
434 attr->lcommunity = lcommunity_intern(peer, attr->lcommunity);
435 else
436 attr->lcommunity->refcnt++;
437 }
438
439 find = (struct bgp_attr *) hash_get(peer, inter_domain_routing_db->attrhash, attr, bgp_attr_hash_alloc);
440 find->refcnt++;
441
442 return find;
443 }
444
445 /* Free bgp attribute and aspath. */
bgp_attr_unintern(struct bgp_peer * peer,struct bgp_attr * attr)446 void bgp_attr_unintern(struct bgp_peer *peer, struct bgp_attr *attr)
447 {
448 struct bgp_rt_structs *inter_domain_routing_db;
449 struct bgp_misc_structs *bms;
450 struct bgp_attr *ret;
451 struct aspath *aspath;
452 struct community *community;
453 struct ecommunity *ecommunity = NULL;
454 struct lcommunity *lcommunity = NULL;
455
456 if (!peer) return;
457
458 inter_domain_routing_db = bgp_select_routing_db(peer->type);
459 bms = bgp_select_misc_db(peer->type);
460
461 if (!inter_domain_routing_db || !bms) return;
462
463 /* Decrement attribute reference. */
464 attr->refcnt--;
465 aspath = attr->aspath;
466 community = attr->community;
467 ecommunity = attr->ecommunity;
468 lcommunity = attr->lcommunity;
469
470 /* If reference becomes zero then free attribute object. */
471 if (attr->refcnt == 0) {
472 ret = (struct bgp_attr *) hash_release(inter_domain_routing_db->attrhash, attr);
473 // assert (ret != NULL);
474 if (!ret) Log(LOG_INFO, "INFO ( %s/%s ): bgp_attr_unintern() hash lookup failed.\n", config.name, bms->log_str);
475 free(attr);
476 }
477
478 /* aspath refcount shoud be decrement. */
479 if (aspath)
480 aspath_unintern(peer, aspath);
481 if (community)
482 community_unintern(peer, community);
483 if (ecommunity)
484 ecommunity_unintern(peer, ecommunity);
485 if (lcommunity)
486 lcommunity_unintern(peer, lcommunity);
487 }
488
bgp_attr_hash_alloc(void * p)489 void *bgp_attr_hash_alloc(void *p)
490 {
491 struct bgp_attr *val = (struct bgp_attr *) p;
492 struct bgp_attr *attr;
493
494 attr = malloc(sizeof (struct bgp_attr));
495 if (!attr) {
496 Log(LOG_ERR, "ERROR ( %s/core/BGP ): malloc() failed (bgp_attr_hash_alloc). Exiting ..\n", config.name); // XXX
497 exit_gracefully(1);
498 }
499 else {
500 memset(attr, 0, sizeof (struct bgp_attr));
501 memcpy(attr, val, sizeof (struct bgp_attr));
502 attr->refcnt = 0;
503 }
504
505 return attr;
506 }
507
bgp_peer_cache_init(struct bgp_peer_cache_bucket * cache,u_int32_t buckets)508 void bgp_peer_cache_init(struct bgp_peer_cache_bucket *cache, u_int32_t buckets)
509 {
510 u_int32_t idx;
511
512 for (idx = 0; idx < buckets; idx++) {
513 memset(&cache[idx], 0, sizeof(struct bgp_peer_cache_bucket));
514 pthread_mutex_init(&cache[idx].mutex, NULL);
515 }
516 }
517
bgp_peer_cache_insert(struct bgp_peer_cache_bucket * cache,u_int32_t bucket,struct bgp_peer * peer)518 struct bgp_peer_cache *bgp_peer_cache_insert(struct bgp_peer_cache_bucket *cache, u_int32_t bucket, struct bgp_peer *peer)
519 {
520 struct bgp_peer_cache *cursor, *last, *new, *ret = NULL;
521
522 pthread_mutex_lock(&peers_cache[bucket].mutex);
523
524 for (cursor = peers_cache[bucket].e, last = NULL; cursor; cursor = cursor->next) last = cursor;
525
526 new = malloc(sizeof(struct bgp_peer_cache));
527 if (new) {
528 new->ptr = peer;
529 new->next = NULL;
530
531 if (!last) peers_cache[bucket].e = new;
532 else last->next = new;
533
534 ret = new;
535 }
536
537 pthread_mutex_unlock(&peers_cache[bucket].mutex);
538
539 return ret;
540 }
541
bgp_peer_cache_delete(struct bgp_peer_cache_bucket * cache,u_int32_t bucket,struct bgp_peer * peer)542 int bgp_peer_cache_delete(struct bgp_peer_cache_bucket *cache, u_int32_t bucket, struct bgp_peer *peer)
543 {
544 struct bgp_peer_cache *cursor, *last;
545 int ret = ERR;
546
547 pthread_mutex_lock(&peers_cache[bucket].mutex);
548
549 for (cursor = peers_cache[bucket].e, last = NULL; cursor; cursor = cursor->next) {
550 if (cursor->ptr == peer) {
551 if (!last) peers_cache[bucket].e = cursor->next;
552 else last->next = cursor->next;
553
554 free(cursor);
555
556 ret = SUCCESS;
557 break;
558 }
559
560 last = cursor;
561 }
562
563 pthread_mutex_unlock(&peers_cache[bucket].mutex);
564
565 return ret;
566 }
567
bgp_peer_cache_search(struct bgp_peer_cache_bucket * cache,u_int32_t bucket,struct host_addr * ha,u_int16_t port)568 struct bgp_peer *bgp_peer_cache_search(struct bgp_peer_cache_bucket *cache, u_int32_t bucket, struct host_addr *ha, u_int16_t port)
569 {
570 struct bgp_peer_cache *cursor;
571 struct bgp_peer *ret = NULL;
572
573 pthread_mutex_lock(&peers_cache[bucket].mutex);
574
575 for (cursor = peers_cache[bucket].e; cursor; cursor = cursor->next) {
576 if (port) {
577 if (cursor->ptr->tcp_port != port) continue;
578 }
579
580 if (!host_addr_cmp(&cursor->ptr->addr, ha)) {
581 ret = cursor->ptr;
582 break;
583 }
584 }
585
586 pthread_mutex_unlock(&peers_cache[bucket].mutex);
587
588 return ret;
589 }
590
bgp_peer_init(struct bgp_peer * peer,int type)591 int bgp_peer_init(struct bgp_peer *peer, int type)
592 {
593 struct bgp_misc_structs *bms;
594 int ret = TRUE;
595
596 bms = bgp_select_misc_db(type);
597
598 if (!peer || !bms) return ERR;
599
600 memset(peer, 0, sizeof(struct bgp_peer));
601 peer->type = type;
602 peer->status = Idle;
603 peer->buf.tot_len = BGP_BUFFER_SIZE;
604 peer->buf.base = malloc(peer->buf.tot_len);
605 if (!peer->buf.base) {
606 Log(LOG_ERR, "ERROR ( %s/%s ): malloc() failed (bgp_peer_init). Exiting ..\n", config.name, bms->log_str);
607 exit_gracefully(1);
608 }
609 else {
610 memset(peer->buf.base, 0, peer->buf.tot_len);
611 ret = FALSE;
612 }
613
614 return ret;
615 }
616
bgp_peer_close(struct bgp_peer * peer,int type,int no_quiet,int send_notification,u_int8_t n_major,u_int8_t n_minor,char * shutdown_msg)617 void bgp_peer_close(struct bgp_peer *peer, int type, int no_quiet, int send_notification, u_int8_t n_major, u_int8_t n_minor, char *shutdown_msg)
618 {
619 struct bgp_misc_structs *bms;
620
621 if (!peer) return;
622
623 bms = bgp_select_misc_db(peer->type);
624
625 if (!bms) return;
626
627 if (!config.bgp_xconnect_map) {
628 if (send_notification) {
629 int ret, notification_msglen = (BGP_MIN_NOTIFICATION_MSG_SIZE + BGP_NOTIFY_CEASE_SM_LEN + 1);
630 char notification_msg[notification_msglen];
631
632 ret = bgp_write_notification_msg(notification_msg, notification_msglen, n_major, n_minor, shutdown_msg);
633 if (ret) send(peer->fd, notification_msg, ret, 0);
634 }
635
636 /* be quiet if we are in a signal handler and already set to exit */
637 if (!no_quiet) bgp_peer_info_delete(peer);
638
639 if (bms->msglog_file || bms->msglog_amqp_routing_key || bms->msglog_kafka_topic)
640 bgp_peer_log_close(peer, bms->msglog_output, peer->type);
641
642 if (bms->peers_cache && bms->peers_port_cache) {
643 u_int32_t bucket;
644
645 bucket = addr_hash(&peer->addr, bms->max_peers);
646 bgp_peer_cache_delete(bms->peers_cache, bucket, peer);
647
648 bucket = addr_port_hash(&peer->addr, peer->tcp_port, bms->max_peers);
649 bgp_peer_cache_delete(bms->peers_port_cache, bucket, peer);
650 }
651 }
652 else {
653 if (peer->xconnect_fd && peer->xconnect_fd != ERR) close(peer->xconnect_fd);
654 }
655
656 if (peer->fd && peer->fd != ERR) close(peer->fd);
657
658 peer->fd = 0;
659 memset(&peer->xc, 0, sizeof(peer->xc));
660 peer->xconnect_fd = 0;
661 memset(&peer->id, 0, sizeof(peer->id));
662 memset(&peer->addr, 0, sizeof(peer->addr));
663 memset(&peer->addr_str, 0, sizeof(peer->addr_str));
664
665 free(peer->buf.base);
666
667 if (bms->neighbors_file)
668 write_neighbors_file(bms->neighbors_file, peer->type);
669 }
670
bgp_peer_xconnect_init(struct bgp_peer * peer,int type)671 int bgp_peer_xconnect_init(struct bgp_peer *peer, int type)
672 {
673 char peer_str[INET6_ADDRSTRLEN], xconnect_str[BGP_XCONNECT_STRLEN];
674 struct bgp_misc_structs *bms;
675 struct bgp_xconnects *bxm;
676 int ret = TRUE, idx, fd;
677
678 assert(!peer->xconnect_fd);
679
680 bms = bgp_select_misc_db(type);
681
682 if (!peer || !bms) return ERR;
683
684 bxm = bms->xconnects;
685
686 if (bxm) {
687 for (idx = 0; idx < bxm->num; idx++) {
688 if (!sa_addr_cmp((struct sockaddr *) &bxm->pool[idx].src, &peer->addr) ||
689 !host_addr_mask_cmp(&bxm->pool[idx].src_addr, &bxm->pool[idx].src_mask, &peer->addr)) {
690 struct sockaddr *sa = (struct sockaddr *) &bxm->pool[idx].dst;
691
692 memcpy(&peer->xc, &bxm->pool[idx], sizeof(struct bgp_xconnect));
693 bgp_peer_xconnect_print(peer, xconnect_str, BGP_XCONNECT_STRLEN);
694
695 fd = socket(sa->sa_family, SOCK_STREAM, 0);
696 if (fd == ERR) {
697 Log(LOG_WARNING, "WARN ( %s/%s ): [%s] bgp_peer_xconnect_init(): socket() failed.\n", config.name, bms->log_str, xconnect_str);
698 memset(&peer->xc, 0, sizeof(peer->xc));
699 peer->xconnect_fd = 0;
700 return ERR;
701 }
702
703 ret = connect(fd, sa, bxm->pool[idx].dst_len);
704 if (ret == ERR) {
705 Log(LOG_WARNING, "WARN ( %s/%s ): [%s] bgp_peer_xconnect_init(): connect() failed.\n", config.name, bms->log_str, xconnect_str);
706 memset(&peer->xc, 0, sizeof(peer->xc));
707 peer->xconnect_fd = 0;
708 return ERR;
709 }
710
711 peer->xconnect_fd = fd;
712 break;
713 }
714 }
715
716 if (!peer->xconnect_fd) {
717 bgp_peer_print(peer, peer_str, INET6_ADDRSTRLEN);
718 Log(LOG_WARNING, "WARN ( %s/%s ): [%s] unable to xconnect BGP peer.\n", config.name, bgp_misc_db->log_str, peer_str);
719 }
720 }
721
722 return ret;
723 }
724
bgp_peer_print(struct bgp_peer * peer,char * buf,int len)725 void bgp_peer_print(struct bgp_peer *peer, char *buf, int len)
726 {
727 char dumb_buf[] = "0.0.0.0";
728 int ret = 0;
729
730 if (!buf || len < INET6_ADDRSTRLEN) return;
731
732 if (peer) {
733 if (peer->id.family) {
734 inet_ntop(AF_INET, &peer->id.address.ipv4, buf, len);
735 ret = AF_INET;
736 }
737 else ret = addr_to_str(buf, &peer->addr);
738 }
739
740 if (!ret) strcpy(buf, dumb_buf);
741 }
742
bgp_peer_xconnect_print(struct bgp_peer * peer,char * buf,int len)743 void bgp_peer_xconnect_print(struct bgp_peer *peer, char *buf, int len)
744 {
745 char src[INET6_ADDRSTRLEN + PORT_STRLEN + 1], dst[INET6_ADDRSTRLEN + PORT_STRLEN + 1];
746 struct sockaddr *sa_src;
747 struct sockaddr *sa_dst;
748
749 if (peer && buf && len >= BGP_XCONNECT_STRLEN) {
750 sa_src = (struct sockaddr *) &peer->xc.src;
751 sa_dst = (struct sockaddr *) &peer->xc.dst;
752
753 if (sa_src->sa_family) sa_to_str(src, sizeof(src), sa_src);
754 else addr_mask_to_str(src, sizeof(src), &peer->xc.src_addr, &peer->xc.src_mask);
755
756 sa_to_str(dst, sizeof(dst), sa_dst);
757
758 snprintf(buf, len, "%s x %s", src, dst);
759 }
760 }
761
bgp_peer_info_delete(struct bgp_peer * peer)762 void bgp_peer_info_delete(struct bgp_peer *peer)
763 {
764 struct bgp_rt_structs *inter_domain_routing_db = bgp_select_routing_db(peer->type);
765 struct bgp_table *table;
766 afi_t afi;
767 safi_t safi;
768
769 if (!inter_domain_routing_db) return;
770
771 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
772 for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
773 table = inter_domain_routing_db->rib[afi][safi];
774 bgp_table_info_delete(peer, table, afi, safi);
775 }
776 }
777 }
778
bgp_table_info_delete(struct bgp_peer * peer,struct bgp_table * table,afi_t afi,safi_t safi)779 void bgp_table_info_delete(struct bgp_peer *peer, struct bgp_table *table, afi_t afi, safi_t safi)
780 {
781 struct bgp_misc_structs *bms = bgp_select_misc_db(peer->type);
782 struct bgp_node *node;
783
784 node = bgp_table_top(peer, table);
785
786 while (node) {
787 u_int32_t modulo;
788 u_int32_t peer_buckets;
789 struct bgp_info *ri;
790 struct bgp_info *ri_next;
791
792 if (bms->route_info_modulo) modulo = bms->route_info_modulo(peer, NULL, bms->table_per_peer_buckets);
793 else modulo = 0;
794
795 for (peer_buckets = 0; peer_buckets < bms->table_per_peer_buckets; peer_buckets++) {
796 for (ri = node->info[modulo + peer_buckets]; ri; ri = ri_next) {
797 if (ri->peer == peer) {
798 if (bms->msglog_backend_methods) {
799 char event_type[] = "log";
800
801 bgp_peer_log_msg(node, ri, afi, safi, event_type, bms->msglog_output, NULL, BGP_LOG_TYPE_DELETE);
802 }
803
804 ri_next = ri->next; /* let's save pointer to next before free up */
805 bgp_info_delete(peer, node, ri, (modulo + peer_buckets));
806 }
807 else ri_next = ri->next;
808 }
809 }
810
811 node = bgp_route_next(peer, node);
812 }
813 }
814
bgp_attr_munge_as4path(struct bgp_peer * peer,struct bgp_attr * attr,struct aspath * as4path)815 int bgp_attr_munge_as4path(struct bgp_peer *peer, struct bgp_attr *attr, struct aspath *as4path)
816 {
817 struct aspath *newpath;
818
819 /* If the BGP peer supports 32bit AS_PATH then we are done */
820 if (peer->cap_4as) return SUCCESS;
821
822 /* pre-requisite for AS4_PATH is AS_PATH indeed */
823 // XXX if (as4path && !attr->aspath) return ERR;
824
825 newpath = aspath_reconcile_as4(attr->aspath, as4path);
826 aspath_unintern(peer, attr->aspath);
827 attr->aspath = aspath_intern(peer, newpath);
828
829 return SUCCESS;
830 }
831
load_comm_patterns(char ** stdcomm,char ** extcomm,char ** lrgcomm,char ** stdcomm_to_asn,char ** lrgcomm_to_asn)832 void load_comm_patterns(char **stdcomm, char **extcomm, char **lrgcomm, char **stdcomm_to_asn, char **lrgcomm_to_asn)
833 {
834 int idx;
835 char *token;
836
837 memset(std_comm_patterns, 0, sizeof(std_comm_patterns));
838 memset(ext_comm_patterns, 0, sizeof(ext_comm_patterns));
839 memset(lrg_comm_patterns, 0, sizeof(lrg_comm_patterns));
840 memset(std_comm_patterns_to_asn, 0, sizeof(std_comm_patterns_to_asn));
841 memset(lrg_comm_patterns_to_asn, 0, sizeof(lrg_comm_patterns_to_asn));
842
843 if (*stdcomm) {
844 idx = 0;
845 while ( (token = extract_token(stdcomm, ',')) && idx < MAX_BGP_COMM_PATTERNS ) {
846 std_comm_patterns[idx] = token;
847 trim_spaces(std_comm_patterns[idx]);
848 idx++;
849 }
850 }
851
852 if (*extcomm) {
853 idx = 0;
854 while ( (token = extract_token(extcomm, ',')) && idx < MAX_BGP_COMM_PATTERNS ) {
855 ext_comm_patterns[idx] = token;
856 trim_spaces(ext_comm_patterns[idx]);
857 idx++;
858 }
859 }
860
861 if (*lrgcomm) {
862 idx = 0;
863 while ( (token = extract_token(lrgcomm, ',')) && idx < MAX_BGP_COMM_PATTERNS ) {
864 lrg_comm_patterns[idx] = token;
865 trim_spaces(lrg_comm_patterns[idx]);
866 idx++;
867 }
868 }
869
870 if (*stdcomm_to_asn) {
871 idx = 0;
872 while ( (token = extract_token(stdcomm_to_asn, ',')) && idx < MAX_BGP_COMM_PATTERNS ) {
873 std_comm_patterns_to_asn[idx] = token;
874 trim_spaces(std_comm_patterns_to_asn[idx]);
875 idx++;
876 }
877 }
878
879 if (*lrgcomm_to_asn) {
880 idx = 0;
881 while ( (token = extract_token(lrgcomm_to_asn, ',')) && idx < MAX_BGP_COMM_PATTERNS ) {
882 lrg_comm_patterns_to_asn[idx] = token;
883 trim_spaces(lrg_comm_patterns_to_asn[idx]);
884 idx++;
885 }
886 }
887 }
888
evaluate_comm_patterns(char * dst,char * src,char ** patterns,int dstlen)889 void evaluate_comm_patterns(char *dst, char *src, char **patterns, int dstlen)
890 {
891 char *ptr, *haystack, *delim_src, *delim_ptn;
892 char local_ptr[MAX_BGP_STD_COMMS], *auxptr;
893 int idx, i, j;
894
895 if (!src || !dst || !dstlen) return;
896
897 memset(dst, 0, dstlen);
898
899 for (idx = 0, j = 0; patterns[idx]; idx++) {
900 haystack = src;
901
902 find_again:
903 delim_ptn = strchr(patterns[idx], '.');
904 if (delim_ptn) *delim_ptn = '\0';
905 ptr = strstr(haystack, patterns[idx]);
906
907 if (ptr && delim_ptn) {
908 delim_src = strchr(ptr, ' ');
909 if (delim_src) {
910 memcpy(local_ptr, ptr, delim_src-ptr);
911 local_ptr[delim_src-ptr] = '\0';
912 }
913 else memcpy(local_ptr, ptr, strlen(ptr)+1);
914 *delim_ptn = '.';
915
916 if (strlen(local_ptr) != strlen(patterns[idx])) ptr = NULL;
917 else {
918 for (auxptr = strchr(patterns[idx], '.'); auxptr; auxptr = strchr(auxptr, '.')) {
919 local_ptr[auxptr-patterns[idx]] = '.';
920 auxptr++;
921 }
922 if (strncmp(patterns[idx], local_ptr, strlen(patterns[idx]))) ptr = NULL;
923 }
924 }
925 else if (delim_ptn) *delim_ptn = '.';
926
927 if (ptr) {
928 /* If we have already something on the stack, let's insert a space */
929 if (j && j < dstlen) {
930 dst[j] = ' ';
931 j++;
932 }
933
934 /* We should be able to trust this string */
935 for (i = 0; ptr[i] != ' ' && ptr[i] != '\0'; i++, j++) {
936 if (j < dstlen) dst[j] = ptr[i];
937 else break;
938 }
939
940 haystack = &ptr[i];
941 }
942
943 /* If we don't have space anymore, let's finish it here */
944 if (j >= dstlen) {
945 dst[dstlen-2] = '+';
946 dst[dstlen-1] = '\0';
947 break;
948 }
949
950 /* Trick to find multiple occurrences */
951 if (ptr) goto find_again;
952 }
953 }
954
evaluate_last_asn(struct aspath * as)955 as_t evaluate_last_asn(struct aspath *as)
956 {
957 if (!as) return 0;
958
959 return as->last_as;
960 }
961
evaluate_first_asn(char * src)962 as_t evaluate_first_asn(char *src)
963 {
964 int idx, is_space = FALSE, len = strlen(src), start, sub_as, iteration;
965 char *endptr, *ptr, saved;
966 as_t asn, real_first_asn;
967
968 start = 0;
969 iteration = 0;
970 real_first_asn = 0;
971
972 start_again:
973
974 asn = 0;
975 sub_as = FALSE;
976
977 for (idx = start; idx < len && (src[idx] != ' ' && src[idx] != ')'); idx++);
978
979 /* Mangling the AS_PATH string */
980 if (src[idx] == ' ' || src[idx] == ')') {
981 is_space = TRUE;
982 saved = src[idx];
983 src[idx] = '\0';
984 }
985
986 if (src[start] == '(') {
987 ptr = &src[start+1];
988 sub_as = TRUE;
989 }
990 else ptr = &src[start];
991
992 asn = strtoul(ptr, &endptr, 10);
993
994 /* Restoring mangled AS_PATH */
995 if (is_space) {
996 src[idx] = saved;
997 saved = '\0';
998 is_space = FALSE;
999 }
1000
1001 if (config.bgp_daemon_peer_as_skip_subas /* XXX */ && sub_as) {
1002 while (idx < len && (src[idx] == ' ' || src[idx] == ')')) idx++;
1003
1004 if (idx != len-1) {
1005 start = idx;
1006 if (iteration == 0) real_first_asn = asn;
1007 iteration++;
1008 goto start_again;
1009 }
1010 }
1011
1012 /* skip sub-as kicks-in only when traffic is delivered to a different ASN */
1013 if (real_first_asn && (!asn || sub_as)) asn = real_first_asn;
1014
1015 return asn;
1016 }
1017
evaluate_bgp_aspath_radius(char * path,int len,int radius)1018 void evaluate_bgp_aspath_radius(char *path, int len, int radius)
1019 {
1020 int count, idx;
1021
1022 for (idx = 0, count = 0; idx < len; idx++) {
1023 if (path[idx] == ' ') count++;
1024 if (count == radius) {
1025 path[idx] = '\0';
1026 break;
1027 }
1028 }
1029 }
1030
copy_stdcomm_to_asn(char * stdcomm,as_t * asn,int is_origin)1031 void copy_stdcomm_to_asn(char *stdcomm, as_t *asn, int is_origin)
1032 {
1033 char *delim, *delim2;
1034 char *p1, *p2;
1035
1036 if (!stdcomm || !strlen(stdcomm) || (delim = strchr(stdcomm, ':')) == NULL) return;
1037 if (validate_truefalse(is_origin)) return;
1038
1039 delim2 = strchr(stdcomm, ',');
1040 *delim = '\0';
1041 if (delim2) *delim2 = '\0';
1042 p1 = stdcomm;
1043 p2 = delim+1;
1044
1045 if (is_origin) *asn = atoi(p2);
1046 else *asn = atoi(p1);
1047 }
1048
copy_lrgcomm_to_asn(char * lrgcomm,as_t * asn,int is_origin)1049 void copy_lrgcomm_to_asn(char *lrgcomm, as_t *asn, int is_origin)
1050 {
1051 char *delim, *delim2;
1052 char *p1, *p2, *endptr;
1053
1054 if (!lrgcomm || !strlen(lrgcomm) || (delim = strchr(lrgcomm, ':')) == NULL) return;
1055 if (validate_truefalse(is_origin)) return;
1056
1057 delim2 = strchr(lrgcomm, ':');
1058 *delim = '\0';
1059 *delim2 = '\0';
1060 p1 = lrgcomm;
1061 p2 = delim+1;
1062
1063 if (is_origin) *asn = strtoul(p2, &endptr, 10);
1064 else *asn = strtoul(p1, &endptr, 10);
1065 }
1066
1067 /* XXX: currently only BGP is supported due to use of peers struct */
write_neighbors_file(char * filename,int type)1068 void write_neighbors_file(char *filename, int type)
1069 {
1070 struct bgp_misc_structs *bms = bgp_select_misc_db(type);
1071 FILE *file;
1072 char neighbor[INET6_ADDRSTRLEN+1];
1073 int idx, len, ret;
1074 uid_t owner = -1;
1075 gid_t group = -1;
1076
1077 if (!bms) return;
1078
1079 unlink(filename);
1080
1081 if (config.files_uid) owner = config.files_uid;
1082 if (config.files_gid) group = config.files_gid;
1083
1084 file = fopen(filename,"w");
1085 if (file) {
1086 if ((ret = chown(filename, owner, group)) == -1)
1087 Log(LOG_WARNING, "WARN ( %s/%s ): [%s] Unable to chown() (%s).\n", config.name, bms->log_str, filename, strerror(errno));
1088
1089 if (file_lock(fileno(file))) {
1090 Log(LOG_ERR, "ERROR ( %s/%s ): [%s] Unable to obtain lock.\n", config.name, bms->log_str, filename);
1091 return;
1092 }
1093 for (idx = 0; idx < bms->max_peers; idx++) {
1094 if (peers[idx].fd) {
1095 if (peers[idx].addr.family == AF_INET) {
1096 inet_ntop(AF_INET, &peers[idx].addr.address.ipv4, neighbor, INET6_ADDRSTRLEN);
1097 len = strlen(neighbor);
1098 neighbor[len] = '\n'; len++;
1099 neighbor[len] = '\0';
1100 fwrite(neighbor, len, 1, file);
1101 }
1102 else if (peers[idx].addr.family == AF_INET6) {
1103 inet_ntop(AF_INET6, &peers[idx].addr.address.ipv6, neighbor, INET6_ADDRSTRLEN);
1104 len = strlen(neighbor);
1105 neighbor[len] = '\n'; len++;
1106 neighbor[len] = '\0';
1107 fwrite(neighbor, len, 1, file);
1108 }
1109 }
1110 }
1111
1112 file_unlock(fileno(file));
1113 fclose(file);
1114 }
1115 else {
1116 Log(LOG_ERR, "ERROR ( %s/%s ): [%s] fopen() failed.\n", config.name, bms->log_str, filename);
1117 return;
1118 }
1119 }
1120
bgp_config_checks(struct configuration * c)1121 void bgp_config_checks(struct configuration *c)
1122 {
1123 if (c->what_to_count & (COUNT_LOCAL_PREF|COUNT_MED|COUNT_PEER_SRC_AS|COUNT_PEER_DST_AS|
1124 COUNT_PEER_SRC_IP|COUNT_PEER_DST_IP|COUNT_SRC_MED|COUNT_SRC_LOCAL_PREF|
1125 COUNT_MPLS_VPN_RD)) {
1126 /* Sanitizing the aggregation method */
1127 if ( (c->what_to_count & COUNT_SRC_LOCAL_PREF && !c->bgp_daemon_src_local_pref_type) ||
1128 (c->what_to_count & COUNT_SRC_MED && !c->bgp_daemon_src_med_type) ||
1129 (c->what_to_count & COUNT_PEER_SRC_AS && !c->bgp_daemon_peer_as_src_type &&
1130 (config.acct_type != ACCT_SF && config.acct_type != ACCT_NF)) ) {
1131 printf("ERROR: At least one of the following primitives is in use but its source type is not specified:\n");
1132 printf(" peer_src_as => bgp_peer_src_as_type\n");
1133 printf(" src_local_pref => bgp_src_local_pref_type\n");
1134 printf(" src_med => bgp_src_med_type\n");
1135 exit_gracefully(1);
1136 }
1137
1138 c->data_type |= PIPE_TYPE_BGP;
1139 }
1140
1141 if ((c->what_to_count & (COUNT_STD_COMM|COUNT_EXT_COMM|COUNT_AS_PATH|COUNT_SRC_STD_COMM|
1142 COUNT_SRC_EXT_COMM|COUNT_SRC_AS_PATH)) ||
1143 (c->what_to_count_2 & (COUNT_LRG_COMM|COUNT_SRC_LRG_COMM))) {
1144 /* Sanitizing the aggregation method */
1145 if ( (c->what_to_count & COUNT_SRC_AS_PATH && !c->bgp_daemon_src_as_path_type) ||
1146 (c->what_to_count & COUNT_SRC_STD_COMM && !c->bgp_daemon_src_std_comm_type) ||
1147 (c->what_to_count & COUNT_SRC_EXT_COMM && !c->bgp_daemon_src_ext_comm_type) ||
1148 (c->what_to_count_2 & COUNT_SRC_LRG_COMM && !c->bgp_daemon_src_lrg_comm_type) ) {
1149 printf("ERROR: At least one of the following primitives is in use but its source type is not specified:\n");
1150 printf(" src_as_path => bgp_src_as_path_type\n");
1151 printf(" src_std_comm => bgp_src_std_comm_type\n");
1152 printf(" src_ext_comm => bgp_src_ext_comm_type\n");
1153 printf(" src_lrg_comm => bgp_src_lrg_comm_type\n");
1154 exit_gracefully(1);
1155 }
1156
1157 if (c->type_id == PLUGIN_ID_MEMORY) c->data_type |= PIPE_TYPE_LBGP;
1158 else c->data_type |= PIPE_TYPE_VLEN;
1159 }
1160 }
1161
bgp_md5_file_init(struct bgp_md5_table * t)1162 void bgp_md5_file_init(struct bgp_md5_table *t)
1163 {
1164 if (t) memset(t, 0, sizeof(struct bgp_md5_table));
1165 }
1166
bgp_md5_file_load(char * filename,struct bgp_md5_table * t)1167 void bgp_md5_file_load(char *filename, struct bgp_md5_table *t)
1168 {
1169 FILE *file;
1170 char buf[SRVBUFLEN], *ptr;
1171 int index = 0;
1172
1173 if (filename && t) {
1174 Log(LOG_INFO, "INFO ( %s/core/BGP ): [%s] (re)loading map.\n", config.name, filename);
1175
1176 if ((file = fopen(filename, "r")) == NULL) {
1177 Log(LOG_ERR, "ERROR ( %s/core/BGP ): [%s] file not found.\n", config.name, filename);
1178 exit_gracefully(1);
1179 }
1180
1181 while (!feof(file)) {
1182 if (index >= BGP_MD5_MAP_ENTRIES) {
1183 Log(LOG_WARNING, "WARN ( %s/core/BGP ): [%s] loaded the first %u entries.\n", config.name, filename, BGP_MD5_MAP_ENTRIES);
1184 break;
1185 }
1186 memset(buf, 0, SRVBUFLEN);
1187 if (fgets(buf, SRVBUFLEN, file)) {
1188 if (!sanitize_buf(buf)) {
1189 char *token;
1190 int tk_idx = 0, ret = 0, len = 0;
1191
1192 ptr = buf;
1193 memset(&t->table[index], 0, sizeof(t->table[index]));
1194 while ( (token = extract_token(&ptr, ',')) && tk_idx < 2 ) {
1195 if (tk_idx == 0) ret = str_to_addr(token, &t->table[index].addr);
1196 else if (tk_idx == 1) {
1197 strlcpy(t->table[index].key, token, TCP_MD5SIG_MAXKEYLEN);
1198 len = strlen(t->table[index].key);
1199 }
1200 tk_idx++;
1201 }
1202
1203 if (ret > 0 && len > 0) index++;
1204 else Log(LOG_WARNING, "WARN ( %s/core/BGP ): [%s] line '%s' ignored.\n", config.name, filename, buf);
1205 }
1206 }
1207 }
1208 t->num = index;
1209
1210 /* Set to -1 to distinguish between no map and empty map conditions */
1211 if (!t->num) t->num = -1;
1212
1213 Log(LOG_INFO, "INFO ( %s/core/BGP ): [%s] map successfully (re)loaded.\n", config.name, filename);
1214 fclose(file);
1215 }
1216 }
1217
bgp_md5_file_unload(struct bgp_md5_table * t)1218 void bgp_md5_file_unload(struct bgp_md5_table *t)
1219 {
1220 int index = 0;
1221
1222 if (!t) return;
1223
1224 while (index < t->num) {
1225 memset(t->table[index].key, 0, TCP_MD5SIG_MAXKEYLEN);
1226 index++;
1227 }
1228 }
1229
bgp_md5_file_process(int sock,struct bgp_md5_table * bgp_md5)1230 void bgp_md5_file_process(int sock, struct bgp_md5_table *bgp_md5)
1231 {
1232 char peer_str[INET6_ADDRSTRLEN + PORT_STRLEN + 1];
1233 struct pm_tcp_md5sig md5sig;
1234 struct sockaddr_storage ss_md5sig, ss_server;
1235 struct sockaddr *sa_md5sig = (struct sockaddr *)&ss_md5sig, *sa_server = (struct sockaddr *)&ss_server;
1236 int rc, keylen, idx = 0, ss_md5sig_len;
1237 socklen_t ss_server_len;
1238
1239 if (!bgp_md5) return;
1240
1241 while (idx < bgp_md5->num) {
1242 memset(&md5sig, 0, sizeof(md5sig));
1243 memset(&ss_md5sig, 0, sizeof(ss_md5sig));
1244
1245 ss_md5sig_len = addr_to_sa((struct sockaddr *)&ss_md5sig, &bgp_md5->table[idx].addr, 0);
1246
1247 ss_server_len = sizeof(ss_server);
1248 getsockname(sock, (struct sockaddr *)&ss_server, &ss_server_len);
1249
1250 if (sa_md5sig->sa_family == AF_INET6 && sa_server->sa_family == AF_INET) {
1251 ipv4_mapped_to_ipv4(&ss_md5sig);
1252 ss_md5sig_len = sizeof(struct sockaddr_in);
1253 }
1254 else if (sa_md5sig->sa_family == AF_INET && sa_server->sa_family == AF_INET6) {
1255 ipv4_to_ipv4_mapped(&ss_md5sig);
1256 ss_md5sig_len = sizeof(struct sockaddr_in6);
1257 }
1258
1259 memcpy(&md5sig.tcpm_addr, &ss_md5sig, ss_md5sig_len);
1260 keylen = strlen(bgp_md5->table[idx].key);
1261 if (keylen) {
1262 md5sig.tcpm_keylen = keylen;
1263 memcpy(md5sig.tcpm_key, &bgp_md5->table[idx].key, keylen);
1264 }
1265
1266 sa_to_str(peer_str, sizeof(peer_str), sa_md5sig);
1267
1268 rc = setsockopt(sock, IPPROTO_TCP, TCP_MD5SIG, &md5sig, (socklen_t) sizeof(md5sig));
1269 if (rc < 0) {
1270 Log(LOG_WARNING, "WARN ( %s/core/BGP ): setsockopt() failed for TCP_MD5SIG peer=%s (errno: %d)\n", config.name, peer_str, errno);
1271 }
1272 else {
1273 Log(LOG_DEBUG, "DEBUG ( %s/core/BGP ): setsockopt() set TCP_MD5SIG peer=%s\n", config.name, peer_str);
1274 }
1275
1276 idx++;
1277 }
1278 }
1279
bgp_batch_init(struct bgp_peer_batch * bp_batch,int num,int interval)1280 void bgp_batch_init(struct bgp_peer_batch *bp_batch, int num, int interval)
1281 {
1282 if (bp_batch) {
1283 memset(bp_batch, 0, sizeof(struct bgp_peer_batch));
1284
1285 bp_batch->num = num;
1286 bp_batch->interval = interval;
1287 }
1288 }
1289
bgp_batch_reset(struct bgp_peer_batch * bp_batch,time_t now)1290 void bgp_batch_reset(struct bgp_peer_batch *bp_batch, time_t now)
1291 {
1292 if (bp_batch) {
1293 bp_batch->num_current = bp_batch->num;
1294 bp_batch->base_stamp = now;
1295 }
1296 }
1297
bgp_batch_is_admitted(struct bgp_peer_batch * bp_batch,time_t now)1298 int bgp_batch_is_admitted(struct bgp_peer_batch *bp_batch, time_t now)
1299 {
1300 if (bp_batch) {
1301 /* bgp_batch_is_not_empty() maybe replaced by a linear
1302 distribution of the peers over the time interval */
1303 if (bgp_batch_is_not_empty(bp_batch) || bgp_batch_is_expired(bp_batch, now)) return TRUE;
1304 else return FALSE;
1305 }
1306 else return ERR;
1307 }
1308
bgp_batch_is_enabled(struct bgp_peer_batch * bp_batch)1309 int bgp_batch_is_enabled(struct bgp_peer_batch *bp_batch)
1310 {
1311 if (bp_batch) {
1312 if (bp_batch->num) return TRUE;
1313 else return FALSE;
1314 }
1315 else return ERR;
1316 }
1317
bgp_batch_is_expired(struct bgp_peer_batch * bp_batch,time_t now)1318 int bgp_batch_is_expired(struct bgp_peer_batch *bp_batch, time_t now)
1319 {
1320 if (bp_batch) {
1321 if (now > (bp_batch->base_stamp + bp_batch->interval)) return TRUE;
1322 else return FALSE;
1323 }
1324 else return ERR;
1325 }
1326
bgp_batch_is_not_empty(struct bgp_peer_batch * bp_batch)1327 int bgp_batch_is_not_empty(struct bgp_peer_batch *bp_batch)
1328 {
1329 if (bp_batch) {
1330 if (bp_batch->num_current) return TRUE;
1331 else return FALSE;
1332 }
1333 else return ERR;
1334 }
1335
bgp_batch_increase_counter(struct bgp_peer_batch * bp_batch)1336 void bgp_batch_increase_counter(struct bgp_peer_batch *bp_batch)
1337 {
1338 if (bp_batch) bp_batch->num_current++;
1339 }
1340
bgp_batch_decrease_counter(struct bgp_peer_batch * bp_batch)1341 void bgp_batch_decrease_counter(struct bgp_peer_batch *bp_batch)
1342 {
1343 if (bp_batch) bp_batch->num_current--;
1344 }
1345
bgp_batch_rollback(struct bgp_peer_batch * bp_batch)1346 void bgp_batch_rollback(struct bgp_peer_batch *bp_batch)
1347 {
1348 if (bp_batch && bgp_batch_is_enabled(bp_batch)) {
1349 bgp_batch_increase_counter(bp_batch);
1350 if (bp_batch->num_current == bp_batch->num)
1351 bgp_batch_init(bp_batch, bp_batch->num, bp_batch->interval);
1352 }
1353 }
1354
bgp_select_routing_db(int peer_type)1355 struct bgp_rt_structs *bgp_select_routing_db(int peer_type)
1356 {
1357 if (peer_type < FUNC_TYPE_MAX)
1358 return &inter_domain_routing_dbs[peer_type];
1359
1360 return NULL;
1361 }
1362
bgp_select_misc_db(int peer_type)1363 struct bgp_misc_structs *bgp_select_misc_db(int peer_type)
1364 {
1365 if (peer_type < FUNC_TYPE_MAX)
1366 return &inter_domain_misc_dbs[peer_type];
1367
1368 return NULL;
1369 }
1370
bgp_link_misc_structs(struct bgp_misc_structs * bms)1371 void bgp_link_misc_structs(struct bgp_misc_structs *bms)
1372 {
1373 #if defined WITH_RABBITMQ
1374 bms->msglog_amqp_host = &bgp_daemon_msglog_amqp_host;
1375 #endif
1376 #if defined WITH_KAFKA
1377 bms->msglog_kafka_host = &bgp_daemon_msglog_kafka_host;
1378 #endif
1379 bms->max_peers = config.bgp_daemon_max_peers;
1380 bms->peers = peers;
1381 bms->peers_cache = peers_cache;
1382 bms->peers_port_cache = peers_port_cache;
1383 bms->xconnects = &bgp_xcs_map;
1384 bms->neighbors_file = config.bgp_daemon_neighbors_file;
1385 bms->dump_file = config.bgp_table_dump_file;
1386 bms->dump_amqp_routing_key = config.bgp_table_dump_amqp_routing_key;
1387 bms->dump_amqp_routing_key_rr = config.bgp_table_dump_amqp_routing_key_rr;
1388 bms->dump_kafka_topic = config.bgp_table_dump_kafka_topic;
1389 bms->dump_kafka_topic_rr = config.bgp_table_dump_kafka_topic_rr;
1390 bms->dump_kafka_avro_schema_registry = config.bgp_table_dump_kafka_avro_schema_registry;
1391 bms->msglog_file = config.bgp_daemon_msglog_file;
1392 bms->msglog_output = config.bgp_daemon_msglog_output;
1393 bms->msglog_amqp_routing_key = config.bgp_daemon_msglog_amqp_routing_key;
1394 bms->msglog_amqp_routing_key_rr = config.bgp_daemon_msglog_amqp_routing_key_rr;
1395 bms->msglog_kafka_topic = config.bgp_daemon_msglog_kafka_topic;
1396 bms->msglog_kafka_topic_rr = config.bgp_daemon_msglog_kafka_topic_rr;
1397 bms->msglog_kafka_avro_schema_registry = config.bgp_daemon_msglog_kafka_avro_schema_registry;
1398 bms->peer_str = malloc(strlen("peer_ip_src") + 1);
1399 strcpy(bms->peer_str, "peer_ip_src");
1400 bms->peer_port_str = malloc(strlen("peer_tcp_port") + 1);
1401 strcpy(bms->peer_port_str, "peer_tcp_port");
1402 bms->bgp_peer_log_msg_extras = NULL;
1403 bms->bgp_peer_logdump_initclose_extras = NULL;
1404
1405 bms->table_peer_buckets = config.bgp_table_peer_buckets;
1406 bms->table_per_peer_buckets = config.bgp_table_per_peer_buckets;
1407 bms->table_attr_hash_buckets = config.bgp_table_attr_hash_buckets;
1408 bms->table_per_peer_hash = config.bgp_table_per_peer_hash;
1409 bms->route_info_modulo = bgp_route_info_modulo;
1410 bms->bgp_lookup_find_peer = bgp_lookup_find_bgp_peer;
1411 bms->bgp_lookup_node_match_cmp = bgp_lookup_node_match_cmp_bgp;
1412
1413 bms->bgp_msg_open_router_id_check = bgp_router_id_check;
1414
1415 if (!bms->is_thread && !bms->dump_backend_methods && !bms->has_lglass && !bms->has_blackhole) {
1416 bms->skip_rib = TRUE;
1417 }
1418 }
1419
bgp_blackhole_link_misc_structs(struct bgp_misc_structs * m_data)1420 void bgp_blackhole_link_misc_structs(struct bgp_misc_structs *m_data)
1421 {
1422 m_data->table_peer_buckets = 1; /* saving on DEFAULT_BGP_INFO_HASH for now */
1423 m_data->table_per_peer_buckets = DEFAULT_BGP_INFO_PER_PEER_HASH;
1424 m_data->table_attr_hash_buckets = HASHTABSIZE;
1425 m_data->table_per_peer_hash = BGP_ASPATH_HASH_PATHID;
1426 m_data->route_info_modulo = NULL;
1427 m_data->bgp_lookup_node_match_cmp = NULL;
1428 }
1429
bgp_peer_cmp(const void * a,const void * b)1430 int bgp_peer_cmp(const void *a, const void *b)
1431 {
1432 return host_addr_cmp(&((struct bgp_peer *)a)->addr, &((struct bgp_peer *)b)->addr);
1433 }
1434
bgp_peer_host_addr_cmp(const void * a,const void * b)1435 int bgp_peer_host_addr_cmp(const void *a, const void *b)
1436 {
1437 return host_addr_cmp((struct host_addr *)a, &((struct bgp_peer *)b)->addr);
1438 }
1439
bgp_peer_sa_addr_cmp(const void * a,const void * b)1440 int bgp_peer_sa_addr_cmp(const void *a, const void *b)
1441 {
1442 return sa_addr_cmp((struct sockaddr *) a, &((struct bgp_peer *)b)->addr);
1443 }
1444
bgp_peer_free(void * a)1445 void bgp_peer_free(void *a)
1446 {
1447 }
1448
bgp_peers_bintree_walk_print(const void * nodep,const pm_VISIT which,const int depth,void * extra)1449 int bgp_peers_bintree_walk_print(const void *nodep, const pm_VISIT which, const int depth, void *extra)
1450 {
1451 struct bgp_misc_structs *bms;
1452 struct bgp_peer *peer;
1453 char peer_str[INET6_ADDRSTRLEN];
1454
1455 peer = (*(struct bgp_peer **) nodep);
1456 bms = bgp_select_misc_db(peer->type);
1457
1458 if (!bms) return FALSE;
1459
1460 if (!peer) Log(LOG_INFO, "INFO ( %s/%s ): bgp_peers_bintree_walk_print(): null\n", config.name, bms->log_str);
1461 else {
1462 addr_to_str(peer_str, &peer->addr);
1463 Log(LOG_INFO, "INFO ( %s/%s ): bgp_peers_bintree_walk_print(): %s\n", config.name, bms->log_str, peer_str);
1464 }
1465
1466 return TRUE;
1467 }
1468
bgp_peers_bintree_walk_delete(const void * nodep,const pm_VISIT which,const int depth,void * extra)1469 int bgp_peers_bintree_walk_delete(const void *nodep, const pm_VISIT which, const int depth, void *extra)
1470 {
1471 struct bgp_misc_structs *bms;
1472 char peer_str[] = "peer_ip", *saved_peer_str;
1473 struct bgp_peer *peer;
1474
1475 peer = (*(struct bgp_peer **) nodep);
1476
1477 if (!peer) return FALSE;
1478
1479 bms = bgp_select_misc_db(peer->type);
1480
1481 if (!bms) return FALSE;
1482
1483 saved_peer_str = bms->peer_str;
1484 bms->peer_str = peer_str;
1485 bgp_peer_info_delete(peer);
1486 bms->peer_str = saved_peer_str;
1487
1488 // XXX: count tree elements to index and free() later
1489
1490 return TRUE;
1491 }
1492
bgp_router_id_check(struct bgp_msg_data * bmd)1493 int bgp_router_id_check(struct bgp_msg_data *bmd)
1494 {
1495 struct bgp_peer *peer = bmd->peer;
1496 struct bgp_misc_structs *bms;
1497 struct bgp_peer *peers_check;
1498 int peers_check_idx = 0;
1499
1500 bms = bgp_select_misc_db(peer->type);
1501
1502 if (!bms) return ERR;
1503
1504 peers_check = bms->peers;
1505
1506 for (; peers_check_idx < bms->max_peers; peers_check_idx++) {
1507 if (peers_check_idx != peer->idx && !memcmp(&peers_check[peers_check_idx].id, &peer->id, sizeof(peers_check[peers_check_idx].id))) {
1508 char bgp_peer_str[INET6_ADDRSTRLEN];
1509
1510 bgp_peer_print(&peers_check[peers_check_idx], bgp_peer_str, INET6_ADDRSTRLEN);
1511 Log(LOG_WARNING, "WARN ( %s/%s ): [%s] Refusing new connection from existing Router-ID.\n", config.name, bms->log_str, bgp_peer_str);
1512
1513 return ERR;
1514 }
1515 }
1516
1517 return FALSE;
1518 }
1519
1520 /*
1521 utility function when an ASN is prepended by 'AS', 'AS ', etc. strings
1522 that need to be stripped.
1523 */
bgp_str2asn(char * asn_str,as_t * asn)1524 int bgp_str2asn(char *asn_str, as_t *asn)
1525 {
1526 char *endptr, *asn_ptr = asn_str;
1527 int len, cnt;
1528
1529 if (!asn_str || !asn) return ERR;
1530
1531 len = strlen(asn_str);
1532
1533 for (cnt = 0; !isdigit(asn_str[cnt]) && (cnt < len); cnt++);
1534
1535 asn_ptr = &asn_str[cnt];
1536
1537 (*asn) = strtoul(asn_ptr, &endptr, 10);
1538 if (endptr == asn_ptr || (*endptr) != '\0') return ERR;
1539 if (errno) {
1540 errno = FALSE;
1541 return ERR;
1542 }
1543
1544 return SUCCESS;
1545 }
1546
bgp_origin_print(u_int8_t origin)1547 const char *bgp_origin_print(u_int8_t origin)
1548 {
1549 if (origin <= BGP_ORIGIN_MAX) return bgp_origin[origin];
1550 else return bgp_origin[BGP_ORIGIN_UNKNOWN];
1551 }
1552
bgp_str2origin(char * origin_str)1553 u_int8_t bgp_str2origin(char *origin_str)
1554 {
1555 if (!strcmp(origin_str, "i")) return BGP_ORIGIN_IGP;
1556 else if (!strcmp(origin_str, "e")) return BGP_ORIGIN_EGP;
1557 else if (!strcmp(origin_str, "u")) return BGP_ORIGIN_INCOMPLETE;
1558
1559 return BGP_ORIGIN_UNKNOWN;
1560 }
1561
bgp_get_packet_len(char * pkt)1562 u_int16_t bgp_get_packet_len(char *pkt)
1563 {
1564 struct bgp_header *bhdr = (struct bgp_header *) pkt;
1565 u_int16_t blen = 0;
1566
1567 if (bgp_marker_check(bhdr, BGP_MARKER_SIZE) != ERR) {
1568 blen = ntohs(bhdr->bgpo_len);
1569 }
1570
1571 return blen;
1572 }
1573