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