1 /* $OpenBSD: parser.c,v 1.2 2015/10/14 13:27:50 jsg 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_log[]; 71 72 static const struct token t_main[] = { 73 {KEYWORD, "reload", RELOAD, NULL}, 74 {KEYWORD, "fib", FIB, t_fib}, 75 {KEYWORD, "show", SHOW, t_show}, 76 {KEYWORD, "log", NONE, t_log}, 77 {ENDTOKEN, "", NONE, NULL} 78 }; 79 80 static const struct token t_fib[] = { 81 { KEYWORD, "couple", FIB_COUPLE, NULL}, 82 { KEYWORD, "decouple", FIB_DECOUPLE, NULL}, 83 { ENDTOKEN, "", NONE, NULL} 84 }; 85 86 static const struct token t_show[] = { 87 {NOTOKEN, "", NONE, NULL}, 88 {KEYWORD, "interfaces", SHOW_IFACE, t_show_iface}, 89 {KEYWORD, "neighbor", SHOW_NBR, t_show_nbr}, 90 {KEYWORD, "topology", SHOW_TOPOLOGY, t_show_topology}, 91 {KEYWORD, "fib", SHOW_FIB, t_show_fib}, 92 {ENDTOKEN, "", NONE, NULL} 93 }; 94 95 static const struct token t_show_iface[] = { 96 {NOTOKEN, "", NONE, NULL}, 97 {KEYWORD, "family", NONE, t_show_iface_af}, 98 {KEYWORD, "as", NONE, t_show_iface_as}, 99 {KEYWORD, "detail", SHOW_IFACE_DTAIL, NULL}, 100 {IFNAME, "", SHOW_IFACE_DTAIL, NULL}, 101 {ENDTOKEN, "", NONE, NULL} 102 }; 103 104 static const struct token t_show_iface_af[] = { 105 {FAMILY, "", NONE, t_show_iface}, 106 {ENDTOKEN, "", NONE, NULL} 107 }; 108 109 static const struct token t_show_iface_as[] = { 110 {ASNUM, "", NONE, t_show_iface}, 111 {ENDTOKEN, "", NONE, NULL} 112 }; 113 114 static const struct token t_show_nbr[] = { 115 {NOTOKEN, "", NONE, NULL}, 116 {KEYWORD, "family", NONE, t_show_nbr_af}, 117 {KEYWORD, "as", NONE, t_show_nbr_as}, 118 {ENDTOKEN, "", NONE, NULL} 119 }; 120 121 static const struct token t_show_nbr_af[] = { 122 {FAMILY, "", NONE, t_show_nbr}, 123 {ENDTOKEN, "", NONE, NULL} 124 }; 125 126 static const struct token t_show_nbr_as[] = { 127 {ASNUM, "", NONE, t_show_nbr}, 128 {ENDTOKEN, "", NONE, NULL} 129 }; 130 131 static const struct token t_show_topology[] = { 132 {NOTOKEN, "", NONE, NULL}, 133 {KEYWORD, "family", NONE, t_show_topology_af}, 134 {KEYWORD, "as", NONE, t_show_topology_as}, 135 {PREFIX, "", NONE, NULL}, 136 {FLAG, "active", F_CTL_ACTIVE, NULL}, 137 {FLAG, "all-links", F_CTL_ALLLINKS, NULL}, 138 {ENDTOKEN, "", NONE, NULL} 139 }; 140 141 static const struct token t_show_topology_af[] = { 142 {FAMILY, "", NONE, t_show_topology}, 143 {ENDTOKEN, "", NONE, NULL} 144 }; 145 146 static const struct token t_show_topology_as[] = { 147 {ASNUM, "", NONE, t_show_topology}, 148 {ENDTOKEN, "", NONE, NULL} 149 }; 150 151 static const struct token t_show_fib[] = { 152 {NOTOKEN, "", NONE, NULL}, 153 {KEYWORD, "family", NONE, t_show_fib_af}, 154 {KEYWORD, "interface", SHOW_FIB_IFACE, t_show_iface}, 155 {FLAG, "connected", F_CONNECTED, t_show_fib}, 156 {FLAG, "static", F_STATIC, t_show_fib}, 157 {FLAG, "eigrp", F_EIGRPD_INSERTED, t_show_fib}, 158 {ENDTOKEN, "", NONE, NULL} 159 }; 160 161 static const struct token t_show_fib_af[] = { 162 {FAMILY, "", NONE, t_show_fib}, 163 {ENDTOKEN, "", NONE, NULL} 164 }; 165 166 static const struct token t_log[] = { 167 {KEYWORD, "verbose", LOG_VERBOSE, NULL}, 168 {KEYWORD, "brief", LOG_BRIEF, NULL}, 169 {ENDTOKEN, "", NONE, NULL} 170 }; 171 172 static const struct token *match_token(const char *, const struct token *, 173 struct parse_result *); 174 static void show_valid_args(const struct token *); 175 176 struct parse_result * 177 parse(int argc, char *argv[]) 178 { 179 static struct parse_result res; 180 const struct token *table = t_main; 181 const struct token *match; 182 183 memset(&res, 0, sizeof(res)); 184 185 while (argc >= 0) { 186 if ((match = match_token(argv[0], table, &res)) == NULL) { 187 fprintf(stderr, "valid commands/args:\n"); 188 show_valid_args(table); 189 return (NULL); 190 } 191 192 argc--; 193 argv++; 194 195 if (match->type == NOTOKEN || match->next == NULL) 196 break; 197 198 table = match->next; 199 } 200 201 if (argc > 0) { 202 fprintf(stderr, "superfluous argument: %s\n", argv[0]); 203 return (NULL); 204 } 205 206 return (&res); 207 } 208 209 static const struct token * 210 match_token(const char *word, const struct token *table, 211 struct parse_result *res) 212 { 213 unsigned int i, match; 214 const struct token *t = NULL; 215 216 match = 0; 217 218 for (i = 0; table[i].type != ENDTOKEN; i++) { 219 switch (table[i].type) { 220 case NOTOKEN: 221 if (word == NULL || strlen(word) == 0) { 222 match++; 223 t = &table[i]; 224 } 225 break; 226 case KEYWORD: 227 if (word != NULL && strncmp(word, table[i].keyword, 228 strlen(word)) == 0) { 229 match++; 230 t = &table[i]; 231 if (t->value) 232 res->action = t->value; 233 } 234 break; 235 case FLAG: 236 if (word != NULL && strncmp(word, table[i].keyword, 237 strlen(word)) == 0) { 238 match++; 239 t = &table[i]; 240 res->flags |= t->value; 241 } 242 break; 243 case FAMILY: 244 if (word == NULL) 245 break; 246 if (!strcmp(word, "inet") || 247 !strcasecmp(word, "IPv4")) { 248 match++; 249 t = &table[i]; 250 res->family = AF_INET; 251 } 252 if (!strcmp(word, "inet6") || 253 !strcasecmp(word, "IPv6")) { 254 match++; 255 t = &table[i]; 256 res->family = AF_INET6; 257 } 258 break; 259 case ASNUM: 260 if (parse_asnum(word, &res->as)) { 261 match++; 262 t = &table[i]; 263 } 264 break; 265 case ADDRESS: 266 if (parse_addr(word, &res->family, &res->addr)) { 267 match++; 268 t = &table[i]; 269 if (t->value) 270 res->action = t->value; 271 } 272 break; 273 case PREFIX: 274 if (parse_prefix(word, &res->family, &res->addr, 275 &res->prefixlen)) { 276 match++; 277 t = &table[i]; 278 if (t->value) 279 res->action = t->value; 280 } 281 break; 282 case IFNAME: 283 if (!match && word != NULL && strlen(word) > 0) { 284 if (strlcpy(res->ifname, word, 285 sizeof(res->ifname)) >= 286 sizeof(res->ifname)) 287 err(1, "interface name too long"); 288 match++; 289 t = &table[i]; 290 if (t->value) 291 res->action = t->value; 292 } 293 break; 294 295 case ENDTOKEN: 296 break; 297 } 298 } 299 300 if (match != 1) { 301 if (word == NULL) 302 fprintf(stderr, "missing argument:\n"); 303 else if (match > 1) 304 fprintf(stderr, "ambiguous argument: %s\n", word); 305 else if (match < 1) 306 fprintf(stderr, "unknown argument: %s\n", word); 307 return (NULL); 308 } 309 310 return (t); 311 } 312 313 static void 314 show_valid_args(const struct token *table) 315 { 316 int i; 317 318 for (i = 0; table[i].type != ENDTOKEN; i++) { 319 switch (table[i].type) { 320 case NOTOKEN: 321 fprintf(stderr, " <cr>\n"); 322 break; 323 case KEYWORD: 324 case FLAG: 325 fprintf(stderr, " %s\n", table[i].keyword); 326 break; 327 case FAMILY: 328 fprintf(stderr, " [ inet | inet6 | IPv4 | IPv6 ]\n"); 329 break; 330 case ASNUM: 331 fprintf(stderr, " <asnum>\n"); 332 break; 333 case ADDRESS: 334 fprintf(stderr, " <address>\n"); 335 break; 336 case PREFIX: 337 fprintf(stderr, " <address>[/<len>]\n"); 338 break; 339 case IFNAME: 340 fprintf(stderr, " <interface>\n"); 341 break; 342 case ENDTOKEN: 343 break; 344 } 345 } 346 } 347 348 int 349 parse_asnum(const char *word, uint16_t *asnum) 350 { 351 const char *errstr; 352 uint32_t uval; 353 354 if (word == NULL) 355 return (0); 356 357 uval = strtonum(word, EIGRP_MIN_AS, EIGRP_MAX_AS, &errstr); 358 if (errstr) 359 errx(1, "AS number is %s: %s", errstr, word); 360 361 *asnum = uval; 362 return (1); 363 } 364 365 int 366 parse_addr(const char *word, int *family, union eigrpd_addr *addr) 367 { 368 struct in_addr ina; 369 struct addrinfo hints, *r; 370 struct sockaddr_in6 *sa_in6; 371 372 if (word == NULL) 373 return (0); 374 375 memset(addr, 0, sizeof(union eigrpd_addr)); 376 memset(&ina, 0, sizeof(ina)); 377 378 if (inet_net_pton(AF_INET, word, &ina, sizeof(ina)) != -1) { 379 *family = AF_INET; 380 addr->v4.s_addr = ina.s_addr; 381 return (1); 382 } 383 384 memset(&hints, 0, sizeof(hints)); 385 hints.ai_family = AF_INET6; 386 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 387 hints.ai_flags = AI_NUMERICHOST; 388 if (getaddrinfo(word, "0", &hints, &r) == 0) { 389 sa_in6 = (struct sockaddr_in6 *)r->ai_addr; 390 *family = AF_INET6; 391 addr->v6 = sa_in6->sin6_addr; 392 freeaddrinfo(r); 393 return (1); 394 } 395 396 return (0); 397 } 398 399 int 400 parse_prefix(const char *word, int *family, union eigrpd_addr *addr, 401 uint8_t *prefixlen) 402 { 403 char *p, *ps; 404 const char *errstr; 405 size_t wordlen; 406 int mask = -1; 407 408 if (word == NULL) 409 return (0); 410 wordlen = strlen(word); 411 412 memset(addr, 0, sizeof(union eigrpd_addr)); 413 414 if ((p = strrchr(word, '/')) != NULL) { 415 size_t plen = strlen(p); 416 mask = strtonum(p + 1, 0, 128, &errstr); 417 if (errstr) 418 errx(1, "netmask %s", errstr); 419 420 if ((ps = malloc(wordlen - plen + 1)) == NULL) 421 err(1, "parse_prefix: malloc"); 422 strlcpy(ps, word, wordlen - plen + 1); 423 424 if (parse_addr(ps, family, addr) == 0) { 425 free(ps); 426 return (0); 427 } 428 429 free(ps); 430 } else 431 if (parse_addr(word, family, addr) == 0) 432 return (0); 433 434 switch (*family) { 435 case AF_INET: 436 if (mask == UINT8_MAX) 437 mask = 32; 438 if (mask > 32) 439 errx(1, "invalid netmask: too large"); 440 break; 441 case AF_INET6: 442 if (mask == UINT8_MAX) 443 mask = 128; 444 if (mask > 128) 445 errx(1, "invalid netmask: too large"); 446 break; 447 default: 448 return (0); 449 } 450 eigrp_applymask(*family, addr, addr, mask); 451 *prefixlen = mask; 452 453 return (1); 454 } 455