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