mrtparser.c revision 1.12
1/* $OpenBSD: mrtparser.c,v 1.12 2019/06/28 05:22:13 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 <time.h> 27#include <unistd.h> 28 29#include "mrt.h" 30#include "mrtparser.h" 31 32void *mrt_read_msg(int, struct mrt_hdr *); 33size_t mrt_read_buf(int, void *, size_t); 34 35struct mrt_peer *mrt_parse_v2_peer(struct mrt_hdr *, void *); 36struct mrt_rib *mrt_parse_v2_rib(struct mrt_hdr *, void *, int); 37int mrt_parse_dump(struct mrt_hdr *, void *, struct mrt_peer **, 38 struct mrt_rib **); 39int mrt_parse_dump_mp(struct mrt_hdr *, void *, struct mrt_peer **, 40 struct mrt_rib **, int); 41int mrt_extract_attr(struct mrt_rib_entry *, u_char *, int, u_int8_t, 42 int); 43 44void mrt_free_peers(struct mrt_peer *); 45void mrt_free_rib(struct mrt_rib *); 46void mrt_free_bgp_state(struct mrt_bgp_state *); 47void mrt_free_bgp_msg(struct mrt_bgp_msg *); 48 49u_char *mrt_aspath_inflate(void *, u_int16_t, u_int16_t *); 50int mrt_extract_addr(void *, u_int, struct bgpd_addr *, u_int8_t); 51int mrt_extract_prefix(void *, u_int, u_int8_t, struct bgpd_addr *, 52 u_int8_t *, int); 53 54struct mrt_bgp_state *mrt_parse_state(struct mrt_hdr *, void *, int); 55struct mrt_bgp_msg *mrt_parse_msg(struct mrt_hdr *, void *, int); 56 57void * 58mrt_read_msg(int fd, struct mrt_hdr *hdr) 59{ 60 void *buf; 61 62 bzero(hdr, sizeof(*hdr)); 63 if (mrt_read_buf(fd, hdr, sizeof(*hdr)) != sizeof(*hdr)) 64 return (NULL); 65 66 if ((buf = malloc(ntohl(hdr->length))) == NULL) 67 err(1, "malloc(%d)", hdr->length); 68 69 if (mrt_read_buf(fd, buf, ntohl(hdr->length)) != ntohl(hdr->length)) { 70 free(buf); 71 return (NULL); 72 } 73 return (buf); 74} 75 76size_t 77mrt_read_buf(int fd, void *buf, size_t len) 78{ 79 char *b = buf; 80 ssize_t n; 81 82 while (len > 0) { 83 if ((n = read(fd, b, len)) == -1) { 84 if (errno == EINTR) 85 continue; 86 err(1, "read"); 87 } 88 if (n == 0) 89 break; 90 b += n; 91 len -= n; 92 } 93 94 return (b - (char *)buf); 95} 96 97void 98mrt_parse(int fd, struct mrt_parser *p, int verbose) 99{ 100 struct mrt_hdr h; 101 struct mrt_peer *pctx = NULL; 102 struct mrt_rib *r; 103 struct mrt_bgp_state *s; 104 struct mrt_bgp_msg *m; 105 void *msg; 106 107 while ((msg = mrt_read_msg(fd, &h))) { 108 switch (ntohs(h.type)) { 109 case MSG_NULL: 110 case MSG_START: 111 case MSG_DIE: 112 case MSG_I_AM_DEAD: 113 case MSG_PEER_DOWN: 114 case MSG_PROTOCOL_BGP: 115 case MSG_PROTOCOL_IDRP: 116 case MSG_PROTOCOL_BGP4PLUS: 117 case MSG_PROTOCOL_BGP4PLUS1: 118 if (verbose) 119 printf("deprecated MRT type %d\n", 120 ntohs(h.type)); 121 break; 122 case MSG_PROTOCOL_RIP: 123 case MSG_PROTOCOL_RIPNG: 124 case MSG_PROTOCOL_OSPF: 125 case MSG_PROTOCOL_ISIS_ET: 126 case MSG_PROTOCOL_ISIS: 127 case MSG_PROTOCOL_OSPFV3_ET: 128 case MSG_PROTOCOL_OSPFV3: 129 if (verbose) 130 printf("unsuported MRT type %d\n", 131 ntohs(h.type)); 132 break; 133 case MSG_TABLE_DUMP: 134 switch (ntohs(h.subtype)) { 135 case MRT_DUMP_AFI_IP: 136 case MRT_DUMP_AFI_IPv6: 137 if (p->dump == NULL) 138 break; 139 if (mrt_parse_dump(&h, msg, &pctx, &r) == 0) { 140 if (p->dump) 141 p->dump(r, pctx, p->arg); 142 mrt_free_rib(r); 143 } 144 break; 145 default: 146 if (verbose) 147 printf("unknown AFI %d in table dump\n", 148 ntohs(h.subtype)); 149 break; 150 } 151 break; 152 case MSG_TABLE_DUMP_V2: 153 switch (ntohs(h.subtype)) { 154 case MRT_DUMP_V2_PEER_INDEX_TABLE: 155 if (p->dump == NULL) 156 break; 157 if (pctx) 158 mrt_free_peers(pctx); 159 pctx = mrt_parse_v2_peer(&h, msg); 160 break; 161 case MRT_DUMP_V2_RIB_IPV4_UNICAST: 162 case MRT_DUMP_V2_RIB_IPV4_MULTICAST: 163 case MRT_DUMP_V2_RIB_IPV6_UNICAST: 164 case MRT_DUMP_V2_RIB_IPV6_MULTICAST: 165 case MRT_DUMP_V2_RIB_GENERIC: 166 if (p->dump == NULL) 167 break; 168 r = mrt_parse_v2_rib(&h, msg, verbose); 169 if (r) { 170 if (p->dump) 171 p->dump(r, pctx, p->arg); 172 mrt_free_rib(r); 173 } 174 break; 175 default: 176 if (verbose) 177 printf("unhandled DUMP_V2 subtype %d\n", 178 ntohs(h.subtype)); 179 break; 180 } 181 break; 182 case MSG_PROTOCOL_BGP4MP_ET: 183 case MSG_PROTOCOL_BGP4MP: 184 switch (ntohs(h.subtype)) { 185 case BGP4MP_STATE_CHANGE: 186 case BGP4MP_STATE_CHANGE_AS4: 187 if ((s = mrt_parse_state(&h, msg, verbose))) { 188 if (p->state) 189 p->state(s, p->arg); 190 free(s); 191 } 192 break; 193 case BGP4MP_MESSAGE: 194 case BGP4MP_MESSAGE_AS4: 195 case BGP4MP_MESSAGE_LOCAL: 196 case BGP4MP_MESSAGE_AS4_LOCAL: 197 if ((m = mrt_parse_msg(&h, msg, verbose))) { 198 if (p->message) 199 p->message(m, p->arg); 200 free(m->msg); 201 free(m); 202 } 203 break; 204 case BGP4MP_ENTRY: 205 if (p->dump == NULL) 206 break; 207 if (mrt_parse_dump_mp(&h, msg, &pctx, &r, 208 verbose) == 0) { 209 if (p->dump) 210 p->dump(r, pctx, p->arg); 211 mrt_free_rib(r); 212 } 213 break; 214 default: 215 if (verbose) 216 printf("unhandled BGP4MP subtype %d\n", 217 ntohs(h.subtype)); 218 break; 219 } 220 break; 221 default: 222 if (verbose) 223 printf("unknown MRT type %d\n", ntohs(h.type)); 224 break; 225 } 226 free(msg); 227 } 228 if (pctx) 229 mrt_free_peers(pctx); 230} 231 232static int 233mrt_afi2aid(int afi, int safi, int verbose) 234{ 235 switch (afi) { 236 case MRT_DUMP_AFI_IP: 237 if (safi == -1 || safi == 1 || safi == 2) 238 return AID_INET; 239 else if (safi == 128) 240 return AID_VPN_IPv4; 241 break; 242 case MRT_DUMP_AFI_IPv6: 243 if (safi == -1 || safi == 1 || safi == 2) 244 return AID_INET6; 245 else if (safi == 128) 246 return AID_VPN_IPv6; 247 break; 248 default: 249 break; 250 } 251 if (verbose) 252 printf("unhandled AFI/SAFI %d/%d\n", afi, safi); 253 return AID_UNSPEC; 254} 255 256struct mrt_peer * 257mrt_parse_v2_peer(struct mrt_hdr *hdr, void *msg) 258{ 259 struct mrt_peer_entry *peers = NULL; 260 struct mrt_peer *p; 261 u_int8_t *b = msg; 262 u_int32_t bid, as4; 263 u_int16_t cnt, i, as2; 264 u_int len = ntohl(hdr->length); 265 266 if (len < 8) /* min msg size */ 267 return NULL; 268 269 p = calloc(1, sizeof(struct mrt_peer)); 270 if (p == NULL) 271 err(1, "calloc"); 272 273 /* collector bgp id */ 274 memcpy(&bid, b, sizeof(bid)); 275 b += sizeof(bid); 276 len -= sizeof(bid); 277 p->bgp_id = ntohl(bid); 278 279 /* view name length */ 280 memcpy(&cnt, b, sizeof(cnt)); 281 b += sizeof(cnt); 282 len -= sizeof(cnt); 283 cnt = ntohs(cnt); 284 285 /* view name */ 286 if (cnt > len) 287 goto fail; 288 if (cnt != 0) { 289 if ((p->view = malloc(cnt + 1)) == NULL) 290 err(1, "malloc"); 291 memcpy(p->view, b, cnt); 292 p->view[cnt] = 0; 293 } else 294 if ((p->view = strdup("")) == NULL) 295 err(1, "strdup"); 296 b += cnt; 297 len -= cnt; 298 299 /* peer_count */ 300 if (len < sizeof(cnt)) 301 goto fail; 302 memcpy(&cnt, b, sizeof(cnt)); 303 b += sizeof(cnt); 304 len -= sizeof(cnt); 305 cnt = ntohs(cnt); 306 307 /* peer entries */ 308 if ((peers = calloc(cnt, sizeof(struct mrt_peer_entry))) == NULL) 309 err(1, "calloc"); 310 for (i = 0; i < cnt; i++) { 311 u_int8_t type; 312 313 if (len < sizeof(u_int8_t) + sizeof(u_int32_t)) 314 goto fail; 315 type = *b++; 316 len -= 1; 317 memcpy(&bid, b, sizeof(bid)); 318 b += sizeof(bid); 319 len -= sizeof(bid); 320 peers[i].bgp_id = ntohl(bid); 321 322 if (type & MRT_DUMP_V2_PEER_BIT_I) { 323 if (mrt_extract_addr(b, len, &peers[i].addr, 324 AID_INET6) == -1) 325 goto fail; 326 b += sizeof(struct in6_addr); 327 len -= sizeof(struct in6_addr); 328 } else { 329 if (mrt_extract_addr(b, len, &peers[i].addr, 330 AID_INET) == -1) 331 goto fail; 332 b += sizeof(struct in_addr); 333 len -= sizeof(struct in_addr); 334 } 335 336 if (type & MRT_DUMP_V2_PEER_BIT_A) { 337 memcpy(&as4, b, sizeof(as4)); 338 b += sizeof(as4); 339 len -= sizeof(as4); 340 as4 = ntohl(as4); 341 } else { 342 memcpy(&as2, b, sizeof(as2)); 343 b += sizeof(as2); 344 len -= sizeof(as2); 345 as4 = ntohs(as2); 346 } 347 peers[i].asnum = as4; 348 } 349 p->peers = peers; 350 p->npeers = cnt; 351 return (p); 352fail: 353 mrt_free_peers(p); 354 free(peers); 355 return (NULL); 356} 357 358struct mrt_rib * 359mrt_parse_v2_rib(struct mrt_hdr *hdr, void *msg, int verbose) 360{ 361 struct mrt_rib_entry *entries = NULL; 362 struct mrt_rib *r; 363 u_int8_t *b = msg; 364 u_int len = ntohl(hdr->length); 365 u_int32_t snum; 366 u_int16_t cnt, i, afi; 367 u_int8_t safi, aid; 368 int ret; 369 370 if (len < sizeof(snum) + 1) 371 return NULL; 372 373 r = calloc(1, sizeof(struct mrt_rib)); 374 if (r == NULL) 375 err(1, "calloc"); 376 377 /* seq_num */ 378 memcpy(&snum, b, sizeof(snum)); 379 b += sizeof(snum); 380 len -= sizeof(snum); 381 r->seqnum = ntohl(snum); 382 383 switch (ntohs(hdr->subtype)) { 384 case MRT_DUMP_V2_RIB_IPV4_UNICAST: 385 case MRT_DUMP_V2_RIB_IPV4_MULTICAST: 386 /* prefix */ 387 ret = mrt_extract_prefix(b, len, AID_INET, &r->prefix, 388 &r->prefixlen, verbose); 389 if (ret == 1) 390 goto fail; 391 break; 392 case MRT_DUMP_V2_RIB_IPV6_UNICAST: 393 case MRT_DUMP_V2_RIB_IPV6_MULTICAST: 394 /* prefix */ 395 ret = mrt_extract_prefix(b, len, AID_INET6, &r->prefix, 396 &r->prefixlen, verbose); 397 if (ret == 1) 398 goto fail; 399 break; 400 case MRT_DUMP_V2_RIB_GENERIC: 401 /* fetch AFI/SAFI pair */ 402 memcpy(&afi, b, sizeof(afi)); 403 b += sizeof(afi); 404 len -= sizeof(afi); 405 afi = ntohs(afi); 406 407 safi = *b++; 408 len -= 1; 409 410 if ((aid = mrt_afi2aid(afi, safi, verbose)) == AID_UNSPEC) 411 goto fail; 412 413 /* prefix */ 414 ret = mrt_extract_prefix(b, len, aid, &r->prefix, 415 &r->prefixlen, verbose); 416 if (ret == 1) 417 goto fail; 418 break; 419 } 420 421 /* adjust length */ 422 b += ret; 423 len -= ret; 424 425 /* entries count */ 426 if (len < sizeof(cnt)) 427 goto fail; 428 memcpy(&cnt, b, sizeof(cnt)); 429 b += sizeof(cnt); 430 len -= sizeof(cnt); 431 cnt = ntohs(cnt); 432 r->nentries = cnt; 433 434 /* entries */ 435 if ((entries = calloc(cnt, sizeof(struct mrt_rib_entry))) == NULL) 436 err(1, "calloc"); 437 for (i = 0; i < cnt; i++) { 438 u_int32_t otm; 439 u_int16_t pix, alen; 440 if (len < 2 * sizeof(u_int16_t) + sizeof(u_int32_t)) 441 goto fail; 442 /* peer index */ 443 memcpy(&pix, b, sizeof(pix)); 444 b += sizeof(pix); 445 len -= sizeof(pix); 446 entries[i].peer_idx = ntohs(pix); 447 448 /* originated */ 449 memcpy(&otm, b, sizeof(otm)); 450 b += sizeof(otm); 451 len -= sizeof(otm); 452 entries[i].originated = ntohl(otm); 453 454 /* attr_len */ 455 memcpy(&alen, b, sizeof(alen)); 456 b += sizeof(alen); 457 len -= sizeof(alen); 458 alen = ntohs(alen); 459 460 /* attr */ 461 if (len < alen) 462 goto fail; 463 if (mrt_extract_attr(&entries[i], b, alen, 464 r->prefix.aid, 1) == -1) 465 goto fail; 466 b += alen; 467 len -= alen; 468 } 469 r->entries = entries; 470 return (r); 471fail: 472 mrt_free_rib(r); 473 free(entries); 474 return (NULL); 475} 476 477int 478mrt_parse_dump(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp, 479 struct mrt_rib **rp) 480{ 481 struct mrt_peer *p; 482 struct mrt_rib *r; 483 struct mrt_rib_entry *re; 484 u_int8_t *b = msg; 485 u_int len = ntohl(hdr->length); 486 u_int16_t asnum, alen; 487 488 if (*pp == NULL) { 489 *pp = calloc(1, sizeof(struct mrt_peer)); 490 if (*pp == NULL) 491 err(1, "calloc"); 492 (*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry)); 493 if ((*pp)->peers == NULL) 494 err(1, "calloc"); 495 (*pp)->npeers = 1; 496 } 497 p = *pp; 498 499 *rp = r = calloc(1, sizeof(struct mrt_rib)); 500 if (r == NULL) 501 err(1, "calloc"); 502 re = calloc(1, sizeof(struct mrt_rib_entry)); 503 if (re == NULL) 504 err(1, "calloc"); 505 r->nentries = 1; 506 r->entries = re; 507 508 if (len < 2 * sizeof(u_int16_t)) 509 goto fail; 510 /* view */ 511 b += sizeof(u_int16_t); 512 len -= sizeof(u_int16_t); 513 /* seqnum */ 514 memcpy(&r->seqnum, b, sizeof(u_int16_t)); 515 b += sizeof(u_int16_t); 516 len -= sizeof(u_int16_t); 517 r->seqnum = ntohs(r->seqnum); 518 519 switch (ntohs(hdr->subtype)) { 520 case MRT_DUMP_AFI_IP: 521 if (mrt_extract_addr(b, len, &r->prefix, AID_INET) == -1) 522 goto fail; 523 b += sizeof(struct in_addr); 524 len -= sizeof(struct in_addr); 525 break; 526 case MRT_DUMP_AFI_IPv6: 527 if (mrt_extract_addr(b, len, &r->prefix, AID_INET6) == -1) 528 goto fail; 529 b += sizeof(struct in6_addr); 530 len -= sizeof(struct in6_addr); 531 break; 532 } 533 if (len < 2 * sizeof(u_int32_t) + 2 * sizeof(u_int16_t) + 2) 534 goto fail; 535 r->prefixlen = *b++; 536 len -= 1; 537 /* status */ 538 b += 1; 539 len -= 1; 540 /* originated */ 541 memcpy(&re->originated, b, sizeof(u_int32_t)); 542 b += sizeof(u_int32_t); 543 len -= sizeof(u_int32_t); 544 re->originated = ntohl(re->originated); 545 /* peer ip */ 546 switch (ntohs(hdr->subtype)) { 547 case MRT_DUMP_AFI_IP: 548 if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET) == -1) 549 goto fail; 550 b += sizeof(struct in_addr); 551 len -= sizeof(struct in_addr); 552 break; 553 case MRT_DUMP_AFI_IPv6: 554 if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET6) == -1) 555 goto fail; 556 b += sizeof(struct in6_addr); 557 len -= sizeof(struct in6_addr); 558 break; 559 } 560 memcpy(&asnum, b, sizeof(asnum)); 561 b += sizeof(asnum); 562 len -= sizeof(asnum); 563 p->peers->asnum = ntohs(asnum); 564 565 memcpy(&alen, b, sizeof(alen)); 566 b += sizeof(alen); 567 len -= sizeof(alen); 568 alen = ntohs(alen); 569 570 /* attr */ 571 if (len < alen) 572 goto fail; 573 if (mrt_extract_attr(re, b, alen, r->prefix.aid, 0) == -1) 574 goto fail; 575 b += alen; 576 len -= alen; 577 578 return (0); 579fail: 580 mrt_free_rib(r); 581 return (-1); 582} 583 584int 585mrt_parse_dump_mp(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp, 586 struct mrt_rib **rp, int verbose) 587{ 588 struct mrt_peer *p; 589 struct mrt_rib *r; 590 struct mrt_rib_entry *re; 591 u_int8_t *b = msg; 592 u_int len = ntohl(hdr->length); 593 u_int16_t asnum, alen, afi; 594 u_int8_t safi, nhlen, aid; 595 int ret; 596 597 /* just ignore the microsec field for _ET header for now */ 598 if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) { 599 b = (char *)b + sizeof(u_int32_t); 600 len -= sizeof(u_int32_t); 601 } 602 603 if (*pp == NULL) { 604 *pp = calloc(1, sizeof(struct mrt_peer)); 605 if (*pp == NULL) 606 err(1, "calloc"); 607 (*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry)); 608 if ((*pp)->peers == NULL) 609 err(1, "calloc"); 610 (*pp)->npeers = 1; 611 } 612 p = *pp; 613 614 *rp = r = calloc(1, sizeof(struct mrt_rib)); 615 if (r == NULL) 616 err(1, "calloc"); 617 re = calloc(1, sizeof(struct mrt_rib_entry)); 618 if (re == NULL) 619 err(1, "calloc"); 620 r->nentries = 1; 621 r->entries = re; 622 623 if (len < 4 * sizeof(u_int16_t)) 624 goto fail; 625 /* source AS */ 626 b += sizeof(u_int16_t); 627 len -= sizeof(u_int16_t); 628 /* dest AS */ 629 memcpy(&asnum, b, sizeof(asnum)); 630 b += sizeof(asnum); 631 len -= sizeof(asnum); 632 p->peers->asnum = ntohs(asnum); 633 /* iface index */ 634 b += sizeof(u_int16_t); 635 len -= sizeof(u_int16_t); 636 /* afi */ 637 memcpy(&afi, b, sizeof(afi)); 638 b += sizeof(afi); 639 len -= sizeof(afi); 640 afi = ntohs(afi); 641 642 /* source + dest ip */ 643 switch (afi) { 644 case MRT_DUMP_AFI_IP: 645 if (len < 2 * sizeof(struct in_addr)) 646 goto fail; 647 /* source IP */ 648 b += sizeof(struct in_addr); 649 len -= sizeof(struct in_addr); 650 /* dest IP */ 651 if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET) == -1) 652 goto fail; 653 b += sizeof(struct in_addr); 654 len -= sizeof(struct in_addr); 655 break; 656 case MRT_DUMP_AFI_IPv6: 657 if (len < 2 * sizeof(struct in6_addr)) 658 goto fail; 659 /* source IP */ 660 b += sizeof(struct in6_addr); 661 len -= sizeof(struct in6_addr); 662 /* dest IP */ 663 if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET6) == -1) 664 goto fail; 665 b += sizeof(struct in6_addr); 666 len -= sizeof(struct in6_addr); 667 break; 668 } 669 670 if (len < 2 * sizeof(u_int16_t) + 2 * sizeof(u_int32_t)) 671 goto fail; 672 /* view + status */ 673 b += 2 * sizeof(u_int16_t); 674 len -= 2 * sizeof(u_int16_t); 675 /* originated */ 676 memcpy(&re->originated, b, sizeof(u_int32_t)); 677 b += sizeof(u_int32_t); 678 len -= sizeof(u_int32_t); 679 re->originated = ntohl(re->originated); 680 681 /* afi */ 682 memcpy(&afi, b, sizeof(afi)); 683 b += sizeof(afi); 684 len -= sizeof(afi); 685 afi = ntohs(afi); 686 687 /* safi */ 688 safi = *b++; 689 len -= 1; 690 691 if ((aid = mrt_afi2aid(afi, safi, verbose)) == AID_UNSPEC) 692 goto fail; 693 694 /* nhlen */ 695 nhlen = *b++; 696 len -= 1; 697 698 /* nexthop */ 699 if (mrt_extract_addr(b, len, &re->nexthop, aid) == -1) 700 goto fail; 701 if (len < nhlen) 702 goto fail; 703 b += nhlen; 704 len -= nhlen; 705 706 /* prefix */ 707 ret = mrt_extract_prefix(b, len, aid, &r->prefix, &r->prefixlen, 708 verbose); 709 if (ret == 1) 710 goto fail; 711 b += ret; 712 len -= ret; 713 714 memcpy(&alen, b, sizeof(alen)); 715 b += sizeof(alen); 716 len -= sizeof(alen); 717 alen = ntohs(alen); 718 719 /* attr */ 720 if (len < alen) 721 goto fail; 722 if (mrt_extract_attr(re, b, alen, r->prefix.aid, 0) == -1) 723 goto fail; 724 b += alen; 725 len -= alen; 726 727 return (0); 728fail: 729 mrt_free_rib(r); 730 return (-1); 731} 732 733int 734mrt_extract_attr(struct mrt_rib_entry *re, u_char *a, int alen, u_int8_t aid, 735 int as4) 736{ 737 struct mrt_attr *ap; 738 u_int32_t tmp; 739 u_int16_t attr_len; 740 u_int8_t type, flags, *attr; 741 742 do { 743 if (alen < 3) 744 return (-1); 745 attr = a; 746 flags = *a++; 747 alen -= 1; 748 type = *a++; 749 alen -= 1; 750 751 if (flags & MRT_ATTR_EXTLEN) { 752 if (alen < 2) 753 return (-1); 754 memcpy(&attr_len, a, sizeof(attr_len)); 755 attr_len = ntohs(attr_len); 756 a += sizeof(attr_len); 757 alen -= sizeof(attr_len); 758 } else { 759 attr_len = *a++; 760 alen -= 1; 761 } 762 switch (type) { 763 case MRT_ATTR_ORIGIN: 764 if (attr_len != 1) 765 return (-1); 766 re->origin = *a; 767 break; 768 case MRT_ATTR_ASPATH: 769 if (as4) { 770 re->aspath_len = attr_len; 771 if ((re->aspath = malloc(attr_len)) == NULL) 772 err(1, "malloc"); 773 memcpy(re->aspath, a, attr_len); 774 } else { 775 re->aspath = mrt_aspath_inflate(a, attr_len, 776 &re->aspath_len); 777 if (re->aspath == NULL) 778 return (-1); 779 } 780 break; 781 case MRT_ATTR_NEXTHOP: 782 if (attr_len != 4) 783 return (-1); 784 if (aid != AID_INET) 785 break; 786 memcpy(&tmp, a, sizeof(tmp)); 787 re->nexthop.aid = AID_INET; 788 re->nexthop.v4.s_addr = tmp; 789 break; 790 case MRT_ATTR_MED: 791 if (attr_len != 4) 792 return (-1); 793 memcpy(&tmp, a, sizeof(tmp)); 794 re->med = ntohl(tmp); 795 break; 796 case MRT_ATTR_LOCALPREF: 797 if (attr_len != 4) 798 return (-1); 799 memcpy(&tmp, a, sizeof(tmp)); 800 re->local_pref = ntohl(tmp); 801 break; 802 case MRT_ATTR_MP_REACH_NLRI: 803 /* 804 * XXX horrible hack: 805 * Once again IETF and the real world differ in the 806 * implementation. In short the abbreviated MP_NLRI 807 * hack in the standard is not used in real life. 808 * Detect the two cases by looking at the first byte 809 * of the payload (either the nexthop addr length (RFC) 810 * or the high byte of the AFI (old form)). If the 811 * first byte matches the expected nexthop length it 812 * is expected to be the RFC 6396 encoding. 813 */ 814 if (*a != attr_len - 1) { 815 a += 3; 816 alen -= 3; 817 attr_len -= 3; 818 } 819 switch (aid) { 820 case AID_INET6: 821 if (attr_len < sizeof(struct in6_addr) + 1) 822 return (-1); 823 re->nexthop.aid = aid; 824 memcpy(&re->nexthop.v6, a + 1, 825 sizeof(struct in6_addr)); 826 break; 827 case AID_VPN_IPv4: 828 if (attr_len < sizeof(u_int64_t) + 829 sizeof(struct in_addr)) 830 return (-1); 831 re->nexthop.aid = aid; 832 memcpy(&tmp, a + 1 + sizeof(u_int64_t), 833 sizeof(tmp)); 834 re->nexthop.vpn4.addr.s_addr = tmp; 835 break; 836 case AID_VPN_IPv6: 837 if (attr_len < sizeof(u_int64_t) + 838 sizeof(struct in6_addr)) 839 return (-1); 840 re->nexthop.aid = aid; 841 memcpy(&re->nexthop.vpn6.addr, 842 a + 1 + sizeof(u_int64_t), 843 sizeof(struct in6_addr)); 844 break; 845 } 846 break; 847 case MRT_ATTR_AS4PATH: 848 if (!as4) { 849 free(re->aspath); 850 re->aspath_len = attr_len; 851 if ((re->aspath = malloc(attr_len)) == NULL) 852 err(1, "malloc"); 853 memcpy(re->aspath, a, attr_len); 854 break; 855 } 856 /* FALLTHROUGH */ 857 default: 858 re->nattrs++; 859 if (re->nattrs >= UCHAR_MAX) 860 err(1, "too many attributes"); 861 ap = reallocarray(re->attrs, 862 re->nattrs, sizeof(struct mrt_attr)); 863 if (ap == NULL) 864 err(1, "realloc"); 865 re->attrs = ap; 866 ap = re->attrs + re->nattrs - 1; 867 ap->attr_len = a + attr_len - attr; 868 if ((ap->attr = malloc(ap->attr_len)) == NULL) 869 err(1, "malloc"); 870 memcpy(ap->attr, attr, ap->attr_len); 871 break; 872 } 873 a += attr_len; 874 alen -= attr_len; 875 } while (alen > 0); 876 877 return (0); 878} 879 880void 881mrt_free_peers(struct mrt_peer *p) 882{ 883 free(p->peers); 884 free(p->view); 885 free(p); 886} 887 888void 889mrt_free_rib(struct mrt_rib *r) 890{ 891 u_int16_t i, j; 892 893 for (i = 0; i < r->nentries && r->entries; i++) { 894 for (j = 0; j < r->entries[i].nattrs; j++) 895 free(r->entries[i].attrs[j].attr); 896 free(r->entries[i].attrs); 897 free(r->entries[i].aspath); 898 } 899 900 free(r->entries); 901 free(r); 902} 903 904void 905mrt_free_bgp_state(struct mrt_bgp_state *s) 906{ 907 free(s); 908} 909 910void 911mrt_free_bgp_msg(struct mrt_bgp_msg *m) 912{ 913 free(m->msg); 914 free(m); 915} 916 917u_char * 918mrt_aspath_inflate(void *data, u_int16_t len, u_int16_t *newlen) 919{ 920 u_int8_t *seg, *nseg, *ndata; 921 u_int16_t seg_size, olen, nlen; 922 u_int8_t seg_len; 923 924 /* first calculate the length of the aspath */ 925 seg = data; 926 nlen = 0; 927 for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) { 928 seg_len = seg[1]; 929 seg_size = 2 + sizeof(u_int16_t) * seg_len; 930 nlen += 2 + sizeof(u_int32_t) * seg_len; 931 932 if (seg_size > olen) 933 return NULL; 934 } 935 936 *newlen = nlen; 937 if ((ndata = malloc(nlen)) == NULL) 938 err(1, "malloc"); 939 940 /* then copy the aspath */ 941 seg = data; 942 for (nseg = ndata; nseg < ndata + nlen; ) { 943 *nseg++ = *seg++; 944 *nseg++ = seg_len = *seg++; 945 for (; seg_len > 0; seg_len--) { 946 *nseg++ = 0; 947 *nseg++ = 0; 948 *nseg++ = *seg++; 949 *nseg++ = *seg++; 950 } 951 } 952 953 return (ndata); 954} 955 956int 957mrt_extract_addr(void *msg, u_int len, struct bgpd_addr *addr, u_int8_t aid) 958{ 959 u_int8_t *b = msg; 960 961 memset(addr, 0, sizeof(*addr)); 962 switch (aid) { 963 case AID_INET: 964 if (len < sizeof(struct in_addr)) 965 return (-1); 966 addr->aid = aid; 967 memcpy(&addr->v4, b, sizeof(struct in_addr)); 968 return sizeof(struct in_addr); 969 case AID_INET6: 970 if (len < sizeof(struct in6_addr)) 971 return (-1); 972 addr->aid = aid; 973 memcpy(&addr->v6, b, sizeof(struct in6_addr)); 974 return sizeof(struct in6_addr); 975 case AID_VPN_IPv4: 976 if (len < sizeof(u_int64_t) + sizeof(struct in_addr)) 977 return (-1); 978 addr->aid = aid; 979 /* XXX labelstack and rd missing */ 980 memcpy(&addr->vpn4.addr, b + sizeof(u_int64_t), 981 sizeof(struct in_addr)); 982 return (sizeof(u_int64_t) + sizeof(struct in_addr)); 983 case AID_VPN_IPv6: 984 if (len < sizeof(u_int64_t) + sizeof(struct in6_addr)) 985 return (-1); 986 addr->aid = aid; 987 /* XXX labelstack and rd missing */ 988 memcpy(&addr->vpn6.addr, b + sizeof(u_int64_t), 989 sizeof(struct in6_addr)); 990 return (sizeof(u_int64_t) + sizeof(struct in6_addr)); 991 default: 992 return (-1); 993 } 994} 995 996int 997mrt_extract_prefix(void *msg, u_int len, u_int8_t aid, 998 struct bgpd_addr *prefix, u_int8_t *prefixlen, int verbose) 999{ 1000 int r; 1001 1002 switch (aid) { 1003 case AID_INET: 1004 r = nlri_get_prefix(msg, len, prefix, prefixlen); 1005 break; 1006 case AID_INET6: 1007 r = nlri_get_prefix6(msg, len, prefix, prefixlen); 1008 break; 1009 case AID_VPN_IPv4: 1010 r = nlri_get_vpn4(msg, len, prefix, prefixlen, 0); 1011 break; 1012 case AID_VPN_IPv6: 1013 r = nlri_get_vpn6(msg, len, prefix, prefixlen, 0); 1014 break; 1015 default: 1016 if (verbose) 1017 printf("unknown prefix AID %d\n", aid); 1018 return -1; 1019 } 1020 if (r == -1 && verbose) 1021 printf("failed to parse prefix of AID %d\n", aid); 1022 return r; 1023} 1024 1025struct mrt_bgp_state * 1026mrt_parse_state(struct mrt_hdr *hdr, void *msg, int verbose) 1027{ 1028 struct timespec t; 1029 struct mrt_bgp_state *s; 1030 u_int8_t *b = msg; 1031 u_int len = ntohl(hdr->length); 1032 u_int32_t sas, das, usec; 1033 u_int16_t tmp16, afi; 1034 int r; 1035 u_int8_t aid; 1036 1037 t.tv_sec = ntohl(hdr->timestamp); 1038 t.tv_nsec = 0; 1039 1040 /* handle the microsec field for _ET header */ 1041 if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) { 1042 memcpy(&usec, b, sizeof(usec)); 1043 b += sizeof(usec); 1044 len -= sizeof(usec); 1045 t.tv_nsec = ntohl(usec) * 1000; 1046 } 1047 1048 switch (ntohs(hdr->subtype)) { 1049 case BGP4MP_STATE_CHANGE: 1050 if (len < 8) 1051 return (0); 1052 /* source as */ 1053 memcpy(&tmp16, b, sizeof(tmp16)); 1054 b += sizeof(tmp16); 1055 len -= sizeof(tmp16); 1056 sas = ntohs(tmp16); 1057 /* dest as */ 1058 memcpy(&tmp16, b, sizeof(tmp16)); 1059 b += sizeof(tmp16); 1060 len -= sizeof(tmp16); 1061 das = ntohs(tmp16); 1062 /* if_index, ignored */ 1063 b += sizeof(tmp16); 1064 len -= sizeof(tmp16); 1065 /* afi */ 1066 memcpy(&tmp16, b, sizeof(tmp16)); 1067 b += sizeof(tmp16); 1068 len -= sizeof(tmp16); 1069 afi = ntohs(tmp16); 1070 break; 1071 case BGP4MP_STATE_CHANGE_AS4: 1072 if (len < 12) 1073 return (0); 1074 /* source as */ 1075 memcpy(&sas, b, sizeof(sas)); 1076 b += sizeof(sas); 1077 len -= sizeof(sas); 1078 sas = ntohl(sas); 1079 /* dest as */ 1080 memcpy(&das, b, sizeof(das)); 1081 b += sizeof(das); 1082 len -= sizeof(das); 1083 das = ntohl(das); 1084 /* if_index, ignored */ 1085 b += sizeof(tmp16); 1086 len -= sizeof(tmp16); 1087 /* afi */ 1088 memcpy(&tmp16, b, sizeof(tmp16)); 1089 b += sizeof(tmp16); 1090 len -= sizeof(tmp16); 1091 afi = ntohs(tmp16); 1092 break; 1093 default: 1094 errx(1, "mrt_parse_state: bad subtype"); 1095 } 1096 1097 /* src & dst addr */ 1098 if ((aid = mrt_afi2aid(afi, -1, verbose)) == AID_UNSPEC) 1099 return (NULL); 1100 1101 if ((s = calloc(1, sizeof(struct mrt_bgp_state))) == NULL) 1102 err(1, "calloc"); 1103 s->time = t; 1104 s->src_as = sas; 1105 s->dst_as = das; 1106 1107 if ((r = mrt_extract_addr(b, len, &s->src, aid)) == -1) 1108 goto fail; 1109 b += r; 1110 len -= r; 1111 if ((r = mrt_extract_addr(b, len, &s->dst, aid)) == -1) 1112 goto fail; 1113 b += r; 1114 len -= r; 1115 1116 /* states */ 1117 memcpy(&tmp16, b, sizeof(tmp16)); 1118 b += sizeof(tmp16); 1119 len -= sizeof(tmp16); 1120 s->old_state = ntohs(tmp16); 1121 memcpy(&tmp16, b, sizeof(tmp16)); 1122 b += sizeof(tmp16); 1123 len -= sizeof(tmp16); 1124 s->new_state = ntohs(tmp16); 1125 1126 return (s); 1127 1128fail: 1129 free(s); 1130 return (NULL); 1131} 1132 1133struct mrt_bgp_msg * 1134mrt_parse_msg(struct mrt_hdr *hdr, void *msg, int verbose) 1135{ 1136 struct timespec t; 1137 struct mrt_bgp_msg *m; 1138 u_int8_t *b = msg; 1139 u_int len = ntohl(hdr->length); 1140 u_int32_t sas, das, usec; 1141 u_int16_t tmp16, afi; 1142 int r; 1143 u_int8_t aid; 1144 1145 t.tv_sec = ntohl(hdr->timestamp); 1146 t.tv_nsec = 0; 1147 1148 /* handle the microsec field for _ET header */ 1149 if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) { 1150 memcpy(&usec, b, sizeof(usec)); 1151 b += sizeof(usec); 1152 len -= sizeof(usec); 1153 t.tv_nsec = ntohl(usec) * 1000; 1154 } 1155 1156 switch (ntohs(hdr->subtype)) { 1157 case BGP4MP_MESSAGE: 1158 if (len < 8) 1159 return (0); 1160 /* source as */ 1161 memcpy(&tmp16, b, sizeof(tmp16)); 1162 b += sizeof(tmp16); 1163 len -= sizeof(tmp16); 1164 sas = ntohs(tmp16); 1165 /* dest as */ 1166 memcpy(&tmp16, b, sizeof(tmp16)); 1167 b += sizeof(tmp16); 1168 len -= sizeof(tmp16); 1169 das = ntohs(tmp16); 1170 /* if_index, ignored */ 1171 b += sizeof(tmp16); 1172 len -= sizeof(tmp16); 1173 /* afi */ 1174 memcpy(&tmp16, b, sizeof(tmp16)); 1175 b += sizeof(tmp16); 1176 len -= sizeof(tmp16); 1177 afi = ntohs(tmp16); 1178 break; 1179 case BGP4MP_MESSAGE_AS4: 1180 if (len < 12) 1181 return (0); 1182 /* source as */ 1183 memcpy(&sas, b, sizeof(sas)); 1184 b += sizeof(sas); 1185 len -= sizeof(sas); 1186 sas = ntohl(sas); 1187 /* dest as */ 1188 memcpy(&das, b, sizeof(das)); 1189 b += sizeof(das); 1190 len -= sizeof(das); 1191 das = ntohl(das); 1192 /* if_index, ignored */ 1193 b += sizeof(tmp16); 1194 len -= sizeof(tmp16); 1195 /* afi */ 1196 memcpy(&tmp16, b, sizeof(tmp16)); 1197 b += sizeof(tmp16); 1198 len -= sizeof(tmp16); 1199 afi = ntohs(tmp16); 1200 break; 1201 default: 1202 errx(1, "mrt_parse_msg: bad subtype"); 1203 } 1204 1205 /* src & dst addr */ 1206 if ((aid = mrt_afi2aid(afi, -1, verbose)) == AID_UNSPEC) 1207 return (NULL); 1208 1209 if ((m = calloc(1, sizeof(struct mrt_bgp_msg))) == NULL) 1210 err(1, "calloc"); 1211 m->time = t; 1212 m->src_as = sas; 1213 m->dst_as = das; 1214 1215 if ((r = mrt_extract_addr(b, len, &m->src, aid)) == -1) 1216 goto fail; 1217 b += r; 1218 len -= r; 1219 if ((r = mrt_extract_addr(b, len, &m->dst, aid)) == -1) 1220 goto fail; 1221 b += r; 1222 len -= r; 1223 1224 /* msg */ 1225 if (len > 0) { 1226 m->msg_len = len; 1227 if ((m->msg = malloc(len)) == NULL) 1228 err(1, "malloc"); 1229 memcpy(m->msg, b, len); 1230 } 1231 1232 return (m); 1233 1234fail: 1235 free(m->msg); 1236 free(m); 1237 return (NULL); 1238} 1239