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 *
parse(int argc,char * argv[])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 *
match_token(const char * word,const struct token * table,struct parse_result * res)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
show_valid_args(const struct token * table)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
parse_asnum(const char * word,uint16_t * asnum)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
parse_addr(const char * word,int * family,union eigrpd_addr * addr)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
parse_prefix(const char * word,int * family,union eigrpd_addr * addr,uint8_t * prefixlen)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