1 /* $OpenBSD: util.c,v 1.17 2013/10/30 17:28:33 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 <netdb.h> 24 #include <stdlib.h> 25 #include <stdio.h> 26 #include <string.h> 27 28 #include "bgpd.h" 29 #include "rde.h" 30 31 const char *aspath_delim(u_int8_t, int); 32 33 const char * 34 log_addr(const struct bgpd_addr *addr) 35 { 36 static char buf[48]; 37 char tbuf[16]; 38 39 switch (addr->aid) { 40 case AID_INET: 41 case AID_INET6: 42 if (inet_ntop(aid2af(addr->aid), &addr->ba, buf, 43 sizeof(buf)) == NULL) 44 return ("?"); 45 return (buf); 46 case AID_VPN_IPv4: 47 if (inet_ntop(AF_INET, &addr->vpn4.addr, tbuf, 48 sizeof(tbuf)) == NULL) 49 return ("?"); 50 snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn4.rd), 51 tbuf); 52 return (buf); 53 } 54 return ("???"); 55 } 56 57 const char * 58 log_in6addr(const struct in6_addr *addr) 59 { 60 struct sockaddr_in6 sa_in6; 61 u_int16_t tmp16; 62 63 bzero(&sa_in6, sizeof(sa_in6)); 64 sa_in6.sin6_len = sizeof(sa_in6); 65 sa_in6.sin6_family = AF_INET6; 66 memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr)); 67 68 /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */ 69 if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) || 70 IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) { 71 memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16)); 72 sa_in6.sin6_scope_id = ntohs(tmp16); 73 sa_in6.sin6_addr.s6_addr[2] = 0; 74 sa_in6.sin6_addr.s6_addr[3] = 0; 75 } 76 77 return (log_sockaddr((struct sockaddr *)&sa_in6)); 78 } 79 80 const char * 81 log_sockaddr(struct sockaddr *sa) 82 { 83 static char buf[NI_MAXHOST]; 84 85 if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0, 86 NI_NUMERICHOST)) 87 return ("(unknown)"); 88 else 89 return (buf); 90 } 91 92 const char * 93 log_as(u_int32_t as) 94 { 95 static char buf[12]; /* "65000.65000\0" */ 96 97 if (as <= USHRT_MAX) { 98 if (snprintf(buf, sizeof(buf), "%u", as) == -1) 99 return ("?"); 100 } else { 101 if (snprintf(buf, sizeof(buf), "%u.%u", as >> 16, 102 as & 0xffff) == -1) 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 = betoh64(rd); 117 switch (rd >> 48) { 118 case EXT_COMMUNITY_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_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_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 /* NOTE: this function does not check if the type/subtype combo is 141 * actually valid. */ 142 const char * 143 log_ext_subtype(u_int8_t subtype) 144 { 145 static char etype[6]; 146 147 switch (subtype) { 148 case EXT_COMMUNITY_ROUTE_TGT: 149 return ("rt"); /* route target */ 150 case EXT_COMMUNITY_ROUTE_ORIG: 151 return ("soo"); /* source of origin */ 152 case EXT_COMMUNITY_OSPF_DOM_ID: 153 return ("odi"); /* ospf domain id */ 154 case EXT_COMMUNITY_OSPF_RTR_TYPE: 155 return ("ort"); /* ospf route type */ 156 case EXT_COMMUNITY_OSPF_RTR_ID: 157 return ("ori"); /* ospf router id */ 158 case EXT_COMMUNITY_BGP_COLLECT: 159 return ("bdc"); /* bgp data collection */ 160 default: 161 snprintf(etype, sizeof(etype), "[%u]", subtype); 162 return (etype); 163 } 164 } 165 166 const char * 167 aspath_delim(u_int8_t seg_type, int closing) 168 { 169 static char db[8]; 170 171 switch (seg_type) { 172 case AS_SET: 173 if (!closing) 174 return ("{ "); 175 else 176 return (" }"); 177 case AS_SEQUENCE: 178 return (""); 179 case AS_CONFED_SEQUENCE: 180 if (!closing) 181 return ("( "); 182 else 183 return (" )"); 184 case AS_CONFED_SET: 185 if (!closing) 186 return ("[ "); 187 else 188 return (" ]"); 189 default: 190 if (!closing) 191 snprintf(db, sizeof(db), "!%u ", seg_type); 192 else 193 snprintf(db, sizeof(db), " !%u", seg_type); 194 return (db); 195 } 196 } 197 198 int 199 aspath_snprint(char *buf, size_t size, void *data, u_int16_t len) 200 { 201 #define UPDATE() \ 202 do { \ 203 if (r == -1) \ 204 return (-1); \ 205 total_size += r; \ 206 if ((unsigned int)r < size) { \ 207 size -= r; \ 208 buf += r; \ 209 } else { \ 210 buf += size; \ 211 size = 0; \ 212 } \ 213 } while (0) 214 u_int8_t *seg; 215 int r, total_size; 216 u_int16_t seg_size; 217 u_int8_t i, seg_type, seg_len; 218 219 total_size = 0; 220 seg = data; 221 for (; len > 0; len -= seg_size, seg += seg_size) { 222 seg_type = seg[0]; 223 seg_len = seg[1]; 224 seg_size = 2 + sizeof(u_int32_t) * seg_len; 225 226 r = snprintf(buf, size, "%s%s", 227 total_size != 0 ? " " : "", 228 aspath_delim(seg_type, 0)); 229 UPDATE(); 230 231 for (i = 0; i < seg_len; i++) { 232 r = snprintf(buf, size, "%s", 233 log_as(aspath_extract(seg, i))); 234 UPDATE(); 235 if (i + 1 < seg_len) { 236 r = snprintf(buf, size, " "); 237 UPDATE(); 238 } 239 } 240 r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1)); 241 UPDATE(); 242 } 243 /* ensure that we have a valid C-string especially for empty as path */ 244 if (size > 0) 245 *buf = '\0'; 246 247 return (total_size); 248 #undef UPDATE 249 } 250 251 int 252 aspath_asprint(char **ret, void *data, u_int16_t len) 253 { 254 size_t slen; 255 int plen; 256 257 slen = aspath_strlen(data, len) + 1; 258 *ret = malloc(slen); 259 if (*ret == NULL) 260 return (-1); 261 262 plen = aspath_snprint(*ret, slen, data, len); 263 if (plen == -1) { 264 free(*ret); 265 *ret = NULL; 266 return (-1); 267 } 268 269 return (0); 270 } 271 272 size_t 273 aspath_strlen(void *data, u_int16_t len) 274 { 275 u_int8_t *seg; 276 int total_size; 277 u_int32_t as; 278 u_int16_t seg_size; 279 u_int8_t i, seg_type, seg_len; 280 281 total_size = 0; 282 seg = data; 283 for (; len > 0; len -= seg_size, seg += seg_size) { 284 seg_type = seg[0]; 285 seg_len = seg[1]; 286 seg_size = 2 + sizeof(u_int32_t) * seg_len; 287 288 if (seg_type == AS_SET) 289 if (total_size != 0) 290 total_size += 3; 291 else 292 total_size += 2; 293 else if (total_size != 0) 294 total_size += 1; 295 296 for (i = 0; i < seg_len; i++) { 297 as = aspath_extract(seg, i); 298 if (as > USHRT_MAX) { 299 u_int32_t a = as >> 16; 300 301 if (a >= 10000) 302 total_size += 5; 303 else if (a >= 1000) 304 total_size += 4; 305 else if (a >= 100) 306 total_size += 3; 307 else if (a >= 10) 308 total_size += 2; 309 else 310 total_size += 1; 311 total_size += 1; /* dot between hi & lo */ 312 as &= 0xffff; 313 } 314 if (as >= 10000) 315 total_size += 5; 316 else if (as >= 1000) 317 total_size += 4; 318 else if (as >= 100) 319 total_size += 3; 320 else if (as >= 10) 321 total_size += 2; 322 else 323 total_size += 1; 324 325 if (i + 1 < seg_len) 326 total_size += 1; 327 } 328 329 if (seg_type == AS_SET) 330 total_size += 2; 331 } 332 return (total_size); 333 } 334 335 /* we need to be able to search more than one as */ 336 int 337 aspath_match(void *data, u_int16_t len, enum as_spec type, u_int32_t as) 338 { 339 u_int8_t *seg; 340 int final; 341 u_int16_t seg_size; 342 u_int8_t i, seg_type, seg_len; 343 344 if (type == AS_EMPTY) { 345 if (len == 0) 346 return (1); 347 else 348 return (0); 349 } 350 351 final = 0; 352 seg = data; 353 for (; len > 0; len -= seg_size, seg += seg_size) { 354 seg_type = seg[0]; 355 seg_len = seg[1]; 356 seg_size = 2 + sizeof(u_int32_t) * seg_len; 357 358 final = (len == seg_size); 359 360 /* just check the first (leftmost) AS */ 361 if (type == AS_PEER) { 362 if (as == aspath_extract(seg, 0)) 363 return (1); 364 else 365 return (0); 366 } 367 /* just check the final (rightmost) AS */ 368 if (type == AS_SOURCE) { 369 /* not yet in the final segment */ 370 if (!final) 371 continue; 372 373 if (as == aspath_extract(seg, seg_len - 1)) 374 return (1); 375 else 376 return (0); 377 } 378 379 /* AS_TRANSIT or AS_ALL */ 380 for (i = 0; i < seg_len; i++) { 381 if (as == aspath_extract(seg, i)) { 382 /* 383 * the source (rightmost) AS is excluded from 384 * AS_TRANSIT matches. 385 */ 386 if (final && i == seg_len - 1 && 387 type == AS_TRANSIT) 388 return (0); 389 return (1); 390 } 391 } 392 } 393 return (0); 394 } 395 396 /* 397 * Extract the asnum out of the as segment at the specified position. 398 * Direct access is not possible because of non-aligned reads. 399 * ATTENTION: no bounds checks are done. 400 */ 401 u_int32_t 402 aspath_extract(const void *seg, int pos) 403 { 404 const u_char *ptr = seg; 405 u_int32_t as; 406 407 ptr += 2 + sizeof(u_int32_t) * pos; 408 memcpy(&as, ptr, sizeof(u_int32_t)); 409 return (ntohl(as)); 410 } 411 412 int 413 prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, 414 int prefixlen) 415 { 416 in_addr_t mask, aa, ba; 417 int i; 418 u_int8_t m; 419 420 if (a->aid != b->aid) 421 return (a->aid - b->aid); 422 423 switch (a->aid) { 424 case AID_INET: 425 if (prefixlen == 0) 426 return (0); 427 if (prefixlen > 32) 428 fatalx("prefix_cmp: bad IPv4 prefixlen"); 429 mask = htonl(prefixlen2mask(prefixlen)); 430 aa = ntohl(a->v4.s_addr & mask); 431 ba = ntohl(b->v4.s_addr & mask); 432 if (aa != ba) 433 return (aa - ba); 434 return (0); 435 case AID_INET6: 436 if (prefixlen == 0) 437 return (0); 438 if (prefixlen > 128) 439 fatalx("prefix_cmp: bad IPv6 prefixlen"); 440 for (i = 0; i < prefixlen / 8; i++) 441 if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) 442 return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); 443 i = prefixlen % 8; 444 if (i) { 445 m = 0xff00 >> i; 446 if ((a->v6.s6_addr[prefixlen / 8] & m) != 447 (b->v6.s6_addr[prefixlen / 8] & m)) 448 return ((a->v6.s6_addr[prefixlen / 8] & m) - 449 (b->v6.s6_addr[prefixlen / 8] & m)); 450 } 451 return (0); 452 case AID_VPN_IPv4: 453 if (prefixlen > 32) 454 fatalx("prefix_cmp: bad IPv4 VPN prefixlen"); 455 if (betoh64(a->vpn4.rd) > betoh64(b->vpn4.rd)) 456 return (1); 457 if (betoh64(a->vpn4.rd) < betoh64(b->vpn4.rd)) 458 return (-1); 459 mask = htonl(prefixlen2mask(prefixlen)); 460 aa = ntohl(a->vpn4.addr.s_addr & mask); 461 ba = ntohl(b->vpn4.addr.s_addr & mask); 462 if (aa != ba) 463 return (aa - ba); 464 if (a->vpn4.labellen > b->vpn4.labellen) 465 return (1); 466 if (a->vpn4.labellen < b->vpn4.labellen) 467 return (-1); 468 return (memcmp(a->vpn4.labelstack, b->vpn4.labelstack, 469 a->vpn4.labellen)); 470 default: 471 fatalx("prefix_cmp: unknown af"); 472 } 473 return (-1); 474 } 475 476 in_addr_t 477 prefixlen2mask(u_int8_t prefixlen) 478 { 479 if (prefixlen == 0) 480 return (0); 481 482 return (0xffffffff << (32 - prefixlen)); 483 } 484 485 void 486 inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) 487 { 488 struct in6_addr mask; 489 int i; 490 491 bzero(&mask, sizeof(mask)); 492 for (i = 0; i < prefixlen / 8; i++) 493 mask.s6_addr[i] = 0xff; 494 i = prefixlen % 8; 495 if (i) 496 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 497 498 for (i = 0; i < 16; i++) 499 dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; 500 } 501 502 /* address family translation functions */ 503 const struct aid aid_vals[AID_MAX] = AID_VALS; 504 505 const char * 506 aid2str(u_int8_t aid) 507 { 508 if (aid < AID_MAX) 509 return (aid_vals[aid].name); 510 return ("unknown AID"); 511 } 512 513 int 514 aid2afi(u_int8_t aid, u_int16_t *afi, u_int8_t *safi) 515 { 516 if (aid < AID_MAX) { 517 *afi = aid_vals[aid].afi; 518 *safi = aid_vals[aid].safi; 519 return (0); 520 } 521 return (-1); 522 } 523 524 int 525 afi2aid(u_int16_t afi, u_int8_t safi, u_int8_t *aid) 526 { 527 u_int8_t i; 528 529 for (i = 0; i < AID_MAX; i++) 530 if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) { 531 *aid = i; 532 return (0); 533 } 534 535 return (-1); 536 } 537 538 sa_family_t 539 aid2af(u_int8_t aid) 540 { 541 if (aid < AID_MAX) 542 return (aid_vals[aid].af); 543 return (AF_UNSPEC); 544 } 545 546 int 547 af2aid(sa_family_t af, u_int8_t safi, u_int8_t *aid) 548 { 549 u_int8_t i; 550 551 if (safi == 0) /* default to unicast subclass */ 552 safi = SAFI_UNICAST; 553 554 for (i = 0; i < AID_MAX; i++) 555 if (aid_vals[i].af == af && aid_vals[i].safi == safi) { 556 *aid = i; 557 return (0); 558 } 559 560 return (-1); 561 } 562 563 struct sockaddr * 564 addr2sa(struct bgpd_addr *addr, u_int16_t port) 565 { 566 static struct sockaddr_storage ss; 567 struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; 568 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; 569 570 if (addr->aid == AID_UNSPEC) 571 return (NULL); 572 573 bzero(&ss, sizeof(ss)); 574 switch (addr->aid) { 575 case AID_INET: 576 sa_in->sin_family = AF_INET; 577 sa_in->sin_len = sizeof(struct sockaddr_in); 578 sa_in->sin_addr.s_addr = addr->v4.s_addr; 579 sa_in->sin_port = htons(port); 580 break; 581 case AID_INET6: 582 sa_in6->sin6_family = AF_INET6; 583 sa_in6->sin6_len = sizeof(struct sockaddr_in6); 584 memcpy(&sa_in6->sin6_addr, &addr->v6, 585 sizeof(sa_in6->sin6_addr)); 586 sa_in6->sin6_port = htons(port); 587 sa_in6->sin6_scope_id = addr->scope_id; 588 break; 589 } 590 591 return ((struct sockaddr *)&ss); 592 } 593 594 void 595 sa2addr(struct sockaddr *sa, struct bgpd_addr *addr) 596 { 597 struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; 598 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; 599 600 bzero(addr, sizeof(*addr)); 601 switch (sa->sa_family) { 602 case AF_INET: 603 addr->aid = AID_INET; 604 memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4)); 605 break; 606 case AF_INET6: 607 addr->aid = AID_INET6; 608 memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6)); 609 addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */ 610 break; 611 } 612 } 613