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