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