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