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