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