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