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