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