1 /* $OpenBSD: util.c,v 1.22 2017/01/13 18:59:12 phessler 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 #include <vis.h> 28 29 #include "bgpd.h" 30 #include "rde.h" 31 32 const char *aspath_delim(u_int8_t, int); 33 34 const char * 35 log_addr(const struct bgpd_addr *addr) 36 { 37 static char buf[48]; 38 char tbuf[16]; 39 40 switch (addr->aid) { 41 case AID_INET: 42 case AID_INET6: 43 if (inet_ntop(aid2af(addr->aid), &addr->ba, buf, 44 sizeof(buf)) == NULL) 45 return ("?"); 46 return (buf); 47 case AID_VPN_IPv4: 48 if (inet_ntop(AF_INET, &addr->vpn4.addr, tbuf, 49 sizeof(tbuf)) == NULL) 50 return ("?"); 51 snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn4.rd), 52 tbuf); 53 return (buf); 54 } 55 return ("???"); 56 } 57 58 const char * 59 log_in6addr(const struct in6_addr *addr) 60 { 61 struct sockaddr_in6 sa_in6; 62 u_int16_t tmp16; 63 64 bzero(&sa_in6, sizeof(sa_in6)); 65 sa_in6.sin6_len = sizeof(sa_in6); 66 sa_in6.sin6_family = AF_INET6; 67 memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr)); 68 69 /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */ 70 if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) || 71 IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) { 72 memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16)); 73 sa_in6.sin6_scope_id = ntohs(tmp16); 74 sa_in6.sin6_addr.s6_addr[2] = 0; 75 sa_in6.sin6_addr.s6_addr[3] = 0; 76 } 77 78 return (log_sockaddr((struct sockaddr *)&sa_in6)); 79 } 80 81 const char * 82 log_sockaddr(struct sockaddr *sa) 83 { 84 static char buf[NI_MAXHOST]; 85 86 if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0, 87 NI_NUMERICHOST)) 88 return ("(unknown)"); 89 else 90 return (buf); 91 } 92 93 const char * 94 log_as(u_int32_t as) 95 { 96 static char buf[11]; /* "4294967294\0" */ 97 98 if (snprintf(buf, sizeof(buf), "%u", as) == -1) 99 return ("?"); 100 101 return (buf); 102 } 103 104 const char * 105 log_rd(u_int64_t rd) 106 { 107 static char buf[32]; 108 struct in_addr addr; 109 u_int32_t u32; 110 u_int16_t u16; 111 112 rd = betoh64(rd); 113 switch (rd >> 48) { 114 case EXT_COMMUNITY_TWO_AS: 115 u32 = rd & 0xffffffff; 116 u16 = (rd >> 32) & 0xffff; 117 snprintf(buf, sizeof(buf), "rd %hu:%u", u16, u32); 118 break; 119 case EXT_COMMUNITY_FOUR_AS: 120 u32 = (rd >> 16) & 0xffffffff; 121 u16 = rd & 0xffff; 122 snprintf(buf, sizeof(buf), "rd %s:%hu", log_as(u32), u16); 123 break; 124 case EXT_COMMUNITY_IPV4: 125 u32 = (rd >> 16) & 0xffffffff; 126 u16 = rd & 0xffff; 127 addr.s_addr = htonl(u32); 128 snprintf(buf, sizeof(buf), "rd %s:%hu", inet_ntoa(addr), u16); 129 break; 130 default: 131 return ("rd ?"); 132 } 133 return (buf); 134 } 135 136 /* NOTE: this function does not check if the type/subtype combo is 137 * actually valid. */ 138 const char * 139 log_ext_subtype(u_int8_t subtype) 140 { 141 static char etype[6]; 142 143 switch (subtype) { 144 case EXT_COMMUNITY_ROUTE_TGT: 145 return ("rt"); /* route target */ 146 case EXT_COMMUNITY_ROUTE_ORIG: 147 return ("soo"); /* source of origin */ 148 case EXT_COMMUNITY_OSPF_DOM_ID: 149 return ("odi"); /* ospf domain id */ 150 case EXT_COMMUNITY_OSPF_RTR_TYPE: 151 return ("ort"); /* ospf route type */ 152 case EXT_COMMUNITY_OSPF_RTR_ID: 153 return ("ori"); /* ospf router id */ 154 case EXT_COMMUNITY_BGP_COLLECT: 155 return ("bdc"); /* bgp data collection */ 156 default: 157 snprintf(etype, sizeof(etype), "[%u]", subtype); 158 return (etype); 159 } 160 } 161 162 const char * 163 log_shutcomm(const char *communication) { 164 static char buf[(SHUT_COMM_LEN - 1) * 4 + 1]; 165 166 strnvis(buf, communication, sizeof(buf), VIS_NL | VIS_OCTAL); 167 168 return buf; 169 } 170 171 const char * 172 aspath_delim(u_int8_t seg_type, int closing) 173 { 174 static char db[8]; 175 176 switch (seg_type) { 177 case AS_SET: 178 if (!closing) 179 return ("{ "); 180 else 181 return (" }"); 182 case AS_SEQUENCE: 183 return (""); 184 case AS_CONFED_SEQUENCE: 185 if (!closing) 186 return ("( "); 187 else 188 return (" )"); 189 case AS_CONFED_SET: 190 if (!closing) 191 return ("[ "); 192 else 193 return (" ]"); 194 default: 195 if (!closing) 196 snprintf(db, sizeof(db), "!%u ", seg_type); 197 else 198 snprintf(db, sizeof(db), " !%u", seg_type); 199 return (db); 200 } 201 } 202 203 int 204 aspath_snprint(char *buf, size_t size, void *data, u_int16_t len) 205 { 206 #define UPDATE() \ 207 do { \ 208 if (r == -1) \ 209 return (-1); \ 210 total_size += r; \ 211 if ((unsigned int)r < size) { \ 212 size -= r; \ 213 buf += r; \ 214 } else { \ 215 buf += size; \ 216 size = 0; \ 217 } \ 218 } while (0) 219 u_int8_t *seg; 220 int r, total_size; 221 u_int16_t seg_size; 222 u_int8_t i, seg_type, seg_len; 223 224 total_size = 0; 225 seg = data; 226 for (; len > 0; len -= seg_size, seg += seg_size) { 227 seg_type = seg[0]; 228 seg_len = seg[1]; 229 seg_size = 2 + sizeof(u_int32_t) * seg_len; 230 231 r = snprintf(buf, size, "%s%s", 232 total_size != 0 ? " " : "", 233 aspath_delim(seg_type, 0)); 234 UPDATE(); 235 236 for (i = 0; i < seg_len; i++) { 237 r = snprintf(buf, size, "%s", 238 log_as(aspath_extract(seg, i))); 239 UPDATE(); 240 if (i + 1 < seg_len) { 241 r = snprintf(buf, size, " "); 242 UPDATE(); 243 } 244 } 245 r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1)); 246 UPDATE(); 247 } 248 /* ensure that we have a valid C-string especially for empty as path */ 249 if (size > 0) 250 *buf = '\0'; 251 252 return (total_size); 253 #undef UPDATE 254 } 255 256 int 257 aspath_asprint(char **ret, void *data, u_int16_t len) 258 { 259 size_t slen; 260 int plen; 261 262 slen = aspath_strlen(data, len) + 1; 263 *ret = malloc(slen); 264 if (*ret == NULL) 265 return (-1); 266 267 plen = aspath_snprint(*ret, slen, data, len); 268 if (plen == -1) { 269 free(*ret); 270 *ret = NULL; 271 return (-1); 272 } 273 274 return (0); 275 } 276 277 size_t 278 aspath_strlen(void *data, u_int16_t len) 279 { 280 u_int8_t *seg; 281 int total_size; 282 u_int32_t as; 283 u_int16_t seg_size; 284 u_int8_t i, seg_type, seg_len; 285 286 total_size = 0; 287 seg = data; 288 for (; len > 0; len -= seg_size, seg += seg_size) { 289 seg_type = seg[0]; 290 seg_len = seg[1]; 291 seg_size = 2 + sizeof(u_int32_t) * seg_len; 292 293 if (seg_type == AS_SET) 294 if (total_size != 0) 295 total_size += 3; 296 else 297 total_size += 2; 298 else if (total_size != 0) 299 total_size += 1; 300 301 for (i = 0; i < seg_len; i++) { 302 as = aspath_extract(seg, i); 303 304 do { 305 total_size++; 306 } while ((as = as / 10) != 0); 307 308 if (i + 1 < seg_len) 309 total_size += 1; 310 } 311 312 if (seg_type == AS_SET) 313 total_size += 2; 314 } 315 return (total_size); 316 } 317 318 /* we need to be able to search more than one as */ 319 int 320 aspath_match(void *data, u_int16_t len, struct filter_as *f, u_int32_t match) 321 { 322 u_int8_t *seg; 323 int final; 324 u_int16_t seg_size; 325 u_int8_t i, seg_len; 326 u_int32_t as; 327 328 if (f->type == AS_EMPTY) { 329 if (len == 0) 330 return (1); 331 else 332 return (0); 333 } 334 335 seg = data; 336 for (; len > 0; len -= seg_size, seg += seg_size) { 337 seg_len = seg[1]; 338 seg_size = 2 + sizeof(u_int32_t) * seg_len; 339 340 final = (len == seg_size); 341 342 /* just check the first (leftmost) AS */ 343 if (f->type == AS_PEER) { 344 as = aspath_extract(seg, 0); 345 if (as_compare(f->op, as, match, f->as_min, f->as_max)) 346 return (1); 347 else 348 return (0); 349 } 350 /* just check the final (rightmost) AS */ 351 if (f->type == AS_SOURCE) { 352 /* not yet in the final segment */ 353 if (!final) 354 continue; 355 as = aspath_extract(seg, seg_len - 1); 356 if (as_compare(f->op, as, match, f->as_min, f->as_max)) 357 return (1); 358 else 359 return (0); 360 } 361 /* AS_TRANSIT or AS_ALL */ 362 for (i = 0; i < seg_len; i++) { 363 /* 364 * the source (rightmost) AS is excluded from 365 * AS_TRANSIT matches. 366 */ 367 if (final && i == seg_len - 1 && f->type == AS_TRANSIT) 368 return (0); 369 as = aspath_extract(seg, i); 370 if (as_compare(f->op, as, match, f->as_min, f->as_max)) 371 return (1); 372 } 373 } 374 return (0); 375 } 376 377 int 378 as_compare(u_int8_t op, u_int32_t as, u_int32_t match, u_int32_t as_min, 379 u_int32_t as_max) 380 { 381 if ((op == OP_NONE || op == OP_EQ) && as == match) 382 return (1); 383 else if (op == OP_NE && as != match) 384 return (1); 385 else if (op == OP_RANGE && as >= as_min && as <= as_max) 386 return (1); 387 else if (op == OP_XRANGE && as > as_min && as < as_max) 388 return (1); 389 return (0); 390 } 391 392 /* 393 * Extract the asnum out of the as segment at the specified position. 394 * Direct access is not possible because of non-aligned reads. 395 * ATTENTION: no bounds checks are done. 396 */ 397 u_int32_t 398 aspath_extract(const void *seg, int pos) 399 { 400 const u_char *ptr = seg; 401 u_int32_t as; 402 403 ptr += 2 + sizeof(u_int32_t) * pos; 404 memcpy(&as, ptr, sizeof(u_int32_t)); 405 return (ntohl(as)); 406 } 407 408 int 409 prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, 410 int prefixlen) 411 { 412 in_addr_t mask, aa, ba; 413 int i; 414 u_int8_t m; 415 416 if (a->aid != b->aid) 417 return (a->aid - b->aid); 418 419 switch (a->aid) { 420 case AID_INET: 421 if (prefixlen == 0) 422 return (0); 423 if (prefixlen > 32) 424 fatalx("prefix_cmp: bad IPv4 prefixlen"); 425 mask = htonl(prefixlen2mask(prefixlen)); 426 aa = ntohl(a->v4.s_addr & mask); 427 ba = ntohl(b->v4.s_addr & mask); 428 if (aa != ba) 429 return (aa - ba); 430 return (0); 431 case AID_INET6: 432 if (prefixlen == 0) 433 return (0); 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