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