1 /* $OpenBSD: mrtparser.c,v 1.3 2012/03/26 20:40:32 claudio Exp $ */ 2 /* 3 * Copyright (c) 2011 Claudio Jeker <claudio@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 #include <sys/types.h> 18 #include <sys/socket.h> 19 #include <netinet/in.h> 20 #include <err.h> 21 #include <errno.h> 22 #include <limits.h> 23 #include <stdlib.h> 24 #include <stdio.h> 25 #include <string.h> 26 #include <unistd.h> 27 28 #include "mrt.h" 29 #include "mrtparser.h" 30 31 void *mrt_read_msg(int, struct mrt_hdr *); 32 size_t mrt_read_buf(int, void *, size_t); 33 34 struct mrt_peer *mrt_parse_v2_peer(struct mrt_hdr *, void *); 35 struct mrt_rib *mrt_parse_v2_rib(struct mrt_hdr *, void *); 36 int mrt_parse_dump(struct mrt_hdr *, void *, struct mrt_peer **, 37 struct mrt_rib **); 38 int mrt_parse_dump_mp(struct mrt_hdr *, void *, struct mrt_peer **, 39 struct mrt_rib **); 40 int mrt_extract_attr(struct mrt_rib_entry *, u_char *, int, sa_family_t, 41 int); 42 43 void mrt_free_peers(struct mrt_peer *); 44 void mrt_free_rib(struct mrt_rib *); 45 void mrt_free_bgp_state(struct mrt_bgp_state *); 46 void mrt_free_bgp_msg(struct mrt_bgp_msg *); 47 48 u_char *mrt_aspath_inflate(void *, u_int16_t, u_int16_t *); 49 int mrt_extract_addr(void *, u_int, union mrt_addr *, sa_family_t); 50 51 void * 52 mrt_read_msg(int fd, struct mrt_hdr *hdr) 53 { 54 void *buf; 55 56 bzero(hdr, sizeof(*hdr)); 57 if (mrt_read_buf(fd, hdr, sizeof(*hdr)) != sizeof(*hdr)) 58 return (NULL); 59 60 if ((buf = malloc(ntohl(hdr->length))) == NULL) 61 err(1, "malloc(%d)", hdr->length); 62 63 if (mrt_read_buf(fd, buf, ntohl(hdr->length)) != ntohl(hdr->length)) { 64 free(buf); 65 return (NULL); 66 } 67 return (buf); 68 } 69 70 size_t 71 mrt_read_buf(int fd, void *buf, size_t len) 72 { 73 char *b = buf; 74 ssize_t n; 75 76 while (len > 0) { 77 if ((n = read(fd, b, len)) == -1) { 78 if (errno == EINTR) 79 continue; 80 err(1, "read"); 81 } 82 if (n == 0) 83 break; 84 b += n; 85 len -= n; 86 } 87 88 return (b - (char *)buf); 89 } 90 91 void 92 mrt_parse(int fd, struct mrt_parser *p, int verbose) 93 { 94 struct mrt_hdr h; 95 struct mrt_peer *pctx = NULL; 96 struct mrt_rib *r; 97 void *msg; 98 99 while ((msg = mrt_read_msg(fd, &h))) { 100 switch (ntohs(h.type)) { 101 case MSG_NULL: 102 case MSG_START: 103 case MSG_DIE: 104 case MSG_I_AM_DEAD: 105 case MSG_PEER_DOWN: 106 case MSG_PROTOCOL_BGP: 107 case MSG_PROTOCOL_IDRP: 108 case MSG_PROTOCOL_BGP4PLUS: 109 case MSG_PROTOCOL_BGP4PLUS1: 110 if (verbose) 111 printf("deprecated MRT type %d\n", 112 ntohs(h.type)); 113 break; 114 case MSG_PROTOCOL_RIP: 115 case MSG_PROTOCOL_RIPNG: 116 case MSG_PROTOCOL_OSPF: 117 case MSG_PROTOCOL_ISIS_ET: 118 case MSG_PROTOCOL_ISIS: 119 case MSG_PROTOCOL_OSPFV3_ET: 120 case MSG_PROTOCOL_OSPFV3: 121 if (verbose) 122 printf("unsuported MRT type %d\n", 123 ntohs(h.type)); 124 break; 125 case MSG_TABLE_DUMP: 126 switch (ntohs(h.subtype)) { 127 case MRT_DUMP_AFI_IP: 128 case MRT_DUMP_AFI_IPv6: 129 if (p->dump == NULL) 130 break; 131 if (mrt_parse_dump(&h, msg, &pctx, &r) == 0) { 132 p->dump(r, pctx, p->arg); 133 mrt_free_rib(r); 134 } 135 break; 136 default: 137 if (verbose) 138 printf("unknown AFI %d in table dump\n", 139 ntohs(h.subtype)); 140 break; 141 } 142 break; 143 case MSG_TABLE_DUMP_V2: 144 switch (ntohs(h.subtype)) { 145 case MRT_DUMP_V2_PEER_INDEX_TABLE: 146 if (p->dump == NULL) 147 break; 148 if (pctx) 149 mrt_free_peers(pctx); 150 pctx = mrt_parse_v2_peer(&h, msg); 151 break; 152 case MRT_DUMP_V2_RIB_IPV4_UNICAST: 153 case MRT_DUMP_V2_RIB_IPV4_MULTICAST: 154 case MRT_DUMP_V2_RIB_IPV6_UNICAST: 155 case MRT_DUMP_V2_RIB_IPV6_MULTICAST: 156 case MRT_DUMP_V2_RIB_GENERIC: 157 if (p->dump == NULL) 158 break; 159 r = mrt_parse_v2_rib(&h, msg); 160 if (r) { 161 p->dump(r, pctx, p->arg); 162 mrt_free_rib(r); 163 } 164 break; 165 default: 166 if (verbose) 167 printf("unhandled BGP4MP subtype %d\n", 168 ntohs(h.subtype)); 169 break; 170 } 171 break; 172 case MSG_PROTOCOL_BGP4MP_ET: 173 /* currently just ignore the microsec field */ 174 msg = (char *)msg + sizeof(u_int32_t); 175 h.length -= sizeof(u_int32_t); 176 /* FALLTHROUGH */ 177 case MSG_PROTOCOL_BGP4MP: 178 switch (ntohs(h.subtype)) { 179 case BGP4MP_STATE_CHANGE: 180 case BGP4MP_STATE_CHANGE_AS4: 181 /* XXX p->state(s, p->arg); */ 182 errx(1, "BGP4MP subtype not yet implemented"); 183 break; 184 case BGP4MP_MESSAGE: 185 case BGP4MP_MESSAGE_AS4: 186 case BGP4MP_MESSAGE_LOCAL: 187 case BGP4MP_MESSAGE_AS4_LOCAL: 188 /* XXX p->message(m, p->arg); */ 189 errx(1, "BGP4MP subtype not yet implemented"); 190 break; 191 case BGP4MP_ENTRY: 192 if (p->dump == NULL) 193 break; 194 if (mrt_parse_dump_mp(&h, msg, &pctx, &r) == 195 0) { 196 p->dump(r, pctx, p->arg); 197 mrt_free_rib(r); 198 } 199 break; 200 default: 201 if (verbose) 202 printf("unhandled BGP4MP subtype %d\n", 203 ntohs(h.subtype)); 204 break; 205 } 206 break; 207 default: 208 if (verbose) 209 printf("unknown MRT type %d\n", ntohs(h.type)); 210 break; 211 } 212 free(msg); 213 } 214 if (pctx) 215 mrt_free_peers(pctx); 216 } 217 218 struct mrt_peer * 219 mrt_parse_v2_peer(struct mrt_hdr *hdr, void *msg) 220 { 221 struct mrt_peer_entry *peers; 222 struct mrt_peer *p; 223 u_int8_t *b = msg; 224 u_int32_t bid, as4; 225 u_int16_t cnt, i, as2; 226 u_int len = ntohl(hdr->length); 227 228 if (len < 8) /* min msg size */ 229 return NULL; 230 231 p = calloc(1, sizeof(struct mrt_peer)); 232 if (p == NULL) 233 err(1, "calloc"); 234 235 /* collector bgp id */ 236 memcpy(&bid, b, sizeof(bid)); 237 b += sizeof(bid); 238 len -= sizeof(bid); 239 p->bgp_id = ntohl(bid); 240 241 /* view name length */ 242 memcpy(&cnt, b, sizeof(cnt)); 243 b += sizeof(cnt); 244 len -= sizeof(cnt); 245 cnt = ntohs(cnt); 246 247 /* view name */ 248 if (cnt > len) 249 goto fail; 250 if (cnt != 0) { 251 if ((p->view = malloc(cnt + 1)) == NULL) 252 err(1, "malloc"); 253 memcpy(p->view, b, cnt); 254 p->view[cnt] = 0; 255 } else 256 if ((p->view = strdup("")) == NULL) 257 err(1, "strdup"); 258 b += cnt; 259 len -= cnt; 260 261 /* peer_count */ 262 if (len < sizeof(cnt)) 263 goto fail; 264 memcpy(&cnt, b, sizeof(cnt)); 265 b += sizeof(cnt); 266 len -= sizeof(cnt); 267 cnt = ntohs(cnt); 268 269 /* peer entries */ 270 if ((peers = calloc(cnt, sizeof(struct mrt_peer_entry))) == NULL) 271 err(1, "calloc"); 272 for (i = 0; i < cnt; i++) { 273 u_int8_t type; 274 275 if (len < sizeof(u_int8_t) + sizeof(u_int32_t)) 276 goto fail; 277 type = *b++; 278 len -= 1; 279 memcpy(&bid, b, sizeof(bid)); 280 b += sizeof(bid); 281 len -= sizeof(bid); 282 peers[i].bgp_id = ntohl(bid); 283 284 if (type & MRT_DUMP_V2_PEER_BIT_I) { 285 if (mrt_extract_addr(b, len, &peers[i].addr, 286 AF_INET6) == -1) 287 goto fail; 288 b += sizeof(struct in6_addr); 289 len -= sizeof(struct in6_addr); 290 } else { 291 if (mrt_extract_addr(b, len, &peers[i].addr, 292 AF_INET) == -1) 293 goto fail; 294 b += sizeof(struct in_addr); 295 len -= sizeof(struct in_addr); 296 } 297 298 if (type & MRT_DUMP_V2_PEER_BIT_A) { 299 memcpy(&as4, b, sizeof(as4)); 300 b += sizeof(as4); 301 len -= sizeof(as4); 302 as4 = ntohl(as4); 303 } else { 304 memcpy(&as2, b, sizeof(as2)); 305 b += sizeof(as2); 306 len -= sizeof(as2); 307 as4 = ntohs(as2); 308 } 309 peers[i].asnum = as4; 310 } 311 p->peers = peers; 312 p->npeers = cnt; 313 return (p); 314 fail: 315 mrt_free_peers(p); 316 return (NULL); 317 } 318 319 struct mrt_rib * 320 mrt_parse_v2_rib(struct mrt_hdr *hdr, void *msg) 321 { 322 struct mrt_rib_entry *entries; 323 struct mrt_rib *r; 324 u_int8_t *b = msg; 325 u_int len = ntohl(hdr->length); 326 u_int32_t snum; 327 u_int16_t cnt, i; 328 u_int8_t plen; 329 330 if (len < sizeof(snum) + 1) 331 return NULL; 332 333 r = calloc(1, sizeof(struct mrt_rib)); 334 if (r == NULL) 335 err(1, "calloc"); 336 337 /* seq_num */ 338 memcpy(&snum, b, sizeof(snum)); 339 b += sizeof(snum); 340 len -= sizeof(snum); 341 r->seqnum = ntohl(snum); 342 343 switch (ntohs(hdr->subtype)) { 344 case MRT_DUMP_V2_RIB_IPV4_UNICAST: 345 case MRT_DUMP_V2_RIB_IPV4_MULTICAST: 346 plen = *b++; 347 len -= 1; 348 if (len < MRT_PREFIX_LEN(plen)) 349 goto fail; 350 r->prefix.sin.sin_family = AF_INET; 351 r->prefix.sin.sin_len = sizeof(struct sockaddr_in); 352 memcpy(&r->prefix.sin.sin_addr, b, MRT_PREFIX_LEN(plen)); 353 b += MRT_PREFIX_LEN(plen); 354 len -= MRT_PREFIX_LEN(plen); 355 r->prefixlen = plen; 356 break; 357 case MRT_DUMP_V2_RIB_IPV6_UNICAST: 358 case MRT_DUMP_V2_RIB_IPV6_MULTICAST: 359 plen = *b++; 360 len -= 1; 361 if (len < MRT_PREFIX_LEN(plen)) 362 goto fail; 363 r->prefix.sin6.sin6_family = AF_INET6; 364 r->prefix.sin6.sin6_len = sizeof(struct sockaddr_in6); 365 memcpy(&r->prefix.sin6.sin6_addr, b, MRT_PREFIX_LEN(plen)); 366 b += MRT_PREFIX_LEN(plen); 367 len -= MRT_PREFIX_LEN(plen); 368 r->prefixlen = plen; 369 break; 370 case MRT_DUMP_V2_RIB_GENERIC: 371 /* XXX unhandled */ 372 errx(1, "MRT_DUMP_V2_RIB_GENERIC subtype not yet implemented"); 373 goto fail; 374 } 375 376 /* entries count */ 377 if (len < sizeof(cnt)) 378 goto fail; 379 memcpy(&cnt, b, sizeof(cnt)); 380 b += sizeof(cnt); 381 len -= sizeof(cnt); 382 cnt = ntohs(cnt); 383 r->nentries = cnt; 384 385 /* entries */ 386 if ((entries = calloc(cnt, sizeof(struct mrt_rib_entry))) == NULL) 387 err(1, "calloc"); 388 for (i = 0; i < cnt; i++) { 389 u_int32_t otm; 390 u_int16_t pix, alen; 391 if (len < 2 * sizeof(u_int16_t) + sizeof(u_int32_t)) 392 goto fail; 393 /* peer index */ 394 memcpy(&pix, b, sizeof(pix)); 395 b += sizeof(pix); 396 len -= sizeof(pix); 397 entries[i].peer_idx = ntohs(pix); 398 399 /* originated */ 400 memcpy(&otm, b, sizeof(otm)); 401 b += sizeof(otm); 402 len -= sizeof(otm); 403 entries[i].originated = ntohl(otm); 404 405 /* attr_len */ 406 memcpy(&alen, b, sizeof(alen)); 407 b += sizeof(alen); 408 len -= sizeof(alen); 409 alen = ntohs(alen); 410 411 /* attr */ 412 if (len < alen) 413 goto fail; 414 if (mrt_extract_attr(&entries[i], b, alen, 415 r->prefix.sa.sa_family, 1) == -1) 416 goto fail; 417 b += alen; 418 len -= alen; 419 } 420 r->entries = entries; 421 return (r); 422 fail: 423 mrt_free_rib(r); 424 return (NULL); 425 } 426 427 int 428 mrt_parse_dump(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp, 429 struct mrt_rib **rp) 430 { 431 struct mrt_peer *p; 432 struct mrt_rib *r; 433 struct mrt_rib_entry *re; 434 u_int8_t *b = msg; 435 u_int len = ntohl(hdr->length); 436 u_int16_t asnum, alen; 437 438 if (*pp == NULL) { 439 *pp = calloc(1, sizeof(struct mrt_peer)); 440 if (*pp == NULL) 441 err(1, "calloc"); 442 (*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry)); 443 if ((*pp)->peers == NULL) 444 err(1, "calloc"); 445 (*pp)->npeers = 1; 446 } 447 p = *pp; 448 449 *rp = r = calloc(1, sizeof(struct mrt_rib)); 450 if (r == NULL) 451 err(1, "calloc"); 452 re = calloc(1, sizeof(struct mrt_rib_entry)); 453 if (re == NULL) 454 err(1, "calloc"); 455 r->nentries = 1; 456 r->entries = re; 457 458 if (len < 2 * sizeof(u_int16_t)) 459 goto fail; 460 /* view */ 461 b += sizeof(u_int16_t); 462 len -= sizeof(u_int16_t); 463 /* seqnum */ 464 memcpy(&r->seqnum, b, sizeof(u_int16_t)); 465 b += sizeof(u_int16_t); 466 len -= sizeof(u_int16_t); 467 r->seqnum = ntohs(r->seqnum); 468 469 switch (ntohs(hdr->subtype)) { 470 case MRT_DUMP_AFI_IP: 471 if (mrt_extract_addr(b, len, &r->prefix, AF_INET) == -1) 472 goto fail; 473 b += sizeof(struct in_addr); 474 len -= sizeof(struct in_addr); 475 break; 476 case MRT_DUMP_AFI_IPv6: 477 if (mrt_extract_addr(b, len, &r->prefix, AF_INET6) == -1) 478 goto fail; 479 b += sizeof(struct in6_addr); 480 len -= sizeof(struct in6_addr); 481 break; 482 } 483 if (len < 2 * sizeof(u_int32_t) + 2 * sizeof(u_int16_t) + 2) 484 goto fail; 485 r->prefixlen = *b++; 486 len -= 1; 487 /* status */ 488 b += 1; 489 len -= 1; 490 /* originated */ 491 memcpy(&re->originated, b, sizeof(u_int32_t)); 492 b += sizeof(u_int32_t); 493 len -= sizeof(u_int32_t); 494 re->originated = ntohl(re->originated); 495 /* peer ip */ 496 switch (ntohs(hdr->subtype)) { 497 case MRT_DUMP_AFI_IP: 498 if (mrt_extract_addr(b, len, &p->peers->addr, AF_INET) == -1) 499 goto fail; 500 b += sizeof(struct in_addr); 501 len -= sizeof(struct in_addr); 502 break; 503 case MRT_DUMP_AFI_IPv6: 504 if (mrt_extract_addr(b, len, &p->peers->addr, AF_INET6) == -1) 505 goto fail; 506 b += sizeof(struct in6_addr); 507 len -= sizeof(struct in6_addr); 508 break; 509 } 510 memcpy(&asnum, b, sizeof(asnum)); 511 b += sizeof(asnum); 512 len -= sizeof(asnum); 513 p->peers->asnum = ntohs(asnum); 514 515 memcpy(&alen, b, sizeof(alen)); 516 b += sizeof(alen); 517 len -= sizeof(alen); 518 alen = ntohs(alen); 519 520 /* attr */ 521 if (len < alen) 522 goto fail; 523 if (mrt_extract_attr(re, b, alen, r->prefix.sa.sa_family, 0) == -1) 524 goto fail; 525 b += alen; 526 len -= alen; 527 528 return (0); 529 fail: 530 mrt_free_rib(r); 531 return (-1); 532 } 533 534 int 535 mrt_parse_dump_mp(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp, 536 struct mrt_rib **rp) 537 { 538 struct mrt_peer *p; 539 struct mrt_rib *r; 540 struct mrt_rib_entry *re; 541 u_int8_t *b = msg; 542 u_int len = ntohl(hdr->length); 543 u_int16_t asnum, alen, afi; 544 u_int8_t safi, nhlen; 545 sa_family_t af; 546 547 if (*pp == NULL) { 548 *pp = calloc(1, sizeof(struct mrt_peer)); 549 if (*pp == NULL) 550 err(1, "calloc"); 551 (*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry)); 552 if ((*pp)->peers == NULL) 553 err(1, "calloc"); 554 (*pp)->npeers = 1; 555 } 556 p = *pp; 557 558 *rp = r = calloc(1, sizeof(struct mrt_rib)); 559 if (r == NULL) 560 err(1, "calloc"); 561 re = calloc(1, sizeof(struct mrt_rib_entry)); 562 if (re == NULL) 563 err(1, "calloc"); 564 r->nentries = 1; 565 r->entries = re; 566 567 if (len < 4 * sizeof(u_int16_t)) 568 goto fail; 569 /* source AS */ 570 b += sizeof(u_int16_t); 571 len -= sizeof(u_int16_t); 572 /* dest AS */ 573 memcpy(&asnum, b, sizeof(asnum)); 574 b += sizeof(asnum); 575 len -= sizeof(asnum); 576 p->peers->asnum = ntohs(asnum); 577 /* iface index */ 578 b += sizeof(u_int16_t); 579 len -= sizeof(u_int16_t); 580 /* afi */ 581 memcpy(&afi, b, sizeof(afi)); 582 b += sizeof(afi); 583 len -= sizeof(afi); 584 afi = ntohs(afi); 585 586 /* source + dest ip */ 587 switch (afi) { 588 case MRT_DUMP_AFI_IP: 589 if (len < 2 * sizeof(struct in_addr)) 590 goto fail; 591 /* source IP */ 592 b += sizeof(struct in_addr); 593 len -= sizeof(struct in_addr); 594 /* dest IP */ 595 if (mrt_extract_addr(b, len, &p->peers->addr, AF_INET) == -1) 596 goto fail; 597 b += sizeof(struct in_addr); 598 len -= sizeof(struct in_addr); 599 break; 600 case MRT_DUMP_AFI_IPv6: 601 if (len < 2 * sizeof(struct in6_addr)) 602 goto fail; 603 /* source IP */ 604 b += sizeof(struct in6_addr); 605 len -= sizeof(struct in6_addr); 606 /* dest IP */ 607 if (mrt_extract_addr(b, len, &p->peers->addr, AF_INET6) == -1) 608 goto fail; 609 b += sizeof(struct in6_addr); 610 len -= sizeof(struct in6_addr); 611 break; 612 } 613 614 if (len < 2 * sizeof(u_int16_t) + 2 * sizeof(u_int32_t)) 615 goto fail; 616 /* view + status */ 617 b += 2 * sizeof(u_int16_t); 618 len -= 2 * sizeof(u_int16_t); 619 /* originated */ 620 memcpy(&re->originated, b, sizeof(u_int32_t)); 621 b += sizeof(u_int32_t); 622 len -= sizeof(u_int32_t); 623 re->originated = ntohl(re->originated); 624 625 /* afi */ 626 memcpy(&afi, b, sizeof(afi)); 627 b += sizeof(afi); 628 len -= sizeof(afi); 629 afi = ntohs(afi); 630 631 /* safi */ 632 safi = *b++; 633 len -= 1; 634 635 switch (afi) { 636 case MRT_DUMP_AFI_IP: 637 if (safi == 1 || safi == 2) { 638 af = AF_INET; 639 break; 640 } else if (safi == 128) { 641 af = AF_VPNv4; 642 break; 643 } 644 goto fail; 645 case MRT_DUMP_AFI_IPv6: 646 if (safi != 1 && safi != 2) 647 goto fail; 648 af = AF_INET6; 649 break; 650 default: 651 goto fail; 652 } 653 654 /* nhlen */ 655 nhlen = *b++; 656 len -= 1; 657 658 /* nexthop */ 659 if (mrt_extract_addr(b, len, &re->nexthop, af) == -1) 660 goto fail; 661 if (len < nhlen) 662 goto fail; 663 b += nhlen; 664 len -= nhlen; 665 666 if (len < 1) 667 goto fail; 668 r->prefixlen = *b++; 669 len -= 1; 670 671 /* prefix */ 672 switch (af) { 673 case AF_INET: 674 if (len < MRT_PREFIX_LEN(r->prefixlen)) 675 goto fail; 676 r->prefix.sin.sin_family = AF_INET; 677 r->prefix.sin.sin_len = sizeof(struct sockaddr_in); 678 memcpy(&r->prefix.sin.sin_addr, b, 679 MRT_PREFIX_LEN(r->prefixlen)); 680 b += MRT_PREFIX_LEN(r->prefixlen); 681 len -= MRT_PREFIX_LEN(r->prefixlen); 682 break; 683 case AF_INET6: 684 if (len < MRT_PREFIX_LEN(r->prefixlen)) 685 goto fail; 686 r->prefix.sin6.sin6_family = AF_INET6; 687 r->prefix.sin6.sin6_len = sizeof(struct sockaddr_in6); 688 memcpy(&r->prefix.sin6.sin6_addr, b, 689 MRT_PREFIX_LEN(r->prefixlen)); 690 b += MRT_PREFIX_LEN(r->prefixlen); 691 len -= MRT_PREFIX_LEN(r->prefixlen); 692 break; 693 case AF_VPNv4: 694 if (len < MRT_PREFIX_LEN(r->prefixlen)) 695 goto fail; 696 errx(1, "AF_VPNv4 handling not yet implemented"); 697 goto fail; 698 } 699 700 memcpy(&alen, b, sizeof(alen)); 701 b += sizeof(alen); 702 len -= sizeof(alen); 703 alen = ntohs(alen); 704 705 /* attr */ 706 if (len < alen) 707 goto fail; 708 if (mrt_extract_attr(re, b, alen, r->prefix.sa.sa_family, 0) == -1) 709 goto fail; 710 b += alen; 711 len -= alen; 712 713 return (0); 714 fail: 715 mrt_free_rib(r); 716 return (-1); 717 } 718 719 int 720 mrt_extract_attr(struct mrt_rib_entry *re, u_char *a, int alen, sa_family_t af, 721 int as4) 722 { 723 struct mrt_attr *ap; 724 u_int32_t tmp; 725 u_int16_t attr_len; 726 u_int8_t type, flags, *attr; 727 728 do { 729 if (alen < 3) 730 return (-1); 731 attr = a; 732 flags = *a++; 733 alen -= 1; 734 type = *a++; 735 alen -= 1; 736 737 if (flags & MRT_ATTR_EXTLEN) { 738 if (alen < 2) 739 return (-1); 740 memcpy(&attr_len, a, sizeof(attr_len)); 741 attr_len = ntohs(attr_len); 742 a += sizeof(attr_len); 743 alen -= sizeof(attr_len); 744 } else { 745 attr_len = *a++; 746 alen -= 1; 747 } 748 switch (type) { 749 case MRT_ATTR_ORIGIN: 750 if (attr_len != 1) 751 return (-1); 752 re->origin = *a; 753 break; 754 case MRT_ATTR_ASPATH: 755 if (as4) { 756 re->aspath_len = attr_len; 757 if ((re->aspath = malloc(attr_len)) == NULL) 758 err(1, "malloc"); 759 memcpy(re->aspath, a, attr_len); 760 } else { 761 re->aspath = mrt_aspath_inflate(a, attr_len, 762 &re->aspath_len); 763 if (re->aspath == NULL) 764 return (-1); 765 } 766 break; 767 case MRT_ATTR_NEXTHOP: 768 if (attr_len != 4) 769 return (-1); 770 if (af != AF_INET) 771 break; 772 memcpy(&tmp, a, sizeof(tmp)); 773 re->nexthop.sin.sin_len = sizeof(struct sockaddr_in); 774 re->nexthop.sin.sin_family = AF_INET; 775 re->nexthop.sin.sin_addr.s_addr = tmp; 776 break; 777 case MRT_ATTR_MED: 778 if (attr_len != 4) 779 return (-1); 780 memcpy(&tmp, a, sizeof(tmp)); 781 re->med = ntohl(tmp); 782 break; 783 case MRT_ATTR_LOCALPREF: 784 if (attr_len != 4) 785 return (-1); 786 memcpy(&tmp, a, sizeof(tmp)); 787 re->local_pref = ntohl(tmp); 788 break; 789 case MRT_ATTR_MP_REACH_NLRI: 790 /* 791 * XXX horrible hack: 792 * Once again IETF and the real world differ in the 793 * implementation. In short the abbreviated MP_NLRI 794 * hack in the standard is not used in real life. 795 * Detect the two cases by looking at the first byte 796 * of the payload (either the nexthop addr length (RFC) 797 * or the high byte of the AFI (old form)). If the 798 * first byte matches the expected nexthop length it 799 * is expected to be the RFC 6396 encoding. 800 */ 801 if (*a != attr_len - 1) { 802 a += 3; 803 alen -= 3; 804 attr_len -= 3; 805 } 806 switch (af) { 807 case AF_INET6: 808 if (attr_len < sizeof(struct in6_addr) + 1) 809 return (-1); 810 re->nexthop.sin6.sin6_len = 811 sizeof(struct sockaddr_in6); 812 re->nexthop.sin6.sin6_family = AF_INET6; 813 memcpy(&re->nexthop.sin6.sin6_addr, a + 1, 814 sizeof(struct in6_addr)); 815 break; 816 case AF_VPNv4: 817 if (attr_len < sizeof(u_int64_t) + 818 sizeof(struct in_addr)) 819 return (-1); 820 re->nexthop.svpn4.sv_len = 821 sizeof(struct sockaddr_vpn4); 822 re->nexthop.svpn4.sv_family = AF_VPNv4; 823 memcpy(&tmp, a + 1 + sizeof(u_int64_t), 824 sizeof(tmp)); 825 re->nexthop.svpn4.sv_addr.s_addr = tmp; 826 break; 827 } 828 break; 829 case MRT_ATTR_AS4PATH: 830 if (!as4) { 831 if (re->aspath) 832 free(re->aspath); 833 re->aspath_len = attr_len; 834 if ((re->aspath = malloc(attr_len)) == NULL) 835 err(1, "malloc"); 836 memcpy(re->aspath, a, attr_len); 837 break; 838 } 839 /* FALLTHROUGH */ 840 default: 841 re->nattrs++; 842 if (re->nattrs >= UCHAR_MAX) 843 err(1, "too many attributes"); 844 ap = realloc(re->attrs, 845 re->nattrs * sizeof(struct mrt_attr)); 846 if (ap == NULL) 847 err(1, "realloc"); 848 re->attrs = ap; 849 ap = re->attrs + re->nattrs - 1; 850 ap->attr_len = a + attr_len - attr; 851 if ((ap->attr = malloc(ap->attr_len)) == NULL) 852 err(1, "malloc"); 853 memcpy(ap->attr, attr, ap->attr_len); 854 break; 855 } 856 a += attr_len; 857 alen -= attr_len; 858 } while (alen > 0); 859 860 return (0); 861 } 862 863 void 864 mrt_free_peers(struct mrt_peer *p) 865 { 866 free(p->peers); 867 free(p->view); 868 free(p); 869 } 870 871 void 872 mrt_free_rib(struct mrt_rib *r) 873 { 874 u_int16_t i, j; 875 876 for (i = 0; i < r->nentries && r->entries; i++) { 877 for (j = 0; j < r->entries[i].nattrs; j++) 878 free(r->entries[i].attrs[j].attr); 879 free(r->entries[i].attrs); 880 free(r->entries[i].aspath); 881 } 882 883 free(r->entries); 884 free(r); 885 } 886 887 void 888 mrt_free_bgp_state(struct mrt_bgp_state *s) 889 { 890 free(s); 891 } 892 893 void 894 mrt_free_bgp_msg(struct mrt_bgp_msg *m) 895 { 896 free(m->msg); 897 free(m); 898 } 899 900 u_char * 901 mrt_aspath_inflate(void *data, u_int16_t len, u_int16_t *newlen) 902 { 903 u_int8_t *seg, *nseg, *ndata; 904 u_int16_t seg_size, olen, nlen; 905 u_int8_t seg_len; 906 907 /* first calculate the length of the aspath */ 908 seg = data; 909 nlen = 0; 910 for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) { 911 seg_len = seg[1]; 912 seg_size = 2 + sizeof(u_int16_t) * seg_len; 913 nlen += 2 + sizeof(u_int32_t) * seg_len; 914 915 if (seg_size > olen) 916 return NULL; 917 } 918 919 *newlen = nlen; 920 if ((ndata = malloc(nlen)) == NULL) 921 err(1, "malloc"); 922 923 /* then copy the aspath */ 924 seg = data; 925 for (nseg = ndata; nseg < ndata + nlen; ) { 926 *nseg++ = *seg++; 927 *nseg++ = seg_len = *seg++; 928 for (; seg_len > 0; seg_len--) { 929 *nseg++ = 0; 930 *nseg++ = 0; 931 *nseg++ = *seg++; 932 *nseg++ = *seg++; 933 } 934 } 935 936 return (ndata); 937 } 938 939 int 940 mrt_extract_addr(void *msg, u_int len, union mrt_addr *addr, sa_family_t af) 941 { 942 u_int8_t *b = msg; 943 944 switch (af) { 945 case AF_INET: 946 if (len < sizeof(struct in_addr)) 947 return (-1); 948 addr->sin.sin_family = AF_INET; 949 addr->sin.sin_len = sizeof(struct sockaddr_in); 950 memcpy(&addr->sin.sin_addr, b, sizeof(struct in_addr)); 951 return sizeof(struct in_addr); 952 case AF_INET6: 953 if (len < sizeof(struct in6_addr)) 954 return (-1); 955 addr->sin6.sin6_family = AF_INET6; 956 addr->sin6.sin6_len = sizeof(struct sockaddr_in6); 957 memcpy(&addr->sin6.sin6_addr, b, sizeof(struct in6_addr)); 958 return sizeof(struct in6_addr); 959 case AF_VPNv4: 960 if (len < sizeof(u_int64_t) + sizeof(struct in_addr)) 961 return (-1); 962 addr->svpn4.sv_len = sizeof(struct sockaddr_vpn4); 963 addr->svpn4.sv_family = AF_VPNv4; 964 memcpy(&addr->svpn4.sv_addr, b + sizeof(u_int64_t), 965 sizeof(struct in_addr)); 966 return (sizeof(u_int64_t) + sizeof(struct in_addr)); 967 default: 968 return (-1); 969 } 970 } 971