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