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