1 /* $OpenBSD: util.c,v 1.61 2021/02/16 08:29:16 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(u_int8_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 u_int16_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(u_int32_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(u_int64_t rd) 107 { 108 static char buf[32]; 109 struct in_addr addr; 110 u_int32_t u32; 111 u_int16_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(short type, u_int8_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(u_int8_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, u_int16_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 u_int8_t *seg; 245 int r, total_size; 246 u_int16_t seg_size; 247 u_int8_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(u_int32_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, u_int16_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, u_int16_t len) 304 { 305 u_int8_t *seg; 306 int total_size; 307 u_int32_t as; 308 u_int16_t seg_size; 309 u_int8_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(u_int32_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 u_int32_t 349 aspath_extract(const void *seg, int pos) 350 { 351 const u_char *ptr = seg; 352 u_int32_t as; 353 354 ptr += 2 + sizeof(u_int32_t) * pos; 355 memcpy(&as, ptr, sizeof(u_int32_t)); 356 return (ntohl(as)); 357 } 358 359 /* 360 * Verify that the aspath is correctly encoded. 361 */ 362 int 363 aspath_verify(void *data, u_int16_t len, int as4byte, int noset) 364 { 365 u_int8_t *seg = data; 366 u_int16_t seg_size, as_size = 2; 367 u_int8_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 u_int8_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 u_int32_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, u_int16_t len, u_int16_t *newlen) 431 { 432 u_int8_t *seg, *nseg, *ndata; 433 u_int16_t seg_size, olen, nlen; 434 u_int8_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(u_int16_t) * seg_len; 442 nlen += 2 + sizeof(u_int32_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, u_int16_t len, void *va, 473 u_int8_t pfxlen, u_int8_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 u_int16_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, u_int16_t len, struct bgpd_addr *prefix, 499 u_int8_t *prefixlen) 500 { 501 u_int8_t pfxlen; 502 int plen; 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, u_int16_t len, struct bgpd_addr *prefix, 525 u_int8_t *prefixlen) 526 { 527 int plen; 528 u_int8_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, u_int16_t len, struct bgpd_addr *prefix, 551 u_int8_t *prefixlen, int withdraw) 552 { 553 int rv, done = 0; 554 u_int8_t pfxlen; 555 u_int16_t plen; 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(u_int64_t) || 592 pfxlen < sizeof(u_int64_t) * 8) 593 return (-1); 594 memcpy(&prefix->rd, p, sizeof(u_int64_t)); 595 pfxlen -= sizeof(u_int64_t) * 8; 596 p += sizeof(u_int64_t); 597 plen += sizeof(u_int64_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, u_int16_t len, struct bgpd_addr *prefix, 614 u_int8_t *prefixlen, int withdraw) 615 { 616 int rv, done = 0; 617 u_int8_t pfxlen; 618 u_int16_t plen; 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(u_int64_t) || 656 pfxlen < sizeof(u_int64_t) * 8) 657 return (-1); 658 659 memcpy(&prefix->rd, p, sizeof(u_int64_t)); 660 pfxlen -= sizeof(u_int64_t) * 8; 661 p += sizeof(u_int64_t); 662 plen += sizeof(u_int64_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 679 680 /* 681 * This function will have undefined behaviour if the passed in prefixlen is 682 * too large for the respective bgpd_addr address family. 683 */ 684 int 685 prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, 686 int prefixlen) 687 { 688 in_addr_t mask, aa, ba; 689 int i; 690 u_int8_t m; 691 692 if (a->aid != b->aid) 693 return (a->aid - b->aid); 694 695 switch (a->aid) { 696 case AID_VPN_IPv4: 697 if (be64toh(a->rd) > be64toh(b->rd)) 698 return (1); 699 if (be64toh(a->rd) < be64toh(b->rd)) 700 return (-1); 701 /* FALLTHROUGH */ 702 case AID_INET: 703 if (prefixlen == 0) 704 return (0); 705 if (prefixlen > 32) 706 return (-1); 707 mask = htonl(prefixlen2mask(prefixlen)); 708 aa = ntohl(a->v4.s_addr & mask); 709 ba = ntohl(b->v4.s_addr & mask); 710 if (aa > ba) 711 return (1); 712 if (aa < ba) 713 return (-1); 714 break; 715 case AID_VPN_IPv6: 716 if (be64toh(a->rd) > be64toh(b->rd)) 717 return (1); 718 if (be64toh(a->rd) < be64toh(b->rd)) 719 return (-1); 720 /* FALLTHROUGH */ 721 case AID_INET6: 722 if (prefixlen == 0) 723 return (0); 724 if (prefixlen > 128) 725 return (-1); 726 for (i = 0; i < prefixlen / 8; i++) 727 if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) 728 return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); 729 i = prefixlen % 8; 730 if (i) { 731 m = 0xff00 >> i; 732 if ((a->v6.s6_addr[prefixlen / 8] & m) != 733 (b->v6.s6_addr[prefixlen / 8] & m)) 734 return ((a->v6.s6_addr[prefixlen / 8] & m) - 735 (b->v6.s6_addr[prefixlen / 8] & m)); 736 } 737 break; 738 default: 739 return (-1); 740 } 741 742 if (a->aid == AID_VPN_IPv4 || a->aid == AID_VPN_IPv6) { 743 if (a->labellen > b->labellen) 744 return (1); 745 if (a->labellen < b->labellen) 746 return (-1); 747 return (memcmp(a->labelstack, b->labelstack, a->labellen)); 748 } 749 return (0); 750 751 } 752 753 in_addr_t 754 prefixlen2mask(u_int8_t prefixlen) 755 { 756 if (prefixlen == 0) 757 return (0); 758 759 return (0xffffffff << (32 - prefixlen)); 760 } 761 762 void 763 inet4applymask(struct in_addr *dest, const struct in_addr *src, int prefixlen) 764 { 765 struct in_addr mask; 766 767 mask.s_addr = htonl(prefixlen2mask(prefixlen)); 768 dest->s_addr = src->s_addr & mask.s_addr; 769 } 770 771 void 772 inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) 773 { 774 struct in6_addr mask; 775 int i; 776 777 bzero(&mask, sizeof(mask)); 778 for (i = 0; i < prefixlen / 8; i++) 779 mask.s6_addr[i] = 0xff; 780 i = prefixlen % 8; 781 if (i) 782 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 783 784 for (i = 0; i < 16; i++) 785 dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; 786 } 787 788 /* address family translation functions */ 789 const struct aid aid_vals[AID_MAX] = AID_VALS; 790 791 const char * 792 aid2str(u_int8_t aid) 793 { 794 if (aid < AID_MAX) 795 return (aid_vals[aid].name); 796 return ("unknown AID"); 797 } 798 799 int 800 aid2afi(u_int8_t aid, u_int16_t *afi, u_int8_t *safi) 801 { 802 if (aid < AID_MAX) { 803 *afi = aid_vals[aid].afi; 804 *safi = aid_vals[aid].safi; 805 return (0); 806 } 807 return (-1); 808 } 809 810 int 811 afi2aid(u_int16_t afi, u_int8_t safi, u_int8_t *aid) 812 { 813 u_int8_t i; 814 815 for (i = 0; i < AID_MAX; i++) 816 if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) { 817 *aid = i; 818 return (0); 819 } 820 821 return (-1); 822 } 823 824 sa_family_t 825 aid2af(u_int8_t aid) 826 { 827 if (aid < AID_MAX) 828 return (aid_vals[aid].af); 829 return (AF_UNSPEC); 830 } 831 832 int 833 af2aid(sa_family_t af, u_int8_t safi, u_int8_t *aid) 834 { 835 u_int8_t i; 836 837 if (safi == 0) /* default to unicast subclass */ 838 safi = SAFI_UNICAST; 839 840 for (i = 0; i < AID_MAX; i++) 841 if (aid_vals[i].af == af && aid_vals[i].safi == safi) { 842 *aid = i; 843 return (0); 844 } 845 846 return (-1); 847 } 848 849 /* 850 * Convert a struct bgpd_addr into a struct sockaddr. For VPN addresses 851 * the included label stack is ignored and needs to be handled by the caller. 852 */ 853 struct sockaddr * 854 addr2sa(const struct bgpd_addr *addr, u_int16_t port, socklen_t *len) 855 { 856 static struct sockaddr_storage ss; 857 struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; 858 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; 859 860 if (addr == NULL || addr->aid == AID_UNSPEC) 861 return (NULL); 862 863 bzero(&ss, sizeof(ss)); 864 switch (addr->aid) { 865 case AID_INET: 866 case AID_VPN_IPv4: 867 sa_in->sin_family = AF_INET; 868 sa_in->sin_addr.s_addr = addr->v4.s_addr; 869 sa_in->sin_port = htons(port); 870 *len = sizeof(struct sockaddr_in); 871 break; 872 case AID_INET6: 873 case AID_VPN_IPv6: 874 sa_in6->sin6_family = AF_INET6; 875 memcpy(&sa_in6->sin6_addr, &addr->v6, 876 sizeof(sa_in6->sin6_addr)); 877 sa_in6->sin6_port = htons(port); 878 sa_in6->sin6_scope_id = addr->scope_id; 879 *len = sizeof(struct sockaddr_in6); 880 break; 881 } 882 883 return ((struct sockaddr *)&ss); 884 } 885 886 void 887 sa2addr(struct sockaddr *sa, struct bgpd_addr *addr, u_int16_t *port) 888 { 889 struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; 890 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; 891 892 bzero(addr, sizeof(*addr)); 893 switch (sa->sa_family) { 894 case AF_INET: 895 addr->aid = AID_INET; 896 memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4)); 897 if (port) 898 *port = ntohs(sa_in->sin_port); 899 break; 900 case AF_INET6: 901 addr->aid = AID_INET6; 902 memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6)); 903 #ifdef __KAME__ 904 /* 905 * XXX thanks, KAME, for this ugliness... 906 * adopted from route/show.c 907 */ 908 if (IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr) || 909 IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr)) { 910 uint16_t tmp16; 911 memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr[2], 912 sizeof(tmp16)); 913 if (tmp16 != 0) { 914 sa_in6->sin6_scope_id = ntohs(tmp16); 915 sa_in6->sin6_addr.s6_addr[2] = 0; 916 sa_in6->sin6_addr.s6_addr[3] = 0; 917 } 918 } 919 #endif 920 addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */ 921 if (port) 922 *port = ntohs(sa_in6->sin6_port); 923 break; 924 } 925 } 926 927 const char * 928 get_baudrate(unsigned long long baudrate, char *unit) 929 { 930 static char bbuf[16]; 931 const unsigned long long kilo = 1000; 932 const unsigned long long mega = 1000ULL * kilo; 933 const unsigned long long giga = 1000ULL * mega; 934 935 if (baudrate > giga) 936 snprintf(bbuf, sizeof(bbuf), "%llu G%s", 937 baudrate / giga, unit); 938 else if (baudrate > mega) 939 snprintf(bbuf, sizeof(bbuf), "%llu M%s", 940 baudrate / mega, unit); 941 else if (baudrate > kilo) 942 snprintf(bbuf, sizeof(bbuf), "%llu K%s", 943 baudrate / kilo, unit); 944 else 945 snprintf(bbuf, sizeof(bbuf), "%llu %s", 946 baudrate, unit); 947 948 return (bbuf); 949 } 950