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