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