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