1 /* $OpenBSD: parser.c,v 1.4 2016/01/15 12:57:49 renato Exp $ */ 2 3 /* 4 * Copyright (c) 2015 Renato Westphal <renato@openbsd.org> 5 * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 6 * Copyright (c) 2003, 2004 Henning Brauer <henning@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 #include <sys/socket.h> 23 #include <netinet/in.h> 24 #include <arpa/inet.h> 25 #include <err.h> 26 #include <errno.h> 27 #include <limits.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <netdb.h> 32 33 #include "eigrpd.h" 34 35 #include "parser.h" 36 37 enum token_type { 38 NOTOKEN, 39 ENDTOKEN, 40 KEYWORD, 41 FAMILY, 42 ASNUM, 43 ADDRESS, 44 FLAG, 45 PREFIX, 46 IFNAME 47 }; 48 49 struct token { 50 enum token_type type; 51 const char *keyword; 52 int value; 53 const struct token *next; 54 }; 55 56 static const struct token t_main[]; 57 static const struct token t_fib[]; 58 static const struct token t_show[]; 59 static const struct token t_show_iface[]; 60 static const struct token t_show_iface_af[]; 61 static const struct token t_show_iface_as[]; 62 static const struct token t_show_nbr[]; 63 static const struct token t_show_nbr_af[]; 64 static const struct token t_show_nbr_as[]; 65 static const struct token t_show_topology[]; 66 static const struct token t_show_topology_af[]; 67 static const struct token t_show_topology_as[]; 68 static const struct token t_show_fib[]; 69 static const struct token t_show_fib_af[]; 70 static const struct token t_show_stats[]; 71 static const struct token t_show_stats_af[]; 72 static const struct token t_show_stats_as[]; 73 static const struct token t_log[]; 74 static const struct token t_clear[]; 75 static const struct token t_clear_nbr[]; 76 static const struct token t_clear_nbr_af[]; 77 static const struct token t_clear_nbr_as[]; 78 79 static const struct token t_main[] = { 80 {KEYWORD, "reload", RELOAD, NULL}, 81 {KEYWORD, "fib", FIB, t_fib}, 82 {KEYWORD, "show", SHOW, t_show}, 83 {KEYWORD, "clear", NONE, t_clear}, 84 {KEYWORD, "log", NONE, t_log}, 85 {ENDTOKEN, "", NONE, NULL} 86 }; 87 88 static const struct token t_fib[] = { 89 { KEYWORD, "couple", FIB_COUPLE, NULL}, 90 { KEYWORD, "decouple", FIB_DECOUPLE, NULL}, 91 { ENDTOKEN, "", NONE, NULL} 92 }; 93 94 static const struct token t_show[] = { 95 {NOTOKEN, "", NONE, NULL}, 96 {KEYWORD, "interfaces", SHOW_IFACE, t_show_iface}, 97 {KEYWORD, "neighbor", SHOW_NBR, t_show_nbr}, 98 {KEYWORD, "topology", SHOW_TOPOLOGY, t_show_topology}, 99 {KEYWORD, "fib", SHOW_FIB, t_show_fib}, 100 {KEYWORD, "traffic", SHOW_STATS, t_show_stats}, 101 {ENDTOKEN, "", NONE, NULL} 102 }; 103 104 static const struct token t_show_iface[] = { 105 {NOTOKEN, "", NONE, NULL}, 106 {KEYWORD, "family", NONE, t_show_iface_af}, 107 {KEYWORD, "as", NONE, t_show_iface_as}, 108 {KEYWORD, "detail", SHOW_IFACE_DTAIL, NULL}, 109 {IFNAME, "", SHOW_IFACE_DTAIL, NULL}, 110 {ENDTOKEN, "", NONE, NULL} 111 }; 112 113 static const struct token t_show_iface_af[] = { 114 {FAMILY, "", NONE, t_show_iface}, 115 {ENDTOKEN, "", NONE, NULL} 116 }; 117 118 static const struct token t_show_iface_as[] = { 119 {ASNUM, "", NONE, t_show_iface}, 120 {ENDTOKEN, "", NONE, NULL} 121 }; 122 123 static const struct token t_show_nbr[] = { 124 {NOTOKEN, "", NONE, NULL}, 125 {KEYWORD, "family", NONE, t_show_nbr_af}, 126 {KEYWORD, "as", NONE, t_show_nbr_as}, 127 {ENDTOKEN, "", NONE, NULL} 128 }; 129 130 static const struct token t_show_nbr_af[] = { 131 {FAMILY, "", NONE, t_show_nbr}, 132 {ENDTOKEN, "", NONE, NULL} 133 }; 134 135 static const struct token t_show_nbr_as[] = { 136 {ASNUM, "", NONE, t_show_nbr}, 137 {ENDTOKEN, "", NONE, NULL} 138 }; 139 140 static const struct token t_show_topology[] = { 141 {NOTOKEN, "", NONE, NULL}, 142 {KEYWORD, "family", NONE, t_show_topology_af}, 143 {KEYWORD, "as", NONE, t_show_topology_as}, 144 {PREFIX, "", NONE, NULL}, 145 {FLAG, "active", F_CTL_ACTIVE, NULL}, 146 {FLAG, "all-links", F_CTL_ALLLINKS, NULL}, 147 {ENDTOKEN, "", NONE, NULL} 148 }; 149 150 static const struct token t_show_topology_af[] = { 151 {FAMILY, "", NONE, t_show_topology}, 152 {ENDTOKEN, "", NONE, NULL} 153 }; 154 155 static const struct token t_show_topology_as[] = { 156 {ASNUM, "", NONE, t_show_topology}, 157 {ENDTOKEN, "", NONE, NULL} 158 }; 159 160 static const struct token t_show_fib[] = { 161 {NOTOKEN, "", NONE, NULL}, 162 {KEYWORD, "family", NONE, t_show_fib_af}, 163 {KEYWORD, "interface", SHOW_FIB_IFACE, t_show_iface}, 164 {FLAG, "connected", F_CONNECTED, t_show_fib}, 165 {FLAG, "static", F_STATIC, t_show_fib}, 166 {FLAG, "eigrp", F_EIGRPD_INSERTED, t_show_fib}, 167 {ENDTOKEN, "", NONE, NULL} 168 }; 169 170 static const struct token t_show_fib_af[] = { 171 {FAMILY, "", NONE, t_show_fib}, 172 {ENDTOKEN, "", NONE, NULL} 173 }; 174 175 176 static const struct token t_show_stats[] = { 177 {NOTOKEN, "", NONE, NULL}, 178 {KEYWORD, "family", NONE, t_show_stats_af}, 179 {KEYWORD, "as", NONE, t_show_stats_as}, 180 {ENDTOKEN, "", NONE, NULL} 181 }; 182 183 static const struct token t_show_stats_af[] = { 184 {FAMILY, "", NONE, t_show_stats}, 185 {ENDTOKEN, "", NONE, NULL} 186 }; 187 188 static const struct token t_show_stats_as[] = { 189 {ASNUM, "", NONE, t_show_stats}, 190 {ENDTOKEN, "", NONE, NULL} 191 }; 192 193 static const struct token t_clear[] = { 194 {KEYWORD, "neighbors", CLEAR_NBR, t_clear_nbr}, 195 {ENDTOKEN, "", NONE, NULL} 196 }; 197 198 static const struct token t_clear_nbr[] = { 199 {NOTOKEN, "", NONE, NULL}, 200 {KEYWORD, "as", NONE, t_clear_nbr_as}, 201 {KEYWORD, "family", NONE, t_clear_nbr_af}, 202 {ADDRESS, "", NONE, NULL}, 203 {ENDTOKEN, "", NONE, NULL} 204 }; 205 206 static const struct token t_clear_nbr_af[] = { 207 {FAMILY, "", NONE, t_clear_nbr}, 208 {ENDTOKEN, "", NONE, NULL} 209 }; 210 211 static const struct token t_clear_nbr_as[] = { 212 {ASNUM, "", NONE, t_clear_nbr}, 213 {ENDTOKEN, "", NONE, NULL} 214 }; 215 216 static const struct token t_log[] = { 217 {KEYWORD, "verbose", LOG_VERBOSE, NULL}, 218 {KEYWORD, "brief", LOG_BRIEF, NULL}, 219 {ENDTOKEN, "", NONE, NULL} 220 }; 221 222 static const struct token *match_token(const char *, const struct token *, 223 struct parse_result *); 224 static void show_valid_args(const struct token *); 225 226 struct parse_result * 227 parse(int argc, char *argv[]) 228 { 229 static struct parse_result res; 230 const struct token *table = t_main; 231 const struct token *match; 232 233 memset(&res, 0, sizeof(res)); 234 235 while (argc >= 0) { 236 if ((match = match_token(argv[0], table, &res)) == NULL) { 237 fprintf(stderr, "valid commands/args:\n"); 238 show_valid_args(table); 239 return (NULL); 240 } 241 242 argc--; 243 argv++; 244 245 if (match->type == NOTOKEN || match->next == NULL) 246 break; 247 248 table = match->next; 249 } 250 251 if (argc > 0) { 252 fprintf(stderr, "superfluous argument: %s\n", argv[0]); 253 return (NULL); 254 } 255 256 return (&res); 257 } 258 259 static const struct token * 260 match_token(const char *word, const struct token *table, 261 struct parse_result *res) 262 { 263 unsigned int i, match; 264 const struct token *t = NULL; 265 266 match = 0; 267 268 for (i = 0; table[i].type != ENDTOKEN; i++) { 269 switch (table[i].type) { 270 case NOTOKEN: 271 if (word == NULL || strlen(word) == 0) { 272 match++; 273 t = &table[i]; 274 } 275 break; 276 case KEYWORD: 277 if (word != NULL && strncmp(word, table[i].keyword, 278 strlen(word)) == 0) { 279 match++; 280 t = &table[i]; 281 if (t->value) 282 res->action = t->value; 283 } 284 break; 285 case FLAG: 286 if (word != NULL && strncmp(word, table[i].keyword, 287 strlen(word)) == 0) { 288 match++; 289 t = &table[i]; 290 res->flags |= t->value; 291 } 292 break; 293 case FAMILY: 294 if (word == NULL) 295 break; 296 if (!strcmp(word, "inet") || 297 !strcasecmp(word, "IPv4")) { 298 match++; 299 t = &table[i]; 300 res->family = AF_INET; 301 } 302 if (!strcmp(word, "inet6") || 303 !strcasecmp(word, "IPv6")) { 304 match++; 305 t = &table[i]; 306 res->family = AF_INET6; 307 } 308 break; 309 case ASNUM: 310 if (parse_asnum(word, &res->as)) { 311 match++; 312 t = &table[i]; 313 } 314 break; 315 case ADDRESS: 316 if (parse_addr(word, &res->family, &res->addr)) { 317 match++; 318 t = &table[i]; 319 if (t->value) 320 res->action = t->value; 321 } 322 break; 323 case PREFIX: 324 if (parse_prefix(word, &res->family, &res->addr, 325 &res->prefixlen)) { 326 match++; 327 t = &table[i]; 328 if (t->value) 329 res->action = t->value; 330 } 331 break; 332 case IFNAME: 333 if (!match && word != NULL && strlen(word) > 0) { 334 if (strlcpy(res->ifname, word, 335 sizeof(res->ifname)) >= 336 sizeof(res->ifname)) 337 err(1, "interface name too long"); 338 match++; 339 t = &table[i]; 340 if (t->value) 341 res->action = t->value; 342 } 343 break; 344 345 case ENDTOKEN: 346 break; 347 } 348 } 349 350 if (match != 1) { 351 if (word == NULL) 352 fprintf(stderr, "missing argument:\n"); 353 else if (match > 1) 354 fprintf(stderr, "ambiguous argument: %s\n", word); 355 else if (match < 1) 356 fprintf(stderr, "unknown argument: %s\n", word); 357 return (NULL); 358 } 359 360 return (t); 361 } 362 363 static void 364 show_valid_args(const struct token *table) 365 { 366 int i; 367 368 for (i = 0; table[i].type != ENDTOKEN; i++) { 369 switch (table[i].type) { 370 case NOTOKEN: 371 fprintf(stderr, " <cr>\n"); 372 break; 373 case KEYWORD: 374 case FLAG: 375 fprintf(stderr, " %s\n", table[i].keyword); 376 break; 377 case FAMILY: 378 fprintf(stderr, " [ inet | inet6 | IPv4 | IPv6 ]\n"); 379 break; 380 case ASNUM: 381 fprintf(stderr, " <asnum>\n"); 382 break; 383 case ADDRESS: 384 fprintf(stderr, " <address>\n"); 385 break; 386 case PREFIX: 387 fprintf(stderr, " <address>[/<len>]\n"); 388 break; 389 case IFNAME: 390 fprintf(stderr, " <interface>\n"); 391 break; 392 case ENDTOKEN: 393 break; 394 } 395 } 396 } 397 398 int 399 parse_asnum(const char *word, uint16_t *asnum) 400 { 401 const char *errstr; 402 uint32_t uval; 403 404 if (word == NULL) 405 return (0); 406 407 uval = strtonum(word, EIGRP_MIN_AS, EIGRP_MAX_AS, &errstr); 408 if (errstr) 409 errx(1, "AS number is %s: %s", errstr, word); 410 411 *asnum = uval; 412 return (1); 413 } 414 415 int 416 parse_addr(const char *word, int *family, union eigrpd_addr *addr) 417 { 418 struct in_addr ina; 419 struct addrinfo hints, *r; 420 struct sockaddr_in6 *sa_in6; 421 422 if (word == NULL) 423 return (0); 424 425 memset(addr, 0, sizeof(union eigrpd_addr)); 426 memset(&ina, 0, sizeof(ina)); 427 428 if (inet_net_pton(AF_INET, word, &ina, sizeof(ina)) != -1) { 429 *family = AF_INET; 430 addr->v4.s_addr = ina.s_addr; 431 return (1); 432 } 433 434 memset(&hints, 0, sizeof(hints)); 435 hints.ai_family = AF_INET6; 436 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 437 hints.ai_flags = AI_NUMERICHOST; 438 if (getaddrinfo(word, "0", &hints, &r) == 0) { 439 sa_in6 = (struct sockaddr_in6 *)r->ai_addr; 440 *family = AF_INET6; 441 addr->v6 = sa_in6->sin6_addr; 442 freeaddrinfo(r); 443 return (1); 444 } 445 446 return (0); 447 } 448 449 int 450 parse_prefix(const char *word, int *family, union eigrpd_addr *addr, 451 uint8_t *prefixlen) 452 { 453 char *p, *ps; 454 const char *errstr; 455 size_t wordlen; 456 int mask = -1; 457 458 if (word == NULL) 459 return (0); 460 wordlen = strlen(word); 461 462 memset(addr, 0, sizeof(union eigrpd_addr)); 463 464 if ((p = strrchr(word, '/')) != NULL) { 465 size_t plen = strlen(p); 466 mask = strtonum(p + 1, 0, 128, &errstr); 467 if (errstr) 468 errx(1, "netmask %s", errstr); 469 470 if ((ps = malloc(wordlen - plen + 1)) == NULL) 471 err(1, "parse_prefix: malloc"); 472 strlcpy(ps, word, wordlen - plen + 1); 473 474 if (parse_addr(ps, family, addr) == 0) { 475 free(ps); 476 return (0); 477 } 478 479 free(ps); 480 } else 481 if (parse_addr(word, family, addr) == 0) 482 return (0); 483 484 switch (*family) { 485 case AF_INET: 486 if (mask == UINT8_MAX) 487 mask = 32; 488 if (mask > 32) 489 errx(1, "invalid netmask: too large"); 490 break; 491 case AF_INET6: 492 if (mask == UINT8_MAX) 493 mask = 128; 494 if (mask > 128) 495 errx(1, "invalid netmask: too large"); 496 break; 497 default: 498 return (0); 499 } 500 eigrp_applymask(*family, addr, addr, mask); 501 *prefixlen = mask; 502 503 return (1); 504 } 505