1 /* $OpenBSD: parser.c,v 1.73 2015/10/11 19:53:57 sthen Exp $ */ 2 3 /* 4 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 21 #include <err.h> 22 #include <errno.h> 23 #include <fcntl.h> 24 #include <limits.h> 25 #include <netdb.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 31 #include "parser.h" 32 #include "irrfilter.h" 33 34 enum token_type { 35 NOTOKEN, 36 ENDTOKEN, 37 KEYWORD, 38 ADDRESS, 39 PEERADDRESS, 40 FLAG, 41 ASNUM, 42 ASTYPE, 43 PREFIX, 44 PEERDESC, 45 RIBNAME, 46 COMMUNITY, 47 LOCALPREF, 48 MED, 49 NEXTHOP, 50 PFTABLE, 51 PREPNBR, 52 PREPSELF, 53 WEIGHT, 54 FAMILY, 55 GETOPT, 56 RTABLE, 57 FILENAME, 58 BULK 59 }; 60 61 enum getopts { 62 GETOPT_NONE, 63 GETOPT_IRRFILTER 64 }; 65 66 struct token { 67 enum token_type type; 68 const char *keyword; 69 int value; 70 const struct token *next; 71 }; 72 73 static const struct token t_main[]; 74 static const struct token t_show[]; 75 static const struct token t_show_summary[]; 76 static const struct token t_show_fib[]; 77 static const struct token t_show_rib[]; 78 static const struct token t_show_mrt[]; 79 static const struct token t_show_mrt_file[]; 80 static const struct token t_show_rib_neigh[]; 81 static const struct token t_show_mrt_neigh[]; 82 static const struct token t_show_rib_rib[]; 83 static const struct token t_show_neighbor[]; 84 static const struct token t_show_neighbor_modifiers[]; 85 static const struct token t_fib[]; 86 static const struct token t_neighbor[]; 87 static const struct token t_neighbor_modifiers[]; 88 static const struct token t_show_rib_as[]; 89 static const struct token t_show_mrt_as[]; 90 static const struct token t_show_prefix[]; 91 static const struct token t_show_ip[]; 92 static const struct token t_show_community[]; 93 static const struct token t_network[]; 94 static const struct token t_network_show[]; 95 static const struct token t_prefix[]; 96 static const struct token t_set[]; 97 static const struct token t_community[]; 98 static const struct token t_localpref[]; 99 static const struct token t_med[]; 100 static const struct token t_nexthop[]; 101 static const struct token t_pftable[]; 102 static const struct token t_prepnbr[]; 103 static const struct token t_prepself[]; 104 static const struct token t_weight[]; 105 static const struct token t_irrfilter[]; 106 static const struct token t_irrfilter_opts[]; 107 static const struct token t_log[]; 108 static const struct token t_fib_table[]; 109 static const struct token t_show_fib_table[]; 110 111 static const struct token t_main[] = { 112 { KEYWORD, "reload", RELOAD, NULL}, 113 { KEYWORD, "show", SHOW, t_show}, 114 { KEYWORD, "fib", FIB, t_fib}, 115 { KEYWORD, "neighbor", NEIGHBOR, t_neighbor}, 116 { KEYWORD, "network", NONE, t_network}, 117 { KEYWORD, "irrfilter", IRRFILTER, t_irrfilter}, 118 { KEYWORD, "log", NONE, t_log}, 119 { ENDTOKEN, "", NONE, NULL} 120 }; 121 122 static const struct token t_show[] = { 123 { NOTOKEN, "", NONE, NULL}, 124 { KEYWORD, "fib", SHOW_FIB, t_show_fib}, 125 { KEYWORD, "interfaces", SHOW_INTERFACE, NULL}, 126 { KEYWORD, "neighbor", SHOW_NEIGHBOR, t_show_neighbor}, 127 { KEYWORD, "network", NETWORK_SHOW, t_network_show}, 128 { KEYWORD, "nexthop", SHOW_NEXTHOP, NULL}, 129 { KEYWORD, "rib", SHOW_RIB, t_show_rib}, 130 { KEYWORD, "tables", SHOW_FIB_TABLES, NULL}, 131 { KEYWORD, "ip", NONE, t_show_ip}, 132 { KEYWORD, "summary", SHOW_SUMMARY, t_show_summary}, 133 { KEYWORD, "mrt", SHOW_MRT, t_show_mrt}, 134 { ENDTOKEN, "", NONE, NULL} 135 }; 136 137 static const struct token t_show_summary[] = { 138 { NOTOKEN, "", NONE, NULL}, 139 { KEYWORD, "terse", SHOW_SUMMARY_TERSE, NULL}, 140 { ENDTOKEN, "", NONE, NULL} 141 }; 142 143 static const struct token t_show_fib[] = { 144 { NOTOKEN, "", NONE, NULL}, 145 { FLAG, "connected", F_CONNECTED, t_show_fib}, 146 { FLAG, "static", F_STATIC, t_show_fib}, 147 { FLAG, "bgp", F_BGPD_INSERTED, t_show_fib}, 148 { FLAG, "nexthop", F_NEXTHOP, t_show_fib}, 149 { KEYWORD, "table", NONE, t_show_fib_table}, 150 { FAMILY, "", NONE, t_show_fib}, 151 { ADDRESS, "", NONE, NULL}, 152 { ENDTOKEN, "", NONE, NULL} 153 }; 154 155 static const struct token t_show_rib[] = { 156 { NOTOKEN, "", NONE, NULL}, 157 { ASTYPE, "as", AS_ALL, t_show_rib_as}, 158 { ASTYPE, "source-as", AS_SOURCE, t_show_rib_as}, 159 { ASTYPE, "transit-as", AS_TRANSIT, t_show_rib_as}, 160 { ASTYPE, "peer-as", AS_PEER, t_show_rib_as}, 161 { ASTYPE, "empty-as", AS_EMPTY, t_show_rib}, 162 { KEYWORD, "community", NONE, t_show_community}, 163 { FLAG, "best", F_CTL_ACTIVE, t_show_rib}, 164 { FLAG, "selected", F_CTL_ACTIVE, t_show_rib}, 165 { FLAG, "detail", F_CTL_DETAIL, t_show_rib}, 166 { FLAG, "in", F_CTL_ADJ_IN, t_show_rib}, 167 { FLAG, "out", F_CTL_ADJ_OUT, t_show_rib}, 168 { KEYWORD, "neighbor", NONE, t_show_rib_neigh}, 169 { KEYWORD, "table", NONE, t_show_rib_rib}, 170 { KEYWORD, "summary", SHOW_SUMMARY, t_show_summary}, 171 { KEYWORD, "memory", SHOW_RIB_MEM, NULL}, 172 { FAMILY, "", NONE, t_show_rib}, 173 { PREFIX, "", NONE, t_show_prefix}, 174 { ENDTOKEN, "", NONE, NULL} 175 }; 176 177 178 static const struct token t_show_mrt[] = { 179 { NOTOKEN, "", NONE, NULL}, 180 { ASTYPE, "as", AS_ALL, t_show_mrt_as}, 181 { ASTYPE, "source-as", AS_SOURCE, t_show_mrt_as}, 182 { ASTYPE, "transit-as", AS_TRANSIT, t_show_mrt_as}, 183 { ASTYPE, "peer-as", AS_PEER, t_show_mrt_as}, 184 { ASTYPE, "empty-as", AS_EMPTY, t_show_mrt}, 185 { FLAG, "detail", F_CTL_DETAIL, t_show_mrt}, 186 { KEYWORD, "neighbor", NONE, t_show_mrt_neigh}, 187 { KEYWORD, "file", NONE, t_show_mrt_file}, 188 { FAMILY, "", NONE, t_show_mrt}, 189 { PREFIX, "", NONE, t_show_prefix}, 190 { ENDTOKEN, "", NONE, NULL} 191 }; 192 193 static const struct token t_show_mrt_file[] = { 194 { FILENAME, "", NONE, t_show_mrt}, 195 { ENDTOKEN, "", NONE, NULL} 196 }; 197 198 static const struct token t_show_rib_neigh[] = { 199 { PEERADDRESS, "", NONE, t_show_rib}, 200 { PEERDESC, "", NONE, t_show_rib}, 201 { ENDTOKEN, "", NONE, NULL} 202 }; 203 204 static const struct token t_show_mrt_neigh[] = { 205 { PEERADDRESS, "", NONE, t_show_mrt}, 206 { ENDTOKEN, "", NONE, NULL} 207 }; 208 209 static const struct token t_show_rib_rib[] = { 210 { RIBNAME, "", NONE, t_show_rib}, 211 { ENDTOKEN, "", NONE, NULL} 212 }; 213 214 static const struct token t_show_neighbor[] = { 215 { NOTOKEN, "", NONE, NULL}, 216 { PEERADDRESS, "", NONE, t_show_neighbor_modifiers}, 217 { PEERDESC, "", NONE, t_show_neighbor_modifiers}, 218 { ENDTOKEN, "", NONE, NULL} 219 }; 220 221 static const struct token t_show_neighbor_modifiers[] = { 222 { NOTOKEN, "", NONE, NULL}, 223 { KEYWORD, "timers", SHOW_NEIGHBOR_TIMERS, NULL}, 224 { KEYWORD, "messages", SHOW_NEIGHBOR, NULL}, 225 { KEYWORD, "terse", SHOW_NEIGHBOR_TERSE, NULL}, 226 { ENDTOKEN, "", NONE, NULL} 227 }; 228 229 static const struct token t_fib[] = { 230 { KEYWORD, "couple", FIB_COUPLE, NULL}, 231 { KEYWORD, "decouple", FIB_DECOUPLE, NULL}, 232 { KEYWORD, "table", NONE, t_fib_table}, 233 { ENDTOKEN, "", NONE, NULL} 234 }; 235 236 static const struct token t_neighbor[] = { 237 { PEERADDRESS, "", NONE, t_neighbor_modifiers}, 238 { PEERDESC, "", NONE, t_neighbor_modifiers}, 239 { ENDTOKEN, "", NONE, NULL} 240 }; 241 242 static const struct token t_neighbor_modifiers[] = { 243 { KEYWORD, "up", NEIGHBOR_UP, NULL}, 244 { KEYWORD, "down", NEIGHBOR_DOWN, NULL}, 245 { KEYWORD, "clear", NEIGHBOR_CLEAR, NULL}, 246 { KEYWORD, "refresh", NEIGHBOR_RREFRESH, NULL}, 247 { KEYWORD, "destroy", NEIGHBOR_DESTROY, NULL}, 248 { ENDTOKEN, "", NONE, NULL} 249 }; 250 251 static const struct token t_show_rib_as[] = { 252 { ASNUM, "", NONE, t_show_rib}, 253 { ENDTOKEN, "", NONE, NULL} 254 }; 255 256 static const struct token t_show_mrt_as[] = { 257 { ASNUM, "", NONE, t_show_mrt}, 258 { ENDTOKEN, "", NONE, NULL} 259 }; 260 261 static const struct token t_show_prefix[] = { 262 { NOTOKEN, "", NONE, NULL}, 263 { FLAG, "all", F_LONGER, NULL}, 264 { FLAG, "longer-prefixes", F_LONGER, NULL}, 265 { ENDTOKEN, "", NONE, NULL} 266 }; 267 268 static const struct token t_show_ip[] = { 269 { KEYWORD, "bgp", SHOW_RIB, t_show_rib}, 270 { ENDTOKEN, "", NONE, NULL} 271 }; 272 273 static const struct token t_show_community[] = { 274 { COMMUNITY, "", NONE, t_show_rib}, 275 { ENDTOKEN, "", NONE, NULL} 276 }; 277 278 static const struct token t_network[] = { 279 { KEYWORD, "add", NETWORK_ADD, t_prefix}, 280 { KEYWORD, "delete", NETWORK_REMOVE, t_prefix}, 281 { KEYWORD, "flush", NETWORK_FLUSH, NULL}, 282 { KEYWORD, "show", NETWORK_SHOW, t_network_show}, 283 { KEYWORD, "mrt", NETWORK_MRT, t_show_mrt}, 284 { KEYWORD, "bulk", NETWORK_BULK_ADD, t_set}, 285 { ENDTOKEN, "", NONE, NULL} 286 }; 287 288 static const struct token t_prefix[] = { 289 { PREFIX, "", NONE, t_set}, 290 { ENDTOKEN, "", NONE, NULL} 291 }; 292 293 static const struct token t_network_show[] = { 294 { NOTOKEN, "", NONE, NULL}, 295 { FAMILY, "", NONE, NULL}, 296 { ENDTOKEN, "", NONE, NULL} 297 }; 298 299 static const struct token t_set[] = { 300 { NOTOKEN, "", NONE, NULL}, 301 { KEYWORD, "community", NONE, t_community}, 302 { KEYWORD, "localpref", NONE, t_localpref}, 303 { KEYWORD, "med", NONE, t_med}, 304 { KEYWORD, "metric", NONE, t_med}, 305 { KEYWORD, "nexthop", NONE, t_nexthop}, 306 { KEYWORD, "pftable", NONE, t_pftable}, 307 { KEYWORD, "prepend-neighbor", NONE, t_prepnbr}, 308 { KEYWORD, "prepend-self", NONE, t_prepself}, 309 { KEYWORD, "weight", NONE, t_weight}, 310 { KEYWORD, "add", NETWORK_BULK_ADD, NULL}, 311 { KEYWORD, "delete", NETWORK_BULK_REMOVE, NULL}, 312 { ENDTOKEN, "", NONE, NULL} 313 }; 314 315 static const struct token t_community[] = { 316 { COMMUNITY, "", NONE, t_set}, 317 { ENDTOKEN, "", NONE, NULL} 318 }; 319 320 static const struct token t_localpref[] = { 321 { LOCALPREF, "", NONE, t_set}, 322 { ENDTOKEN, "", NONE, NULL} 323 }; 324 325 static const struct token t_med[] = { 326 { MED, "", NONE, t_set}, 327 { ENDTOKEN, "", NONE, NULL} 328 }; 329 330 static const struct token t_nexthop[] = { 331 { NEXTHOP, "", NONE, t_set}, 332 { ENDTOKEN, "", NONE, NULL} 333 }; 334 335 static const struct token t_pftable[] = { 336 { PFTABLE, "", NONE, t_set}, 337 { ENDTOKEN, "", NONE, NULL} 338 }; 339 340 static const struct token t_prepnbr[] = { 341 { PREPNBR, "", NONE, t_set}, 342 { ENDTOKEN, "", NONE, NULL} 343 }; 344 345 static const struct token t_prepself[] = { 346 { PREPSELF, "", NONE, t_set}, 347 { ENDTOKEN, "", NONE, NULL} 348 }; 349 350 static const struct token t_weight[] = { 351 { WEIGHT, "", NONE, t_set}, 352 { ENDTOKEN, "", NONE, NULL} 353 }; 354 355 static const struct token t_irrfilter[] = { 356 { GETOPT, "", GETOPT_IRRFILTER, t_irrfilter}, 357 { ASNUM, "", NONE, t_irrfilter_opts}, 358 { ENDTOKEN, "", NONE, NULL} 359 }; 360 361 static const struct token t_irrfilter_opts[] = { 362 { NOTOKEN, "", NONE, NULL}, 363 { FLAG, "importonly", F_IMPORTONLY, t_irrfilter_opts}, 364 { ENDTOKEN, "", NONE, NULL} 365 }; 366 367 static const struct token t_log[] = { 368 { KEYWORD, "verbose", LOG_VERBOSE, NULL}, 369 { KEYWORD, "brief", LOG_BRIEF, NULL}, 370 { ENDTOKEN, "", NONE, NULL} 371 }; 372 373 static const struct token t_fib_table[] = { 374 { RTABLE, "", NONE, t_fib}, 375 { ENDTOKEN, "", NONE, NULL} 376 }; 377 378 static const struct token t_show_fib_table[] = { 379 { RTABLE, "", NONE, t_show_fib}, 380 { ENDTOKEN, "", NONE, NULL} 381 }; 382 383 static struct parse_result res; 384 385 const struct token *match_token(int *argc, char **argv[], 386 const struct token []); 387 void show_valid_args(const struct token []); 388 int parse_addr(const char *, struct bgpd_addr *); 389 int parse_asnum(const char *, size_t, u_int32_t *); 390 int parse_number(const char *, struct parse_result *, 391 enum token_type); 392 int getcommunity(const char *); 393 int parse_community(const char *, struct parse_result *); 394 int parse_nexthop(const char *, struct parse_result *); 395 int bgpctl_getopt(int *, char **[], int); 396 397 struct parse_result * 398 parse(int argc, char *argv[]) 399 { 400 const struct token *table = t_main; 401 const struct token *match; 402 403 bzero(&res, sizeof(res)); 404 res.community.as = COMMUNITY_UNSET; 405 res.community.type = COMMUNITY_UNSET; 406 TAILQ_INIT(&res.set); 407 if ((res.irr_outdir = getcwd(NULL, 0)) == NULL) { 408 fprintf(stderr, "getcwd failed: %s\n", strerror(errno)); 409 return (NULL); 410 } 411 412 while (argc >= 0) { 413 if ((match = match_token(&argc, &argv, table)) == NULL) { 414 fprintf(stderr, "valid commands/args:\n"); 415 show_valid_args(table); 416 return (NULL); 417 } 418 419 argc--; 420 argv++; 421 422 if (match->type == NOTOKEN || match->next == NULL) 423 break; 424 425 table = match->next; 426 } 427 428 if (argc > 0) { 429 fprintf(stderr, "superfluous argument: %s\n", argv[0]); 430 return (NULL); 431 } 432 433 return (&res); 434 } 435 436 const struct token * 437 match_token(int *argc, char **argv[], const struct token table[]) 438 { 439 u_int i, match; 440 const struct token *t = NULL; 441 struct filter_set *fs; 442 const char *word = *argv[0]; 443 size_t wordlen = 0; 444 445 match = 0; 446 if (word != NULL) 447 wordlen = strlen(word); 448 for (i = 0; table[i].type != ENDTOKEN; i++) { 449 switch (table[i].type) { 450 case NOTOKEN: 451 if (word == NULL || wordlen == 0) { 452 match++; 453 t = &table[i]; 454 } 455 break; 456 case KEYWORD: 457 if (word != NULL && strncmp(word, table[i].keyword, 458 wordlen) == 0) { 459 match++; 460 t = &table[i]; 461 if (t->value) 462 res.action = t->value; 463 } 464 break; 465 case FLAG: 466 if (word != NULL && strncmp(word, table[i].keyword, 467 wordlen) == 0) { 468 match++; 469 t = &table[i]; 470 res.flags |= t->value; 471 } 472 break; 473 case FAMILY: 474 if (word == NULL) 475 break; 476 if (!strcmp(word, "inet") || 477 !strcasecmp(word, "IPv4")) { 478 match++; 479 t = &table[i]; 480 res.aid = AID_INET; 481 } 482 if (!strcmp(word, "inet6") || 483 !strcasecmp(word, "IPv6")) { 484 match++; 485 t = &table[i]; 486 res.aid = AID_INET6; 487 } 488 if (!strcasecmp(word, "VPNv4")) { 489 match++; 490 t = &table[i]; 491 res.aid = AID_VPN_IPv4; 492 } 493 break; 494 case ADDRESS: 495 if (parse_addr(word, &res.addr)) { 496 match++; 497 t = &table[i]; 498 if (t->value) 499 res.action = t->value; 500 } 501 break; 502 case PEERADDRESS: 503 if (parse_addr(word, &res.peeraddr)) { 504 match++; 505 t = &table[i]; 506 if (t->value) 507 res.action = t->value; 508 } 509 break; 510 case PREFIX: 511 if (parse_prefix(word, wordlen, &res.addr, &res.prefixlen)) { 512 match++; 513 t = &table[i]; 514 if (t->value) 515 res.action = t->value; 516 } 517 break; 518 case ASTYPE: 519 if (word != NULL && strncmp(word, table[i].keyword, 520 wordlen) == 0) { 521 match++; 522 t = &table[i]; 523 res.as.type = t->value; 524 } 525 break; 526 case ASNUM: 527 if (parse_asnum(word, wordlen, &res.as.as)) { 528 match++; 529 t = &table[i]; 530 } 531 break; 532 case PEERDESC: 533 if (!match && word != NULL && wordlen > 0) { 534 if (strlcpy(res.peerdesc, word, 535 sizeof(res.peerdesc)) >= 536 sizeof(res.peerdesc)) 537 errx(1, "neighbor description too " 538 "long"); 539 match++; 540 t = &table[i]; 541 } 542 break; 543 case RIBNAME: 544 if (!match && word != NULL && wordlen > 0) { 545 if (strlcpy(res.rib, word, sizeof(res.rib)) >= 546 sizeof(res.rib)) 547 errx(1, "rib name too long"); 548 match++; 549 t = &table[i]; 550 } 551 break; 552 case COMMUNITY: 553 if (word != NULL && wordlen > 0 && 554 parse_community(word, &res)) { 555 match++; 556 t = &table[i]; 557 } 558 break; 559 case LOCALPREF: 560 case MED: 561 case PREPNBR: 562 case PREPSELF: 563 case WEIGHT: 564 case RTABLE: 565 if (word != NULL && wordlen > 0 && 566 parse_number(word, &res, table[i].type)) { 567 match++; 568 t = &table[i]; 569 } 570 break; 571 case NEXTHOP: 572 if (word != NULL && wordlen > 0 && 573 parse_nexthop(word, &res)) { 574 match++; 575 t = &table[i]; 576 } 577 break; 578 case PFTABLE: 579 if (word != NULL && wordlen > 0) { 580 if ((fs = calloc(1, 581 sizeof(struct filter_set))) == NULL) 582 err(1, NULL); 583 if (strlcpy(fs->action.pftable, word, 584 sizeof(fs->action.pftable)) >= 585 sizeof(fs->action.pftable)) 586 errx(1, "pftable name too long"); 587 TAILQ_INSERT_TAIL(&res.set, fs, entry); 588 match++; 589 t = &table[i]; 590 } 591 break; 592 case GETOPT: 593 if (bgpctl_getopt(argc, argv, table[i].value)) { 594 match++; 595 t = &table[i]; 596 } 597 break; 598 case FILENAME: 599 if (word != NULL && wordlen > 0) { 600 if ((res.mrtfd = open(word, O_RDONLY)) == -1) { 601 /* 602 * ignore error if path has no / and 603 * does not exist. In hope to print 604 * usage. 605 */ 606 if (errno == ENOENT && 607 !strchr(word, '/')) 608 break; 609 err(1, "mrt open(%s)", word); 610 } 611 match++; 612 t = &table[i]; 613 } 614 break; 615 case BULK: 616 match++; 617 t = &table[i]; 618 break; 619 case ENDTOKEN: 620 break; 621 } 622 } 623 624 if (match != 1) { 625 if (word == NULL) 626 fprintf(stderr, "missing argument:\n"); 627 else if (match > 1) 628 fprintf(stderr, "ambiguous argument: %s\n", word); 629 else if (match < 1) 630 fprintf(stderr, "unknown argument: %s\n", word); 631 return (NULL); 632 } 633 634 return (t); 635 } 636 637 void 638 show_valid_args(const struct token table[]) 639 { 640 int i; 641 642 for (i = 0; table[i].type != ENDTOKEN; i++) { 643 switch (table[i].type) { 644 case NOTOKEN: 645 fprintf(stderr, " <cr>\n"); 646 break; 647 case KEYWORD: 648 case FLAG: 649 case ASTYPE: 650 fprintf(stderr, " %s\n", table[i].keyword); 651 break; 652 case ADDRESS: 653 case PEERADDRESS: 654 fprintf(stderr, " <address>\n"); 655 break; 656 case PREFIX: 657 fprintf(stderr, " <address>[/<len>]\n"); 658 break; 659 case ASNUM: 660 fprintf(stderr, " <asnum>\n"); 661 break; 662 case PEERDESC: 663 fprintf(stderr, " <neighbor description>\n"); 664 break; 665 case RIBNAME: 666 fprintf(stderr, " <rib name>\n"); 667 break; 668 case COMMUNITY: 669 fprintf(stderr, " <community>\n"); 670 break; 671 case LOCALPREF: 672 case MED: 673 case PREPNBR: 674 case PREPSELF: 675 case WEIGHT: 676 fprintf(stderr, " <number>\n"); 677 break; 678 case RTABLE: 679 fprintf(stderr, " <rtableid>\n"); 680 break; 681 case NEXTHOP: 682 fprintf(stderr, " <address>\n"); 683 break; 684 case PFTABLE: 685 fprintf(stderr, " <pftable>\n"); 686 break; 687 case FAMILY: 688 fprintf(stderr, " [ inet | inet6 | IPv4 | IPv6 | VPNv4 ]\n"); 689 break; 690 case GETOPT: 691 fprintf(stderr, " <options>\n"); 692 break; 693 case FILENAME: 694 fprintf(stderr, " <filename>\n"); 695 break; 696 case BULK: 697 case ENDTOKEN: 698 break; 699 } 700 } 701 } 702 703 int 704 parse_addr(const char *word, struct bgpd_addr *addr) 705 { 706 struct in_addr ina; 707 struct addrinfo hints, *r; 708 709 if (word == NULL) 710 return (0); 711 712 bzero(addr, sizeof(struct bgpd_addr)); 713 bzero(&ina, sizeof(ina)); 714 715 if (inet_net_pton(AF_INET, word, &ina, sizeof(ina)) != -1) { 716 addr->aid = AID_INET; 717 addr->v4 = ina; 718 return (1); 719 } 720 721 bzero(&hints, sizeof(hints)); 722 hints.ai_family = AF_INET6; 723 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 724 hints.ai_flags = AI_NUMERICHOST; 725 if (getaddrinfo(word, "0", &hints, &r) == 0) { 726 sa2addr(r->ai_addr, addr); 727 freeaddrinfo(r); 728 return (1); 729 } 730 731 return (0); 732 } 733 734 int 735 parse_prefix(const char *word, size_t wordlen, struct bgpd_addr *addr, u_int8_t *prefixlen) 736 { 737 char *p, *ps; 738 const char *errstr; 739 int mask = -1; 740 741 if (word == NULL) 742 return (0); 743 744 bzero(addr, sizeof(struct bgpd_addr)); 745 746 if ((p = strrchr(word, '/')) != NULL) { 747 size_t plen = strlen(p); 748 mask = strtonum(p + 1, 0, 128, &errstr); 749 if (errstr) 750 errx(1, "netmask %s", errstr); 751 752 if ((ps = malloc(wordlen - plen + 1)) == NULL) 753 err(1, "parse_prefix: malloc"); 754 strlcpy(ps, word, wordlen - plen + 1); 755 756 if (parse_addr(ps, addr) == 0) { 757 free(ps); 758 return (0); 759 } 760 761 free(ps); 762 } else 763 if (parse_addr(word, addr) == 0) 764 return (0); 765 766 switch (addr->aid) { 767 case AID_INET: 768 if (mask == -1) 769 mask = 32; 770 if (mask > 32) 771 errx(1, "invalid netmask: too large"); 772 addr->v4.s_addr = addr->v4.s_addr & htonl(prefixlen2mask(mask)); 773 break; 774 case AID_INET6: 775 if (mask == -1) 776 mask = 128; 777 inet6applymask(&addr->v6, &addr->v6, mask); 778 break; 779 default: 780 return (0); 781 } 782 783 *prefixlen = mask; 784 return (1); 785 } 786 787 int 788 parse_asnum(const char *word, size_t wordlen, u_int32_t *asnum) 789 { 790 const char *errstr; 791 char *dot; 792 u_int32_t uval, uvalh = 0; 793 794 if (word == NULL) 795 return (0); 796 797 if (wordlen < 1 || word[0] < '0' || word[0] > '9') 798 return (0); 799 800 if ((dot = strchr(word,'.')) != NULL) { 801 *dot++ = '\0'; 802 uvalh = strtonum(word, 0, USHRT_MAX, &errstr); 803 if (errstr) 804 errx(1, "AS number is %s: %s", errstr, word); 805 uval = strtonum(dot, 0, USHRT_MAX, &errstr); 806 if (errstr) 807 errx(1, "AS number is %s: %s", errstr, word); 808 } else { 809 uval = strtonum(word, 0, UINT_MAX, &errstr); 810 if (errstr) 811 errx(1, "AS number is %s: %s", errstr, word); 812 } 813 814 *asnum = uval | (uvalh << 16); 815 return (1); 816 } 817 818 int 819 parse_number(const char *word, struct parse_result *r, enum token_type type) 820 { 821 struct filter_set *fs; 822 const char *errstr; 823 u_int uval; 824 825 if (word == NULL) 826 return (0); 827 828 uval = strtonum(word, 0, UINT_MAX, &errstr); 829 if (errstr) 830 errx(1, "number is %s: %s", errstr, word); 831 832 /* number was parseable */ 833 if (type == RTABLE) { 834 r->rtableid = uval; 835 return (1); 836 } 837 838 if ((fs = calloc(1, sizeof(struct filter_set))) == NULL) 839 err(1, NULL); 840 switch (type) { 841 case LOCALPREF: 842 fs->type = ACTION_SET_LOCALPREF; 843 fs->action.metric = uval; 844 break; 845 case MED: 846 fs->type = ACTION_SET_MED; 847 fs->action.metric = uval; 848 break; 849 case PREPNBR: 850 if (uval > 128) { 851 free(fs); 852 return (0); 853 } 854 fs->type = ACTION_SET_PREPEND_PEER; 855 fs->action.prepend = uval; 856 break; 857 case PREPSELF: 858 if (uval > 128) { 859 free(fs); 860 return (0); 861 } 862 fs->type = ACTION_SET_PREPEND_SELF; 863 fs->action.prepend = uval; 864 break; 865 case WEIGHT: 866 fs->type = ACTION_SET_WEIGHT; 867 fs->action.metric = uval; 868 break; 869 default: 870 errx(1, "king bula sez bad things happen"); 871 } 872 873 TAILQ_INSERT_TAIL(&r->set, fs, entry); 874 return (1); 875 } 876 877 int 878 getcommunity(const char *s) 879 { 880 const char *errstr; 881 u_int16_t uval; 882 883 if (strcmp(s, "*") == 0) 884 return (COMMUNITY_ANY); 885 886 uval = strtonum(s, 0, USHRT_MAX, &errstr); 887 if (errstr) 888 errx(1, "Community is %s: %s", errstr, s); 889 890 return (uval); 891 } 892 893 int 894 parse_community(const char *word, struct parse_result *r) 895 { 896 struct filter_set *fs; 897 char *p; 898 int as, type; 899 900 /* Well-known communities */ 901 if (strcasecmp(word, "NO_EXPORT") == 0) { 902 as = COMMUNITY_WELLKNOWN; 903 type = COMMUNITY_NO_EXPORT; 904 goto done; 905 } else if (strcasecmp(word, "NO_ADVERTISE") == 0) { 906 as = COMMUNITY_WELLKNOWN; 907 type = COMMUNITY_NO_ADVERTISE; 908 goto done; 909 } else if (strcasecmp(word, "NO_EXPORT_SUBCONFED") == 0) { 910 as = COMMUNITY_WELLKNOWN; 911 type = COMMUNITY_NO_EXPSUBCONFED; 912 goto done; 913 } else if (strcasecmp(word, "NO_PEER") == 0) { 914 as = COMMUNITY_WELLKNOWN; 915 type = COMMUNITY_NO_PEER; 916 goto done; 917 } else if (strcasecmp(word, "BLACKHOLE") == 0) { 918 as = COMMUNITY_WELLKNOWN; 919 type = COMMUNITY_BLACKHOLE; 920 goto done; 921 } 922 923 if ((p = strchr(word, ':')) == NULL) { 924 fprintf(stderr, "Bad community syntax\n"); 925 return (0); 926 } 927 *p++ = 0; 928 929 as = getcommunity(word); 930 type = getcommunity(p); 931 932 done: 933 if (as == 0) { 934 fprintf(stderr, "Invalid community\n"); 935 return (0); 936 } 937 if (as == COMMUNITY_WELLKNOWN) 938 switch (type) { 939 case COMMUNITY_NO_EXPORT: 940 case COMMUNITY_NO_ADVERTISE: 941 case COMMUNITY_NO_EXPSUBCONFED: 942 case COMMUNITY_BLACKHOLE: 943 /* valid */ 944 break; 945 default: 946 /* unknown */ 947 fprintf(stderr, "Unknown well-known community\n"); 948 return (0); 949 } 950 951 if ((fs = calloc(1, sizeof(struct filter_set))) == NULL) 952 err(1, NULL); 953 fs->type = ACTION_SET_COMMUNITY; 954 fs->action.community.as = as; 955 fs->action.community.type = type; 956 957 r->community.as = as; 958 r->community.type = type; 959 960 TAILQ_INSERT_TAIL(&r->set, fs, entry); 961 return (1); 962 } 963 964 int 965 parse_nexthop(const char *word, struct parse_result *r) 966 { 967 struct filter_set *fs; 968 969 if ((fs = calloc(1, sizeof(struct filter_set))) == NULL) 970 err(1, NULL); 971 972 if (strcmp(word, "blackhole") == 0) 973 fs->type = ACTION_SET_NEXTHOP_BLACKHOLE; 974 else if (strcmp(word, "reject") == 0) 975 fs->type = ACTION_SET_NEXTHOP_REJECT; 976 else if (strcmp(word, "no-modify") == 0) 977 fs->type = ACTION_SET_NEXTHOP_NOMODIFY; 978 else if (parse_addr(word, &fs->action.nexthop)) { 979 fs->type = ACTION_SET_NEXTHOP; 980 } else { 981 free(fs); 982 return (0); 983 } 984 985 TAILQ_INSERT_TAIL(&r->set, fs, entry); 986 return (1); 987 } 988 989 int 990 bgpctl_getopt(int *argc, char **argv[], int type) 991 { 992 int ch; 993 994 optind = optreset = 1; 995 while ((ch = getopt((*argc) + 1, (*argv) - 1, "46o:")) != -1) { 996 switch (ch) { 997 case '4': 998 res.flags = (res.flags | F_IPV4) & ~F_IPV6; 999 break; 1000 case '6': 1001 res.flags = (res.flags | F_IPV6) & ~F_IPV4; 1002 break; 1003 case 'o': 1004 res.irr_outdir = optarg; 1005 break; 1006 default: 1007 usage(); 1008 /* NOTREACHED */ 1009 } 1010 } 1011 1012 if (optind > 1) { 1013 (*argc) -= (optind - 1); 1014 (*argv) += (optind - 1); 1015 1016 /* need to move one backwards as calling code moves forward */ 1017 (*argc)++; 1018 (*argv)--; 1019 return (1); 1020 } else 1021 return (0); 1022 } 1023