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