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