1 /* $OpenBSD: util.c,v 1.77 2023/04/17 08:02:21 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(enum role role) 202 { 203 switch (role) { 204 case ROLE_PROVIDER: 205 return "provider"; 206 case ROLE_RS: 207 return "rs"; 208 case ROLE_RS_CLIENT: 209 return "rs-client"; 210 case ROLE_CUSTOMER: 211 return "customer"; 212 case 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 int 498 extract_prefix(const u_char *p, int len, void *va, uint8_t pfxlen, uint8_t max) 499 { 500 static u_char addrmask[] = { 501 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 502 u_char *a = va; 503 int plen; 504 505 plen = PREFIX_SIZE(pfxlen) - 1; 506 if (len < plen || max < plen) 507 return -1; 508 509 while (pfxlen > 0) { 510 if (pfxlen < 8) { 511 *a++ = *p++ & addrmask[pfxlen]; 512 break; 513 } else { 514 *a++ = *p++; 515 pfxlen -= 8; 516 } 517 } 518 return (plen); 519 } 520 521 int 522 nlri_get_prefix(u_char *p, uint16_t len, struct bgpd_addr *prefix, 523 uint8_t *prefixlen) 524 { 525 int plen; 526 uint8_t pfxlen; 527 528 if (len < 1) 529 return (-1); 530 531 pfxlen = *p++; 532 len--; 533 534 memset(prefix, 0, sizeof(struct bgpd_addr)); 535 prefix->aid = AID_INET; 536 *prefixlen = pfxlen; 537 538 if (pfxlen > 32) 539 return (-1); 540 if ((plen = extract_prefix(p, len, &prefix->v4, pfxlen, 541 sizeof(prefix->v4))) == -1) 542 return (-1); 543 544 return (plen + 1); /* pfxlen needs to be added */ 545 } 546 547 int 548 nlri_get_prefix6(u_char *p, uint16_t len, struct bgpd_addr *prefix, 549 uint8_t *prefixlen) 550 { 551 int plen; 552 uint8_t pfxlen; 553 554 if (len < 1) 555 return (-1); 556 557 pfxlen = *p++; 558 len--; 559 560 memset(prefix, 0, sizeof(struct bgpd_addr)); 561 prefix->aid = AID_INET6; 562 *prefixlen = pfxlen; 563 564 if (pfxlen > 128) 565 return (-1); 566 if ((plen = extract_prefix(p, len, &prefix->v6, pfxlen, 567 sizeof(prefix->v6))) == -1) 568 return (-1); 569 570 return (plen + 1); /* pfxlen needs to be added */ 571 } 572 573 int 574 nlri_get_vpn4(u_char *p, uint16_t len, struct bgpd_addr *prefix, 575 uint8_t *prefixlen, int withdraw) 576 { 577 int rv, done = 0; 578 uint16_t plen; 579 uint8_t pfxlen; 580 581 if (len < 1) 582 return (-1); 583 584 memcpy(&pfxlen, p, 1); 585 p += 1; 586 plen = 1; 587 588 memset(prefix, 0, sizeof(struct bgpd_addr)); 589 590 /* label stack */ 591 do { 592 if (len - plen < 3 || pfxlen < 3 * 8) 593 return (-1); 594 if (prefix->labellen + 3U > 595 sizeof(prefix->labelstack)) 596 return (-1); 597 if (withdraw) { 598 /* on withdraw ignore the labelstack all together */ 599 p += 3; 600 plen += 3; 601 pfxlen -= 3 * 8; 602 break; 603 } 604 prefix->labelstack[prefix->labellen++] = *p++; 605 prefix->labelstack[prefix->labellen++] = *p++; 606 prefix->labelstack[prefix->labellen] = *p++; 607 if (prefix->labelstack[prefix->labellen] & 608 BGP_MPLS_BOS) 609 done = 1; 610 prefix->labellen++; 611 plen += 3; 612 pfxlen -= 3 * 8; 613 } while (!done); 614 615 /* RD */ 616 if (len - plen < (int)sizeof(uint64_t) || 617 pfxlen < sizeof(uint64_t) * 8) 618 return (-1); 619 memcpy(&prefix->rd, p, sizeof(uint64_t)); 620 pfxlen -= sizeof(uint64_t) * 8; 621 p += sizeof(uint64_t); 622 plen += sizeof(uint64_t); 623 624 /* prefix */ 625 prefix->aid = AID_VPN_IPv4; 626 *prefixlen = pfxlen; 627 628 if (pfxlen > 32) 629 return (-1); 630 if ((rv = extract_prefix(p, len, &prefix->v4, 631 pfxlen, sizeof(prefix->v4))) == -1) 632 return (-1); 633 634 return (plen + rv); 635 } 636 637 int 638 nlri_get_vpn6(u_char *p, uint16_t len, struct bgpd_addr *prefix, 639 uint8_t *prefixlen, int withdraw) 640 { 641 int rv, done = 0; 642 uint16_t plen; 643 uint8_t pfxlen; 644 645 if (len < 1) 646 return (-1); 647 648 memcpy(&pfxlen, p, 1); 649 p += 1; 650 plen = 1; 651 652 memset(prefix, 0, sizeof(struct bgpd_addr)); 653 654 /* label stack */ 655 do { 656 if (len - plen < 3 || pfxlen < 3 * 8) 657 return (-1); 658 if (prefix->labellen + 3U > 659 sizeof(prefix->labelstack)) 660 return (-1); 661 if (withdraw) { 662 /* on withdraw ignore the labelstack all together */ 663 p += 3; 664 plen += 3; 665 pfxlen -= 3 * 8; 666 break; 667 } 668 669 prefix->labelstack[prefix->labellen++] = *p++; 670 prefix->labelstack[prefix->labellen++] = *p++; 671 prefix->labelstack[prefix->labellen] = *p++; 672 if (prefix->labelstack[prefix->labellen] & 673 BGP_MPLS_BOS) 674 done = 1; 675 prefix->labellen++; 676 plen += 3; 677 pfxlen -= 3 * 8; 678 } while (!done); 679 680 /* RD */ 681 if (len - plen < (int)sizeof(uint64_t) || 682 pfxlen < sizeof(uint64_t) * 8) 683 return (-1); 684 685 memcpy(&prefix->rd, p, sizeof(uint64_t)); 686 pfxlen -= sizeof(uint64_t) * 8; 687 p += sizeof(uint64_t); 688 plen += sizeof(uint64_t); 689 690 /* prefix */ 691 prefix->aid = AID_VPN_IPv6; 692 *prefixlen = pfxlen; 693 694 if (pfxlen > 128) 695 return (-1); 696 697 if ((rv = extract_prefix(p, len, &prefix->v6, 698 pfxlen, sizeof(prefix->v6))) == -1) 699 return (-1); 700 701 return (plen + rv); 702 } 703 704 static in_addr_t 705 prefixlen2mask(uint8_t prefixlen) 706 { 707 if (prefixlen == 0) 708 return (0); 709 710 return (0xffffffff << (32 - prefixlen)); 711 } 712 713 /* 714 * This function will have undefined behaviour if the passed in prefixlen is 715 * too large for the respective bgpd_addr address family. 716 */ 717 int 718 prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, 719 int prefixlen) 720 { 721 in_addr_t mask, aa, ba; 722 int i; 723 uint8_t m; 724 725 if (a->aid != b->aid) 726 return (a->aid - b->aid); 727 728 switch (a->aid) { 729 case AID_VPN_IPv4: 730 if (be64toh(a->rd) > be64toh(b->rd)) 731 return (1); 732 if (be64toh(a->rd) < be64toh(b->rd)) 733 return (-1); 734 /* FALLTHROUGH */ 735 case AID_INET: 736 if (prefixlen == 0) 737 return (0); 738 if (prefixlen > 32) 739 return (-1); 740 mask = htonl(prefixlen2mask(prefixlen)); 741 aa = ntohl(a->v4.s_addr & mask); 742 ba = ntohl(b->v4.s_addr & mask); 743 if (aa > ba) 744 return (1); 745 if (aa < ba) 746 return (-1); 747 break; 748 case AID_VPN_IPv6: 749 if (be64toh(a->rd) > be64toh(b->rd)) 750 return (1); 751 if (be64toh(a->rd) < be64toh(b->rd)) 752 return (-1); 753 /* FALLTHROUGH */ 754 case AID_INET6: 755 if (prefixlen == 0) 756 return (0); 757 if (prefixlen > 128) 758 return (-1); 759 for (i = 0; i < prefixlen / 8; i++) 760 if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) 761 return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); 762 i = prefixlen % 8; 763 if (i) { 764 m = 0xff00 >> i; 765 if ((a->v6.s6_addr[prefixlen / 8] & m) != 766 (b->v6.s6_addr[prefixlen / 8] & m)) 767 return ((a->v6.s6_addr[prefixlen / 8] & m) - 768 (b->v6.s6_addr[prefixlen / 8] & m)); 769 } 770 break; 771 default: 772 return (-1); 773 } 774 775 if (a->aid == AID_VPN_IPv4 || a->aid == AID_VPN_IPv6) { 776 if (a->labellen > b->labellen) 777 return (1); 778 if (a->labellen < b->labellen) 779 return (-1); 780 return (memcmp(a->labelstack, b->labelstack, a->labellen)); 781 } 782 return (0); 783 784 } 785 786 void 787 inet4applymask(struct in_addr *dest, const struct in_addr *src, int prefixlen) 788 { 789 struct in_addr mask; 790 791 mask.s_addr = htonl(prefixlen2mask(prefixlen)); 792 dest->s_addr = src->s_addr & mask.s_addr; 793 } 794 795 void 796 inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) 797 { 798 struct in6_addr mask; 799 int i; 800 801 memset(&mask, 0, sizeof(mask)); 802 for (i = 0; i < prefixlen / 8; i++) 803 mask.s6_addr[i] = 0xff; 804 i = prefixlen % 8; 805 if (i) 806 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 807 808 for (i = 0; i < 16; i++) 809 dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; 810 } 811 812 void 813 applymask(struct bgpd_addr *dest, const struct bgpd_addr *src, int prefixlen) 814 { 815 *dest = *src; 816 switch (src->aid) { 817 case AID_INET: 818 case AID_VPN_IPv4: 819 inet4applymask(&dest->v4, &src->v4, prefixlen); 820 break; 821 case AID_INET6: 822 case AID_VPN_IPv6: 823 inet6applymask(&dest->v6, &src->v6, prefixlen); 824 break; 825 } 826 } 827 828 /* address family translation functions */ 829 const struct aid aid_vals[AID_MAX] = AID_VALS; 830 831 const char * 832 aid2str(uint8_t aid) 833 { 834 if (aid < AID_MAX) 835 return (aid_vals[aid].name); 836 return ("unknown AID"); 837 } 838 839 int 840 aid2afi(uint8_t aid, uint16_t *afi, uint8_t *safi) 841 { 842 if (aid < AID_MAX) { 843 *afi = aid_vals[aid].afi; 844 *safi = aid_vals[aid].safi; 845 return (0); 846 } 847 return (-1); 848 } 849 850 int 851 afi2aid(uint16_t afi, uint8_t safi, uint8_t *aid) 852 { 853 uint8_t i; 854 855 for (i = 0; i < AID_MAX; i++) 856 if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) { 857 *aid = i; 858 return (0); 859 } 860 861 return (-1); 862 } 863 864 sa_family_t 865 aid2af(uint8_t aid) 866 { 867 if (aid < AID_MAX) 868 return (aid_vals[aid].af); 869 return (AF_UNSPEC); 870 } 871 872 int 873 af2aid(sa_family_t af, uint8_t safi, uint8_t *aid) 874 { 875 uint8_t i; 876 877 if (safi == 0) /* default to unicast subclass */ 878 safi = SAFI_UNICAST; 879 880 for (i = 0; i < AID_MAX; i++) 881 if (aid_vals[i].af == af && aid_vals[i].safi == safi) { 882 *aid = i; 883 return (0); 884 } 885 886 return (-1); 887 } 888 889 /* 890 * Convert a struct bgpd_addr into a struct sockaddr. For VPN addresses 891 * the included label stack is ignored and needs to be handled by the caller. 892 */ 893 struct sockaddr * 894 addr2sa(const struct bgpd_addr *addr, uint16_t port, socklen_t *len) 895 { 896 static struct sockaddr_storage ss; 897 struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; 898 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; 899 900 if (addr == NULL || addr->aid == AID_UNSPEC) 901 return (NULL); 902 903 memset(&ss, 0, sizeof(ss)); 904 switch (addr->aid) { 905 case AID_INET: 906 case AID_VPN_IPv4: 907 sa_in->sin_family = AF_INET; 908 sa_in->sin_addr.s_addr = addr->v4.s_addr; 909 sa_in->sin_port = htons(port); 910 *len = sizeof(struct sockaddr_in); 911 break; 912 case AID_INET6: 913 case AID_VPN_IPv6: 914 sa_in6->sin6_family = AF_INET6; 915 memcpy(&sa_in6->sin6_addr, &addr->v6, 916 sizeof(sa_in6->sin6_addr)); 917 sa_in6->sin6_port = htons(port); 918 sa_in6->sin6_scope_id = addr->scope_id; 919 *len = sizeof(struct sockaddr_in6); 920 break; 921 case AID_FLOWSPECv4: 922 case AID_FLOWSPECv6: 923 return (NULL); 924 } 925 926 return ((struct sockaddr *)&ss); 927 } 928 929 void 930 sa2addr(struct sockaddr *sa, struct bgpd_addr *addr, uint16_t *port) 931 { 932 struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; 933 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; 934 935 memset(addr, 0, sizeof(*addr)); 936 switch (sa->sa_family) { 937 case AF_INET: 938 addr->aid = AID_INET; 939 memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4)); 940 if (port) 941 *port = ntohs(sa_in->sin_port); 942 break; 943 case AF_INET6: 944 addr->aid = AID_INET6; 945 #ifdef __KAME__ 946 /* 947 * XXX thanks, KAME, for this ugliness... 948 * adopted from route/show.c 949 */ 950 if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr) || 951 IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr) || 952 IN6_IS_ADDR_MC_NODELOCAL(&sa_in6->sin6_addr)) && 953 sa_in6->sin6_scope_id == 0) { 954 uint16_t tmp16; 955 memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr[2], 956 sizeof(tmp16)); 957 sa_in6->sin6_scope_id = ntohs(tmp16); 958 sa_in6->sin6_addr.s6_addr[2] = 0; 959 sa_in6->sin6_addr.s6_addr[3] = 0; 960 } 961 #endif 962 memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6)); 963 addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */ 964 if (port) 965 *port = ntohs(sa_in6->sin6_port); 966 break; 967 } 968 } 969 970 const char * 971 get_baudrate(unsigned long long baudrate, char *unit) 972 { 973 static char bbuf[16]; 974 const unsigned long long kilo = 1000; 975 const unsigned long long mega = 1000ULL * kilo; 976 const unsigned long long giga = 1000ULL * mega; 977 978 if (baudrate > giga) 979 snprintf(bbuf, sizeof(bbuf), "%llu G%s", 980 baudrate / giga, unit); 981 else if (baudrate > mega) 982 snprintf(bbuf, sizeof(bbuf), "%llu M%s", 983 baudrate / mega, unit); 984 else if (baudrate > kilo) 985 snprintf(bbuf, sizeof(bbuf), "%llu K%s", 986 baudrate / kilo, unit); 987 else 988 snprintf(bbuf, sizeof(bbuf), "%llu %s", 989 baudrate, unit); 990 991 return (bbuf); 992 } 993