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