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