1 /* $OpenBSD: parser.c,v 1.80 2017/08/10 14:12:34 benno Exp $ */ 2 3 /* 4 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 5 * Copyright (c) 2016 Job Snijders <job@instituut.net> 6 * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/types.h> 22 23 #include <err.h> 24 #include <errno.h> 25 #include <fcntl.h> 26 #include <limits.h> 27 #include <netdb.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <unistd.h> 32 33 #include "parser.h" 34 #include "irrfilter.h" 35 36 enum token_type { 37 NOTOKEN, 38 ENDTOKEN, 39 KEYWORD, 40 ADDRESS, 41 PEERADDRESS, 42 FLAG, 43 ASNUM, 44 ASTYPE, 45 PREFIX, 46 PEERDESC, 47 RIBNAME, 48 SHUTDOWN_COMMUNICATION, 49 COMMUNITY, 50 EXTCOMMUNITY, 51 EXTCOM_SUBTYPE, 52 LARGE_COMMUNITY, 53 LOCALPREF, 54 MED, 55 NEXTHOP, 56 PFTABLE, 57 PREPNBR, 58 PREPSELF, 59 WEIGHT, 60 FAMILY, 61 GETOPT, 62 RTABLE, 63 FILENAME, 64 BULK 65 }; 66 67 enum getopts { 68 GETOPT_NONE, 69 GETOPT_IRRFILTER 70 }; 71 72 struct token { 73 enum token_type type; 74 const char *keyword; 75 int value; 76 const struct token *next; 77 }; 78 79 static const struct token t_main[]; 80 static const struct token t_show[]; 81 static const struct token t_show_summary[]; 82 static const struct token t_show_fib[]; 83 static const struct token t_show_rib[]; 84 static const struct token t_show_mrt[]; 85 static const struct token t_show_mrt_file[]; 86 static const struct token t_show_rib_neigh[]; 87 static const struct token t_show_mrt_neigh[]; 88 static const struct token t_show_rib_rib[]; 89 static const struct token t_show_neighbor[]; 90 static const struct token t_show_neighbor_modifiers[]; 91 static const struct token t_fib[]; 92 static const struct token t_neighbor[]; 93 static const struct token t_neighbor_modifiers[]; 94 static const struct token t_show_rib_as[]; 95 static const struct token t_show_mrt_as[]; 96 static const struct token t_show_prefix[]; 97 static const struct token t_show_ip[]; 98 static const struct token t_show_community[]; 99 static const struct token t_show_extcommunity[]; 100 static const struct token t_show_ext_subtype[]; 101 static const struct token t_show_largecommunity[]; 102 static const struct token t_network[]; 103 static const struct token t_network_show[]; 104 static const struct token t_prefix[]; 105 static const struct token t_set[]; 106 static const struct token t_community[]; 107 static const struct token t_extcommunity[]; 108 static const struct token t_ext_subtype[]; 109 static const struct token t_largecommunity[]; 110 static const struct token t_localpref[]; 111 static const struct token t_med[]; 112 static const struct token t_nexthop[]; 113 static const struct token t_pftable[]; 114 static const struct token t_prepnbr[]; 115 static const struct token t_prepself[]; 116 static const struct token t_weight[]; 117 static const struct token t_irrfilter[]; 118 static const struct token t_irrfilter_opts[]; 119 static const struct token t_log[]; 120 static const struct token t_fib_table[]; 121 static const struct token t_show_fib_table[]; 122 123 static const struct token t_main[] = { 124 { KEYWORD, "reload", RELOAD, NULL}, 125 { KEYWORD, "show", SHOW, t_show}, 126 { KEYWORD, "fib", FIB, t_fib}, 127 { KEYWORD, "neighbor", NEIGHBOR, t_neighbor}, 128 { KEYWORD, "network", NONE, t_network}, 129 { KEYWORD, "irrfilter", IRRFILTER, t_irrfilter}, 130 { KEYWORD, "log", NONE, t_log}, 131 { ENDTOKEN, "", NONE, NULL} 132 }; 133 134 static const struct token t_show[] = { 135 { NOTOKEN, "", NONE, NULL}, 136 { KEYWORD, "fib", SHOW_FIB, t_show_fib}, 137 { KEYWORD, "interfaces", SHOW_INTERFACE, NULL}, 138 { KEYWORD, "neighbor", SHOW_NEIGHBOR, t_show_neighbor}, 139 { KEYWORD, "network", NETWORK_SHOW, t_network_show}, 140 { KEYWORD, "nexthop", SHOW_NEXTHOP, NULL}, 141 { KEYWORD, "rib", SHOW_RIB, t_show_rib}, 142 { KEYWORD, "tables", SHOW_FIB_TABLES, NULL}, 143 { KEYWORD, "ip", NONE, t_show_ip}, 144 { KEYWORD, "summary", SHOW_SUMMARY, t_show_summary}, 145 { KEYWORD, "mrt", SHOW_MRT, t_show_mrt}, 146 { ENDTOKEN, "", NONE, NULL} 147 }; 148 149 static const struct token t_show_summary[] = { 150 { NOTOKEN, "", NONE, NULL}, 151 { KEYWORD, "terse", SHOW_SUMMARY_TERSE, NULL}, 152 { ENDTOKEN, "", NONE, NULL} 153 }; 154 155 static const struct token t_show_fib[] = { 156 { NOTOKEN, "", NONE, NULL}, 157 { FLAG, "connected", F_CONNECTED, t_show_fib}, 158 { FLAG, "static", F_STATIC, t_show_fib}, 159 { FLAG, "bgp", F_BGPD_INSERTED, t_show_fib}, 160 { FLAG, "nexthop", F_NEXTHOP, t_show_fib}, 161 { KEYWORD, "table", NONE, t_show_fib_table}, 162 { FAMILY, "", NONE, t_show_fib}, 163 { ADDRESS, "", NONE, NULL}, 164 { ENDTOKEN, "", NONE, NULL} 165 }; 166 167 static const struct token t_show_rib[] = { 168 { NOTOKEN, "", NONE, NULL}, 169 { ASTYPE, "as", AS_ALL, t_show_rib_as}, 170 { ASTYPE, "source-as", AS_SOURCE, t_show_rib_as}, 171 { ASTYPE, "transit-as", AS_TRANSIT, t_show_rib_as}, 172 { ASTYPE, "peer-as", AS_PEER, t_show_rib_as}, 173 { ASTYPE, "empty-as", AS_EMPTY, t_show_rib}, 174 { KEYWORD, "community", NONE, t_show_community}, 175 { KEYWORD, "ext-community", NONE, t_show_extcommunity}, 176 { KEYWORD, "large-community", NONE, t_show_largecommunity}, 177 { FLAG, "best", F_CTL_ACTIVE, t_show_rib}, 178 { FLAG, "selected", F_CTL_ACTIVE, t_show_rib}, 179 { FLAG, "detail", F_CTL_DETAIL, t_show_rib}, 180 { FLAG, "in", F_CTL_ADJ_IN, t_show_rib}, 181 { FLAG, "out", F_CTL_ADJ_OUT, t_show_rib}, 182 { KEYWORD, "neighbor", NONE, t_show_rib_neigh}, 183 { KEYWORD, "table", NONE, t_show_rib_rib}, 184 { KEYWORD, "summary", SHOW_SUMMARY, t_show_summary}, 185 { KEYWORD, "memory", SHOW_RIB_MEM, NULL}, 186 { FAMILY, "", NONE, t_show_rib}, 187 { PREFIX, "", NONE, t_show_prefix}, 188 { ENDTOKEN, "", NONE, NULL} 189 }; 190 191 192 static const struct token t_show_mrt[] = { 193 { NOTOKEN, "", NONE, NULL}, 194 { ASTYPE, "as", AS_ALL, t_show_mrt_as}, 195 { ASTYPE, "source-as", AS_SOURCE, t_show_mrt_as}, 196 { ASTYPE, "transit-as", AS_TRANSIT, t_show_mrt_as}, 197 { ASTYPE, "peer-as", AS_PEER, t_show_mrt_as}, 198 { ASTYPE, "empty-as", AS_EMPTY, t_show_mrt}, 199 { FLAG, "detail", F_CTL_DETAIL, t_show_mrt}, 200 { KEYWORD, "neighbor", NONE, t_show_mrt_neigh}, 201 { KEYWORD, "file", NONE, t_show_mrt_file}, 202 { FAMILY, "", NONE, t_show_mrt}, 203 { PREFIX, "", NONE, t_show_prefix}, 204 { ENDTOKEN, "", NONE, NULL} 205 }; 206 207 static const struct token t_show_mrt_file[] = { 208 { FILENAME, "", NONE, t_show_mrt}, 209 { ENDTOKEN, "", NONE, NULL} 210 }; 211 212 static const struct token t_show_rib_neigh[] = { 213 { PEERADDRESS, "", NONE, t_show_rib}, 214 { PEERDESC, "", NONE, t_show_rib}, 215 { ENDTOKEN, "", NONE, NULL} 216 }; 217 218 static const struct token t_show_mrt_neigh[] = { 219 { PEERADDRESS, "", NONE, t_show_mrt}, 220 { ENDTOKEN, "", NONE, NULL} 221 }; 222 223 static const struct token t_show_rib_rib[] = { 224 { RIBNAME, "", NONE, t_show_rib}, 225 { ENDTOKEN, "", NONE, NULL} 226 }; 227 228 static const struct token t_show_neighbor[] = { 229 { NOTOKEN, "", NONE, NULL}, 230 { PEERADDRESS, "", NONE, t_show_neighbor_modifiers}, 231 { PEERDESC, "", NONE, t_show_neighbor_modifiers}, 232 { ENDTOKEN, "", NONE, NULL} 233 }; 234 235 static const struct token t_show_neighbor_modifiers[] = { 236 { NOTOKEN, "", NONE, NULL}, 237 { KEYWORD, "timers", SHOW_NEIGHBOR_TIMERS, NULL}, 238 { KEYWORD, "messages", SHOW_NEIGHBOR, NULL}, 239 { KEYWORD, "terse", SHOW_NEIGHBOR_TERSE, NULL}, 240 { ENDTOKEN, "", NONE, NULL} 241 }; 242 243 static const struct token t_fib[] = { 244 { KEYWORD, "couple", FIB_COUPLE, NULL}, 245 { KEYWORD, "decouple", FIB_DECOUPLE, NULL}, 246 { KEYWORD, "table", NONE, t_fib_table}, 247 { ENDTOKEN, "", NONE, NULL} 248 }; 249 250 static const struct token t_neighbor[] = { 251 { PEERADDRESS, "", NONE, t_neighbor_modifiers}, 252 { PEERDESC, "", NONE, t_neighbor_modifiers}, 253 { ENDTOKEN, "", NONE, NULL} 254 }; 255 256 static const struct token t_nei_mod_shutc[] = { 257 { NOTOKEN, "", NONE, NULL}, 258 { SHUTDOWN_COMMUNICATION, "", NONE, NULL}, 259 { ENDTOKEN, "", NONE, NULL} 260 }; 261 262 static const struct token t_neighbor_modifiers[] = { 263 { KEYWORD, "up", NEIGHBOR_UP, NULL}, 264 { KEYWORD, "down", NEIGHBOR_DOWN, t_nei_mod_shutc}, 265 { KEYWORD, "clear", NEIGHBOR_CLEAR, t_nei_mod_shutc}, 266 { KEYWORD, "refresh", NEIGHBOR_RREFRESH, NULL}, 267 { KEYWORD, "destroy", NEIGHBOR_DESTROY, NULL}, 268 { ENDTOKEN, "", NONE, NULL} 269 }; 270 271 static const struct token t_show_rib_as[] = { 272 { ASNUM, "", NONE, t_show_rib}, 273 { ENDTOKEN, "", NONE, NULL} 274 }; 275 276 static const struct token t_show_mrt_as[] = { 277 { ASNUM, "", NONE, t_show_mrt}, 278 { ENDTOKEN, "", NONE, NULL} 279 }; 280 281 static const struct token t_show_prefix[] = { 282 { NOTOKEN, "", NONE, NULL}, 283 { FLAG, "all", F_LONGER, NULL}, 284 { FLAG, "longer-prefixes", F_LONGER, NULL}, 285 { ENDTOKEN, "", NONE, NULL} 286 }; 287 288 static const struct token t_show_ip[] = { 289 { KEYWORD, "bgp", SHOW_RIB, t_show_rib}, 290 { ENDTOKEN, "", NONE, NULL} 291 }; 292 293 static const struct token t_show_community[] = { 294 { COMMUNITY, "", NONE, t_show_rib}, 295 { ENDTOKEN, "", NONE, NULL} 296 }; 297 298 static const struct token t_show_extcommunity[] = { 299 { EXTCOM_SUBTYPE, "bdc", NONE, t_show_ext_subtype}, 300 { EXTCOM_SUBTYPE, "defgw", NONE, t_show_ext_subtype}, 301 { EXTCOM_SUBTYPE, "esi-lab", NONE, t_show_ext_subtype}, 302 { EXTCOM_SUBTYPE, "esi-rt", NONE, t_show_ext_subtype}, 303 { EXTCOM_SUBTYPE, "l2vid", NONE, t_show_ext_subtype}, 304 { EXTCOM_SUBTYPE, "mac-mob", NONE, t_show_ext_subtype}, 305 { EXTCOM_SUBTYPE, "odi", NONE, t_show_ext_subtype}, 306 { EXTCOM_SUBTYPE, "ort", NONE, t_show_ext_subtype}, 307 { EXTCOM_SUBTYPE, "ori", NONE, t_show_ext_subtype}, 308 { EXTCOM_SUBTYPE, "ovs", NONE, t_show_ext_subtype}, 309 { EXTCOM_SUBTYPE, "rt", NONE, t_show_ext_subtype}, 310 { EXTCOM_SUBTYPE, "soo", NONE, t_show_ext_subtype}, 311 { EXTCOM_SUBTYPE, "srcas", NONE, t_show_ext_subtype}, 312 { EXTCOM_SUBTYPE, "vrfri", NONE, t_show_ext_subtype}, 313 { ENDTOKEN, "", NONE, NULL} 314 }; 315 316 static const struct token t_show_ext_subtype[] = { 317 { EXTCOMMUNITY, "", NONE, t_show_rib}, 318 { ENDTOKEN, "", NONE, NULL} 319 }; 320 321 static const struct token t_show_largecommunity[] = { 322 { LARGE_COMMUNITY, "", NONE, t_show_rib}, 323 { ENDTOKEN, "", NONE, NULL} 324 }; 325 326 static const struct token t_network[] = { 327 { KEYWORD, "add", NETWORK_ADD, t_prefix}, 328 { KEYWORD, "delete", NETWORK_REMOVE, t_prefix}, 329 { KEYWORD, "flush", NETWORK_FLUSH, NULL}, 330 { KEYWORD, "show", NETWORK_SHOW, t_network_show}, 331 { KEYWORD, "mrt", NETWORK_MRT, t_show_mrt}, 332 { KEYWORD, "bulk", NETWORK_BULK_ADD, t_set}, 333 { ENDTOKEN, "", NONE, NULL} 334 }; 335 336 static const struct token t_prefix[] = { 337 { PREFIX, "", NONE, t_set}, 338 { ENDTOKEN, "", NONE, NULL} 339 }; 340 341 static const struct token t_network_show[] = { 342 { NOTOKEN, "", NONE, NULL}, 343 { FAMILY, "", NONE, NULL}, 344 { ENDTOKEN, "", NONE, NULL} 345 }; 346 347 static const struct token t_set[] = { 348 { NOTOKEN, "", NONE, NULL}, 349 { KEYWORD, "community", NONE, t_community}, 350 { KEYWORD, "ext-community", NONE, t_extcommunity}, 351 { KEYWORD, "large-community", NONE, t_largecommunity}, 352 { KEYWORD, "localpref", NONE, t_localpref}, 353 { KEYWORD, "med", NONE, t_med}, 354 { KEYWORD, "metric", NONE, t_med}, 355 { KEYWORD, "nexthop", NONE, t_nexthop}, 356 { KEYWORD, "pftable", NONE, t_pftable}, 357 { KEYWORD, "prepend-neighbor", NONE, t_prepnbr}, 358 { KEYWORD, "prepend-self", NONE, t_prepself}, 359 { KEYWORD, "weight", NONE, t_weight}, 360 { KEYWORD, "add", NETWORK_BULK_ADD, NULL}, 361 { KEYWORD, "delete", NETWORK_BULK_REMOVE, NULL}, 362 { ENDTOKEN, "", NONE, NULL} 363 }; 364 365 static const struct token t_community[] = { 366 { COMMUNITY, "", NONE, t_set}, 367 { ENDTOKEN, "", NONE, NULL} 368 }; 369 370 static const struct token t_extcommunity[] = { 371 { EXTCOM_SUBTYPE, "bdc", NONE, t_ext_subtype}, 372 { EXTCOM_SUBTYPE, "defgw", NONE, t_ext_subtype}, 373 { EXTCOM_SUBTYPE, "esi-lab", NONE, t_ext_subtype}, 374 { EXTCOM_SUBTYPE, "esi-rt", NONE, t_ext_subtype}, 375 { EXTCOM_SUBTYPE, "l2vid", NONE, t_ext_subtype}, 376 { EXTCOM_SUBTYPE, "mac-mob", NONE, t_ext_subtype}, 377 { EXTCOM_SUBTYPE, "odi", NONE, t_ext_subtype}, 378 { EXTCOM_SUBTYPE, "ort", NONE, t_ext_subtype}, 379 { EXTCOM_SUBTYPE, "ori", NONE, t_ext_subtype}, 380 { EXTCOM_SUBTYPE, "ovs", NONE, t_ext_subtype}, 381 { EXTCOM_SUBTYPE, "rt", NONE, t_ext_subtype}, 382 { EXTCOM_SUBTYPE, "soo", NONE, t_ext_subtype}, 383 { EXTCOM_SUBTYPE, "srcas", NONE, t_ext_subtype}, 384 { EXTCOM_SUBTYPE, "vrfri", NONE, t_ext_subtype}, 385 { ENDTOKEN, "", NONE, NULL} 386 }; 387 388 static const struct token t_ext_subtype[] = { 389 { EXTCOMMUNITY, "", NONE, t_set}, 390 { ENDTOKEN, "", NONE, NULL} 391 }; 392 393 static const struct token t_largecommunity[] = { 394 { LARGE_COMMUNITY, "", NONE, t_set}, 395 { ENDTOKEN, "", NONE, NULL} 396 }; 397 398 static const struct token t_localpref[] = { 399 { LOCALPREF, "", NONE, t_set}, 400 { ENDTOKEN, "", NONE, NULL} 401 }; 402 403 static const struct token t_med[] = { 404 { MED, "", NONE, t_set}, 405 { ENDTOKEN, "", NONE, NULL} 406 }; 407 408 static const struct token t_nexthop[] = { 409 { NEXTHOP, "", NONE, t_set}, 410 { ENDTOKEN, "", NONE, NULL} 411 }; 412 413 static const struct token t_pftable[] = { 414 { PFTABLE, "", NONE, t_set}, 415 { ENDTOKEN, "", NONE, NULL} 416 }; 417 418 static const struct token t_prepnbr[] = { 419 { PREPNBR, "", NONE, t_set}, 420 { ENDTOKEN, "", NONE, NULL} 421 }; 422 423 static const struct token t_prepself[] = { 424 { PREPSELF, "", NONE, t_set}, 425 { ENDTOKEN, "", NONE, NULL} 426 }; 427 428 static const struct token t_weight[] = { 429 { WEIGHT, "", NONE, t_set}, 430 { ENDTOKEN, "", NONE, NULL} 431 }; 432 433 static const struct token t_irrfilter[] = { 434 { GETOPT, "", GETOPT_IRRFILTER, t_irrfilter}, 435 { ASNUM, "", NONE, t_irrfilter_opts}, 436 { ENDTOKEN, "", NONE, NULL} 437 }; 438 439 static const struct token t_irrfilter_opts[] = { 440 { NOTOKEN, "", NONE, NULL}, 441 { FLAG, "importonly", F_IMPORTONLY, t_irrfilter_opts}, 442 { ENDTOKEN, "", NONE, NULL} 443 }; 444 445 static const struct token t_log[] = { 446 { KEYWORD, "verbose", LOG_VERBOSE, NULL}, 447 { KEYWORD, "brief", LOG_BRIEF, NULL}, 448 { ENDTOKEN, "", NONE, NULL} 449 }; 450 451 static const struct token t_fib_table[] = { 452 { RTABLE, "", NONE, t_fib}, 453 { ENDTOKEN, "", NONE, NULL} 454 }; 455 456 static const struct token t_show_fib_table[] = { 457 { RTABLE, "", NONE, t_show_fib}, 458 { ENDTOKEN, "", NONE, NULL} 459 }; 460 461 static struct parse_result res; 462 463 const struct token *match_token(int *argc, char **argv[], 464 const struct token []); 465 void show_valid_args(const struct token []); 466 int parse_addr(const char *, struct bgpd_addr *); 467 int parse_asnum(const char *, size_t, u_int32_t *); 468 int parse_number(const char *, struct parse_result *, 469 enum token_type); 470 int getcommunity(const char *); 471 int parse_community(const char *, struct parse_result *); 472 int parsesubtype(const char *, u_int8_t *, u_int8_t *); 473 int parseextvalue(const char *, u_int32_t *); 474 u_int parseextcommunity(const char *, struct parse_result *); 475 u_int getlargecommunity(const char *); 476 int parse_largecommunity(const char *, 477 struct parse_result *); 478 int parse_nexthop(const char *, struct parse_result *); 479 int bgpctl_getopt(int *, char **[], int); 480 481 struct parse_result * 482 parse(int argc, char *argv[]) 483 { 484 const struct token *table = t_main; 485 const struct token *match; 486 487 bzero(&res, sizeof(res)); 488 res.community.as = COMMUNITY_UNSET; 489 res.community.type = COMMUNITY_UNSET; 490 res.large_community.as = COMMUNITY_UNSET; 491 res.large_community.ld1 = COMMUNITY_UNSET; 492 res.large_community.ld2 = COMMUNITY_UNSET; 493 TAILQ_INIT(&res.set); 494 if ((res.irr_outdir = getcwd(NULL, 0)) == NULL) { 495 fprintf(stderr, "getcwd failed: %s\n", strerror(errno)); 496 return (NULL); 497 } 498 499 while (argc >= 0) { 500 if ((match = match_token(&argc, &argv, table)) == NULL) { 501 fprintf(stderr, "valid commands/args:\n"); 502 show_valid_args(table); 503 return (NULL); 504 } 505 506 argc--; 507 argv++; 508 509 if (match->type == NOTOKEN || match->next == NULL) 510 break; 511 512 table = match->next; 513 } 514 515 if (argc > 0) { 516 fprintf(stderr, "superfluous argument: %s\n", argv[0]); 517 return (NULL); 518 } 519 520 return (&res); 521 } 522 523 const struct token * 524 match_token(int *argc, char **argv[], const struct token table[]) 525 { 526 u_int i, match; 527 const struct token *t = NULL; 528 struct filter_set *fs; 529 const char *word = *argv[0]; 530 size_t wordlen = 0; 531 532 match = 0; 533 if (word != NULL) 534 wordlen = strlen(word); 535 for (i = 0; table[i].type != ENDTOKEN; i++) { 536 switch (table[i].type) { 537 case NOTOKEN: 538 if (word == NULL || wordlen == 0) { 539 match++; 540 t = &table[i]; 541 } 542 break; 543 case KEYWORD: 544 if (word != NULL && strncmp(word, table[i].keyword, 545 wordlen) == 0) { 546 match++; 547 t = &table[i]; 548 if (t->value) 549 res.action = t->value; 550 } 551 break; 552 case FLAG: 553 if (word != NULL && strncmp(word, table[i].keyword, 554 wordlen) == 0) { 555 match++; 556 t = &table[i]; 557 res.flags |= t->value; 558 } 559 break; 560 case FAMILY: 561 if (word == NULL) 562 break; 563 if (!strcmp(word, "inet") || 564 !strcasecmp(word, "IPv4")) { 565 match++; 566 t = &table[i]; 567 res.aid = AID_INET; 568 } 569 if (!strcmp(word, "inet6") || 570 !strcasecmp(word, "IPv6")) { 571 match++; 572 t = &table[i]; 573 res.aid = AID_INET6; 574 } 575 if (!strcasecmp(word, "VPNv4")) { 576 match++; 577 t = &table[i]; 578 res.aid = AID_VPN_IPv4; 579 } 580 break; 581 case ADDRESS: 582 if (parse_addr(word, &res.addr)) { 583 match++; 584 t = &table[i]; 585 if (t->value) 586 res.action = t->value; 587 } 588 break; 589 case PEERADDRESS: 590 if (parse_addr(word, &res.peeraddr)) { 591 match++; 592 t = &table[i]; 593 if (t->value) 594 res.action = t->value; 595 } 596 break; 597 case PREFIX: 598 if (parse_prefix(word, wordlen, &res.addr, &res.prefixlen)) { 599 match++; 600 t = &table[i]; 601 if (t->value) 602 res.action = t->value; 603 } 604 break; 605 case ASTYPE: 606 if (word != NULL && strncmp(word, table[i].keyword, 607 wordlen) == 0) { 608 match++; 609 t = &table[i]; 610 res.as.type = t->value; 611 } 612 break; 613 case ASNUM: 614 if (parse_asnum(word, wordlen, &res.as.as)) { 615 match++; 616 t = &table[i]; 617 } 618 break; 619 case PEERDESC: 620 if (!match && word != NULL && wordlen > 0) { 621 if (strlcpy(res.peerdesc, word, 622 sizeof(res.peerdesc)) >= 623 sizeof(res.peerdesc)) 624 errx(1, "neighbor description too " 625 "long"); 626 match++; 627 t = &table[i]; 628 } 629 break; 630 case RIBNAME: 631 if (!match && word != NULL && wordlen > 0) { 632 if (strlcpy(res.rib, word, sizeof(res.rib)) >= 633 sizeof(res.rib)) 634 errx(1, "rib name too long"); 635 match++; 636 t = &table[i]; 637 } 638 break; 639 case SHUTDOWN_COMMUNICATION: 640 if (!match && word != NULL && wordlen > 0) { 641 if (strlcpy(res.shutcomm, word, 642 sizeof(res.shutcomm)) >= 643 sizeof(res.shutcomm)) 644 errx(1, "shutdown reason too long"); 645 match++; 646 t = &table[i]; 647 } 648 break; 649 case COMMUNITY: 650 if (word != NULL && wordlen > 0 && 651 parse_community(word, &res)) { 652 match++; 653 t = &table[i]; 654 } 655 break; 656 case EXTCOM_SUBTYPE: 657 if (word != NULL && strncmp(word, table[i].keyword, 658 wordlen) == 0) { 659 if (parsesubtype(word, &res.extcommunity.type, 660 &res.extcommunity.subtype) == 0) 661 errx(1, "Bad ext-community unknown " 662 "type"); 663 match++; 664 t = &table[i]; 665 } 666 break; 667 case EXTCOMMUNITY: 668 if (word != NULL && wordlen > 0 && 669 parseextcommunity(word, &res)) { 670 match++; 671 t = &table[i]; 672 } 673 break; 674 case LARGE_COMMUNITY: 675 if (word != NULL && wordlen > 0 && 676 parse_largecommunity(word, &res)) { 677 match++; 678 t = &table[i]; 679 } 680 break; 681 case LOCALPREF: 682 case MED: 683 case PREPNBR: 684 case PREPSELF: 685 case WEIGHT: 686 case RTABLE: 687 if (word != NULL && wordlen > 0 && 688 parse_number(word, &res, table[i].type)) { 689 match++; 690 t = &table[i]; 691 } 692 break; 693 case NEXTHOP: 694 if (word != NULL && wordlen > 0 && 695 parse_nexthop(word, &res)) { 696 match++; 697 t = &table[i]; 698 } 699 break; 700 case PFTABLE: 701 if (word != NULL && wordlen > 0) { 702 if ((fs = calloc(1, 703 sizeof(struct filter_set))) == NULL) 704 err(1, NULL); 705 if (strlcpy(fs->action.pftable, word, 706 sizeof(fs->action.pftable)) >= 707 sizeof(fs->action.pftable)) 708 errx(1, "pftable name too long"); 709 TAILQ_INSERT_TAIL(&res.set, fs, entry); 710 match++; 711 t = &table[i]; 712 } 713 break; 714 case GETOPT: 715 if (bgpctl_getopt(argc, argv, table[i].value)) { 716 match++; 717 t = &table[i]; 718 } 719 break; 720 case FILENAME: 721 if (word != NULL && wordlen > 0) { 722 if ((res.mrtfd = open(word, O_RDONLY)) == -1) { 723 /* 724 * ignore error if path has no / and 725 * does not exist. In hope to print 726 * usage. 727 */ 728 if (errno == ENOENT && 729 !strchr(word, '/')) 730 break; 731 err(1, "mrt open(%s)", word); 732 } 733 match++; 734 t = &table[i]; 735 } 736 break; 737 case BULK: 738 match++; 739 t = &table[i]; 740 break; 741 case ENDTOKEN: 742 break; 743 } 744 } 745 746 if (match != 1) { 747 if (word == NULL) 748 fprintf(stderr, "missing argument:\n"); 749 else if (match > 1) 750 fprintf(stderr, "ambiguous argument: %s\n", word); 751 else if (match < 1) 752 fprintf(stderr, "unknown argument: %s\n", word); 753 return (NULL); 754 } 755 756 return (t); 757 } 758 759 void 760 show_valid_args(const struct token table[]) 761 { 762 int i; 763 764 for (i = 0; table[i].type != ENDTOKEN; i++) { 765 switch (table[i].type) { 766 case NOTOKEN: 767 fprintf(stderr, " <cr>\n"); 768 break; 769 case KEYWORD: 770 case FLAG: 771 case ASTYPE: 772 case EXTCOM_SUBTYPE: 773 fprintf(stderr, " %s\n", table[i].keyword); 774 break; 775 case ADDRESS: 776 case PEERADDRESS: 777 fprintf(stderr, " <address>\n"); 778 break; 779 case PREFIX: 780 fprintf(stderr, " <address>[/<len>]\n"); 781 break; 782 case ASNUM: 783 fprintf(stderr, " <asnum>\n"); 784 break; 785 case PEERDESC: 786 fprintf(stderr, " <neighbor description>\n"); 787 break; 788 case RIBNAME: 789 fprintf(stderr, " <rib name>\n"); 790 break; 791 case SHUTDOWN_COMMUNICATION: 792 fprintf(stderr, " <shutdown reason>\n"); 793 break; 794 case COMMUNITY: 795 fprintf(stderr, " <community>\n"); 796 break; 797 case EXTCOMMUNITY: 798 fprintf(stderr, " <extended-community>\n"); 799 break; 800 case LARGE_COMMUNITY: 801 fprintf(stderr, " <large-community>\n"); 802 break; 803 case LOCALPREF: 804 case MED: 805 case PREPNBR: 806 case PREPSELF: 807 case WEIGHT: 808 fprintf(stderr, " <number>\n"); 809 break; 810 case RTABLE: 811 fprintf(stderr, " <rtableid>\n"); 812 break; 813 case NEXTHOP: 814 fprintf(stderr, " <address>\n"); 815 break; 816 case PFTABLE: 817 fprintf(stderr, " <pftable>\n"); 818 break; 819 case FAMILY: 820 fprintf(stderr, " [ inet | inet6 | IPv4 | IPv6 | VPNv4 ]\n"); 821 break; 822 case GETOPT: 823 fprintf(stderr, " <options>\n"); 824 break; 825 case FILENAME: 826 fprintf(stderr, " <filename>\n"); 827 break; 828 case BULK: 829 case ENDTOKEN: 830 break; 831 } 832 } 833 } 834 835 int 836 parse_addr(const char *word, struct bgpd_addr *addr) 837 { 838 struct in_addr ina; 839 struct addrinfo hints, *r; 840 841 if (word == NULL) 842 return (0); 843 844 bzero(addr, sizeof(struct bgpd_addr)); 845 bzero(&ina, sizeof(ina)); 846 847 if (inet_net_pton(AF_INET, word, &ina, sizeof(ina)) != -1) { 848 addr->aid = AID_INET; 849 addr->v4 = ina; 850 return (1); 851 } 852 853 bzero(&hints, sizeof(hints)); 854 hints.ai_family = AF_INET6; 855 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 856 hints.ai_flags = AI_NUMERICHOST; 857 if (getaddrinfo(word, "0", &hints, &r) == 0) { 858 sa2addr(r->ai_addr, addr); 859 freeaddrinfo(r); 860 return (1); 861 } 862 863 return (0); 864 } 865 866 int 867 parse_prefix(const char *word, size_t wordlen, struct bgpd_addr *addr, u_int8_t *prefixlen) 868 { 869 char *p, *ps; 870 const char *errstr; 871 int mask = -1; 872 873 if (word == NULL) 874 return (0); 875 876 bzero(addr, sizeof(struct bgpd_addr)); 877 878 if ((p = strrchr(word, '/')) != NULL) { 879 size_t plen = strlen(p); 880 mask = strtonum(p + 1, 0, 128, &errstr); 881 if (errstr) 882 errx(1, "netmask %s", errstr); 883 884 if ((ps = malloc(wordlen - plen + 1)) == NULL) 885 err(1, "parse_prefix: malloc"); 886 strlcpy(ps, word, wordlen - plen + 1); 887 888 if (parse_addr(ps, addr) == 0) { 889 free(ps); 890 return (0); 891 } 892 893 free(ps); 894 } else 895 if (parse_addr(word, addr) == 0) 896 return (0); 897 898 switch (addr->aid) { 899 case AID_INET: 900 if (mask == -1) 901 mask = 32; 902 if (mask > 32) 903 errx(1, "invalid netmask: too large"); 904 addr->v4.s_addr = addr->v4.s_addr & htonl(prefixlen2mask(mask)); 905 break; 906 case AID_INET6: 907 if (mask == -1) 908 mask = 128; 909 inet6applymask(&addr->v6, &addr->v6, mask); 910 break; 911 default: 912 return (0); 913 } 914 915 *prefixlen = mask; 916 return (1); 917 } 918 919 int 920 parse_asnum(const char *word, size_t wordlen, u_int32_t *asnum) 921 { 922 const char *errstr; 923 char *dot; 924 u_int32_t uval, uvalh = 0; 925 926 if (word == NULL) 927 return (0); 928 929 if (wordlen < 1 || word[0] < '0' || word[0] > '9') 930 return (0); 931 932 if ((dot = strchr(word,'.')) != NULL) { 933 *dot++ = '\0'; 934 uvalh = strtonum(word, 0, USHRT_MAX, &errstr); 935 if (errstr) 936 errx(1, "AS number is %s: %s", errstr, word); 937 uval = strtonum(dot, 0, USHRT_MAX, &errstr); 938 if (errstr) 939 errx(1, "AS number is %s: %s", errstr, word); 940 } else { 941 uval = strtonum(word, 0, UINT_MAX, &errstr); 942 if (errstr) 943 errx(1, "AS number is %s: %s", errstr, word); 944 } 945 946 *asnum = uval | (uvalh << 16); 947 return (1); 948 } 949 950 int 951 parse_number(const char *word, struct parse_result *r, enum token_type type) 952 { 953 struct filter_set *fs; 954 const char *errstr; 955 u_int uval; 956 957 if (word == NULL) 958 return (0); 959 960 uval = strtonum(word, 0, UINT_MAX, &errstr); 961 if (errstr) 962 errx(1, "number is %s: %s", errstr, word); 963 964 /* number was parseable */ 965 if (type == RTABLE) { 966 r->rtableid = uval; 967 return (1); 968 } 969 970 if ((fs = calloc(1, sizeof(struct filter_set))) == NULL) 971 err(1, NULL); 972 switch (type) { 973 case LOCALPREF: 974 fs->type = ACTION_SET_LOCALPREF; 975 fs->action.metric = uval; 976 break; 977 case MED: 978 fs->type = ACTION_SET_MED; 979 fs->action.metric = uval; 980 break; 981 case PREPNBR: 982 if (uval > 128) { 983 free(fs); 984 return (0); 985 } 986 fs->type = ACTION_SET_PREPEND_PEER; 987 fs->action.prepend = uval; 988 break; 989 case PREPSELF: 990 if (uval > 128) { 991 free(fs); 992 return (0); 993 } 994 fs->type = ACTION_SET_PREPEND_SELF; 995 fs->action.prepend = uval; 996 break; 997 case WEIGHT: 998 fs->type = ACTION_SET_WEIGHT; 999 fs->action.metric = uval; 1000 break; 1001 default: 1002 errx(1, "king bula sez bad things happen"); 1003 } 1004 1005 TAILQ_INSERT_TAIL(&r->set, fs, entry); 1006 return (1); 1007 } 1008 1009 int 1010 getcommunity(const char *s) 1011 { 1012 const char *errstr; 1013 u_int16_t uval; 1014 1015 if (strcmp(s, "*") == 0) 1016 return (COMMUNITY_ANY); 1017 1018 uval = strtonum(s, 0, USHRT_MAX, &errstr); 1019 if (errstr) 1020 errx(1, "Community is %s: %s", errstr, s); 1021 1022 return (uval); 1023 } 1024 1025 int 1026 parse_community(const char *word, struct parse_result *r) 1027 { 1028 struct filter_set *fs; 1029 char *p; 1030 int as, type; 1031 1032 /* Well-known communities */ 1033 if (strcasecmp(word, "GRACEFUL_SHUTDOWN") == 0) { 1034 as = COMMUNITY_WELLKNOWN; 1035 type = COMMUNITY_GRACEFUL_SHUTDOWN; 1036 goto done; 1037 } else if (strcasecmp(word, "NO_EXPORT") == 0) { 1038 as = COMMUNITY_WELLKNOWN; 1039 type = COMMUNITY_NO_EXPORT; 1040 goto done; 1041 } else if (strcasecmp(word, "NO_ADVERTISE") == 0) { 1042 as = COMMUNITY_WELLKNOWN; 1043 type = COMMUNITY_NO_ADVERTISE; 1044 goto done; 1045 } else if (strcasecmp(word, "NO_EXPORT_SUBCONFED") == 0) { 1046 as = COMMUNITY_WELLKNOWN; 1047 type = COMMUNITY_NO_EXPSUBCONFED; 1048 goto done; 1049 } else if (strcasecmp(word, "NO_PEER") == 0) { 1050 as = COMMUNITY_WELLKNOWN; 1051 type = COMMUNITY_NO_PEER; 1052 goto done; 1053 } else if (strcasecmp(word, "BLACKHOLE") == 0) { 1054 as = COMMUNITY_WELLKNOWN; 1055 type = COMMUNITY_BLACKHOLE; 1056 goto done; 1057 } 1058 1059 if ((p = strchr(word, ':')) == NULL) { 1060 fprintf(stderr, "Bad community syntax\n"); 1061 return (0); 1062 } 1063 *p++ = 0; 1064 1065 as = getcommunity(word); 1066 type = getcommunity(p); 1067 1068 done: 1069 if (as == 0) { 1070 fprintf(stderr, "Invalid community\n"); 1071 return (0); 1072 } 1073 if (as == COMMUNITY_WELLKNOWN) 1074 switch (type) { 1075 case COMMUNITY_GRACEFUL_SHUTDOWN: 1076 case COMMUNITY_NO_EXPORT: 1077 case COMMUNITY_NO_ADVERTISE: 1078 case COMMUNITY_NO_EXPSUBCONFED: 1079 case COMMUNITY_BLACKHOLE: 1080 /* valid */ 1081 break; 1082 } 1083 1084 if ((fs = calloc(1, sizeof(struct filter_set))) == NULL) 1085 err(1, NULL); 1086 fs->type = ACTION_SET_COMMUNITY; 1087 fs->action.community.as = as; 1088 fs->action.community.type = type; 1089 1090 r->community.as = as; 1091 r->community.type = type; 1092 1093 TAILQ_INSERT_TAIL(&r->set, fs, entry); 1094 return (1); 1095 } 1096 1097 int 1098 parsesubtype(const char *name, u_int8_t *type, u_int8_t *subtype) 1099 { 1100 const struct ext_comm_pairs *cp; 1101 int found = 0; 1102 1103 for (cp = iana_ext_comms; cp->subname != NULL; cp++) { 1104 if (strcmp(name, cp->subname) == 0) { 1105 if (found == 0) { 1106 *type = cp->type; 1107 *subtype = cp->subtype; 1108 } 1109 found++; 1110 } 1111 } 1112 if (found > 1) 1113 *type = -1; 1114 return (found); 1115 } 1116 1117 int 1118 parseextvalue(const char *s, u_int32_t *v) 1119 { 1120 const char *errstr; 1121 char *p; 1122 struct in_addr ip; 1123 u_int32_t uvalh = 0, uval; 1124 1125 if ((p = strchr(s, '.')) == NULL) { 1126 /* AS_PLAIN number (4 or 2 byte) */ 1127 uval = strtonum(s, 0, UINT_MAX, &errstr); 1128 if (errstr) { 1129 fprintf(stderr, "Bad ext-community: %s is %s\n", s, 1130 errstr); 1131 return (-1); 1132 } 1133 *v = uval; 1134 if (uval <= USHRT_MAX) 1135 return (EXT_COMMUNITY_TRANS_TWO_AS); 1136 else 1137 return (EXT_COMMUNITY_TRANS_FOUR_AS); 1138 } else if (strchr(p + 1, '.') == NULL) { 1139 /* AS_DOT number (4-byte) */ 1140 *p++ = '\0'; 1141 uvalh = strtonum(s, 0, USHRT_MAX, &errstr); 1142 if (errstr) { 1143 fprintf(stderr, "Bad ext-community: %s is %s\n", s, 1144 errstr); 1145 return (-1); 1146 } 1147 uval = strtonum(p, 0, USHRT_MAX, &errstr); 1148 if (errstr) { 1149 fprintf(stderr, "Bad ext-community: %s is %s\n", p, 1150 errstr); 1151 return (-1); 1152 } 1153 *v = uval | (uvalh << 16); 1154 return (EXT_COMMUNITY_TRANS_FOUR_AS); 1155 } else { 1156 /* more than one dot -> IP address */ 1157 if (inet_aton(s, &ip) == 0) { 1158 fprintf(stderr, "Bad ext-community: %s not parseable\n", 1159 s); 1160 return (-1); 1161 } 1162 *v = ip.s_addr; 1163 return (EXT_COMMUNITY_TRANS_IPV4); 1164 } 1165 return (-1); 1166 } 1167 1168 u_int 1169 parseextcommunity(const char *word, struct parse_result *r) 1170 { 1171 struct filter_set *fs; 1172 const struct ext_comm_pairs *cp; 1173 const char *errstr; 1174 u_int64_t ullval; 1175 u_int32_t uval; 1176 char *p, *ep; 1177 int type; 1178 1179 type = r->extcommunity.type; 1180 1181 switch (type) { 1182 case 0xff: 1183 if ((p = strchr(word, ':')) == NULL) { 1184 fprintf(stderr, "Bad ext-community: %s\n", word); 1185 return (0); 1186 } 1187 *p++ = '\0'; 1188 if ((type = parseextvalue(word, &uval)) == -1) 1189 return (0); 1190 switch (type) { 1191 case EXT_COMMUNITY_TRANS_TWO_AS: 1192 ullval = strtonum(p, 0, UINT_MAX, &errstr); 1193 break; 1194 case EXT_COMMUNITY_TRANS_IPV4: 1195 case EXT_COMMUNITY_TRANS_FOUR_AS: 1196 ullval = strtonum(p, 0, USHRT_MAX, &errstr); 1197 break; 1198 default: 1199 fprintf(stderr, "parseextcommunity: unexpected " 1200 "result\n"); 1201 return (0); 1202 } 1203 if (errstr) { 1204 fprintf(stderr, "Bad ext-community: %s is %s\n", p, 1205 errstr); 1206 return (0); 1207 } 1208 switch (type) { 1209 case EXT_COMMUNITY_TRANS_TWO_AS: 1210 r->extcommunity.data.ext_as.as = uval; 1211 r->extcommunity.data.ext_as.val = ullval; 1212 break; 1213 case EXT_COMMUNITY_TRANS_IPV4: 1214 r->extcommunity.data.ext_ip.addr.s_addr = uval; 1215 r->extcommunity.data.ext_ip.val = ullval; 1216 break; 1217 case EXT_COMMUNITY_TRANS_FOUR_AS: 1218 r->extcommunity.data.ext_as4.as4 = uval; 1219 r->extcommunity.data.ext_as4.val = ullval; 1220 break; 1221 } 1222 break; 1223 case EXT_COMMUNITY_TRANS_OPAQUE: 1224 case EXT_COMMUNITY_TRANS_EVPN: 1225 errno = 0; 1226 ullval = strtoull(word, &ep, 0); 1227 if (word[0] == '\0' || *ep != '\0') { 1228 fprintf(stderr, "Bad ext-community: bad value\n"); 1229 return (0); 1230 } 1231 if (errno == ERANGE && ullval > EXT_COMMUNITY_OPAQUE_MAX) { 1232 fprintf(stderr, "Bad ext-community: too big\n"); 1233 return (0); 1234 } 1235 r->extcommunity.data.ext_opaq = ullval; 1236 break; 1237 case EXT_COMMUNITY_NON_TRANS_OPAQUE: 1238 if (strcmp(word, "valid") == 0) 1239 r->extcommunity.data.ext_opaq = EXT_COMMUNITY_OVS_VALID; 1240 else if (strcmp(word, "invalid") == 0) 1241 r->extcommunity.data.ext_opaq = 1242 EXT_COMMUNITY_OVS_INVALID; 1243 else if (strcmp(word, "not-found") == 0) 1244 r->extcommunity.data.ext_opaq = 1245 EXT_COMMUNITY_OVS_NOTFOUND; 1246 else { 1247 fprintf(stderr, "Bad ext-community value: %s\n", word); 1248 return (0); 1249 } 1250 break; 1251 } 1252 r->extcommunity.type = type; 1253 1254 /* verify type/subtype combo */ 1255 for (cp = iana_ext_comms; cp->subname != NULL; cp++) { 1256 if (cp->type == r->extcommunity.type && 1257 cp->subtype == r->extcommunity.subtype) { 1258 r->extcommunity.flags |= EXT_COMMUNITY_FLAG_VALID; 1259 if ((fs = calloc(1, sizeof(struct filter_set))) == NULL) 1260 err(1, NULL); 1261 1262 fs->type = ACTION_SET_EXT_COMMUNITY; 1263 memcpy(&fs->action.ext_community, &r->extcommunity, 1264 sizeof(struct filter_extcommunity)); 1265 1266 TAILQ_INSERT_TAIL(&r->set, fs, entry); 1267 return (1); 1268 } 1269 } 1270 1271 fprintf(stderr, "Bad ext-community: bad format for type\n"); 1272 return (0); 1273 } 1274 1275 u_int 1276 getlargecommunity(const char *s) 1277 { 1278 const char *errstr; 1279 u_int32_t uval; 1280 1281 if (strcmp(s, "*") == 0) 1282 return (COMMUNITY_ANY); 1283 1284 uval = strtonum(s, 0, UINT_MAX, &errstr); 1285 if (errstr) 1286 errx(1, "Large Community is %s: %s", errstr, s); 1287 1288 return (uval); 1289 } 1290 1291 int 1292 parse_largecommunity(const char *word, struct parse_result *r) 1293 { 1294 struct filter_set *fs; 1295 char *p, *po = strdup(word); 1296 char *array[3] = { NULL, NULL, NULL }; 1297 char *val; 1298 int64_t as, ld1, ld2; 1299 int i = 0; 1300 1301 p = po; 1302 while ((p != NULL) && (i < 3)) { 1303 val = strsep(&p, ":"); 1304 array[i++] = val; 1305 } 1306 1307 if ((p != NULL) || !(array[0] && array[1] && array[2])) 1308 errx(1, "Invalid Large-Community syntax"); 1309 1310 as = getlargecommunity(array[0]); 1311 ld1 = getlargecommunity(array[1]); 1312 ld2 = getlargecommunity(array[2]); 1313 1314 free(po); 1315 1316 if ((fs = calloc(1, sizeof(struct filter_set))) == NULL) 1317 err(1, NULL); 1318 fs->type = ACTION_SET_LARGE_COMMUNITY; 1319 fs->action.large_community.as = as; 1320 fs->action.large_community.ld1 = ld1; 1321 fs->action.large_community.ld2 = ld2; 1322 1323 r->large_community.as = as; 1324 r->large_community.ld1 = ld1; 1325 r->large_community.ld2 = ld2; 1326 1327 TAILQ_INSERT_TAIL(&r->set, fs, entry); 1328 return (1); 1329 } 1330 1331 int 1332 parse_nexthop(const char *word, struct parse_result *r) 1333 { 1334 struct filter_set *fs; 1335 1336 if ((fs = calloc(1, sizeof(struct filter_set))) == NULL) 1337 err(1, NULL); 1338 1339 if (strcmp(word, "blackhole") == 0) 1340 fs->type = ACTION_SET_NEXTHOP_BLACKHOLE; 1341 else if (strcmp(word, "reject") == 0) 1342 fs->type = ACTION_SET_NEXTHOP_REJECT; 1343 else if (strcmp(word, "no-modify") == 0) 1344 fs->type = ACTION_SET_NEXTHOP_NOMODIFY; 1345 else if (parse_addr(word, &fs->action.nexthop)) { 1346 fs->type = ACTION_SET_NEXTHOP; 1347 } else { 1348 free(fs); 1349 return (0); 1350 } 1351 1352 TAILQ_INSERT_TAIL(&r->set, fs, entry); 1353 return (1); 1354 } 1355 1356 int 1357 bgpctl_getopt(int *argc, char **argv[], int type) 1358 { 1359 int ch; 1360 1361 optind = optreset = 1; 1362 while ((ch = getopt((*argc) + 1, (*argv) - 1, "46o:")) != -1) { 1363 switch (ch) { 1364 case '4': 1365 res.flags = (res.flags | F_IPV4) & ~F_IPV6; 1366 break; 1367 case '6': 1368 res.flags = (res.flags | F_IPV6) & ~F_IPV4; 1369 break; 1370 case 'o': 1371 res.irr_outdir = optarg; 1372 break; 1373 default: 1374 usage(); 1375 /* NOTREACHED */ 1376 } 1377 } 1378 1379 if (optind > 1) { 1380 (*argc) -= (optind - 1); 1381 (*argv) += (optind - 1); 1382 1383 /* need to move one backwards as calling code moves forward */ 1384 (*argc)++; 1385 (*argv)--; 1386 return (1); 1387 } else 1388 return (0); 1389 } 1390