1 /* $OpenBSD: util.c,v 1.73 2022/11/09 14:23:53 claudio 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 *aspath_delim(uint8_t, int); 36 37 const char * 38 log_addr(const struct bgpd_addr *addr) 39 { 40 static char buf[74]; 41 struct sockaddr *sa; 42 socklen_t len; 43 44 sa = addr2sa(addr, 0, &len); 45 switch (addr->aid) { 46 case AID_INET: 47 case AID_INET6: 48 return log_sockaddr(sa, len); 49 case AID_VPN_IPv4: 50 case AID_VPN_IPv6: 51 snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->rd), 52 log_sockaddr(sa, len)); 53 return (buf); 54 } 55 return ("???"); 56 } 57 58 const char * 59 log_in6addr(const struct in6_addr *addr) 60 { 61 struct sockaddr_in6 sa_in6; 62 63 memset(&sa_in6, 0, sizeof(sa_in6)); 64 sa_in6.sin6_family = AF_INET6; 65 memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr)); 66 67 #ifdef __KAME__ 68 /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */ 69 if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) || 70 IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr) || 71 IN6_IS_ADDR_MC_NODELOCAL(&sa_in6.sin6_addr)) && 72 sa_in6.sin6_scope_id == 0) { 73 uint16_t tmp16; 74 memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16)); 75 sa_in6.sin6_scope_id = ntohs(tmp16); 76 sa_in6.sin6_addr.s6_addr[2] = 0; 77 sa_in6.sin6_addr.s6_addr[3] = 0; 78 } 79 #endif 80 81 return (log_sockaddr((struct sockaddr *)&sa_in6, sizeof(sa_in6))); 82 } 83 84 const char * 85 log_sockaddr(struct sockaddr *sa, socklen_t len) 86 { 87 static char buf[NI_MAXHOST]; 88 89 if (sa == NULL || getnameinfo(sa, len, buf, sizeof(buf), NULL, 0, 90 NI_NUMERICHOST)) 91 return ("(unknown)"); 92 else 93 return (buf); 94 } 95 96 const char * 97 log_as(uint32_t as) 98 { 99 static char buf[11]; /* "4294967294\0" */ 100 101 if (snprintf(buf, sizeof(buf), "%u", as) < 0) 102 return ("?"); 103 104 return (buf); 105 } 106 107 const char * 108 log_rd(uint64_t rd) 109 { 110 static char buf[32]; 111 struct in_addr addr; 112 uint32_t u32; 113 uint16_t u16; 114 115 rd = be64toh(rd); 116 switch (rd >> 48) { 117 case EXT_COMMUNITY_TRANS_TWO_AS: 118 u32 = rd & 0xffffffff; 119 u16 = (rd >> 32) & 0xffff; 120 snprintf(buf, sizeof(buf), "rd %hu:%u", u16, u32); 121 break; 122 case EXT_COMMUNITY_TRANS_FOUR_AS: 123 u32 = (rd >> 16) & 0xffffffff; 124 u16 = rd & 0xffff; 125 snprintf(buf, sizeof(buf), "rd %s:%hu", log_as(u32), u16); 126 break; 127 case EXT_COMMUNITY_TRANS_IPV4: 128 u32 = (rd >> 16) & 0xffffffff; 129 u16 = rd & 0xffff; 130 addr.s_addr = htonl(u32); 131 snprintf(buf, sizeof(buf), "rd %s:%hu", inet_ntoa(addr), u16); 132 break; 133 default: 134 snprintf(buf, sizeof(buf), "rd #%016llx", 135 (unsigned long long)rd); 136 break; 137 } 138 return (buf); 139 } 140 141 const struct ext_comm_pairs iana_ext_comms[] = IANA_EXT_COMMUNITIES; 142 143 /* NOTE: this function does not check if the type/subtype combo is 144 * actually valid. */ 145 const char * 146 log_ext_subtype(int type, uint8_t subtype) 147 { 148 static char etype[6]; 149 const struct ext_comm_pairs *cp; 150 151 for (cp = iana_ext_comms; cp->subname != NULL; cp++) { 152 if ((type == cp->type || type == -1) && subtype == cp->subtype) 153 return (cp->subname); 154 } 155 snprintf(etype, sizeof(etype), "[%u]", subtype); 156 return (etype); 157 } 158 159 const char * 160 log_reason(const char *communication) { 161 static char buf[(REASON_LEN - 1) * 4 + 1]; 162 163 strnvis(buf, communication, sizeof(buf), VIS_NL | VIS_OCTAL); 164 165 return buf; 166 } 167 168 const char * 169 log_rtr_error(enum rtr_error err) 170 { 171 static char buf[20]; 172 173 switch (err) { 174 case NO_ERROR: 175 return "No Error"; 176 case CORRUPT_DATA: 177 return "Corrupt Data"; 178 case INTERNAL_ERROR: 179 return "Internal Error"; 180 case NO_DATA_AVAILABLE: 181 return "No Data Available"; 182 case INVALID_REQUEST: 183 return "Invalid Request"; 184 case UNSUPP_PROTOCOL_VERS: 185 return "Unsupported Protocol Version"; 186 case UNSUPP_PDU_TYPE: 187 return "Unsupported PDU Type"; 188 case UNK_REC_WDRAWL: 189 return "Withdrawal of Unknown Record"; 190 case DUP_REC_RECV: 191 return "Duplicate Announcement Received"; 192 case UNEXP_PROTOCOL_VERS: 193 return "Unexpected Protocol Version"; 194 default: 195 snprintf(buf, sizeof(buf), "unknown %u", err); 196 return buf; 197 } 198 } 199 200 const char * 201 log_policy(uint8_t role) 202 { 203 switch (role) { 204 case CAPA_ROLE_PROVIDER: 205 return "provider"; 206 case CAPA_ROLE_RS: 207 return "rs"; 208 case CAPA_ROLE_RS_CLIENT: 209 return "rs-client"; 210 case CAPA_ROLE_CUSTOMER: 211 return "customer"; 212 case CAPA_ROLE_PEER: 213 return "peer"; 214 default: 215 return "unknown"; 216 } 217 } 218 219 const char * 220 aspath_delim(uint8_t seg_type, int closing) 221 { 222 static char db[8]; 223 224 switch (seg_type) { 225 case AS_SET: 226 if (!closing) 227 return ("{ "); 228 else 229 return (" }"); 230 case AS_SEQUENCE: 231 return (""); 232 case AS_CONFED_SEQUENCE: 233 if (!closing) 234 return ("( "); 235 else 236 return (" )"); 237 case AS_CONFED_SET: 238 if (!closing) 239 return ("[ "); 240 else 241 return (" ]"); 242 default: 243 if (!closing) 244 snprintf(db, sizeof(db), "!%u ", seg_type); 245 else 246 snprintf(db, sizeof(db), " !%u", seg_type); 247 return (db); 248 } 249 } 250 251 int 252 aspath_snprint(char *buf, size_t size, void *data, uint16_t len) 253 { 254 #define UPDATE() \ 255 do { \ 256 if (r < 0) \ 257 return (-1); \ 258 total_size += r; \ 259 if ((unsigned int)r < size) { \ 260 size -= r; \ 261 buf += r; \ 262 } else { \ 263 buf += size; \ 264 size = 0; \ 265 } \ 266 } while (0) 267 uint8_t *seg; 268 int r, total_size; 269 uint16_t seg_size; 270 uint8_t i, seg_type, seg_len; 271 272 total_size = 0; 273 seg = data; 274 for (; len > 0; len -= seg_size, seg += seg_size) { 275 seg_type = seg[0]; 276 seg_len = seg[1]; 277 seg_size = 2 + sizeof(uint32_t) * seg_len; 278 279 r = snprintf(buf, size, "%s%s", 280 total_size != 0 ? " " : "", 281 aspath_delim(seg_type, 0)); 282 UPDATE(); 283 284 for (i = 0; i < seg_len; i++) { 285 r = snprintf(buf, size, "%s", 286 log_as(aspath_extract(seg, i))); 287 UPDATE(); 288 if (i + 1 < seg_len) { 289 r = snprintf(buf, size, " "); 290 UPDATE(); 291 } 292 } 293 r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1)); 294 UPDATE(); 295 } 296 /* ensure that we have a valid C-string especially for empty as path */ 297 if (size > 0) 298 *buf = '\0'; 299 300 return (total_size); 301 #undef UPDATE 302 } 303 304 int 305 aspath_asprint(char **ret, void *data, uint16_t len) 306 { 307 size_t slen; 308 int plen; 309 310 slen = aspath_strlen(data, len) + 1; 311 *ret = malloc(slen); 312 if (*ret == NULL) 313 return (-1); 314 315 plen = aspath_snprint(*ret, slen, data, len); 316 if (plen == -1) { 317 free(*ret); 318 *ret = NULL; 319 return (-1); 320 } 321 322 return (0); 323 } 324 325 size_t 326 aspath_strlen(void *data, uint16_t len) 327 { 328 uint8_t *seg; 329 int total_size; 330 uint32_t as; 331 uint16_t seg_size; 332 uint8_t i, seg_type, seg_len; 333 334 total_size = 0; 335 seg = data; 336 for (; len > 0; len -= seg_size, seg += seg_size) { 337 seg_type = seg[0]; 338 seg_len = seg[1]; 339 seg_size = 2 + sizeof(uint32_t) * seg_len; 340 341 if (seg_type == AS_SET) 342 if (total_size != 0) 343 total_size += 3; 344 else 345 total_size += 2; 346 else if (total_size != 0) 347 total_size += 1; 348 349 for (i = 0; i < seg_len; i++) { 350 as = aspath_extract(seg, i); 351 352 do { 353 total_size++; 354 } while ((as = as / 10) != 0); 355 356 if (i + 1 < seg_len) 357 total_size += 1; 358 } 359 360 if (seg_type == AS_SET) 361 total_size += 2; 362 } 363 return (total_size); 364 } 365 366 /* 367 * Extract the asnum out of the as segment at the specified position. 368 * Direct access is not possible because of non-aligned reads. 369 * Only works on verified 4-byte AS paths. 370 */ 371 uint32_t 372 aspath_extract(const void *seg, int pos) 373 { 374 const u_char *ptr = seg; 375 uint32_t as; 376 377 /* minimal pos check, return 0 since that is an invalid ASN */ 378 if (pos < 0 || pos >= ptr[1]) 379 return (0); 380 ptr += 2 + sizeof(uint32_t) * pos; 381 memcpy(&as, ptr, sizeof(uint32_t)); 382 return (ntohl(as)); 383 } 384 385 /* 386 * Verify that the aspath is correctly encoded. 387 */ 388 int 389 aspath_verify(void *data, uint16_t len, int as4byte, int noset) 390 { 391 uint8_t *seg = data; 392 uint16_t seg_size, as_size = 2; 393 uint8_t seg_len, seg_type; 394 int error = 0; 395 396 if (len & 1) 397 /* odd length aspath are invalid */ 398 return (AS_ERR_BAD); 399 400 if (as4byte) 401 as_size = 4; 402 403 for (; len > 0; len -= seg_size, seg += seg_size) { 404 const uint8_t *ptr; 405 int pos; 406 407 if (len < 2) /* header length check */ 408 return (AS_ERR_BAD); 409 seg_type = seg[0]; 410 seg_len = seg[1]; 411 412 if (seg_len == 0) 413 /* empty aspath segments are not allowed */ 414 return (AS_ERR_BAD); 415 416 /* 417 * BGP confederations should not show up but consider them 418 * as a soft error which invalidates the path but keeps the 419 * bgp session running. 420 */ 421 if (seg_type == AS_CONFED_SEQUENCE || seg_type == AS_CONFED_SET) 422 error = AS_ERR_SOFT; 423 /* 424 * If AS_SET filtering (RFC6472) is on, error out on AS_SET 425 * as well. 426 */ 427 if (noset && seg_type == AS_SET) 428 error = AS_ERR_SOFT; 429 if (seg_type != AS_SET && seg_type != AS_SEQUENCE && 430 seg_type != AS_CONFED_SEQUENCE && seg_type != AS_CONFED_SET) 431 return (AS_ERR_TYPE); 432 433 seg_size = 2 + as_size * seg_len; 434 435 if (seg_size > len) 436 return (AS_ERR_LEN); 437 438 /* RFC 7607 - AS 0 is considered malformed */ 439 ptr = seg + 2; 440 for (pos = 0; pos < seg_len; pos++) { 441 uint32_t as; 442 443 memcpy(&as, ptr, as_size); 444 if (as == 0) 445 error = AS_ERR_SOFT; 446 ptr += as_size; 447 } 448 } 449 return (error); /* aspath is valid but probably not loop free */ 450 } 451 452 /* 453 * convert a 2 byte aspath to a 4 byte one. 454 */ 455 u_char * 456 aspath_inflate(void *data, uint16_t len, uint16_t *newlen) 457 { 458 uint8_t *seg, *nseg, *ndata; 459 uint16_t seg_size, olen, nlen; 460 uint8_t seg_len; 461 462 /* first calculate the length of the aspath */ 463 seg = data; 464 nlen = 0; 465 for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) { 466 seg_len = seg[1]; 467 seg_size = 2 + sizeof(uint16_t) * seg_len; 468 nlen += 2 + sizeof(uint32_t) * seg_len; 469 470 if (seg_size > olen) { 471 errno = ERANGE; 472 return (NULL); 473 } 474 } 475 476 *newlen = nlen; 477 if ((ndata = malloc(nlen)) == NULL) 478 return (NULL); 479 480 /* then copy the aspath */ 481 seg = data; 482 for (nseg = ndata; nseg < ndata + nlen; ) { 483 *nseg++ = *seg++; 484 *nseg++ = seg_len = *seg++; 485 for (; seg_len > 0; seg_len--) { 486 *nseg++ = 0; 487 *nseg++ = 0; 488 *nseg++ = *seg++; 489 *nseg++ = *seg++; 490 } 491 } 492 493 return (ndata); 494 } 495 496 /* NLRI functions to extract prefixes from the NLRI blobs */ 497 static int 498 extract_prefix(u_char *p, uint16_t len, void *va, 499 uint8_t pfxlen, uint8_t max) 500 { 501 static u_char addrmask[] = { 502 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 503 u_char *a = va; 504 int i; 505 uint16_t plen = 0; 506 507 for (i = 0; pfxlen && i < max; i++) { 508 if (len <= plen) 509 return (-1); 510 if (pfxlen < 8) { 511 a[i] = *p++ & addrmask[pfxlen]; 512 plen++; 513 break; 514 } else { 515 a[i] = *p++; 516 plen++; 517 pfxlen -= 8; 518 } 519 } 520 return (plen); 521 } 522 523 int 524 nlri_get_prefix(u_char *p, uint16_t len, struct bgpd_addr *prefix, 525 uint8_t *prefixlen) 526 { 527 int plen; 528 uint8_t pfxlen; 529 530 if (len < 1) 531 return (-1); 532 533 pfxlen = *p++; 534 len--; 535 536 memset(prefix, 0, sizeof(struct bgpd_addr)); 537 prefix->aid = AID_INET; 538 *prefixlen = pfxlen; 539 540 if (pfxlen > 32) 541 return (-1); 542 if ((plen = extract_prefix(p, len, &prefix->v4, pfxlen, 543 sizeof(prefix->v4))) == -1) 544 return (-1); 545 546 return (plen + 1); /* pfxlen needs to be added */ 547 } 548 549 int 550 nlri_get_prefix6(u_char *p, uint16_t len, struct bgpd_addr *prefix, 551 uint8_t *prefixlen) 552 { 553 int plen; 554 uint8_t pfxlen; 555 556 if (len < 1) 557 return (-1); 558 559 pfxlen = *p++; 560 len--; 561 562 memset(prefix, 0, sizeof(struct bgpd_addr)); 563 prefix->aid = AID_INET6; 564 *prefixlen = pfxlen; 565 566 if (pfxlen > 128) 567 return (-1); 568 if ((plen = extract_prefix(p, len, &prefix->v6, pfxlen, 569 sizeof(prefix->v6))) == -1) 570 return (-1); 571 572 return (plen + 1); /* pfxlen needs to be added */ 573 } 574 575 int 576 nlri_get_vpn4(u_char *p, uint16_t len, struct bgpd_addr *prefix, 577 uint8_t *prefixlen, int withdraw) 578 { 579 int rv, done = 0; 580 uint16_t plen; 581 uint8_t pfxlen; 582 583 if (len < 1) 584 return (-1); 585 586 memcpy(&pfxlen, p, 1); 587 p += 1; 588 plen = 1; 589 590 memset(prefix, 0, sizeof(struct bgpd_addr)); 591 592 /* label stack */ 593 do { 594 if (len - plen < 3 || pfxlen < 3 * 8) 595 return (-1); 596 if (prefix->labellen + 3U > 597 sizeof(prefix->labelstack)) 598 return (-1); 599 if (withdraw) { 600 /* on withdraw ignore the labelstack all together */ 601 p += 3; 602 plen += 3; 603 pfxlen -= 3 * 8; 604 break; 605 } 606 prefix->labelstack[prefix->labellen++] = *p++; 607 prefix->labelstack[prefix->labellen++] = *p++; 608 prefix->labelstack[prefix->labellen] = *p++; 609 if (prefix->labelstack[prefix->labellen] & 610 BGP_MPLS_BOS) 611 done = 1; 612 prefix->labellen++; 613 plen += 3; 614 pfxlen -= 3 * 8; 615 } while (!done); 616 617 /* RD */ 618 if (len - plen < (int)sizeof(uint64_t) || 619 pfxlen < sizeof(uint64_t) * 8) 620 return (-1); 621 memcpy(&prefix->rd, p, sizeof(uint64_t)); 622 pfxlen -= sizeof(uint64_t) * 8; 623 p += sizeof(uint64_t); 624 plen += sizeof(uint64_t); 625 626 /* prefix */ 627 prefix->aid = AID_VPN_IPv4; 628 *prefixlen = pfxlen; 629 630 if (pfxlen > 32) 631 return (-1); 632 if ((rv = extract_prefix(p, len, &prefix->v4, 633 pfxlen, sizeof(prefix->v4))) == -1) 634 return (-1); 635 636 return (plen + rv); 637 } 638 639 int 640 nlri_get_vpn6(u_char *p, uint16_t len, struct bgpd_addr *prefix, 641 uint8_t *prefixlen, int withdraw) 642 { 643 int rv, done = 0; 644 uint16_t plen; 645 uint8_t pfxlen; 646 647 if (len < 1) 648 return (-1); 649 650 memcpy(&pfxlen, p, 1); 651 p += 1; 652 plen = 1; 653 654 memset(prefix, 0, sizeof(struct bgpd_addr)); 655 656 /* label stack */ 657 do { 658 if (len - plen < 3 || pfxlen < 3 * 8) 659 return (-1); 660 if (prefix->labellen + 3U > 661 sizeof(prefix->labelstack)) 662 return (-1); 663 if (withdraw) { 664 /* on withdraw ignore the labelstack all together */ 665 p += 3; 666 plen += 3; 667 pfxlen -= 3 * 8; 668 break; 669 } 670 671 prefix->labelstack[prefix->labellen++] = *p++; 672 prefix->labelstack[prefix->labellen++] = *p++; 673 prefix->labelstack[prefix->labellen] = *p++; 674 if (prefix->labelstack[prefix->labellen] & 675 BGP_MPLS_BOS) 676 done = 1; 677 prefix->labellen++; 678 plen += 3; 679 pfxlen -= 3 * 8; 680 } while (!done); 681 682 /* RD */ 683 if (len - plen < (int)sizeof(uint64_t) || 684 pfxlen < sizeof(uint64_t) * 8) 685 return (-1); 686 687 memcpy(&prefix->rd, p, sizeof(uint64_t)); 688 pfxlen -= sizeof(uint64_t) * 8; 689 p += sizeof(uint64_t); 690 plen += sizeof(uint64_t); 691 692 /* prefix */ 693 prefix->aid = AID_VPN_IPv6; 694 *prefixlen = pfxlen; 695 696 if (pfxlen > 128) 697 return (-1); 698 699 if ((rv = extract_prefix(p, len, &prefix->v6, 700 pfxlen, sizeof(prefix->v6))) == -1) 701 return (-1); 702 703 return (plen + rv); 704 } 705 706 static in_addr_t 707 prefixlen2mask(uint8_t prefixlen) 708 { 709 if (prefixlen == 0) 710 return (0); 711 712 return (0xffffffff << (32 - prefixlen)); 713 } 714 715 /* 716 * This function will have undefined behaviour if the passed in prefixlen is 717 * too large for the respective bgpd_addr address family. 718 */ 719 int 720 prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, 721 int prefixlen) 722 { 723 in_addr_t mask, aa, ba; 724 int i; 725 uint8_t m; 726 727 if (a->aid != b->aid) 728 return (a->aid - b->aid); 729 730 switch (a->aid) { 731 case AID_VPN_IPv4: 732 if (be64toh(a->rd) > be64toh(b->rd)) 733 return (1); 734 if (be64toh(a->rd) < be64toh(b->rd)) 735 return (-1); 736 /* FALLTHROUGH */ 737 case AID_INET: 738 if (prefixlen == 0) 739 return (0); 740 if (prefixlen > 32) 741 return (-1); 742 mask = htonl(prefixlen2mask(prefixlen)); 743 aa = ntohl(a->v4.s_addr & mask); 744 ba = ntohl(b->v4.s_addr & mask); 745 if (aa > ba) 746 return (1); 747 if (aa < ba) 748 return (-1); 749 break; 750 case AID_VPN_IPv6: 751 if (be64toh(a->rd) > be64toh(b->rd)) 752 return (1); 753 if (be64toh(a->rd) < be64toh(b->rd)) 754 return (-1); 755 /* FALLTHROUGH */ 756 case AID_INET6: 757 if (prefixlen == 0) 758 return (0); 759 if (prefixlen > 128) 760 return (-1); 761 for (i = 0; i < prefixlen / 8; i++) 762 if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) 763 return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); 764 i = prefixlen % 8; 765 if (i) { 766 m = 0xff00 >> i; 767 if ((a->v6.s6_addr[prefixlen / 8] & m) != 768 (b->v6.s6_addr[prefixlen / 8] & m)) 769 return ((a->v6.s6_addr[prefixlen / 8] & m) - 770 (b->v6.s6_addr[prefixlen / 8] & m)); 771 } 772 break; 773 default: 774 return (-1); 775 } 776 777 if (a->aid == AID_VPN_IPv4 || a->aid == AID_VPN_IPv6) { 778 if (a->labellen > b->labellen) 779 return (1); 780 if (a->labellen < b->labellen) 781 return (-1); 782 return (memcmp(a->labelstack, b->labelstack, a->labellen)); 783 } 784 return (0); 785 786 } 787 788 void 789 inet4applymask(struct in_addr *dest, const struct in_addr *src, int prefixlen) 790 { 791 struct in_addr mask; 792 793 mask.s_addr = htonl(prefixlen2mask(prefixlen)); 794 dest->s_addr = src->s_addr & mask.s_addr; 795 } 796 797 void 798 inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) 799 { 800 struct in6_addr mask; 801 int i; 802 803 memset(&mask, 0, sizeof(mask)); 804 for (i = 0; i < prefixlen / 8; i++) 805 mask.s6_addr[i] = 0xff; 806 i = prefixlen % 8; 807 if (i) 808 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 809 810 for (i = 0; i < 16; i++) 811 dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; 812 } 813 814 void 815 applymask(struct bgpd_addr *dest, const struct bgpd_addr *src, int prefixlen) 816 { 817 *dest = *src; 818 switch (src->aid) { 819 case AID_INET: 820 case AID_VPN_IPv4: 821 inet4applymask(&dest->v4, &src->v4, prefixlen); 822 break; 823 case AID_INET6: 824 case AID_VPN_IPv6: 825 inet6applymask(&dest->v6, &src->v6, prefixlen); 826 break; 827 } 828 } 829 830 /* address family translation functions */ 831 const struct aid aid_vals[AID_MAX] = AID_VALS; 832 833 const char * 834 aid2str(uint8_t aid) 835 { 836 if (aid < AID_MAX) 837 return (aid_vals[aid].name); 838 return ("unknown AID"); 839 } 840 841 int 842 aid2afi(uint8_t aid, uint16_t *afi, uint8_t *safi) 843 { 844 if (aid < AID_MAX) { 845 *afi = aid_vals[aid].afi; 846 *safi = aid_vals[aid].safi; 847 return (0); 848 } 849 return (-1); 850 } 851 852 int 853 afi2aid(uint16_t afi, uint8_t safi, uint8_t *aid) 854 { 855 uint8_t i; 856 857 for (i = 0; i < AID_MAX; i++) 858 if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) { 859 *aid = i; 860 return (0); 861 } 862 863 return (-1); 864 } 865 866 sa_family_t 867 aid2af(uint8_t aid) 868 { 869 if (aid < AID_MAX) 870 return (aid_vals[aid].af); 871 return (AF_UNSPEC); 872 } 873 874 int 875 af2aid(sa_family_t af, uint8_t safi, uint8_t *aid) 876 { 877 uint8_t i; 878 879 if (safi == 0) /* default to unicast subclass */ 880 safi = SAFI_UNICAST; 881 882 for (i = 0; i < AID_MAX; i++) 883 if (aid_vals[i].af == af && aid_vals[i].safi == safi) { 884 *aid = i; 885 return (0); 886 } 887 888 return (-1); 889 } 890 891 /* 892 * Convert a struct bgpd_addr into a struct sockaddr. For VPN addresses 893 * the included label stack is ignored and needs to be handled by the caller. 894 */ 895 struct sockaddr * 896 addr2sa(const struct bgpd_addr *addr, uint16_t port, socklen_t *len) 897 { 898 static struct sockaddr_storage ss; 899 struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; 900 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; 901 902 if (addr == NULL || addr->aid == AID_UNSPEC) 903 return (NULL); 904 905 memset(&ss, 0, sizeof(ss)); 906 switch (addr->aid) { 907 case AID_INET: 908 case AID_VPN_IPv4: 909 sa_in->sin_family = AF_INET; 910 sa_in->sin_addr.s_addr = addr->v4.s_addr; 911 sa_in->sin_port = htons(port); 912 *len = sizeof(struct sockaddr_in); 913 break; 914 case AID_INET6: 915 case AID_VPN_IPv6: 916 sa_in6->sin6_family = AF_INET6; 917 memcpy(&sa_in6->sin6_addr, &addr->v6, 918 sizeof(sa_in6->sin6_addr)); 919 sa_in6->sin6_port = htons(port); 920 sa_in6->sin6_scope_id = addr->scope_id; 921 *len = sizeof(struct sockaddr_in6); 922 break; 923 } 924 925 return ((struct sockaddr *)&ss); 926 } 927 928 void 929 sa2addr(struct sockaddr *sa, struct bgpd_addr *addr, uint16_t *port) 930 { 931 struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; 932 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; 933 934 memset(addr, 0, sizeof(*addr)); 935 switch (sa->sa_family) { 936 case AF_INET: 937 addr->aid = AID_INET; 938 memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4)); 939 if (port) 940 *port = ntohs(sa_in->sin_port); 941 break; 942 case AF_INET6: 943 addr->aid = AID_INET6; 944 #ifdef __KAME__ 945 /* 946 * XXX thanks, KAME, for this ugliness... 947 * adopted from route/show.c 948 */ 949 if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr) || 950 IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr) || 951 IN6_IS_ADDR_MC_NODELOCAL(&sa_in6->sin6_addr)) && 952 sa_in6->sin6_scope_id == 0) { 953 uint16_t tmp16; 954 memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr[2], 955 sizeof(tmp16)); 956 sa_in6->sin6_scope_id = ntohs(tmp16); 957 sa_in6->sin6_addr.s6_addr[2] = 0; 958 sa_in6->sin6_addr.s6_addr[3] = 0; 959 } 960 #endif 961 memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6)); 962 addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */ 963 if (port) 964 *port = ntohs(sa_in6->sin6_port); 965 break; 966 } 967 } 968 969 const char * 970 get_baudrate(unsigned long long baudrate, char *unit) 971 { 972 static char bbuf[16]; 973 const unsigned long long kilo = 1000; 974 const unsigned long long mega = 1000ULL * kilo; 975 const unsigned long long giga = 1000ULL * mega; 976 977 if (baudrate > giga) 978 snprintf(bbuf, sizeof(bbuf), "%llu G%s", 979 baudrate / giga, unit); 980 else if (baudrate > mega) 981 snprintf(bbuf, sizeof(bbuf), "%llu M%s", 982 baudrate / mega, unit); 983 else if (baudrate > kilo) 984 snprintf(bbuf, sizeof(bbuf), "%llu K%s", 985 baudrate / kilo, unit); 986 else 987 snprintf(bbuf, sizeof(bbuf), "%llu %s", 988 baudrate, unit); 989 990 return (bbuf); 991 } 992