1 /* $OpenBSD: parser.c,v 1.56 2009/09/08 16:11:36 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 #include <sys/socket.h> 21 22 #include <err.h> 23 #include <errno.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 }; 57 58 enum getopts { 59 GETOPT_NONE, 60 GETOPT_IRRFILTER 61 }; 62 63 struct token { 64 enum token_type type; 65 const char *keyword; 66 int value; 67 const struct token *next; 68 }; 69 70 static const struct token t_main[]; 71 static const struct token t_show[]; 72 static const struct token t_show_summary[]; 73 static const struct token t_show_fib[]; 74 static const struct token t_show_rib[]; 75 static const struct token t_show_rib_neigh[]; 76 static const struct token t_show_rib_rib[]; 77 static const struct token t_show_neighbor[]; 78 static const struct token t_show_neighbor_modifiers[]; 79 static const struct token t_fib[]; 80 static const struct token t_neighbor[]; 81 static const struct token t_neighbor_modifiers[]; 82 static const struct token t_show_as[]; 83 static const struct token t_show_prefix[]; 84 static const struct token t_show_ip[]; 85 static const struct token t_show_community[]; 86 static const struct token t_network[]; 87 static const struct token t_network_show[]; 88 static const struct token t_prefix[]; 89 static const struct token t_set[]; 90 static const struct token t_community[]; 91 static const struct token t_localpref[]; 92 static const struct token t_med[]; 93 static const struct token t_nexthop[]; 94 static const struct token t_pftable[]; 95 static const struct token t_prepnbr[]; 96 static const struct token t_prepself[]; 97 static const struct token t_weight[]; 98 static const struct token t_irrfilter[]; 99 static const struct token t_irrfilter_opts[]; 100 101 static const struct token t_main[] = { 102 { KEYWORD, "reload", RELOAD, NULL}, 103 { KEYWORD, "show", SHOW, t_show}, 104 { KEYWORD, "fib", FIB, t_fib}, 105 { KEYWORD, "neighbor", NEIGHBOR, t_neighbor}, 106 { KEYWORD, "network", NONE, t_network}, 107 { KEYWORD, "irrfilter", IRRFILTER, t_irrfilter}, 108 { ENDTOKEN, "", NONE, NULL} 109 }; 110 111 static const struct token t_show[] = { 112 { NOTOKEN, "", NONE, NULL}, 113 { KEYWORD, "fib", SHOW_FIB, t_show_fib}, 114 { KEYWORD, "interfaces", SHOW_INTERFACE, NULL}, 115 { KEYWORD, "neighbor", SHOW_NEIGHBOR, t_show_neighbor}, 116 { KEYWORD, "network", NETWORK_SHOW, t_network_show}, 117 { KEYWORD, "nexthop", SHOW_NEXTHOP, NULL}, 118 { KEYWORD, "rib", SHOW_RIB, t_show_rib}, 119 { KEYWORD, "ip", NONE, t_show_ip}, 120 { KEYWORD, "summary", SHOW_SUMMARY, t_show_summary}, 121 { ENDTOKEN, "", NONE, NULL} 122 }; 123 124 static const struct token t_show_summary[] = { 125 { NOTOKEN, "", NONE, NULL}, 126 { KEYWORD, "terse", SHOW_SUMMARY_TERSE, NULL}, 127 { ENDTOKEN, "", NONE, NULL} 128 }; 129 130 static const struct token t_show_fib[] = { 131 { NOTOKEN, "", NONE, NULL}, 132 { FLAG, "connected", F_CONNECTED, t_show_fib}, 133 { FLAG, "static", F_STATIC, t_show_fib}, 134 { FLAG, "bgp", F_BGPD_INSERTED, t_show_fib}, 135 { FLAG, "nexthop", F_NEXTHOP, t_show_fib}, 136 { FAMILY, "", NONE, t_show_fib}, 137 { ADDRESS, "", NONE, NULL}, 138 { ENDTOKEN, "", NONE, NULL} 139 }; 140 141 static const struct token t_show_rib[] = { 142 { NOTOKEN, "", NONE, NULL}, 143 { ASTYPE, "as", AS_ALL, t_show_as}, 144 { ASTYPE, "source-as", AS_SOURCE, t_show_as}, 145 { ASTYPE, "transit-as", AS_TRANSIT, t_show_as}, 146 { ASTYPE, "peer-as", AS_PEER, t_show_as}, 147 { ASTYPE, "empty-as", AS_EMPTY, t_show_rib}, 148 { KEYWORD, "community", NONE, t_show_community}, 149 { FLAG, "detail", F_CTL_DETAIL, t_show_rib}, 150 { FLAG, "in", F_CTL_ADJ_IN, t_show_rib}, 151 { FLAG, "out", F_CTL_ADJ_OUT, t_show_rib}, 152 { KEYWORD, "neighbor", NONE, t_show_rib_neigh}, 153 { KEYWORD, "table", NONE, t_show_rib_rib}, 154 { KEYWORD, "summary", SHOW_SUMMARY, t_show_summary}, 155 { KEYWORD, "memory", SHOW_RIB_MEM, NULL}, 156 { FAMILY, "", NONE, t_show_rib}, 157 { PREFIX, "", NONE, t_show_prefix}, 158 { ENDTOKEN, "", NONE, NULL} 159 }; 160 161 static const struct token t_show_rib_neigh[] = { 162 { PEERADDRESS, "", NONE, t_show_rib}, 163 { PEERDESC, "", NONE, t_show_rib}, 164 { ENDTOKEN, "", NONE, NULL} 165 }; 166 167 static const struct token t_show_rib_rib[] = { 168 { RIBNAME, "", NONE, t_show_rib}, 169 { ENDTOKEN, "", NONE, NULL} 170 }; 171 172 static const struct token t_show_neighbor[] = { 173 { NOTOKEN, "", NONE, NULL}, 174 { PEERADDRESS, "", NONE, t_show_neighbor_modifiers}, 175 { PEERDESC, "", NONE, t_show_neighbor_modifiers}, 176 { ENDTOKEN, "", NONE, NULL} 177 }; 178 179 static const struct token t_show_neighbor_modifiers[] = { 180 { NOTOKEN, "", NONE, NULL}, 181 { KEYWORD, "timers", SHOW_NEIGHBOR_TIMERS, NULL}, 182 { KEYWORD, "messages", SHOW_NEIGHBOR, NULL}, 183 { KEYWORD, "terse", SHOW_NEIGHBOR_TERSE, NULL}, 184 { ENDTOKEN, "", NONE, NULL} 185 }; 186 187 static const struct token t_fib[] = { 188 { KEYWORD, "couple", FIB_COUPLE, NULL}, 189 { KEYWORD, "decouple", FIB_DECOUPLE, NULL}, 190 { ENDTOKEN, "", NONE, NULL} 191 }; 192 193 static const struct token t_neighbor[] = { 194 { PEERADDRESS, "", NONE, t_neighbor_modifiers}, 195 { PEERDESC, "", NONE, t_neighbor_modifiers}, 196 { ENDTOKEN, "", NONE, NULL} 197 }; 198 199 static const struct token t_neighbor_modifiers[] = { 200 { KEYWORD, "up", NEIGHBOR_UP, NULL}, 201 { KEYWORD, "down", NEIGHBOR_DOWN, NULL}, 202 { KEYWORD, "clear", NEIGHBOR_CLEAR, NULL}, 203 { KEYWORD, "refresh", NEIGHBOR_RREFRESH, NULL}, 204 { ENDTOKEN, "", NONE, NULL} 205 }; 206 207 static const struct token t_show_as[] = { 208 { ASNUM, "", NONE, t_show_rib}, 209 { ENDTOKEN, "", NONE, NULL} 210 }; 211 212 static const struct token t_show_prefix[] = { 213 { NOTOKEN, "", NONE, NULL}, 214 { FLAG, "all", F_LONGER, NULL}, 215 { FLAG, "longer-prefixes", F_LONGER, NULL}, 216 { ENDTOKEN, "", NONE, NULL} 217 }; 218 219 static const struct token t_show_ip[] = { 220 { KEYWORD, "bgp", SHOW_RIB, t_show_rib}, 221 { ENDTOKEN, "", NONE, NULL} 222 }; 223 224 static const struct token t_show_community[] = { 225 { COMMUNITY, "", NONE, t_show_rib}, 226 { ENDTOKEN, "", NONE, NULL} 227 }; 228 229 static const struct token t_network[] = { 230 { KEYWORD, "add", NETWORK_ADD, t_prefix}, 231 { KEYWORD, "delete", NETWORK_REMOVE, t_prefix}, 232 { KEYWORD, "flush", NETWORK_FLUSH, NULL}, 233 { KEYWORD, "show", NETWORK_SHOW, t_network_show}, 234 { ENDTOKEN, "", NONE, NULL} 235 }; 236 237 static const struct token t_prefix[] = { 238 { PREFIX, "", NONE, t_set}, 239 { ENDTOKEN, "", NONE, NULL} 240 }; 241 242 static const struct token t_network_show[] = { 243 { NOTOKEN, "", NONE, NULL}, 244 { FAMILY, "", NONE, NULL}, 245 { ENDTOKEN, "", NONE, NULL} 246 }; 247 248 static const struct token t_set[] = { 249 { NOTOKEN, "", NONE, NULL}, 250 { KEYWORD, "community", NONE, t_community}, 251 { KEYWORD, "localpref", NONE, t_localpref}, 252 { KEYWORD, "med", NONE, t_med}, 253 { KEYWORD, "metric", NONE, t_med}, 254 { KEYWORD, "nexthop", NONE, t_nexthop}, 255 { KEYWORD, "pftable", NONE, t_pftable}, 256 { KEYWORD, "prepend-neighbor", NONE, t_prepnbr}, 257 { KEYWORD, "prepend-self", NONE, t_prepself}, 258 { KEYWORD, "weight", NONE, t_weight}, 259 { ENDTOKEN, "", NONE, NULL} 260 }; 261 262 static const struct token t_community[] = { 263 { COMMUNITY, "", NONE, t_set}, 264 { ENDTOKEN, "", NONE, NULL} 265 }; 266 267 static const struct token t_localpref[] = { 268 { LOCALPREF, "", NONE, t_set}, 269 { ENDTOKEN, "", NONE, NULL} 270 }; 271 272 static const struct token t_med[] = { 273 { MED, "", NONE, t_set}, 274 { ENDTOKEN, "", NONE, NULL} 275 }; 276 277 static const struct token t_nexthop[] = { 278 { NEXTHOP, "", NONE, t_set}, 279 { ENDTOKEN, "", NONE, NULL} 280 }; 281 282 static const struct token t_pftable[] = { 283 { PFTABLE, "", NONE, t_set}, 284 { ENDTOKEN, "", NONE, NULL} 285 }; 286 287 static const struct token t_prepnbr[] = { 288 { PREPNBR, "", NONE, t_set}, 289 { ENDTOKEN, "", NONE, NULL} 290 }; 291 292 static const struct token t_prepself[] = { 293 { PREPSELF, "", NONE, t_set}, 294 { ENDTOKEN, "", NONE, NULL} 295 }; 296 297 static const struct token t_weight[] = { 298 { WEIGHT, "", NONE, t_set}, 299 { ENDTOKEN, "", NONE, NULL} 300 }; 301 302 static const struct token t_irrfilter[] = { 303 { GETOPT, "", GETOPT_IRRFILTER, t_irrfilter}, 304 { ASNUM, "", NONE, t_irrfilter_opts}, 305 { ENDTOKEN, "", NONE, NULL} 306 }; 307 308 static const struct token t_irrfilter_opts[] = { 309 { NOTOKEN, "", NONE, NULL}, 310 { FLAG, "importonly", F_IMPORTONLY, t_irrfilter_opts}, 311 { ENDTOKEN, "", NONE, NULL} 312 }; 313 314 static struct parse_result res; 315 316 const struct token *match_token(int *argc, char **argv[], 317 const struct token []); 318 void show_valid_args(const struct token []); 319 int parse_addr(const char *, struct bgpd_addr *); 320 int parse_prefix(const char *, struct bgpd_addr *, 321 u_int8_t *); 322 int parse_asnum(const char *, u_int32_t *); 323 int parse_number(const char *, struct parse_result *, 324 enum token_type); 325 int getcommunity(const char *); 326 int parse_community(const char *, struct parse_result *); 327 int parse_nexthop(const char *, struct parse_result *); 328 int bgpctl_getopt(int *, char **[], int); 329 330 struct parse_result * 331 parse(int argc, char *argv[]) 332 { 333 const struct token *table = t_main; 334 const struct token *match; 335 336 bzero(&res, sizeof(res)); 337 res.community.as = COMMUNITY_UNSET; 338 res.community.type = COMMUNITY_UNSET; 339 res.flags = (F_IPV4 | F_IPV6); 340 TAILQ_INIT(&res.set); 341 if ((res.irr_outdir = getcwd(NULL, 0)) == NULL) { 342 fprintf(stderr, "getcwd failed: %s", strerror(errno)); 343 return (NULL); 344 } 345 346 while (argc >= 0) { 347 if ((match = match_token(&argc, &argv, table)) == NULL) { 348 fprintf(stderr, "valid commands/args:\n"); 349 show_valid_args(table); 350 return (NULL); 351 } 352 353 argc--; 354 argv++; 355 356 if (match->type == NOTOKEN || match->next == NULL) 357 break; 358 359 table = match->next; 360 } 361 362 if (argc > 0) { 363 fprintf(stderr, "superfluous argument: %s\n", argv[0]); 364 return (NULL); 365 } 366 367 return (&res); 368 } 369 370 const struct token * 371 match_token(int *argc, char **argv[], const struct token table[]) 372 { 373 u_int i, match; 374 const struct token *t = NULL; 375 struct filter_set *fs; 376 const char *word = *argv[0]; 377 378 match = 0; 379 380 for (i = 0; table[i].type != ENDTOKEN; i++) { 381 switch (table[i].type) { 382 case NOTOKEN: 383 if (word == NULL || strlen(word) == 0) { 384 match++; 385 t = &table[i]; 386 } 387 break; 388 case KEYWORD: 389 if (word != NULL && strncmp(word, table[i].keyword, 390 strlen(word)) == 0) { 391 match++; 392 t = &table[i]; 393 if (t->value) 394 res.action = t->value; 395 } 396 break; 397 case FLAG: 398 if (word != NULL && strncmp(word, table[i].keyword, 399 strlen(word)) == 0) { 400 match++; 401 t = &table[i]; 402 res.flags |= t->value; 403 } 404 break; 405 case FAMILY: 406 if (word == NULL) 407 break; 408 if (!strcmp(word, "inet") || !strcmp(word, "IPv4")) { 409 match++; 410 t = &table[i]; 411 res.af = AF_INET; 412 } 413 if (!strcmp(word, "inet6") || !strcmp(word, "IPv6")) { 414 match++; 415 t = &table[i]; 416 res.af = AF_INET6; 417 } 418 break; 419 case ADDRESS: 420 if (parse_addr(word, &res.addr)) { 421 match++; 422 t = &table[i]; 423 if (t->value) 424 res.action = t->value; 425 } 426 break; 427 case PEERADDRESS: 428 if (parse_addr(word, &res.peeraddr)) { 429 match++; 430 t = &table[i]; 431 if (t->value) 432 res.action = t->value; 433 } 434 break; 435 case PREFIX: 436 if (parse_prefix(word, &res.addr, &res.prefixlen)) { 437 match++; 438 t = &table[i]; 439 if (t->value) 440 res.action = t->value; 441 } 442 break; 443 case ASTYPE: 444 if (word != NULL && strncmp(word, table[i].keyword, 445 strlen(word)) == 0) { 446 match++; 447 t = &table[i]; 448 res.as.type = t->value; 449 } 450 break; 451 case ASNUM: 452 if (parse_asnum(word, &res.as.as)) { 453 match++; 454 t = &table[i]; 455 } 456 break; 457 case PEERDESC: 458 if (!match && word != NULL && strlen(word) > 0) { 459 if (strlcpy(res.peerdesc, word, 460 sizeof(res.peerdesc)) >= 461 sizeof(res.peerdesc)) 462 errx(1, "neighbor description too " 463 "long"); 464 match++; 465 t = &table[i]; 466 } 467 break; 468 case RIBNAME: 469 if (!match && word != NULL && strlen(word) > 0) { 470 if (strlcpy(res.rib, word, sizeof(res.rib)) >= 471 sizeof(res.rib)) 472 errx(1, "rib name too long"); 473 match++; 474 t = &table[i]; 475 } 476 break; 477 case COMMUNITY: 478 if (word != NULL && strlen(word) > 0 && 479 parse_community(word, &res)) { 480 match++; 481 t = &table[i]; 482 } 483 break; 484 case LOCALPREF: 485 case MED: 486 case PREPNBR: 487 case PREPSELF: 488 case WEIGHT: 489 if (word != NULL && strlen(word) > 0 && 490 parse_number(word, &res, table[i].type)) { 491 match++; 492 t = &table[i]; 493 } 494 break; 495 case NEXTHOP: 496 if (word != NULL && strlen(word) > 0 && 497 parse_nexthop(word, &res)) { 498 match++; 499 t = &table[i]; 500 } 501 break; 502 case PFTABLE: 503 if (word != NULL && strlen(word) > 0) { 504 if ((fs = calloc(1, 505 sizeof(struct filter_set))) == NULL) 506 err(1, NULL); 507 if (strlcpy(fs->action.pftable, word, 508 sizeof(fs->action.pftable)) >= 509 sizeof(fs->action.pftable)) 510 errx(1, "pftable name too long"); 511 TAILQ_INSERT_TAIL(&res.set, fs, entry); 512 match++; 513 t = &table[i]; 514 } 515 break; 516 case GETOPT: 517 if (bgpctl_getopt(argc, argv, table[i].value)) { 518 match++; 519 t = &table[i]; 520 } 521 break; 522 case ENDTOKEN: 523 break; 524 } 525 } 526 527 if (match != 1) { 528 if (word == NULL) 529 fprintf(stderr, "missing argument:\n"); 530 else if (match > 1) 531 fprintf(stderr, "ambiguous argument: %s\n", word); 532 else if (match < 1) 533 fprintf(stderr, "unknown argument: %s\n", word); 534 return (NULL); 535 } 536 537 return (t); 538 } 539 540 void 541 show_valid_args(const struct token table[]) 542 { 543 int i; 544 545 for (i = 0; table[i].type != ENDTOKEN; i++) { 546 switch (table[i].type) { 547 case NOTOKEN: 548 fprintf(stderr, " <cr>\n"); 549 break; 550 case KEYWORD: 551 case FLAG: 552 case ASTYPE: 553 fprintf(stderr, " %s\n", table[i].keyword); 554 break; 555 case ADDRESS: 556 case PEERADDRESS: 557 fprintf(stderr, " <address>\n"); 558 break; 559 case PREFIX: 560 fprintf(stderr, " <address>[/<len>]\n"); 561 break; 562 case ASNUM: 563 fprintf(stderr, " <asnum>\n"); 564 break; 565 case PEERDESC: 566 fprintf(stderr, " <neighbor description>\n"); 567 break; 568 case RIBNAME: 569 fprintf(stderr, " <rib name>\n"); 570 break; 571 case COMMUNITY: 572 fprintf(stderr, " <community>\n"); 573 break; 574 case LOCALPREF: 575 case MED: 576 case PREPNBR: 577 case PREPSELF: 578 case WEIGHT: 579 fprintf(stderr, " <number>\n"); 580 break; 581 case NEXTHOP: 582 fprintf(stderr, " <address>\n"); 583 break; 584 case PFTABLE: 585 fprintf(stderr, " <pftable>\n"); 586 break; 587 case FAMILY: 588 fprintf(stderr, " [ inet | inet6 | IPv4 | IPv6 ]\n"); 589 break; 590 case GETOPT: 591 fprintf(stderr, " <options>\n"); 592 break; 593 case ENDTOKEN: 594 break; 595 } 596 } 597 } 598 599 int 600 parse_addr(const char *word, struct bgpd_addr *addr) 601 { 602 struct in_addr ina; 603 struct addrinfo hints, *r; 604 605 if (word == NULL) 606 return (0); 607 608 bzero(addr, sizeof(struct bgpd_addr)); 609 bzero(&ina, sizeof(ina)); 610 611 if (inet_net_pton(AF_INET, word, &ina, sizeof(ina)) != -1) { 612 addr->af = AF_INET; 613 addr->v4 = ina; 614 return (1); 615 } 616 617 bzero(&hints, sizeof(hints)); 618 hints.ai_family = AF_INET6; 619 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 620 hints.ai_flags = AI_NUMERICHOST; 621 if (getaddrinfo(word, "0", &hints, &r) == 0) { 622 addr->af = AF_INET6; 623 memcpy(&addr->v6, 624 &((struct sockaddr_in6 *)r->ai_addr)->sin6_addr, 625 sizeof(addr->v6)); 626 addr->scope_id = 627 ((struct sockaddr_in6 *)r->ai_addr)->sin6_scope_id; 628 629 freeaddrinfo(r); 630 return (1); 631 } 632 633 return (0); 634 } 635 636 int 637 parse_prefix(const char *word, struct bgpd_addr *addr, u_int8_t *prefixlen) 638 { 639 char *p, *ps; 640 const char *errstr; 641 int mask = -1; 642 643 if (word == NULL) 644 return (0); 645 646 bzero(addr, sizeof(struct bgpd_addr)); 647 648 if ((p = strrchr(word, '/')) != NULL) { 649 mask = strtonum(p + 1, 0, 128, &errstr); 650 if (errstr) 651 errx(1, "invalid netmask: %s", errstr); 652 653 if ((ps = malloc(strlen(word) - strlen(p) + 1)) == NULL) 654 err(1, "parse_prefix: malloc"); 655 strlcpy(ps, word, strlen(word) - strlen(p) + 1); 656 657 if (parse_addr(ps, addr) == 0) { 658 free(ps); 659 return (0); 660 } 661 662 free(ps); 663 } else 664 if (parse_addr(word, addr) == 0) 665 return (0); 666 667 switch (addr->af) { 668 case AF_INET: 669 if (mask == -1) 670 mask = 32; 671 if (mask > 32) 672 errx(1, "invalid netmask: too large"); 673 addr->v4.s_addr = addr->v4.s_addr & htonl(prefixlen2mask(mask)); 674 break; 675 case AF_INET6: 676 if (mask == -1) 677 mask = 128; 678 inet6applymask(&addr->v6, &addr->v6, mask); 679 break; 680 default: 681 return (0); 682 } 683 684 *prefixlen = mask; 685 return (1); 686 } 687 688 int 689 parse_asnum(const char *word, u_int32_t *asnum) 690 { 691 const char *errstr; 692 char *dot; 693 u_int32_t uval, uvalh = 0; 694 695 if (word == NULL) 696 return (0); 697 698 if (strlen(word) < 1 || word[0] < '0' || word[0] > '9') 699 return (0); 700 701 if ((dot = strchr(word,'.')) != NULL) { 702 *dot++ = '\0'; 703 uvalh = strtonum(word, 0, USHRT_MAX, &errstr); 704 if (errstr) 705 errx(1, "AS number is %s: %s", errstr, word); 706 uval = strtonum(dot, 0, USHRT_MAX, &errstr); 707 if (errstr) 708 errx(1, "AS number is %s: %s", errstr, word); 709 } else { 710 uval = strtonum(word, 0, UINT_MAX, &errstr); 711 if (errstr) 712 errx(1, "AS number is %s: %s", errstr, word); 713 } 714 715 *asnum = uval | (uvalh << 16); 716 return (1); 717 } 718 719 int 720 parse_number(const char *word, struct parse_result *r, enum token_type type) 721 { 722 struct filter_set *fs; 723 const char *errstr; 724 u_int uval; 725 726 if (word == NULL) 727 return (0); 728 729 uval = strtonum(word, 0, UINT_MAX, &errstr); 730 if (errstr) 731 errx(1, "number is %s: %s", errstr, word); 732 733 /* number was parseable */ 734 if ((fs = calloc(1, sizeof(struct filter_set))) == NULL) 735 err(1, NULL); 736 switch (type) { 737 case LOCALPREF: 738 fs->type = ACTION_SET_LOCALPREF; 739 fs->action.metric = uval; 740 break; 741 case MED: 742 fs->type = ACTION_SET_MED; 743 fs->action.metric = uval; 744 break; 745 case PREPNBR: 746 if (uval > 128) { 747 free(fs); 748 return (0); 749 } 750 fs->type = ACTION_SET_PREPEND_PEER; 751 fs->action.prepend = uval; 752 break; 753 case PREPSELF: 754 if (uval > 128) { 755 free(fs); 756 return (0); 757 } 758 fs->type = ACTION_SET_PREPEND_SELF; 759 fs->action.prepend = uval; 760 break; 761 case WEIGHT: 762 fs->type = ACTION_SET_WEIGHT; 763 fs->action.metric = uval; 764 break; 765 default: 766 errx(1, "king bula sez bad things happen"); 767 } 768 769 TAILQ_INSERT_TAIL(&r->set, fs, entry); 770 return (1); 771 } 772 773 int 774 getcommunity(const char *s) 775 { 776 const char *errstr; 777 u_int16_t uval; 778 779 if (strcmp(s, "*") == 0) 780 return (COMMUNITY_ANY); 781 782 uval = strtonum(s, 0, USHRT_MAX, &errstr); 783 if (errstr) 784 errx(1, "Community is %s: %s", errstr, s); 785 786 return (uval); 787 } 788 789 int 790 parse_community(const char *word, struct parse_result *r) 791 { 792 struct filter_set *fs; 793 char *p; 794 int as, type; 795 796 /* Well-known communities */ 797 if (strcasecmp(word, "NO_EXPORT") == 0) { 798 as = COMMUNITY_WELLKNOWN; 799 type = COMMUNITY_NO_EXPORT; 800 goto done; 801 } else if (strcasecmp(word, "NO_ADVERTISE") == 0) { 802 as = COMMUNITY_WELLKNOWN; 803 type = COMMUNITY_NO_ADVERTISE; 804 goto done; 805 } else if (strcasecmp(word, "NO_EXPORT_SUBCONFED") == 0) { 806 as = COMMUNITY_WELLKNOWN; 807 type = COMMUNITY_NO_EXPSUBCONFED; 808 goto done; 809 } else if (strcasecmp(word, "NO_PEER") == 0) { 810 as = COMMUNITY_WELLKNOWN; 811 type = COMMUNITY_NO_PEER; 812 goto done; 813 } 814 815 if ((p = strchr(word, ':')) == NULL) { 816 fprintf(stderr, "Bad community syntax\n"); 817 return (0); 818 } 819 *p++ = 0; 820 821 as = getcommunity(word); 822 type = getcommunity(p); 823 824 done: 825 if (as == 0) { 826 fprintf(stderr, "Invalid community\n"); 827 return (0); 828 } 829 if (as == COMMUNITY_WELLKNOWN) 830 switch (type) { 831 case COMMUNITY_NO_EXPORT: 832 case COMMUNITY_NO_ADVERTISE: 833 case COMMUNITY_NO_EXPSUBCONFED: 834 /* valid */ 835 break; 836 default: 837 /* unknown */ 838 fprintf(stderr, "Unknown well-known community\n"); 839 return (0); 840 } 841 842 if ((fs = calloc(1, sizeof(struct filter_set))) == NULL) 843 err(1, NULL); 844 fs->type = ACTION_SET_COMMUNITY; 845 fs->action.community.as = as; 846 fs->action.community.type = type; 847 848 r->community.as = as; 849 r->community.type = type; 850 851 TAILQ_INSERT_TAIL(&r->set, fs, entry); 852 return (1); 853 } 854 855 int 856 parse_nexthop(const char *word, struct parse_result *r) 857 { 858 struct filter_set *fs; 859 860 if ((fs = calloc(1, sizeof(struct filter_set))) == NULL) 861 err(1, NULL); 862 863 if (strcmp(word, "blackhole") == 0) 864 fs->type = ACTION_SET_NEXTHOP_BLACKHOLE; 865 else if (strcmp(word, "reject") == 0) 866 fs->type = ACTION_SET_NEXTHOP_REJECT; 867 else if (strcmp(word, "no-modify") == 0) 868 fs->type = ACTION_SET_NEXTHOP_NOMODIFY; 869 else if (parse_addr(word, &fs->action.nexthop)) { 870 fs->type = ACTION_SET_NEXTHOP; 871 } else { 872 free(fs); 873 return (0); 874 } 875 876 TAILQ_INSERT_TAIL(&r->set, fs, entry); 877 return (1); 878 } 879 880 int 881 bgpctl_getopt(int *argc, char **argv[], int type) 882 { 883 int ch; 884 885 optind = optreset = 1; 886 while ((ch = getopt((*argc) + 1, (*argv) - 1, "46o:")) != -1) { 887 switch (ch) { 888 case '4': 889 res.flags = (res.flags | F_IPV4) & ~F_IPV6; 890 break; 891 case '6': 892 res.flags = (res.flags | F_IPV6) & ~F_IPV4; 893 break; 894 case 'o': 895 res.irr_outdir = optarg; 896 break; 897 default: 898 usage(); 899 /* NOTREACHED */ 900 } 901 } 902 903 if (optind > 1) { 904 (*argc) -= (optind - 1); 905 (*argv) += (optind - 1); 906 907 /* need to move one backwards as calling code moves forward */ 908 (*argc)++; 909 (*argv)--; 910 return (1); 911 } else 912 return (0); 913 } 914