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