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