1 /* $OpenBSD: util.c,v 1.93 2025/02/04 18:16:56 denis Exp $ */
2
3 /*
4 * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <endian.h>
24 #include <errno.h>
25 #include <netdb.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <vis.h>
30
31 #include "bgpd.h"
32 #include "rde.h"
33 #include "log.h"
34
35 const char *
log_addr(const struct bgpd_addr * addr)36 log_addr(const struct bgpd_addr *addr)
37 {
38 static char buf[74];
39 struct sockaddr *sa;
40 socklen_t len;
41
42 sa = addr2sa(addr, 0, &len);
43 switch (addr->aid) {
44 case AID_INET:
45 case AID_INET6:
46 return log_sockaddr(sa, len);
47 case AID_VPN_IPv4:
48 case AID_VPN_IPv6:
49 snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->rd),
50 log_sockaddr(sa, len));
51 return (buf);
52 case AID_EVPN:
53 return log_evpnaddr(addr, sa, len);
54 break;
55 }
56 return ("???");
57 }
58
59 static const char *
log_mac(const uint8_t mac[ETHER_ADDR_LEN])60 log_mac(const uint8_t mac[ETHER_ADDR_LEN])
61 {
62 static char buf[18];
63
64 snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", mac[0],
65 mac[1], mac[2], mac[3], mac[4], mac[5]);
66
67 return (buf);
68 }
69
70 static const uint8_t zero_esi[ESI_ADDR_LEN];
71
72 static const char *
log_esi(const uint8_t esi[ESI_ADDR_LEN])73 log_esi(const uint8_t esi[ESI_ADDR_LEN])
74 {
75 static char buf[30];
76
77 if (memcmp(esi, zero_esi, sizeof(zero_esi)) == 0)
78 return ("");
79
80 snprintf(buf, sizeof(buf),
81 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", esi[0],
82 esi[1], esi[2], esi[3], esi[4], esi[5], esi[6], esi[7], esi[8],
83 esi[9]);
84
85 return (buf);
86 }
87
88 const char *
log_evpnaddr(const struct bgpd_addr * addr,struct sockaddr * sa,socklen_t salen)89 log_evpnaddr(const struct bgpd_addr *addr, struct sockaddr *sa,
90 socklen_t salen)
91 {
92 static char buf[138];
93 uint32_t vni;
94 uint8_t len;
95
96 switch(addr->evpn.type) {
97 case EVPN_ROUTE_TYPE_2:
98 memcpy(&vni, addr->labelstack, addr->labellen);
99 snprintf(buf, sizeof(buf), "[2]:[%s]:[%s]:[%d]:[48]:[%s]",
100 log_rd(addr->rd),log_esi(addr->evpn.esi), htonl(vni)>>8,
101 log_mac(addr->evpn.mac));
102 if (sa != NULL) {
103 len = strlen(buf);
104 snprintf(buf+len, sizeof(buf)-len, ":[%d]:[%s]",
105 sa->sa_family == AF_INET ? 32 : 128,
106 log_sockaddr(sa, salen));
107 }
108 break;
109 case EVPN_ROUTE_TYPE_3:
110 if (sa != NULL) {
111 memcpy(&vni, addr->labelstack, addr->labellen);
112 snprintf(buf, sizeof(buf), "[3]:[%s]:[%d]:[%s]",
113 log_rd(addr->rd),
114 sa->sa_family == AF_INET ? 32 : 128,
115 log_sockaddr(sa, salen));
116 }
117 break;
118 default:
119 break;
120 }
121 return (buf);
122 }
123
124 const char *
log_in6addr(const struct in6_addr * addr)125 log_in6addr(const struct in6_addr *addr)
126 {
127 struct sockaddr_in6 sa_in6;
128
129 memset(&sa_in6, 0, sizeof(sa_in6));
130 sa_in6.sin6_family = AF_INET6;
131 memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
132
133 #ifdef __KAME__
134 /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
135 if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
136 IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr) ||
137 IN6_IS_ADDR_MC_NODELOCAL(&sa_in6.sin6_addr)) &&
138 sa_in6.sin6_scope_id == 0) {
139 uint16_t tmp16;
140 memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16));
141 sa_in6.sin6_scope_id = ntohs(tmp16);
142 sa_in6.sin6_addr.s6_addr[2] = 0;
143 sa_in6.sin6_addr.s6_addr[3] = 0;
144 }
145 #endif
146
147 return (log_sockaddr((struct sockaddr *)&sa_in6, sizeof(sa_in6)));
148 }
149
150 const char *
log_sockaddr(struct sockaddr * sa,socklen_t len)151 log_sockaddr(struct sockaddr *sa, socklen_t len)
152 {
153 static char buf[4][NI_MAXHOST];
154 static int bufidx;
155
156 bufidx = (bufidx + 1) % 4;
157 if (sa == NULL || getnameinfo(sa, len, buf[bufidx], sizeof(buf[0]),
158 NULL, 0, NI_NUMERICHOST))
159 return ("(unknown)");
160 else
161 return (buf[bufidx]);
162 }
163
164 const char *
log_as(uint32_t as)165 log_as(uint32_t as)
166 {
167 static char buf[11]; /* "4294967294\0" */
168
169 if (snprintf(buf, sizeof(buf), "%u", as) < 0)
170 return ("?");
171
172 return (buf);
173 }
174
175 const char *
log_rd(uint64_t rd)176 log_rd(uint64_t rd)
177 {
178 static char buf[32];
179 struct in_addr addr;
180 uint32_t u32;
181 uint16_t u16;
182
183 rd = be64toh(rd);
184 switch (rd >> 48) {
185 case EXT_COMMUNITY_TRANS_TWO_AS:
186 u32 = rd & 0xffffffff;
187 u16 = (rd >> 32) & 0xffff;
188 snprintf(buf, sizeof(buf), "rd %hu:%u", u16, u32);
189 break;
190 case EXT_COMMUNITY_TRANS_FOUR_AS:
191 u32 = (rd >> 16) & 0xffffffff;
192 u16 = rd & 0xffff;
193 snprintf(buf, sizeof(buf), "rd %s:%hu", log_as(u32), u16);
194 break;
195 case EXT_COMMUNITY_TRANS_IPV4:
196 u32 = (rd >> 16) & 0xffffffff;
197 u16 = rd & 0xffff;
198 addr.s_addr = htonl(u32);
199 snprintf(buf, sizeof(buf), "rd %s:%hu", inet_ntoa(addr), u16);
200 break;
201 default:
202 snprintf(buf, sizeof(buf), "rd #%016llx",
203 (unsigned long long)rd);
204 break;
205 }
206 return (buf);
207 }
208
209 const struct ext_comm_pairs iana_ext_comms[] = IANA_EXT_COMMUNITIES;
210
211 /* NOTE: this function does not check if the type/subtype combo is
212 * actually valid. */
213 const char *
log_ext_subtype(int type,uint8_t subtype)214 log_ext_subtype(int type, uint8_t subtype)
215 {
216 static char etype[16];
217 const struct ext_comm_pairs *cp;
218
219 for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
220 if ((type == cp->type || type == -1) && subtype == cp->subtype)
221 return (cp->subname);
222 }
223 if (type == -1)
224 return ("???");
225 snprintf(etype, sizeof(etype), "[%hhx:%hhx]", (uint8_t)type, subtype);
226 return (etype);
227 }
228
229 const char *
log_reason(const char * communication)230 log_reason(const char *communication) {
231 static char buf[(REASON_LEN - 1) * 4 + 1];
232
233 strnvis(buf, communication, sizeof(buf), VIS_NL | VIS_OCTAL);
234
235 return buf;
236 }
237
238 static const char *
log_expires(time_t expires)239 log_expires(time_t expires)
240 {
241 static char buf[32];
242
243 buf[0] = '\0';
244 if (expires != 0)
245 snprintf(buf, sizeof(buf), " expires %lld", (long long)expires);
246 return buf;
247 }
248
249 const char *
log_roa(struct roa * roa)250 log_roa(struct roa *roa)
251 {
252 static char buf[256];
253 char maxbuf[32];
254 #if defined(__GNUC__) && __GNUC__ < 4
255 struct bgpd_addr addr = { .aid = roa->aid };
256 addr.v6 = roa->prefix.inet6;
257 #else
258 struct bgpd_addr addr = { .aid = roa->aid, .v6 = roa->prefix.inet6 };
259 #endif
260
261 maxbuf[0] = '\0';
262 if (roa->prefixlen != roa->maxlen)
263 snprintf(maxbuf, sizeof(maxbuf), " maxlen %u", roa->maxlen);
264 snprintf(buf, sizeof(buf), "%s/%u%s source-as %u%s", log_addr(&addr),
265 roa->prefixlen, maxbuf, roa->asnum, log_expires(roa->expires));
266 return buf;
267 }
268
269 const char *
log_aspa(struct aspa_set * aspa)270 log_aspa(struct aspa_set *aspa)
271 {
272 static char errbuf[256];
273 static char *buf;
274 static size_t len;
275 char asbuf[16];
276 size_t needed;
277 uint32_t i;
278
279 /* include enough space for header and trailer */
280 if ((uint64_t)aspa->num > (SIZE_MAX / sizeof(asbuf) - 72))
281 goto fail;
282 needed = aspa->num * sizeof(asbuf) + 72;
283 if (needed > len) {
284 char *nbuf;
285
286 if ((nbuf = realloc(buf, needed)) == NULL)
287 goto fail;
288 len = needed;
289 buf = nbuf;
290 }
291
292 snprintf(buf, len, "customer-as %s%s provider-as { ",
293 log_as(aspa->as), log_expires(aspa->expires));
294
295 for (i = 0; i < aspa->num; i++) {
296 snprintf(asbuf, sizeof(asbuf), "%s ", log_as(aspa->tas[i]));
297 if (strlcat(buf, asbuf, len) >= len)
298 goto fail;
299 }
300 if (strlcat(buf, "}", len) >= len)
301 goto fail;
302 return buf;
303
304 fail:
305 free(buf);
306 buf = NULL;
307 len = 0;
308 snprintf(errbuf, sizeof(errbuf), "customer-as %s%s provider-as { ... }",
309 log_as(aspa->as), log_expires(aspa->expires));
310 return errbuf;
311 }
312
313 const char *
log_aspath_error(int error)314 log_aspath_error(int error)
315 {
316 static char buf[20];
317
318 switch (error) {
319 case AS_ERR_LEN:
320 return "inconsistent length";
321 case AS_ERR_TYPE:
322 return "unknown segment type";
323 case AS_ERR_BAD:
324 return "invalid encoding";
325 case AS_ERR_SOFT:
326 return "soft failure";
327 default:
328 snprintf(buf, sizeof(buf), "unknown %d", error);
329 return buf;
330 }
331 }
332
333 const char *
log_rtr_error(enum rtr_error err)334 log_rtr_error(enum rtr_error err)
335 {
336 static char buf[20];
337
338 switch (err) {
339 case NO_ERROR:
340 return "No Error";
341 case CORRUPT_DATA:
342 return "Corrupt Data";
343 case INTERNAL_ERROR:
344 return "Internal Error";
345 case NO_DATA_AVAILABLE:
346 return "No Data Available";
347 case INVALID_REQUEST:
348 return "Invalid Request";
349 case UNSUPP_PROTOCOL_VERS:
350 return "Unsupported Protocol Version";
351 case UNSUPP_PDU_TYPE:
352 return "Unsupported PDU Type";
353 case UNK_REC_WDRAWL:
354 return "Withdrawal of Unknown Record";
355 case DUP_REC_RECV:
356 return "Duplicate Announcement Received";
357 case UNEXP_PROTOCOL_VERS:
358 return "Unexpected Protocol Version";
359 default:
360 snprintf(buf, sizeof(buf), "unknown %u", err);
361 return buf;
362 }
363 }
364
365 const char *
log_policy(enum role role)366 log_policy(enum role role)
367 {
368 switch (role) {
369 case ROLE_PROVIDER:
370 return "provider";
371 case ROLE_RS:
372 return "rs";
373 case ROLE_RS_CLIENT:
374 return "rs-client";
375 case ROLE_CUSTOMER:
376 return "customer";
377 case ROLE_PEER:
378 return "peer";
379 default:
380 return "unknown";
381 }
382 }
383
384 const char *
log_capability(uint8_t capa)385 log_capability(uint8_t capa)
386 {
387 static char buf[20];
388
389 switch (capa) {
390 case CAPA_MP:
391 return "Multiprotocol Extensions";
392 case CAPA_REFRESH:
393 return "Route Refresh";
394 case CAPA_EXT_NEXTHOP:
395 return "Extended Nexhop Encoding";
396 case CAPA_EXT_MSG:
397 return "Extended Message";
398 case CAPA_ROLE:
399 return "BGP Role";
400 case CAPA_RESTART:
401 return "Graceful Restart";
402 case CAPA_AS4BYTE:
403 return "4-octet AS number";
404 case CAPA_ADD_PATH:
405 return "ADD-PATH";
406 case CAPA_ENHANCED_RR:
407 return "Enhanced Route Refresh";
408 default:
409 snprintf(buf, sizeof(buf), "unknown %u", capa);
410 return buf;
411 }
412 }
413
414 static const char *
aspath_delim(uint8_t seg_type,int closing)415 aspath_delim(uint8_t seg_type, int closing)
416 {
417 static char db[8];
418
419 switch (seg_type) {
420 case AS_SET:
421 if (!closing)
422 return ("{ ");
423 else
424 return (" }");
425 case AS_SEQUENCE:
426 return ("");
427 case AS_CONFED_SEQUENCE:
428 if (!closing)
429 return ("( ");
430 else
431 return (" )");
432 case AS_CONFED_SET:
433 if (!closing)
434 return ("[ ");
435 else
436 return (" ]");
437 default:
438 if (!closing)
439 snprintf(db, sizeof(db), "!%u ", seg_type);
440 else
441 snprintf(db, sizeof(db), " !%u", seg_type);
442 return (db);
443 }
444 }
445
446 static int
aspath_snprint(char * buf,size_t size,struct ibuf * in)447 aspath_snprint(char *buf, size_t size, struct ibuf *in)
448 {
449 #define UPDATE() \
450 do { \
451 if (r < 0 || (unsigned int)r >= size) \
452 return (-1); \
453 size -= r; \
454 buf += r; \
455 } while (0)
456
457 struct ibuf data;
458 uint32_t as;
459 int r, n = 0;
460 uint8_t i, seg_type, seg_len;
461
462 ibuf_from_ibuf(&data, in);
463 while (ibuf_size(&data) > 0) {
464 if (ibuf_get_n8(&data, &seg_type) == -1 ||
465 ibuf_get_n8(&data, &seg_len) == -1 ||
466 seg_len == 0)
467 return (-1);
468
469 r = snprintf(buf, size, "%s%s", n++ != 0 ? " " : "",
470 aspath_delim(seg_type, 0));
471 UPDATE();
472
473 for (i = 0; i < seg_len; i++) {
474 if (ibuf_get_n32(&data, &as) == -1)
475 return -1;
476
477 r = snprintf(buf, size, "%s", log_as(as));
478 UPDATE();
479 if (i + 1 < seg_len) {
480 r = snprintf(buf, size, " ");
481 UPDATE();
482 }
483 }
484 r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1));
485 UPDATE();
486 }
487 /* ensure that we have a valid C-string especially for empty as path */
488 *buf = '\0';
489 return (0);
490 #undef UPDATE
491 }
492
493 static ssize_t
aspath_strsize(struct ibuf * in)494 aspath_strsize(struct ibuf *in)
495 {
496 struct ibuf buf;
497 ssize_t total_size = 0;
498 uint32_t as;
499 uint8_t i, seg_type, seg_len;
500
501 ibuf_from_ibuf(&buf, in);
502 while (ibuf_size(&buf) > 0) {
503 if (ibuf_get_n8(&buf, &seg_type) == -1 ||
504 ibuf_get_n8(&buf, &seg_len) == -1 ||
505 seg_len == 0)
506 return (-1);
507
508 if (total_size != 0)
509 total_size += 1;
510 total_size += strlen(aspath_delim(seg_type, 0));
511
512 for (i = 0; i < seg_len; i++) {
513 if (ibuf_get_n32(&buf, &as) == -1)
514 return (-1);
515
516 do {
517 total_size++;
518 } while ((as = as / 10) != 0);
519 }
520 total_size += seg_len - 1;
521
522 total_size += strlen(aspath_delim(seg_type, 1));
523 }
524 return (total_size + 1);
525 }
526
527 int
aspath_asprint(char ** ret,struct ibuf * data)528 aspath_asprint(char **ret, struct ibuf *data)
529 {
530 ssize_t slen;
531
532 if ((slen = aspath_strsize(data)) == -1) {
533 *ret = NULL;
534 errno = EINVAL;
535 return (-1);
536 }
537
538 *ret = malloc(slen);
539 if (*ret == NULL)
540 return (-1);
541
542 if (aspath_snprint(*ret, slen, data) == -1) {
543 free(*ret);
544 *ret = NULL;
545 errno = EINVAL;
546 return (-1);
547 }
548
549 return (0);
550 }
551
552 /*
553 * Extract the asnum out of the as segment at the specified position.
554 * Direct access is not possible because of non-aligned reads.
555 * Only works on verified 4-byte AS paths.
556 */
557 uint32_t
aspath_extract(const void * seg,int pos)558 aspath_extract(const void *seg, int pos)
559 {
560 const u_char *ptr = seg;
561 uint32_t as;
562
563 /* minimal pos check, return 0 since that is an invalid ASN */
564 if (pos < 0 || pos >= ptr[1])
565 return (0);
566 ptr += 2 + sizeof(uint32_t) * pos;
567 memcpy(&as, ptr, sizeof(uint32_t));
568 return (ntohl(as));
569 }
570
571 /*
572 * Verify that the aspath is correctly encoded.
573 */
574 int
aspath_verify(struct ibuf * in,int as4byte,int permit_set)575 aspath_verify(struct ibuf *in, int as4byte, int permit_set)
576 {
577 struct ibuf buf;
578 int pos, error = 0;
579 uint8_t seg_len, seg_type;
580
581 ibuf_from_ibuf(&buf, in);
582 if (ibuf_size(&buf) & 1) {
583 /* odd length aspath are invalid */
584 error = AS_ERR_BAD;
585 goto done;
586 }
587
588 while (ibuf_size(&buf) > 0) {
589 if (ibuf_get_n8(&buf, &seg_type) == -1 ||
590 ibuf_get_n8(&buf, &seg_len) == -1) {
591 error = AS_ERR_LEN;
592 goto done;
593 }
594
595 if (seg_len == 0) {
596 /* empty aspath segments are not allowed */
597 error = AS_ERR_BAD;
598 goto done;
599 }
600
601 /*
602 * BGP confederations should not show up but consider them
603 * as a soft error which invalidates the path but keeps the
604 * bgp session running.
605 */
606 if (seg_type == AS_CONFED_SEQUENCE || seg_type == AS_CONFED_SET)
607 error = AS_ERR_SOFT;
608 /*
609 * If AS_SET filtering (RFC6472) is on, error out on AS_SET
610 * as well.
611 */
612 if (!permit_set && seg_type == AS_SET)
613 error = AS_ERR_SOFT;
614 if (seg_type != AS_SET && seg_type != AS_SEQUENCE &&
615 seg_type != AS_CONFED_SEQUENCE &&
616 seg_type != AS_CONFED_SET) {
617 error = AS_ERR_TYPE;
618 goto done;
619 }
620
621 /* RFC 7607 - AS 0 is considered malformed */
622 for (pos = 0; pos < seg_len; pos++) {
623 uint32_t as;
624
625 if (as4byte) {
626 if (ibuf_get_n32(&buf, &as) == -1) {
627 error = AS_ERR_LEN;
628 goto done;
629 }
630 } else {
631 uint16_t tmp;
632 if (ibuf_get_n16(&buf, &tmp) == -1) {
633 error = AS_ERR_LEN;
634 goto done;
635 }
636 as = tmp;
637 }
638 if (as == 0)
639 error = AS_ERR_SOFT;
640 }
641 }
642
643 done:
644 return (error); /* aspath is valid but probably not loop free */
645 }
646
647 /*
648 * convert a 2 byte aspath to a 4 byte one.
649 */
650 struct ibuf *
aspath_inflate(struct ibuf * in)651 aspath_inflate(struct ibuf *in)
652 {
653 struct ibuf *out;
654 uint16_t short_as;
655 uint8_t seg_type, seg_len;
656
657 /*
658 * Allocate enough space for the worst case.
659 * XXX add 1 byte for the empty ASPATH case since we can't
660 * allocate an ibuf of 0 length.
661 */
662 if ((out = ibuf_open(ibuf_size(in) * 2 + 1)) == NULL)
663 return (NULL);
664
665 /* then copy the aspath */
666 while (ibuf_size(in) > 0) {
667 if (ibuf_get_n8(in, &seg_type) == -1 ||
668 ibuf_get_n8(in, &seg_len) == -1 ||
669 seg_len == 0)
670 goto fail;
671 if (ibuf_add_n8(out, seg_type) == -1 ||
672 ibuf_add_n8(out, seg_len) == -1)
673 goto fail;
674
675 for (; seg_len > 0; seg_len--) {
676 if (ibuf_get_n16(in, &short_as) == -1)
677 goto fail;
678 if (ibuf_add_n32(out, short_as) == -1)
679 goto fail;
680 }
681 }
682
683 return (out);
684
685 fail:
686 ibuf_free(out);
687 return (NULL);
688 }
689
690 static const u_char addrmask[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0,
691 0xf8, 0xfc, 0xfe, 0xff };
692
693 /* NLRI functions to extract prefixes from the NLRI blobs */
694 int
extract_prefix(const u_char * p,int len,void * va,uint8_t pfxlen,uint8_t max)695 extract_prefix(const u_char *p, int len, void *va, uint8_t pfxlen, uint8_t max)
696 {
697 u_char *a = va;
698 int plen;
699
700 plen = PREFIX_SIZE(pfxlen) - 1;
701 if (len < plen || max < plen)
702 return -1;
703
704 while (pfxlen > 0) {
705 if (pfxlen < 8) {
706 *a++ = *p++ & addrmask[pfxlen];
707 break;
708 } else {
709 *a++ = *p++;
710 pfxlen -= 8;
711 }
712 }
713 return (plen);
714 }
715
716 static int
extract_prefix_buf(struct ibuf * buf,void * va,uint8_t pfxlen,uint8_t max)717 extract_prefix_buf(struct ibuf *buf, void *va, uint8_t pfxlen, uint8_t max)
718 {
719 u_char *a = va;
720 unsigned int plen;
721 uint8_t tmp;
722
723 plen = PREFIX_SIZE(pfxlen) - 1;
724 if (ibuf_size(buf) < plen || max < plen)
725 return -1;
726
727 while (pfxlen > 0) {
728 if (ibuf_get_n8(buf, &tmp) == -1)
729 return -1;
730
731 if (pfxlen < 8) {
732 *a++ = tmp & addrmask[pfxlen];
733 break;
734 } else {
735 *a++ = tmp;
736 pfxlen -= 8;
737 }
738 }
739 return (0);
740 }
741
742 int
nlri_get_prefix(struct ibuf * buf,struct bgpd_addr * prefix,uint8_t * prefixlen)743 nlri_get_prefix(struct ibuf *buf, struct bgpd_addr *prefix, uint8_t *prefixlen)
744 {
745 uint8_t pfxlen;
746
747 if (ibuf_get_n8(buf, &pfxlen) == -1)
748 return (-1);
749 if (pfxlen > 32)
750 return (-1);
751
752 memset(prefix, 0, sizeof(struct bgpd_addr));
753 prefix->aid = AID_INET;
754
755 if (extract_prefix_buf(buf, &prefix->v4, pfxlen,
756 sizeof(prefix->v4)) == -1)
757 return (-1);
758
759 *prefixlen = pfxlen;
760 return (0);
761 }
762
763 int
nlri_get_prefix6(struct ibuf * buf,struct bgpd_addr * prefix,uint8_t * prefixlen)764 nlri_get_prefix6(struct ibuf *buf, struct bgpd_addr *prefix, uint8_t *prefixlen)
765 {
766 uint8_t pfxlen;
767
768 if (ibuf_get_n8(buf, &pfxlen) == -1)
769 return (-1);
770 if (pfxlen > 128)
771 return (-1);
772
773 memset(prefix, 0, sizeof(struct bgpd_addr));
774 prefix->aid = AID_INET6;
775
776 if (extract_prefix_buf(buf, &prefix->v6, pfxlen,
777 sizeof(prefix->v6)) == -1)
778 return (-1);
779
780 *prefixlen = pfxlen;
781 return (0);
782 }
783
784 int
nlri_get_vpn4(struct ibuf * buf,struct bgpd_addr * prefix,uint8_t * prefixlen,int withdraw)785 nlri_get_vpn4(struct ibuf *buf, struct bgpd_addr *prefix,
786 uint8_t *prefixlen, int withdraw)
787 {
788 int done = 0;
789 uint8_t pfxlen;
790
791 if (ibuf_get_n8(buf, &pfxlen) == -1)
792 return (-1);
793
794 memset(prefix, 0, sizeof(struct bgpd_addr));
795 prefix->aid = AID_VPN_IPv4;
796
797 /* label stack */
798 do {
799 if (prefix->labellen + 3U > sizeof(prefix->labelstack) ||
800 pfxlen < 3 * 8)
801 return (-1);
802 if (withdraw) {
803 /* on withdraw ignore the labelstack all together */
804 if (ibuf_skip(buf, 3) == -1)
805 return (-1);
806 pfxlen -= 3 * 8;
807 break;
808 }
809 if (ibuf_get(buf, &prefix->labelstack[prefix->labellen], 3) ==
810 -1)
811 return -1;
812 if (prefix->labelstack[prefix->labellen + 2] &
813 BGP_MPLS_BOS)
814 done = 1;
815 prefix->labellen += 3;
816 pfxlen -= 3 * 8;
817 } while (!done);
818
819 /* RD */
820 if (pfxlen < sizeof(uint64_t) * 8 ||
821 ibuf_get_h64(buf, &prefix->rd) == -1)
822 return (-1);
823 pfxlen -= sizeof(uint64_t) * 8;
824
825 /* prefix */
826 if (pfxlen > 32)
827 return (-1);
828 if (extract_prefix_buf(buf, &prefix->v4, pfxlen,
829 sizeof(prefix->v4)) == -1)
830 return (-1);
831
832 *prefixlen = pfxlen;
833 return (0);
834 }
835
836 int
nlri_get_vpn6(struct ibuf * buf,struct bgpd_addr * prefix,uint8_t * prefixlen,int withdraw)837 nlri_get_vpn6(struct ibuf *buf, struct bgpd_addr *prefix,
838 uint8_t *prefixlen, int withdraw)
839 {
840 int done = 0;
841 uint8_t pfxlen;
842
843 if (ibuf_get_n8(buf, &pfxlen) == -1)
844 return (-1);
845
846 memset(prefix, 0, sizeof(struct bgpd_addr));
847 prefix->aid = AID_VPN_IPv6;
848
849 /* label stack */
850 do {
851 if (prefix->labellen + 3U > sizeof(prefix->labelstack) ||
852 pfxlen < 3 * 8)
853 return (-1);
854 if (withdraw) {
855 /* on withdraw ignore the labelstack all together */
856 if (ibuf_skip(buf, 3) == -1)
857 return (-1);
858 pfxlen -= 3 * 8;
859 break;
860 }
861
862 if (ibuf_get(buf, &prefix->labelstack[prefix->labellen], 3) ==
863 -1)
864 return (-1);
865 if (prefix->labelstack[prefix->labellen + 2] &
866 BGP_MPLS_BOS)
867 done = 1;
868 prefix->labellen += 3;
869 pfxlen -= 3 * 8;
870 } while (!done);
871
872 /* RD */
873 if (pfxlen < sizeof(uint64_t) * 8 ||
874 ibuf_get_h64(buf, &prefix->rd) == -1)
875 return (-1);
876 pfxlen -= sizeof(uint64_t) * 8;
877
878 /* prefix */
879 if (pfxlen > 128)
880 return (-1);
881 if (extract_prefix_buf(buf, &prefix->v6, pfxlen,
882 sizeof(prefix->v6)) == -1)
883 return (-1);
884
885 *prefixlen = pfxlen;
886 return (0);
887 }
888
889 int
nlri_get_evpn(struct ibuf * buf,struct bgpd_addr * prefix,uint8_t * prefixlen)890 nlri_get_evpn(struct ibuf *buf, struct bgpd_addr *prefix,
891 uint8_t *prefixlen)
892 {
893 struct ibuf evpnbuf;
894 uint8_t nlrilen, type, pfxlen = 0, maclen = 0;
895
896 if (ibuf_get_n8(buf, &type) == -1)
897 return (-1);
898 if (ibuf_get_n8(buf, &nlrilen) == -1)
899 return (-1);
900
901 memset(prefix, 0, sizeof(struct bgpd_addr));
902 prefix->aid = AID_EVPN;
903
904 switch (type) {
905 case EVPN_ROUTE_TYPE_2:
906 if (ibuf_get_ibuf(buf, nlrilen, &evpnbuf) == -1)
907 return (-1);
908 prefix->evpn.type = EVPN_ROUTE_TYPE_2;
909 /* RD */
910 if (ibuf_get_h64(&evpnbuf, &prefix->rd) == -1)
911 return (-1);
912 /* ESI */
913 if (ibuf_get(&evpnbuf, &prefix->evpn.esi,
914 sizeof(prefix->evpn.esi)) == -1)
915 return (-1);
916 /* Ethernet Tag */
917 if (ibuf_get_h32(&evpnbuf, &prefix->evpn.ethtag) == -1)
918 return (-1);
919 /* MAC length */
920 if (ibuf_get_n8(&evpnbuf, &maclen) == -1)
921 return (-1);
922 if (maclen != 48)
923 return (-1);
924 /* MAC address */
925 if (ibuf_get(&evpnbuf, &prefix->evpn.mac,
926 sizeof(prefix->evpn.mac)) == -1)
927 return (-1);
928 /* Prefix length */
929 if (ibuf_get_n8(&evpnbuf, &pfxlen) == -1)
930 return (-1);
931 /* Destination */
932 if (pfxlen == 0) {
933 /* nothing */
934 } else if (pfxlen == 32) {
935 prefix->evpn.aid = AID_INET;
936 if (ibuf_get(&evpnbuf, &prefix->evpn.v4,
937 sizeof(prefix->evpn.v4)) == -1)
938 return (-1);
939 } else if (pfxlen == 128) {
940 prefix->evpn.aid = AID_INET6;
941 if (ibuf_get(&evpnbuf, &prefix->evpn.v6,
942 sizeof(prefix->evpn.v6)) == -1)
943 return (-1);
944 } else
945 return (-1);
946 /* VNI */
947 if (ibuf_size(&evpnbuf) != 3 && ibuf_size(&evpnbuf) != 6)
948 return (-1);
949 prefix->labellen = ibuf_size(&evpnbuf);
950 if (ibuf_get(&evpnbuf, prefix->labelstack,
951 prefix->labellen) == -1)
952 return (-1);
953 break;
954 case EVPN_ROUTE_TYPE_3:
955 if (ibuf_get_ibuf(buf, nlrilen, &evpnbuf) == -1)
956 return (-1);
957 prefix->evpn.type = EVPN_ROUTE_TYPE_3;
958 /* RD */
959 if (ibuf_get_h64(&evpnbuf, &prefix->rd) == -1)
960 return (-1);
961 /* Ethernet Tag */
962 if (ibuf_get_h32(&evpnbuf, &prefix->evpn.ethtag) == -1)
963 return (-1);
964 /* Prefix length */
965 if (ibuf_get_n8(&evpnbuf, &pfxlen) == -1)
966 return (-1);
967 /* Destination */
968 if (pfxlen == 32) {
969 prefix->evpn.aid = AID_INET;
970 if (ibuf_get(&evpnbuf, &prefix->evpn.v4,
971 sizeof(prefix->evpn.v4)) == -1)
972 return (-1);
973 } else if (pfxlen == 128) {
974 prefix->evpn.aid = AID_INET6;
975 if (ibuf_get(&evpnbuf, &prefix->evpn.v6,
976 sizeof(prefix->evpn.v6)) == -1)
977 return (-1);
978 } else
979 return (-1);
980 if (ibuf_size(&evpnbuf) != 0)
981 return (-1);
982 break;
983 default:
984 return (-1);
985 }
986
987 *prefixlen = pfxlen;
988 return (0);
989 }
990
991 static in_addr_t
prefixlen2mask(uint8_t prefixlen)992 prefixlen2mask(uint8_t prefixlen)
993 {
994 if (prefixlen == 0)
995 return (0);
996
997 return (0xffffffff << (32 - prefixlen));
998 }
999
1000 /*
1001 * This function will have undefined behaviour if the passed in prefixlen is
1002 * too large for the respective bgpd_addr address family.
1003 */
1004 int
prefix_compare(const struct bgpd_addr * a,const struct bgpd_addr * b,int prefixlen)1005 prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
1006 int prefixlen)
1007 {
1008 in_addr_t mask, aa, ba;
1009 int i;
1010 uint8_t m;
1011
1012 if (a->aid != b->aid)
1013 return (a->aid - b->aid);
1014
1015 switch (a->aid) {
1016 case AID_VPN_IPv4:
1017 if (be64toh(a->rd) > be64toh(b->rd))
1018 return (1);
1019 if (be64toh(a->rd) < be64toh(b->rd))
1020 return (-1);
1021 /* FALLTHROUGH */
1022 case AID_INET:
1023 if (prefixlen == 0)
1024 return (0);
1025 if (prefixlen > 32)
1026 return (-1);
1027 mask = htonl(prefixlen2mask(prefixlen));
1028 aa = ntohl(a->v4.s_addr & mask);
1029 ba = ntohl(b->v4.s_addr & mask);
1030 if (aa > ba)
1031 return (1);
1032 if (aa < ba)
1033 return (-1);
1034 break;
1035 case AID_VPN_IPv6:
1036 if (be64toh(a->rd) > be64toh(b->rd))
1037 return (1);
1038 if (be64toh(a->rd) < be64toh(b->rd))
1039 return (-1);
1040 /* FALLTHROUGH */
1041 case AID_INET6:
1042 if (prefixlen == 0)
1043 return (0);
1044 if (prefixlen > 128)
1045 return (-1);
1046 for (i = 0; i < prefixlen / 8; i++)
1047 if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
1048 return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
1049 i = prefixlen % 8;
1050 if (i) {
1051 m = 0xff00 >> i;
1052 if ((a->v6.s6_addr[prefixlen / 8] & m) !=
1053 (b->v6.s6_addr[prefixlen / 8] & m))
1054 return ((a->v6.s6_addr[prefixlen / 8] & m) -
1055 (b->v6.s6_addr[prefixlen / 8] & m));
1056 }
1057 break;
1058 default:
1059 return (-1);
1060 }
1061
1062 if (a->aid == AID_VPN_IPv4 || a->aid == AID_VPN_IPv6) {
1063 if (a->labellen > b->labellen)
1064 return (1);
1065 if (a->labellen < b->labellen)
1066 return (-1);
1067 return (memcmp(a->labelstack, b->labelstack, a->labellen));
1068 }
1069 return (0);
1070
1071 }
1072
1073 void
inet4applymask(struct in_addr * dest,const struct in_addr * src,int prefixlen)1074 inet4applymask(struct in_addr *dest, const struct in_addr *src, int prefixlen)
1075 {
1076 struct in_addr mask;
1077
1078 mask.s_addr = htonl(prefixlen2mask(prefixlen));
1079 dest->s_addr = src->s_addr & mask.s_addr;
1080 }
1081
1082 void
inet6applymask(struct in6_addr * dest,const struct in6_addr * src,int prefixlen)1083 inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen)
1084 {
1085 struct in6_addr mask;
1086 int i;
1087
1088 memset(&mask, 0, sizeof(mask));
1089 for (i = 0; i < prefixlen / 8; i++)
1090 mask.s6_addr[i] = 0xff;
1091 i = prefixlen % 8;
1092 if (i)
1093 mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
1094
1095 for (i = 0; i < 16; i++)
1096 dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i];
1097 }
1098
1099 void
applymask(struct bgpd_addr * dest,const struct bgpd_addr * src,int prefixlen)1100 applymask(struct bgpd_addr *dest, const struct bgpd_addr *src, int prefixlen)
1101 {
1102 *dest = *src;
1103 switch (src->aid) {
1104 case AID_INET:
1105 case AID_VPN_IPv4:
1106 inet4applymask(&dest->v4, &src->v4, prefixlen);
1107 break;
1108 case AID_INET6:
1109 case AID_VPN_IPv6:
1110 inet6applymask(&dest->v6, &src->v6, prefixlen);
1111 break;
1112 }
1113 }
1114
1115 /* address family translation functions */
1116 const struct aid aid_vals[AID_MAX] = AID_VALS;
1117
1118 const char *
aid2str(uint8_t aid)1119 aid2str(uint8_t aid)
1120 {
1121 if (aid < AID_MAX)
1122 return (aid_vals[aid].name);
1123 return ("unknown AID");
1124 }
1125
1126 int
aid2afi(uint8_t aid,uint16_t * afi,uint8_t * safi)1127 aid2afi(uint8_t aid, uint16_t *afi, uint8_t *safi)
1128 {
1129 if (aid != AID_UNSPEC && aid < AID_MAX) {
1130 *afi = aid_vals[aid].afi;
1131 *safi = aid_vals[aid].safi;
1132 return (0);
1133 }
1134 return (-1);
1135 }
1136
1137 int
afi2aid(uint16_t afi,uint8_t safi,uint8_t * aid)1138 afi2aid(uint16_t afi, uint8_t safi, uint8_t *aid)
1139 {
1140 uint8_t i;
1141
1142 for (i = AID_MIN; i < AID_MAX; i++)
1143 if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) {
1144 *aid = i;
1145 return (0);
1146 }
1147
1148 return (-1);
1149 }
1150
1151 sa_family_t
aid2af(uint8_t aid)1152 aid2af(uint8_t aid)
1153 {
1154 if (aid < AID_MAX)
1155 return (aid_vals[aid].af);
1156 return (AF_UNSPEC);
1157 }
1158
1159 int
af2aid(sa_family_t af,uint8_t safi,uint8_t * aid)1160 af2aid(sa_family_t af, uint8_t safi, uint8_t *aid)
1161 {
1162 uint8_t i;
1163
1164 if (safi == 0) /* default to unicast subclass */
1165 safi = SAFI_UNICAST;
1166
1167 for (i = AID_UNSPEC; i < AID_MAX; i++)
1168 if (aid_vals[i].af == af && aid_vals[i].safi == safi) {
1169 *aid = i;
1170 return (0);
1171 }
1172
1173 return (-1);
1174 }
1175
1176 static socklen_t
addr2sa_in6(struct sockaddr_in6 * sin6,struct in6_addr in6,uint16_t port,uint32_t scope_id)1177 addr2sa_in6(struct sockaddr_in6 *sin6, struct in6_addr in6, uint16_t port,
1178 uint32_t scope_id)
1179 {
1180 sin6->sin6_family = AF_INET6;
1181 memcpy(&sin6->sin6_addr, &in6, sizeof(sin6->sin6_addr));
1182 sin6->sin6_port = htons(port);
1183 sin6->sin6_scope_id = scope_id;
1184 return (sizeof(struct sockaddr_in6));
1185 }
1186
1187 static socklen_t
addr2sa_in(struct sockaddr_in * sin,struct in_addr in,uint16_t port)1188 addr2sa_in(struct sockaddr_in *sin, struct in_addr in, uint16_t port)
1189 {
1190 sin->sin_family = AF_INET;
1191 sin->sin_addr.s_addr = in.s_addr;
1192 sin->sin_port = htons(port);
1193 return (sizeof(struct sockaddr_in));
1194 }
1195
1196 /*
1197 * Convert a struct bgpd_addr into a struct sockaddr. For VPN addresses
1198 * the included label stack is ignored and needs to be handled by the caller.
1199 */
1200 struct sockaddr *
addr2sa(const struct bgpd_addr * addr,uint16_t port,socklen_t * len)1201 addr2sa(const struct bgpd_addr *addr, uint16_t port, socklen_t *len)
1202 {
1203 static struct sockaddr_storage ss;
1204 struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss;
1205 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss;
1206
1207 if (addr == NULL || addr->aid == AID_UNSPEC)
1208 return (NULL);
1209
1210 memset(&ss, 0, sizeof(ss));
1211 switch (addr->aid) {
1212 case AID_INET:
1213 case AID_VPN_IPv4:
1214 *len = addr2sa_in(sa_in, addr->v4, port);
1215 break;
1216 case AID_INET6:
1217 case AID_VPN_IPv6:
1218 *len = addr2sa_in6(sa_in6, addr->v6, port, addr->scope_id);
1219 break;
1220 case AID_EVPN:
1221 if (addr->evpn.aid == AID_INET)
1222 *len = addr2sa_in(sa_in, addr->evpn.v4, port);
1223 else if (addr->evpn.aid == AID_INET6)
1224 *len = addr2sa_in6(sa_in6, addr->evpn.v6, port,
1225 addr->scope_id);
1226 else {
1227 *len = 0;
1228 return (NULL);
1229 }
1230 break;
1231 case AID_FLOWSPECv4:
1232 case AID_FLOWSPECv6:
1233 default:
1234 return (NULL);
1235 }
1236
1237 return ((struct sockaddr *)&ss);
1238 }
1239
1240 void
sa2addr(struct sockaddr * sa,struct bgpd_addr * addr,uint16_t * port)1241 sa2addr(struct sockaddr *sa, struct bgpd_addr *addr, uint16_t *port)
1242 {
1243 struct sockaddr_in *sa_in = (struct sockaddr_in *)sa;
1244 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa;
1245
1246 memset(addr, 0, sizeof(*addr));
1247 switch (sa->sa_family) {
1248 case AF_INET:
1249 addr->aid = AID_INET;
1250 memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4));
1251 if (port)
1252 *port = ntohs(sa_in->sin_port);
1253 break;
1254 case AF_INET6:
1255 addr->aid = AID_INET6;
1256 #ifdef __KAME__
1257 /*
1258 * XXX thanks, KAME, for this ugliness...
1259 * adopted from route/show.c
1260 */
1261 if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr) ||
1262 IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr) ||
1263 IN6_IS_ADDR_MC_NODELOCAL(&sa_in6->sin6_addr)) &&
1264 sa_in6->sin6_scope_id == 0) {
1265 uint16_t tmp16;
1266 memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr[2],
1267 sizeof(tmp16));
1268 sa_in6->sin6_scope_id = ntohs(tmp16);
1269 sa_in6->sin6_addr.s6_addr[2] = 0;
1270 sa_in6->sin6_addr.s6_addr[3] = 0;
1271 }
1272 #endif
1273 memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6));
1274 addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */
1275 if (port)
1276 *port = ntohs(sa_in6->sin6_port);
1277 break;
1278 }
1279 }
1280
1281 const char *
get_baudrate(unsigned long long baudrate,char * unit)1282 get_baudrate(unsigned long long baudrate, char *unit)
1283 {
1284 static char bbuf[16];
1285 const unsigned long long kilo = 1000;
1286 const unsigned long long mega = 1000ULL * kilo;
1287 const unsigned long long giga = 1000ULL * mega;
1288
1289 if (baudrate > giga)
1290 snprintf(bbuf, sizeof(bbuf), "%llu G%s",
1291 baudrate / giga, unit);
1292 else if (baudrate > mega)
1293 snprintf(bbuf, sizeof(bbuf), "%llu M%s",
1294 baudrate / mega, unit);
1295 else if (baudrate > kilo)
1296 snprintf(bbuf, sizeof(bbuf), "%llu K%s",
1297 baudrate / kilo, unit);
1298 else
1299 snprintf(bbuf, sizeof(bbuf), "%llu %s",
1300 baudrate, unit);
1301
1302 return (bbuf);
1303 }
1304