1 /* $OpenBSD: util.c,v 1.24 2017/01/24 04:22:42 benno 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 #include "log.h" 32 33 const char *aspath_delim(u_int8_t, int); 34 35 const char * 36 log_addr(const struct bgpd_addr *addr) 37 { 38 static char buf[48]; 39 char tbuf[16]; 40 41 switch (addr->aid) { 42 case AID_INET: 43 case AID_INET6: 44 if (inet_ntop(aid2af(addr->aid), &addr->ba, buf, 45 sizeof(buf)) == NULL) 46 return ("?"); 47 return (buf); 48 case AID_VPN_IPv4: 49 if (inet_ntop(AF_INET, &addr->vpn4.addr, tbuf, 50 sizeof(tbuf)) == NULL) 51 return ("?"); 52 snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn4.rd), 53 tbuf); 54 return (buf); 55 } 56 return ("???"); 57 } 58 59 const char * 60 log_in6addr(const struct in6_addr *addr) 61 { 62 struct sockaddr_in6 sa_in6; 63 u_int16_t tmp16; 64 65 bzero(&sa_in6, sizeof(sa_in6)); 66 sa_in6.sin6_len = sizeof(sa_in6); 67 sa_in6.sin6_family = AF_INET6; 68 memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr)); 69 70 /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */ 71 if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) || 72 IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) { 73 memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16)); 74 sa_in6.sin6_scope_id = ntohs(tmp16); 75 sa_in6.sin6_addr.s6_addr[2] = 0; 76 sa_in6.sin6_addr.s6_addr[3] = 0; 77 } 78 79 return (log_sockaddr((struct sockaddr *)&sa_in6)); 80 } 81 82 const char * 83 log_sockaddr(struct sockaddr *sa) 84 { 85 static char buf[NI_MAXHOST]; 86 87 if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0, 88 NI_NUMERICHOST)) 89 return ("(unknown)"); 90 else 91 return (buf); 92 } 93 94 const char * 95 log_as(u_int32_t as) 96 { 97 static char buf[11]; /* "4294967294\0" */ 98 99 if (snprintf(buf, sizeof(buf), "%u", as) == -1) 100 return ("?"); 101 102 return (buf); 103 } 104 105 const char * 106 log_rd(u_int64_t rd) 107 { 108 static char buf[32]; 109 struct in_addr addr; 110 u_int32_t u32; 111 u_int16_t u16; 112 113 rd = betoh64(rd); 114 switch (rd >> 48) { 115 case EXT_COMMUNITY_TWO_AS: 116 u32 = rd & 0xffffffff; 117 u16 = (rd >> 32) & 0xffff; 118 snprintf(buf, sizeof(buf), "rd %hu:%u", u16, u32); 119 break; 120 case EXT_COMMUNITY_FOUR_AS: 121 u32 = (rd >> 16) & 0xffffffff; 122 u16 = rd & 0xffff; 123 snprintf(buf, sizeof(buf), "rd %s:%hu", log_as(u32), u16); 124 break; 125 case EXT_COMMUNITY_IPV4: 126 u32 = (rd >> 16) & 0xffffffff; 127 u16 = rd & 0xffff; 128 addr.s_addr = htonl(u32); 129 snprintf(buf, sizeof(buf), "rd %s:%hu", inet_ntoa(addr), u16); 130 break; 131 default: 132 return ("rd ?"); 133 } 134 return (buf); 135 } 136 137 /* NOTE: this function does not check if the type/subtype combo is 138 * actually valid. */ 139 const char * 140 log_ext_subtype(u_int8_t subtype) 141 { 142 static char etype[6]; 143 144 switch (subtype) { 145 case EXT_COMMUNITY_ROUTE_TGT: 146 return ("rt"); /* route target */ 147 case EXT_COMMUNITY_ROUTE_ORIG: 148 return ("soo"); /* source of origin */ 149 case EXT_COMMUNITY_OSPF_DOM_ID: 150 return ("odi"); /* ospf domain id */ 151 case EXT_COMMUNITY_OSPF_RTR_TYPE: 152 return ("ort"); /* ospf route type */ 153 case EXT_COMMUNITY_OSPF_RTR_ID: 154 return ("ori"); /* ospf router id */ 155 case EXT_COMMUNITY_BGP_COLLECT: 156 return ("bdc"); /* bgp data collection */ 157 default: 158 snprintf(etype, sizeof(etype), "[%u]", subtype); 159 return (etype); 160 } 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 /* we need to be able to search more than one as */ 320 int 321 aspath_match(void *data, u_int16_t len, struct filter_as *f, u_int32_t match) 322 { 323 u_int8_t *seg; 324 int final; 325 u_int16_t seg_size; 326 u_int8_t i, seg_len; 327 u_int32_t as; 328 329 if (f->type == AS_EMPTY) { 330 if (len == 0) 331 return (1); 332 else 333 return (0); 334 } 335 336 seg = data; 337 for (; len > 0; len -= seg_size, seg += seg_size) { 338 seg_len = seg[1]; 339 seg_size = 2 + sizeof(u_int32_t) * seg_len; 340 341 final = (len == seg_size); 342 343 /* just check the first (leftmost) AS */ 344 if (f->type == AS_PEER) { 345 as = aspath_extract(seg, 0); 346 if (as_compare(f->op, as, match, f->as_min, f->as_max)) 347 return (1); 348 else 349 return (0); 350 } 351 /* just check the final (rightmost) AS */ 352 if (f->type == AS_SOURCE) { 353 /* not yet in the final segment */ 354 if (!final) 355 continue; 356 as = aspath_extract(seg, seg_len - 1); 357 if (as_compare(f->op, as, match, f->as_min, f->as_max)) 358 return (1); 359 else 360 return (0); 361 } 362 /* AS_TRANSIT or AS_ALL */ 363 for (i = 0; i < seg_len; i++) { 364 /* 365 * the source (rightmost) AS is excluded from 366 * AS_TRANSIT matches. 367 */ 368 if (final && i == seg_len - 1 && f->type == AS_TRANSIT) 369 return (0); 370 as = aspath_extract(seg, i); 371 if (as_compare(f->op, as, match, f->as_min, f->as_max)) 372 return (1); 373 } 374 } 375 return (0); 376 } 377 378 int 379 as_compare(u_int8_t op, u_int32_t as, u_int32_t match, u_int32_t as_min, 380 u_int32_t as_max) 381 { 382 if ((op == OP_NONE || op == OP_EQ) && as == match) 383 return (1); 384 else if (op == OP_NE && as != match) 385 return (1); 386 else if (op == OP_RANGE && as >= as_min && as <= as_max) 387 return (1); 388 else if (op == OP_XRANGE && as > as_min && as < as_max) 389 return (1); 390 return (0); 391 } 392 393 /* 394 * Extract the asnum out of the as segment at the specified position. 395 * Direct access is not possible because of non-aligned reads. 396 * ATTENTION: no bounds checks are done. 397 */ 398 u_int32_t 399 aspath_extract(const void *seg, int pos) 400 { 401 const u_char *ptr = seg; 402 u_int32_t as; 403 404 ptr += 2 + sizeof(u_int32_t) * pos; 405 memcpy(&as, ptr, sizeof(u_int32_t)); 406 return (ntohl(as)); 407 } 408 409 /* 410 * This function will have undefined behaviour if the passed in prefixlen is 411 * to large for the respective bgpd_addr address family. 412 */ 413 int 414 prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, 415 int prefixlen) 416 { 417 in_addr_t mask, aa, ba; 418 int i; 419 u_int8_t m; 420 421 if (a->aid != b->aid) 422 return (a->aid - b->aid); 423 424 switch (a->aid) { 425 case AID_INET: 426 if (prefixlen == 0) 427 return (0); 428 if (prefixlen > 32) 429 return (-1); 430 mask = htonl(prefixlen2mask(prefixlen)); 431 aa = ntohl(a->v4.s_addr & mask); 432 ba = ntohl(b->v4.s_addr & mask); 433 if (aa != ba) 434 return (aa - ba); 435 return (0); 436 case AID_INET6: 437 if (prefixlen == 0) 438 return (0); 439 if (prefixlen > 128) 440 return (-1); 441 for (i = 0; i < prefixlen / 8; i++) 442 if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) 443 return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); 444 i = prefixlen % 8; 445 if (i) { 446 m = 0xff00 >> i; 447 if ((a->v6.s6_addr[prefixlen / 8] & m) != 448 (b->v6.s6_addr[prefixlen / 8] & m)) 449 return ((a->v6.s6_addr[prefixlen / 8] & m) - 450 (b->v6.s6_addr[prefixlen / 8] & m)); 451 } 452 return (0); 453 case AID_VPN_IPv4: 454 if (prefixlen > 32) 455 return (-1); 456 if (betoh64(a->vpn4.rd) > betoh64(b->vpn4.rd)) 457 return (1); 458 if (betoh64(a->vpn4.rd) < betoh64(b->vpn4.rd)) 459 return (-1); 460 mask = htonl(prefixlen2mask(prefixlen)); 461 aa = ntohl(a->vpn4.addr.s_addr & mask); 462 ba = ntohl(b->vpn4.addr.s_addr & mask); 463 if (aa != ba) 464 return (aa - ba); 465 if (a->vpn4.labellen > b->vpn4.labellen) 466 return (1); 467 if (a->vpn4.labellen < b->vpn4.labellen) 468 return (-1); 469 return (memcmp(a->vpn4.labelstack, b->vpn4.labelstack, 470 a->vpn4.labellen)); 471 } 472 return (-1); 473 } 474 475 in_addr_t 476 prefixlen2mask(u_int8_t prefixlen) 477 { 478 if (prefixlen == 0) 479 return (0); 480 481 return (0xffffffff << (32 - prefixlen)); 482 } 483 484 void 485 inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) 486 { 487 struct in6_addr mask; 488 int i; 489 490 bzero(&mask, sizeof(mask)); 491 for (i = 0; i < prefixlen / 8; i++) 492 mask.s6_addr[i] = 0xff; 493 i = prefixlen % 8; 494 if (i) 495 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 496 497 for (i = 0; i < 16; i++) 498 dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; 499 } 500 501 /* address family translation functions */ 502 const struct aid aid_vals[AID_MAX] = AID_VALS; 503 504 const char * 505 aid2str(u_int8_t aid) 506 { 507 if (aid < AID_MAX) 508 return (aid_vals[aid].name); 509 return ("unknown AID"); 510 } 511 512 int 513 aid2afi(u_int8_t aid, u_int16_t *afi, u_int8_t *safi) 514 { 515 if (aid < AID_MAX) { 516 *afi = aid_vals[aid].afi; 517 *safi = aid_vals[aid].safi; 518 return (0); 519 } 520 return (-1); 521 } 522 523 int 524 afi2aid(u_int16_t afi, u_int8_t safi, u_int8_t *aid) 525 { 526 u_int8_t i; 527 528 for (i = 0; i < AID_MAX; i++) 529 if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) { 530 *aid = i; 531 return (0); 532 } 533 534 return (-1); 535 } 536 537 sa_family_t 538 aid2af(u_int8_t aid) 539 { 540 if (aid < AID_MAX) 541 return (aid_vals[aid].af); 542 return (AF_UNSPEC); 543 } 544 545 int 546 af2aid(sa_family_t af, u_int8_t safi, u_int8_t *aid) 547 { 548 u_int8_t i; 549 550 if (safi == 0) /* default to unicast subclass */ 551 safi = SAFI_UNICAST; 552 553 for (i = 0; i < AID_MAX; i++) 554 if (aid_vals[i].af == af && aid_vals[i].safi == safi) { 555 *aid = i; 556 return (0); 557 } 558 559 return (-1); 560 } 561 562 struct sockaddr * 563 addr2sa(struct bgpd_addr *addr, u_int16_t port) 564 { 565 static struct sockaddr_storage ss; 566 struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; 567 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; 568 569 if (addr->aid == AID_UNSPEC) 570 return (NULL); 571 572 bzero(&ss, sizeof(ss)); 573 switch (addr->aid) { 574 case AID_INET: 575 sa_in->sin_family = AF_INET; 576 sa_in->sin_len = sizeof(struct sockaddr_in); 577 sa_in->sin_addr.s_addr = addr->v4.s_addr; 578 sa_in->sin_port = htons(port); 579 break; 580 case AID_INET6: 581 sa_in6->sin6_family = AF_INET6; 582 sa_in6->sin6_len = sizeof(struct sockaddr_in6); 583 memcpy(&sa_in6->sin6_addr, &addr->v6, 584 sizeof(sa_in6->sin6_addr)); 585 sa_in6->sin6_port = htons(port); 586 sa_in6->sin6_scope_id = addr->scope_id; 587 break; 588 } 589 590 return ((struct sockaddr *)&ss); 591 } 592 593 void 594 sa2addr(struct sockaddr *sa, struct bgpd_addr *addr) 595 { 596 struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; 597 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; 598 599 bzero(addr, sizeof(*addr)); 600 switch (sa->sa_family) { 601 case AF_INET: 602 addr->aid = AID_INET; 603 memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4)); 604 break; 605 case AF_INET6: 606 addr->aid = AID_INET6; 607 memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6)); 608 addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */ 609 break; 610 } 611 } 612