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