xref: /openbsd/usr.sbin/eigrpctl/parser.c (revision 956c66a0)
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