mrtparser.c revision 1.6
1/* $OpenBSD: mrtparser.c,v 1.6 2015/01/09 08:09:39 henning 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 31void *mrt_read_msg(int, struct mrt_hdr *); 32size_t mrt_read_buf(int, void *, size_t); 33 34struct mrt_peer *mrt_parse_v2_peer(struct mrt_hdr *, void *); 35struct mrt_rib *mrt_parse_v2_rib(struct mrt_hdr *, void *); 36int mrt_parse_dump(struct mrt_hdr *, void *, struct mrt_peer **, 37 struct mrt_rib **); 38int mrt_parse_dump_mp(struct mrt_hdr *, void *, struct mrt_peer **, 39 struct mrt_rib **); 40int mrt_extract_attr(struct mrt_rib_entry *, u_char *, int, sa_family_t, 41 int); 42 43void mrt_free_peers(struct mrt_peer *); 44void mrt_free_rib(struct mrt_rib *); 45void mrt_free_bgp_state(struct mrt_bgp_state *); 46void mrt_free_bgp_msg(struct mrt_bgp_msg *); 47 48u_char *mrt_aspath_inflate(void *, u_int16_t, u_int16_t *); 49int mrt_extract_addr(void *, u_int, union mrt_addr *, sa_family_t); 50 51void * 52mrt_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 70size_t 71mrt_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 91void 92mrt_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 case MSG_PROTOCOL_BGP4MP: 174 switch (ntohs(h.subtype)) { 175 case BGP4MP_STATE_CHANGE: 176 case BGP4MP_STATE_CHANGE_AS4: 177 /* XXX p->state(s, p->arg); */ 178 errx(1, "BGP4MP subtype not yet implemented"); 179 break; 180 case BGP4MP_MESSAGE: 181 case BGP4MP_MESSAGE_AS4: 182 case BGP4MP_MESSAGE_LOCAL: 183 case BGP4MP_MESSAGE_AS4_LOCAL: 184 /* XXX p->message(m, p->arg); */ 185 errx(1, "BGP4MP subtype not yet implemented"); 186 break; 187 case BGP4MP_ENTRY: 188 if (p->dump == NULL) 189 break; 190 if (mrt_parse_dump_mp(&h, msg, &pctx, &r) == 191 0) { 192 p->dump(r, pctx, p->arg); 193 mrt_free_rib(r); 194 } 195 break; 196 default: 197 if (verbose) 198 printf("unhandled BGP4MP subtype %d\n", 199 ntohs(h.subtype)); 200 break; 201 } 202 break; 203 default: 204 if (verbose) 205 printf("unknown MRT type %d\n", ntohs(h.type)); 206 break; 207 } 208 free(msg); 209 } 210 if (pctx) 211 mrt_free_peers(pctx); 212} 213 214struct mrt_peer * 215mrt_parse_v2_peer(struct mrt_hdr *hdr, void *msg) 216{ 217 struct mrt_peer_entry *peers = NULL; 218 struct mrt_peer *p; 219 u_int8_t *b = msg; 220 u_int32_t bid, as4; 221 u_int16_t cnt, i, as2; 222 u_int len = ntohl(hdr->length); 223 224 if (len < 8) /* min msg size */ 225 return NULL; 226 227 p = calloc(1, sizeof(struct mrt_peer)); 228 if (p == NULL) 229 err(1, "calloc"); 230 231 /* collector bgp id */ 232 memcpy(&bid, b, sizeof(bid)); 233 b += sizeof(bid); 234 len -= sizeof(bid); 235 p->bgp_id = ntohl(bid); 236 237 /* view name length */ 238 memcpy(&cnt, b, sizeof(cnt)); 239 b += sizeof(cnt); 240 len -= sizeof(cnt); 241 cnt = ntohs(cnt); 242 243 /* view name */ 244 if (cnt > len) 245 goto fail; 246 if (cnt != 0) { 247 if ((p->view = malloc(cnt + 1)) == NULL) 248 err(1, "malloc"); 249 memcpy(p->view, b, cnt); 250 p->view[cnt] = 0; 251 } else 252 if ((p->view = strdup("")) == NULL) 253 err(1, "strdup"); 254 b += cnt; 255 len -= cnt; 256 257 /* peer_count */ 258 if (len < sizeof(cnt)) 259 goto fail; 260 memcpy(&cnt, b, sizeof(cnt)); 261 b += sizeof(cnt); 262 len -= sizeof(cnt); 263 cnt = ntohs(cnt); 264 265 /* peer entries */ 266 if ((peers = calloc(cnt, sizeof(struct mrt_peer_entry))) == NULL) 267 err(1, "calloc"); 268 for (i = 0; i < cnt; i++) { 269 u_int8_t type; 270 271 if (len < sizeof(u_int8_t) + sizeof(u_int32_t)) 272 goto fail; 273 type = *b++; 274 len -= 1; 275 memcpy(&bid, b, sizeof(bid)); 276 b += sizeof(bid); 277 len -= sizeof(bid); 278 peers[i].bgp_id = ntohl(bid); 279 280 if (type & MRT_DUMP_V2_PEER_BIT_I) { 281 if (mrt_extract_addr(b, len, &peers[i].addr, 282 AF_INET6) == -1) 283 goto fail; 284 b += sizeof(struct in6_addr); 285 len -= sizeof(struct in6_addr); 286 } else { 287 if (mrt_extract_addr(b, len, &peers[i].addr, 288 AF_INET) == -1) 289 goto fail; 290 b += sizeof(struct in_addr); 291 len -= sizeof(struct in_addr); 292 } 293 294 if (type & MRT_DUMP_V2_PEER_BIT_A) { 295 memcpy(&as4, b, sizeof(as4)); 296 b += sizeof(as4); 297 len -= sizeof(as4); 298 as4 = ntohl(as4); 299 } else { 300 memcpy(&as2, b, sizeof(as2)); 301 b += sizeof(as2); 302 len -= sizeof(as2); 303 as4 = ntohs(as2); 304 } 305 peers[i].asnum = as4; 306 } 307 p->peers = peers; 308 p->npeers = cnt; 309 return (p); 310fail: 311 mrt_free_peers(p); 312 free(peers); 313 return (NULL); 314} 315 316struct mrt_rib * 317mrt_parse_v2_rib(struct mrt_hdr *hdr, void *msg) 318{ 319 struct mrt_rib_entry *entries = NULL; 320 struct mrt_rib *r; 321 u_int8_t *b = msg; 322 u_int len = ntohl(hdr->length); 323 u_int32_t snum; 324 u_int16_t cnt, i; 325 u_int8_t plen; 326 327 if (len < sizeof(snum) + 1) 328 return NULL; 329 330 r = calloc(1, sizeof(struct mrt_rib)); 331 if (r == NULL) 332 err(1, "calloc"); 333 334 /* seq_num */ 335 memcpy(&snum, b, sizeof(snum)); 336 b += sizeof(snum); 337 len -= sizeof(snum); 338 r->seqnum = ntohl(snum); 339 340 switch (ntohs(hdr->subtype)) { 341 case MRT_DUMP_V2_RIB_IPV4_UNICAST: 342 case MRT_DUMP_V2_RIB_IPV4_MULTICAST: 343 plen = *b++; 344 len -= 1; 345 if (len < MRT_PREFIX_LEN(plen)) 346 goto fail; 347 r->prefix.sin.sin_family = AF_INET; 348 r->prefix.sin.sin_len = sizeof(struct sockaddr_in); 349 memcpy(&r->prefix.sin.sin_addr, b, MRT_PREFIX_LEN(plen)); 350 b += MRT_PREFIX_LEN(plen); 351 len -= MRT_PREFIX_LEN(plen); 352 r->prefixlen = plen; 353 break; 354 case MRT_DUMP_V2_RIB_IPV6_UNICAST: 355 case MRT_DUMP_V2_RIB_IPV6_MULTICAST: 356 plen = *b++; 357 len -= 1; 358 if (len < MRT_PREFIX_LEN(plen)) 359 goto fail; 360 r->prefix.sin6.sin6_family = AF_INET6; 361 r->prefix.sin6.sin6_len = sizeof(struct sockaddr_in6); 362 memcpy(&r->prefix.sin6.sin6_addr, b, MRT_PREFIX_LEN(plen)); 363 b += MRT_PREFIX_LEN(plen); 364 len -= MRT_PREFIX_LEN(plen); 365 r->prefixlen = plen; 366 break; 367 case MRT_DUMP_V2_RIB_GENERIC: 368 /* XXX unhandled */ 369 errx(1, "MRT_DUMP_V2_RIB_GENERIC subtype not yet implemented"); 370 goto fail; 371 } 372 373 /* entries count */ 374 if (len < sizeof(cnt)) 375 goto fail; 376 memcpy(&cnt, b, sizeof(cnt)); 377 b += sizeof(cnt); 378 len -= sizeof(cnt); 379 cnt = ntohs(cnt); 380 r->nentries = cnt; 381 382 /* entries */ 383 if ((entries = calloc(cnt, sizeof(struct mrt_rib_entry))) == NULL) 384 err(1, "calloc"); 385 for (i = 0; i < cnt; i++) { 386 u_int32_t otm; 387 u_int16_t pix, alen; 388 if (len < 2 * sizeof(u_int16_t) + sizeof(u_int32_t)) 389 goto fail; 390 /* peer index */ 391 memcpy(&pix, b, sizeof(pix)); 392 b += sizeof(pix); 393 len -= sizeof(pix); 394 entries[i].peer_idx = ntohs(pix); 395 396 /* originated */ 397 memcpy(&otm, b, sizeof(otm)); 398 b += sizeof(otm); 399 len -= sizeof(otm); 400 entries[i].originated = ntohl(otm); 401 402 /* attr_len */ 403 memcpy(&alen, b, sizeof(alen)); 404 b += sizeof(alen); 405 len -= sizeof(alen); 406 alen = ntohs(alen); 407 408 /* attr */ 409 if (len < alen) 410 goto fail; 411 if (mrt_extract_attr(&entries[i], b, alen, 412 r->prefix.sa.sa_family, 1) == -1) 413 goto fail; 414 b += alen; 415 len -= alen; 416 } 417 r->entries = entries; 418 return (r); 419fail: 420 mrt_free_rib(r); 421 free(entries); 422 return (NULL); 423} 424 425int 426mrt_parse_dump(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp, 427 struct mrt_rib **rp) 428{ 429 struct mrt_peer *p; 430 struct mrt_rib *r; 431 struct mrt_rib_entry *re; 432 u_int8_t *b = msg; 433 u_int len = ntohl(hdr->length); 434 u_int16_t asnum, alen; 435 436 if (*pp == NULL) { 437 *pp = calloc(1, sizeof(struct mrt_peer)); 438 if (*pp == NULL) 439 err(1, "calloc"); 440 (*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry)); 441 if ((*pp)->peers == NULL) 442 err(1, "calloc"); 443 (*pp)->npeers = 1; 444 } 445 p = *pp; 446 447 *rp = r = calloc(1, sizeof(struct mrt_rib)); 448 if (r == NULL) 449 err(1, "calloc"); 450 re = calloc(1, sizeof(struct mrt_rib_entry)); 451 if (re == NULL) 452 err(1, "calloc"); 453 r->nentries = 1; 454 r->entries = re; 455 456 if (len < 2 * sizeof(u_int16_t)) 457 goto fail; 458 /* view */ 459 b += sizeof(u_int16_t); 460 len -= sizeof(u_int16_t); 461 /* seqnum */ 462 memcpy(&r->seqnum, b, sizeof(u_int16_t)); 463 b += sizeof(u_int16_t); 464 len -= sizeof(u_int16_t); 465 r->seqnum = ntohs(r->seqnum); 466 467 switch (ntohs(hdr->subtype)) { 468 case MRT_DUMP_AFI_IP: 469 if (mrt_extract_addr(b, len, &r->prefix, AF_INET) == -1) 470 goto fail; 471 b += sizeof(struct in_addr); 472 len -= sizeof(struct in_addr); 473 break; 474 case MRT_DUMP_AFI_IPv6: 475 if (mrt_extract_addr(b, len, &r->prefix, AF_INET6) == -1) 476 goto fail; 477 b += sizeof(struct in6_addr); 478 len -= sizeof(struct in6_addr); 479 break; 480 } 481 if (len < 2 * sizeof(u_int32_t) + 2 * sizeof(u_int16_t) + 2) 482 goto fail; 483 r->prefixlen = *b++; 484 len -= 1; 485 /* status */ 486 b += 1; 487 len -= 1; 488 /* originated */ 489 memcpy(&re->originated, b, sizeof(u_int32_t)); 490 b += sizeof(u_int32_t); 491 len -= sizeof(u_int32_t); 492 re->originated = ntohl(re->originated); 493 /* peer ip */ 494 switch (ntohs(hdr->subtype)) { 495 case MRT_DUMP_AFI_IP: 496 if (mrt_extract_addr(b, len, &p->peers->addr, AF_INET) == -1) 497 goto fail; 498 b += sizeof(struct in_addr); 499 len -= sizeof(struct in_addr); 500 break; 501 case MRT_DUMP_AFI_IPv6: 502 if (mrt_extract_addr(b, len, &p->peers->addr, AF_INET6) == -1) 503 goto fail; 504 b += sizeof(struct in6_addr); 505 len -= sizeof(struct in6_addr); 506 break; 507 } 508 memcpy(&asnum, b, sizeof(asnum)); 509 b += sizeof(asnum); 510 len -= sizeof(asnum); 511 p->peers->asnum = ntohs(asnum); 512 513 memcpy(&alen, b, sizeof(alen)); 514 b += sizeof(alen); 515 len -= sizeof(alen); 516 alen = ntohs(alen); 517 518 /* attr */ 519 if (len < alen) 520 goto fail; 521 if (mrt_extract_attr(re, b, alen, r->prefix.sa.sa_family, 0) == -1) 522 goto fail; 523 b += alen; 524 len -= alen; 525 526 return (0); 527fail: 528 mrt_free_rib(r); 529 return (-1); 530} 531 532int 533mrt_parse_dump_mp(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp, 534 struct mrt_rib **rp) 535{ 536 struct mrt_peer *p; 537 struct mrt_rib *r; 538 struct mrt_rib_entry *re; 539 u_int8_t *b = msg; 540 u_int len = ntohl(hdr->length); 541 u_int16_t asnum, alen, afi; 542 u_int8_t safi, nhlen; 543 sa_family_t af; 544 545 /* just ignore the microsec field for _ET header for now */ 546 if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) { 547 b = (char *)b + sizeof(u_int32_t); 548 len -= sizeof(u_int32_t); 549 } 550 551 if (*pp == NULL) { 552 *pp = calloc(1, sizeof(struct mrt_peer)); 553 if (*pp == NULL) 554 err(1, "calloc"); 555 (*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry)); 556 if ((*pp)->peers == NULL) 557 err(1, "calloc"); 558 (*pp)->npeers = 1; 559 } 560 p = *pp; 561 562 *rp = r = calloc(1, sizeof(struct mrt_rib)); 563 if (r == NULL) 564 err(1, "calloc"); 565 re = calloc(1, sizeof(struct mrt_rib_entry)); 566 if (re == NULL) 567 err(1, "calloc"); 568 r->nentries = 1; 569 r->entries = re; 570 571 if (len < 4 * sizeof(u_int16_t)) 572 goto fail; 573 /* source AS */ 574 b += sizeof(u_int16_t); 575 len -= sizeof(u_int16_t); 576 /* dest AS */ 577 memcpy(&asnum, b, sizeof(asnum)); 578 b += sizeof(asnum); 579 len -= sizeof(asnum); 580 p->peers->asnum = ntohs(asnum); 581 /* iface index */ 582 b += sizeof(u_int16_t); 583 len -= sizeof(u_int16_t); 584 /* afi */ 585 memcpy(&afi, b, sizeof(afi)); 586 b += sizeof(afi); 587 len -= sizeof(afi); 588 afi = ntohs(afi); 589 590 /* source + dest ip */ 591 switch (afi) { 592 case MRT_DUMP_AFI_IP: 593 if (len < 2 * sizeof(struct in_addr)) 594 goto fail; 595 /* source IP */ 596 b += sizeof(struct in_addr); 597 len -= sizeof(struct in_addr); 598 /* dest IP */ 599 if (mrt_extract_addr(b, len, &p->peers->addr, AF_INET) == -1) 600 goto fail; 601 b += sizeof(struct in_addr); 602 len -= sizeof(struct in_addr); 603 break; 604 case MRT_DUMP_AFI_IPv6: 605 if (len < 2 * sizeof(struct in6_addr)) 606 goto fail; 607 /* source IP */ 608 b += sizeof(struct in6_addr); 609 len -= sizeof(struct in6_addr); 610 /* dest IP */ 611 if (mrt_extract_addr(b, len, &p->peers->addr, AF_INET6) == -1) 612 goto fail; 613 b += sizeof(struct in6_addr); 614 len -= sizeof(struct in6_addr); 615 break; 616 } 617 618 if (len < 2 * sizeof(u_int16_t) + 2 * sizeof(u_int32_t)) 619 goto fail; 620 /* view + status */ 621 b += 2 * sizeof(u_int16_t); 622 len -= 2 * sizeof(u_int16_t); 623 /* originated */ 624 memcpy(&re->originated, b, sizeof(u_int32_t)); 625 b += sizeof(u_int32_t); 626 len -= sizeof(u_int32_t); 627 re->originated = ntohl(re->originated); 628 629 /* afi */ 630 memcpy(&afi, b, sizeof(afi)); 631 b += sizeof(afi); 632 len -= sizeof(afi); 633 afi = ntohs(afi); 634 635 /* safi */ 636 safi = *b++; 637 len -= 1; 638 639 switch (afi) { 640 case MRT_DUMP_AFI_IP: 641 if (safi == 1 || safi == 2) { 642 af = AF_INET; 643 break; 644 } else if (safi == 128) { 645 af = AF_VPNv4; 646 break; 647 } 648 goto fail; 649 case MRT_DUMP_AFI_IPv6: 650 if (safi != 1 && safi != 2) 651 goto fail; 652 af = AF_INET6; 653 break; 654 default: 655 goto fail; 656 } 657 658 /* nhlen */ 659 nhlen = *b++; 660 len -= 1; 661 662 /* nexthop */ 663 if (mrt_extract_addr(b, len, &re->nexthop, af) == -1) 664 goto fail; 665 if (len < nhlen) 666 goto fail; 667 b += nhlen; 668 len -= nhlen; 669 670 if (len < 1) 671 goto fail; 672 r->prefixlen = *b++; 673 len -= 1; 674 675 /* prefix */ 676 switch (af) { 677 case AF_INET: 678 if (len < MRT_PREFIX_LEN(r->prefixlen)) 679 goto fail; 680 r->prefix.sin.sin_family = AF_INET; 681 r->prefix.sin.sin_len = sizeof(struct sockaddr_in); 682 memcpy(&r->prefix.sin.sin_addr, b, 683 MRT_PREFIX_LEN(r->prefixlen)); 684 b += MRT_PREFIX_LEN(r->prefixlen); 685 len -= MRT_PREFIX_LEN(r->prefixlen); 686 break; 687 case AF_INET6: 688 if (len < MRT_PREFIX_LEN(r->prefixlen)) 689 goto fail; 690 r->prefix.sin6.sin6_family = AF_INET6; 691 r->prefix.sin6.sin6_len = sizeof(struct sockaddr_in6); 692 memcpy(&r->prefix.sin6.sin6_addr, b, 693 MRT_PREFIX_LEN(r->prefixlen)); 694 b += MRT_PREFIX_LEN(r->prefixlen); 695 len -= MRT_PREFIX_LEN(r->prefixlen); 696 break; 697 case AF_VPNv4: 698 if (len < MRT_PREFIX_LEN(r->prefixlen)) 699 goto fail; 700 errx(1, "AF_VPNv4 handling not yet implemented"); 701 goto fail; 702 } 703 704 memcpy(&alen, b, sizeof(alen)); 705 b += sizeof(alen); 706 len -= sizeof(alen); 707 alen = ntohs(alen); 708 709 /* attr */ 710 if (len < alen) 711 goto fail; 712 if (mrt_extract_attr(re, b, alen, r->prefix.sa.sa_family, 0) == -1) 713 goto fail; 714 b += alen; 715 len -= alen; 716 717 return (0); 718fail: 719 mrt_free_rib(r); 720 return (-1); 721} 722 723int 724mrt_extract_attr(struct mrt_rib_entry *re, u_char *a, int alen, sa_family_t af, 725 int as4) 726{ 727 struct mrt_attr *ap; 728 u_int32_t tmp; 729 u_int16_t attr_len; 730 u_int8_t type, flags, *attr; 731 732 do { 733 if (alen < 3) 734 return (-1); 735 attr = a; 736 flags = *a++; 737 alen -= 1; 738 type = *a++; 739 alen -= 1; 740 741 if (flags & MRT_ATTR_EXTLEN) { 742 if (alen < 2) 743 return (-1); 744 memcpy(&attr_len, a, sizeof(attr_len)); 745 attr_len = ntohs(attr_len); 746 a += sizeof(attr_len); 747 alen -= sizeof(attr_len); 748 } else { 749 attr_len = *a++; 750 alen -= 1; 751 } 752 switch (type) { 753 case MRT_ATTR_ORIGIN: 754 if (attr_len != 1) 755 return (-1); 756 re->origin = *a; 757 break; 758 case MRT_ATTR_ASPATH: 759 if (as4) { 760 re->aspath_len = attr_len; 761 if ((re->aspath = malloc(attr_len)) == NULL) 762 err(1, "malloc"); 763 memcpy(re->aspath, a, attr_len); 764 } else { 765 re->aspath = mrt_aspath_inflate(a, attr_len, 766 &re->aspath_len); 767 if (re->aspath == NULL) 768 return (-1); 769 } 770 break; 771 case MRT_ATTR_NEXTHOP: 772 if (attr_len != 4) 773 return (-1); 774 if (af != AF_INET) 775 break; 776 memcpy(&tmp, a, sizeof(tmp)); 777 re->nexthop.sin.sin_len = sizeof(struct sockaddr_in); 778 re->nexthop.sin.sin_family = AF_INET; 779 re->nexthop.sin.sin_addr.s_addr = tmp; 780 break; 781 case MRT_ATTR_MED: 782 if (attr_len != 4) 783 return (-1); 784 memcpy(&tmp, a, sizeof(tmp)); 785 re->med = ntohl(tmp); 786 break; 787 case MRT_ATTR_LOCALPREF: 788 if (attr_len != 4) 789 return (-1); 790 memcpy(&tmp, a, sizeof(tmp)); 791 re->local_pref = ntohl(tmp); 792 break; 793 case MRT_ATTR_MP_REACH_NLRI: 794 /* 795 * XXX horrible hack: 796 * Once again IETF and the real world differ in the 797 * implementation. In short the abbreviated MP_NLRI 798 * hack in the standard is not used in real life. 799 * Detect the two cases by looking at the first byte 800 * of the payload (either the nexthop addr length (RFC) 801 * or the high byte of the AFI (old form)). If the 802 * first byte matches the expected nexthop length it 803 * is expected to be the RFC 6396 encoding. 804 */ 805 if (*a != attr_len - 1) { 806 a += 3; 807 alen -= 3; 808 attr_len -= 3; 809 } 810 switch (af) { 811 case AF_INET6: 812 if (attr_len < sizeof(struct in6_addr) + 1) 813 return (-1); 814 re->nexthop.sin6.sin6_len = 815 sizeof(struct sockaddr_in6); 816 re->nexthop.sin6.sin6_family = AF_INET6; 817 memcpy(&re->nexthop.sin6.sin6_addr, a + 1, 818 sizeof(struct in6_addr)); 819 break; 820 case AF_VPNv4: 821 if (attr_len < sizeof(u_int64_t) + 822 sizeof(struct in_addr)) 823 return (-1); 824 re->nexthop.svpn4.sv_len = 825 sizeof(struct sockaddr_vpn4); 826 re->nexthop.svpn4.sv_family = AF_VPNv4; 827 memcpy(&tmp, a + 1 + sizeof(u_int64_t), 828 sizeof(tmp)); 829 re->nexthop.svpn4.sv_addr.s_addr = tmp; 830 break; 831 } 832 break; 833 case MRT_ATTR_AS4PATH: 834 if (!as4) { 835 if (re->aspath) 836 free(re->aspath); 837 re->aspath_len = attr_len; 838 if ((re->aspath = malloc(attr_len)) == NULL) 839 err(1, "malloc"); 840 memcpy(re->aspath, a, attr_len); 841 break; 842 } 843 /* FALLTHROUGH */ 844 default: 845 re->nattrs++; 846 if (re->nattrs >= UCHAR_MAX) 847 err(1, "too many attributes"); 848 ap = reallocarray(re->attrs, 849 re->nattrs, sizeof(struct mrt_attr)); 850 if (ap == NULL) 851 err(1, "realloc"); 852 re->attrs = ap; 853 ap = re->attrs + re->nattrs - 1; 854 ap->attr_len = a + attr_len - attr; 855 if ((ap->attr = malloc(ap->attr_len)) == NULL) 856 err(1, "malloc"); 857 memcpy(ap->attr, attr, ap->attr_len); 858 break; 859 } 860 a += attr_len; 861 alen -= attr_len; 862 } while (alen > 0); 863 864 return (0); 865} 866 867void 868mrt_free_peers(struct mrt_peer *p) 869{ 870 free(p->peers); 871 free(p->view); 872 free(p); 873} 874 875void 876mrt_free_rib(struct mrt_rib *r) 877{ 878 u_int16_t i, j; 879 880 for (i = 0; i < r->nentries && r->entries; i++) { 881 for (j = 0; j < r->entries[i].nattrs; j++) 882 free(r->entries[i].attrs[j].attr); 883 free(r->entries[i].attrs); 884 free(r->entries[i].aspath); 885 } 886 887 free(r->entries); 888 free(r); 889} 890 891void 892mrt_free_bgp_state(struct mrt_bgp_state *s) 893{ 894 free(s); 895} 896 897void 898mrt_free_bgp_msg(struct mrt_bgp_msg *m) 899{ 900 free(m->msg); 901 free(m); 902} 903 904u_char * 905mrt_aspath_inflate(void *data, u_int16_t len, u_int16_t *newlen) 906{ 907 u_int8_t *seg, *nseg, *ndata; 908 u_int16_t seg_size, olen, nlen; 909 u_int8_t seg_len; 910 911 /* first calculate the length of the aspath */ 912 seg = data; 913 nlen = 0; 914 for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) { 915 seg_len = seg[1]; 916 seg_size = 2 + sizeof(u_int16_t) * seg_len; 917 nlen += 2 + sizeof(u_int32_t) * seg_len; 918 919 if (seg_size > olen) 920 return NULL; 921 } 922 923 *newlen = nlen; 924 if ((ndata = malloc(nlen)) == NULL) 925 err(1, "malloc"); 926 927 /* then copy the aspath */ 928 seg = data; 929 for (nseg = ndata; nseg < ndata + nlen; ) { 930 *nseg++ = *seg++; 931 *nseg++ = seg_len = *seg++; 932 for (; seg_len > 0; seg_len--) { 933 *nseg++ = 0; 934 *nseg++ = 0; 935 *nseg++ = *seg++; 936 *nseg++ = *seg++; 937 } 938 } 939 940 return (ndata); 941} 942 943int 944mrt_extract_addr(void *msg, u_int len, union mrt_addr *addr, sa_family_t af) 945{ 946 u_int8_t *b = msg; 947 948 switch (af) { 949 case AF_INET: 950 if (len < sizeof(struct in_addr)) 951 return (-1); 952 addr->sin.sin_family = AF_INET; 953 addr->sin.sin_len = sizeof(struct sockaddr_in); 954 memcpy(&addr->sin.sin_addr, b, sizeof(struct in_addr)); 955 return sizeof(struct in_addr); 956 case AF_INET6: 957 if (len < sizeof(struct in6_addr)) 958 return (-1); 959 addr->sin6.sin6_family = AF_INET6; 960 addr->sin6.sin6_len = sizeof(struct sockaddr_in6); 961 memcpy(&addr->sin6.sin6_addr, b, sizeof(struct in6_addr)); 962 return sizeof(struct in6_addr); 963 case AF_VPNv4: 964 if (len < sizeof(u_int64_t) + sizeof(struct in_addr)) 965 return (-1); 966 addr->svpn4.sv_len = sizeof(struct sockaddr_vpn4); 967 addr->svpn4.sv_family = AF_VPNv4; 968 memcpy(&addr->svpn4.sv_addr, b + sizeof(u_int64_t), 969 sizeof(struct in_addr)); 970 return (sizeof(u_int64_t) + sizeof(struct in_addr)); 971 default: 972 return (-1); 973 } 974} 975