1 /* $OpenBSD: util.c,v 1.14 2011/09/20 21:19:07 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 <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 %i:%i", 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:%i", 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:%i", 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_CUMMUNITY_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 > 32) 426 fatalx("prefix_cmp: bad IPv4 prefixlen"); 427 mask = htonl(prefixlen2mask(prefixlen)); 428 aa = ntohl(a->v4.s_addr & mask); 429 ba = ntohl(b->v4.s_addr & mask); 430 if (aa != ba) 431 return (aa - ba); 432 return (0); 433 case AID_INET6: 434 if (prefixlen > 128) 435 fatalx("prefix_cmp: bad IPv6 prefixlen"); 436 for (i = 0; i < prefixlen / 8; i++) 437 if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) 438 return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); 439 i = prefixlen % 8; 440 if (i) { 441 m = 0xff00 >> i; 442 if ((a->v6.s6_addr[prefixlen / 8] & m) != 443 (b->v6.s6_addr[prefixlen / 8] & m)) 444 return ((a->v6.s6_addr[prefixlen / 8] & m) - 445 (b->v6.s6_addr[prefixlen / 8] & m)); 446 } 447 return (0); 448 case AID_VPN_IPv4: 449 if (prefixlen > 32) 450 fatalx("prefix_cmp: bad IPv4 VPN prefixlen"); 451 if (betoh64(a->vpn4.rd) > betoh64(b->vpn4.rd)) 452 return (1); 453 if (betoh64(a->vpn4.rd) < betoh64(b->vpn4.rd)) 454 return (-1); 455 mask = htonl(prefixlen2mask(prefixlen)); 456 aa = ntohl(a->vpn4.addr.s_addr & mask); 457 ba = ntohl(b->vpn4.addr.s_addr & mask); 458 if (aa != ba) 459 return (aa - ba); 460 if (a->vpn4.labellen > b->vpn4.labellen) 461 return (1); 462 if (a->vpn4.labellen < b->vpn4.labellen) 463 return (-1); 464 return (memcmp(a->vpn4.labelstack, b->vpn4.labelstack, 465 a->vpn4.labellen)); 466 default: 467 fatalx("prefix_cmp: unknown af"); 468 } 469 return (-1); 470 } 471 472 in_addr_t 473 prefixlen2mask(u_int8_t prefixlen) 474 { 475 if (prefixlen == 0) 476 return (0); 477 478 return (0xffffffff << (32 - prefixlen)); 479 } 480 481 void 482 inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) 483 { 484 struct in6_addr mask; 485 int i; 486 487 bzero(&mask, sizeof(mask)); 488 for (i = 0; i < prefixlen / 8; i++) 489 mask.s6_addr[i] = 0xff; 490 i = prefixlen % 8; 491 if (i) 492 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 493 494 for (i = 0; i < 16; i++) 495 dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; 496 } 497 498 /* address family translation functions */ 499 const struct aid aid_vals[AID_MAX] = AID_VALS; 500 501 const char * 502 aid2str(u_int8_t aid) 503 { 504 if (aid < AID_MAX) 505 return (aid_vals[aid].name); 506 return ("unknown AID"); 507 } 508 509 int 510 aid2afi(u_int8_t aid, u_int16_t *afi, u_int8_t *safi) 511 { 512 if (aid < AID_MAX) { 513 *afi = aid_vals[aid].afi; 514 *safi = aid_vals[aid].safi; 515 return (0); 516 } 517 return (-1); 518 } 519 520 int 521 afi2aid(u_int16_t afi, u_int8_t safi, u_int8_t *aid) 522 { 523 u_int8_t i; 524 525 for (i = 0; i < AID_MAX; i++) 526 if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) { 527 *aid = i; 528 return (0); 529 } 530 531 return (-1); 532 } 533 534 sa_family_t 535 aid2af(u_int8_t aid) 536 { 537 if (aid < AID_MAX) 538 return (aid_vals[aid].af); 539 return (AF_UNSPEC); 540 } 541 542 int 543 af2aid(sa_family_t af, u_int8_t safi, u_int8_t *aid) 544 { 545 u_int8_t i; 546 547 if (safi == 0) /* default to unicast subclass */ 548 safi = SAFI_UNICAST; 549 550 for (i = 0; i < AID_MAX; i++) 551 if (aid_vals[i].af == af && aid_vals[i].safi == safi) { 552 *aid = i; 553 return (0); 554 } 555 556 return (-1); 557 } 558 559 struct sockaddr * 560 addr2sa(struct bgpd_addr *addr, u_int16_t port) 561 { 562 static struct sockaddr_storage ss; 563 struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; 564 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; 565 566 if (addr->aid == AID_UNSPEC) 567 return (NULL); 568 569 bzero(&ss, sizeof(ss)); 570 switch (addr->aid) { 571 case AID_INET: 572 sa_in->sin_family = AF_INET; 573 sa_in->sin_len = sizeof(struct sockaddr_in); 574 sa_in->sin_addr.s_addr = addr->v4.s_addr; 575 sa_in->sin_port = htons(port); 576 break; 577 case AID_INET6: 578 sa_in6->sin6_family = AF_INET6; 579 sa_in6->sin6_len = sizeof(struct sockaddr_in6); 580 memcpy(&sa_in6->sin6_addr, &addr->v6, 581 sizeof(sa_in6->sin6_addr)); 582 sa_in6->sin6_port = htons(port); 583 sa_in6->sin6_scope_id = addr->scope_id; 584 break; 585 } 586 587 return ((struct sockaddr *)&ss); 588 } 589 590 void 591 sa2addr(struct sockaddr *sa, struct bgpd_addr *addr) 592 { 593 struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; 594 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; 595 596 bzero(addr, sizeof(*addr)); 597 switch (sa->sa_family) { 598 case AF_INET: 599 addr->aid = AID_INET; 600 memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4)); 601 break; 602 case AF_INET6: 603 addr->aid = AID_INET6; 604 memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6)); 605 addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */ 606 break; 607 } 608 } 609