xref: /openbsd-src/usr.sbin/ripctl/parser.c (revision 33a9ef426717cea0731f7d9607264e1db814a61a)
1*33a9ef42Sflorian /*	$OpenBSD: parser.c,v 1.7 2017/07/28 13:02:35 florian Exp $ */
28eeeb81eSnorby 
38eeeb81eSnorby /*
48eeeb81eSnorby  * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
58eeeb81eSnorby  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
68eeeb81eSnorby  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
78eeeb81eSnorby  *
88eeeb81eSnorby  * Permission to use, copy, modify, and distribute this software for any
98eeeb81eSnorby  * purpose with or without fee is hereby granted, provided that the above
108eeeb81eSnorby  * copyright notice and this permission notice appear in all copies.
118eeeb81eSnorby  *
128eeeb81eSnorby  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
138eeeb81eSnorby  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
148eeeb81eSnorby  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
158eeeb81eSnorby  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
168eeeb81eSnorby  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
178eeeb81eSnorby  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
188eeeb81eSnorby  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
198eeeb81eSnorby  */
208eeeb81eSnorby 
218eeeb81eSnorby #include <sys/types.h>
228eeeb81eSnorby #include <sys/socket.h>
238eeeb81eSnorby #include <netinet/in.h>
248eeeb81eSnorby #include <arpa/inet.h>
258eeeb81eSnorby #include <err.h>
268eeeb81eSnorby #include <errno.h>
278eeeb81eSnorby #include <limits.h>
288eeeb81eSnorby #include <stdio.h>
298eeeb81eSnorby #include <stdlib.h>
308eeeb81eSnorby #include <string.h>
318eeeb81eSnorby 
328eeeb81eSnorby #include "ripd.h"
338eeeb81eSnorby 
348eeeb81eSnorby #include "parser.h"
358eeeb81eSnorby 
368eeeb81eSnorby enum token_type {
378eeeb81eSnorby 	NOTOKEN,
388eeeb81eSnorby 	ENDTOKEN,
398eeeb81eSnorby 	KEYWORD,
408eeeb81eSnorby 	ADDRESS,
418eeeb81eSnorby 	FLAG,
428eeeb81eSnorby 	PREFIX,
438eeeb81eSnorby 	IFNAME
448eeeb81eSnorby };
458eeeb81eSnorby 
468eeeb81eSnorby struct token {
478eeeb81eSnorby 	enum token_type		 type;
488eeeb81eSnorby 	const char		*keyword;
498eeeb81eSnorby 	int			 value;
508eeeb81eSnorby 	const struct token	*next;
518eeeb81eSnorby };
528eeeb81eSnorby 
538eeeb81eSnorby static const struct token t_main[];
548eeeb81eSnorby static const struct token t_fib[];
558eeeb81eSnorby static const struct token t_show[];
568eeeb81eSnorby static const struct token t_show_iface[];
578eeeb81eSnorby static const struct token t_show_nbr[];
588eeeb81eSnorby static const struct token t_show_rib[];
598eeeb81eSnorby static const struct token t_show_fib[];
60c3319070Sclaudio static const struct token t_log[];
618eeeb81eSnorby 
628eeeb81eSnorby static const struct token t_main[] = {
638eeeb81eSnorby /*	{KEYWORD,	"reload",	RELOAD,		NULL}, */
648eeeb81eSnorby 	{KEYWORD,	"fib",		FIB,		t_fib},
658eeeb81eSnorby 	{KEYWORD,	"show",		SHOW,		t_show},
66c3319070Sclaudio 	{KEYWORD,	"log",		NONE,		t_log},
678eeeb81eSnorby 	{ENDTOKEN,	"",		NONE,		NULL}
688eeeb81eSnorby };
698eeeb81eSnorby 
708eeeb81eSnorby static const struct token t_fib[] = {
718eeeb81eSnorby 	{ KEYWORD,	"couple",	FIB_COUPLE,	NULL},
728eeeb81eSnorby 	{ KEYWORD,	"decouple",	FIB_DECOUPLE,	NULL},
738eeeb81eSnorby 	{ ENDTOKEN,	"",		NONE,		NULL}
748eeeb81eSnorby };
758eeeb81eSnorby 
768eeeb81eSnorby static const struct token t_show[] = {
778eeeb81eSnorby 	{NOTOKEN,	"",		NONE,		NULL},
788eeeb81eSnorby 	{KEYWORD,	"interfaces",	SHOW_IFACE,	t_show_iface},
798eeeb81eSnorby 	{KEYWORD,	"neighbor",	SHOW_NBR,	t_show_nbr},
808eeeb81eSnorby 	{KEYWORD,	"rib",		SHOW_RIB,	t_show_rib},
818eeeb81eSnorby 	{KEYWORD,	"fib",		SHOW_FIB,	t_show_fib},
828eeeb81eSnorby 	{ENDTOKEN,	"",		NONE,		NULL}
838eeeb81eSnorby };
848eeeb81eSnorby 
858eeeb81eSnorby static const struct token t_show_iface[] = {
868eeeb81eSnorby 	{NOTOKEN,	"",		NONE,			NULL},
878eeeb81eSnorby 	{ENDTOKEN,	"",		NONE,			NULL}
888eeeb81eSnorby };
898eeeb81eSnorby 
908eeeb81eSnorby static const struct token t_show_nbr[] = {
918eeeb81eSnorby 	{NOTOKEN,	"",		NONE,		NULL},
928eeeb81eSnorby 	{ENDTOKEN,	"",		NONE,		NULL}
938eeeb81eSnorby };
948eeeb81eSnorby 
958eeeb81eSnorby static const struct token t_show_rib[] = {
968eeeb81eSnorby 	{NOTOKEN,	"",		NONE,		NULL},
978eeeb81eSnorby 	{ENDTOKEN,	"",		NONE,		NULL}
988eeeb81eSnorby };
998eeeb81eSnorby 
1008eeeb81eSnorby static const struct token t_show_fib[] = {
1018eeeb81eSnorby 	{NOTOKEN,	"",		NONE,			NULL},
1028eeeb81eSnorby 	{KEYWORD,	"interface",	SHOW_FIB_IFACE,		t_show_iface},
1038eeeb81eSnorby 	{FLAG,		"connected",	F_CONNECTED,		t_show_fib},
1048eeeb81eSnorby 	{FLAG,		"static",	F_STATIC,		t_show_fib},
1058eeeb81eSnorby 	{FLAG,		"rip",		F_RIPD_INSERTED,	t_show_fib},
1068eeeb81eSnorby 	{ADDRESS,	"",		NONE,			NULL},
1078eeeb81eSnorby 	{ENDTOKEN,	"",		NONE,			NULL}
1088eeeb81eSnorby };
1098eeeb81eSnorby 
110c3319070Sclaudio static const struct token t_log[] = {
111c3319070Sclaudio 	{KEYWORD,	"verbose",	LOG_VERBOSE,		NULL},
112c3319070Sclaudio 	{KEYWORD,	"brief",	LOG_BRIEF,		NULL},
113c3319070Sclaudio 	{ENDTOKEN,	"",		NONE,			NULL}
114c3319070Sclaudio };
115c3319070Sclaudio 
1166be5843eStedu static const struct token *match_token(const char *, const struct token *,
1176be5843eStedu     struct parse_result *);
1186c9c7f05Skettenis static void show_valid_args(const struct token *table);
1198eeeb81eSnorby 
1208eeeb81eSnorby struct parse_result *
parse(int argc,char * argv[])1218eeeb81eSnorby parse(int argc, char *argv[])
1228eeeb81eSnorby {
1236be5843eStedu 	static struct parse_result res;
1248eeeb81eSnorby 	const struct token	*table = t_main;
1258eeeb81eSnorby 	const struct token	*match;
1268eeeb81eSnorby 
1278eeeb81eSnorby 	bzero(&res, sizeof(res));
1288eeeb81eSnorby 
1297500ebd3Sclaudio 	while (argc >= 0) {
1306be5843eStedu 		if ((match = match_token(argv[0], table, &res)) == NULL) {
1318eeeb81eSnorby 			fprintf(stderr, "valid commands/args:\n");
1328eeeb81eSnorby 			show_valid_args(table);
1338eeeb81eSnorby 			return (NULL);
1348eeeb81eSnorby 		}
1358eeeb81eSnorby 
1368eeeb81eSnorby 		argc--;
1378eeeb81eSnorby 		argv++;
1388eeeb81eSnorby 
1398eeeb81eSnorby 		if (match->type == NOTOKEN || match->next == NULL)
1408eeeb81eSnorby 			break;
1418eeeb81eSnorby 
1428eeeb81eSnorby 		table = match->next;
1438eeeb81eSnorby 	}
1448eeeb81eSnorby 
1458eeeb81eSnorby 	if (argc > 0) {
1468eeeb81eSnorby 		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
1478eeeb81eSnorby 		return (NULL);
1488eeeb81eSnorby 	}
1498eeeb81eSnorby 
1508eeeb81eSnorby 	return (&res);
1518eeeb81eSnorby }
1528eeeb81eSnorby 
1536be5843eStedu static const struct token *
match_token(const char * word,const struct token * table,struct parse_result * res)1546be5843eStedu match_token(const char *word, const struct token *table,
1556be5843eStedu     struct parse_result *res)
1568eeeb81eSnorby {
1578eeeb81eSnorby 	u_int			 i, match;
1588eeeb81eSnorby 	const struct token	*t = NULL;
1598eeeb81eSnorby 
1608eeeb81eSnorby 	match = 0;
1618eeeb81eSnorby 
1628eeeb81eSnorby 	for (i = 0; table[i].type != ENDTOKEN; i++) {
1638eeeb81eSnorby 		switch (table[i].type) {
1648eeeb81eSnorby 		case NOTOKEN:
1658eeeb81eSnorby 			if (word == NULL || strlen(word) == 0) {
1668eeeb81eSnorby 				match++;
1678eeeb81eSnorby 				t = &table[i];
1688eeeb81eSnorby 			}
1698eeeb81eSnorby 			break;
1708eeeb81eSnorby 		case KEYWORD:
1718eeeb81eSnorby 			if (word != NULL && strncmp(word, table[i].keyword,
1728eeeb81eSnorby 			    strlen(word)) == 0) {
1738eeeb81eSnorby 				match++;
1748eeeb81eSnorby 				t = &table[i];
1758eeeb81eSnorby 				if (t->value)
1766be5843eStedu 					res->action = t->value;
1778eeeb81eSnorby 			}
1788eeeb81eSnorby 			break;
1798eeeb81eSnorby 		case FLAG:
1808eeeb81eSnorby 			if (word != NULL && strncmp(word, table[i].keyword,
1818eeeb81eSnorby 			    strlen(word)) == 0) {
1828eeeb81eSnorby 				match++;
1838eeeb81eSnorby 				t = &table[i];
1846be5843eStedu 				res->flags |= t->value;
1858eeeb81eSnorby 			}
1868eeeb81eSnorby 			break;
1878eeeb81eSnorby 		case ADDRESS:
1886be5843eStedu 			if (parse_addr(word, &res->addr)) {
1898eeeb81eSnorby 				match++;
1908eeeb81eSnorby 				t = &table[i];
1918eeeb81eSnorby 				if (t->value)
1926be5843eStedu 					res->action = t->value;
1938eeeb81eSnorby 			}
1948eeeb81eSnorby 			break;
1958eeeb81eSnorby 		case PREFIX:
1966be5843eStedu 			if (parse_prefix(word, &res->addr, &res->prefixlen)) {
1978eeeb81eSnorby 				match++;
1988eeeb81eSnorby 				t = &table[i];
1998eeeb81eSnorby 				if (t->value)
2006be5843eStedu 					res->action = t->value;
2018eeeb81eSnorby 			}
2028eeeb81eSnorby 			break;
2038eeeb81eSnorby 		case IFNAME:
2048eeeb81eSnorby 			if (!match && word != NULL && strlen(word) > 0) {
2056be5843eStedu 				if (strlcpy(res->ifname, word,
2066be5843eStedu 				    sizeof(res->ifname)) >=
2076be5843eStedu 				    sizeof(res->ifname))
2088eeeb81eSnorby 					err(1, "interface name too long");
2098eeeb81eSnorby 				match++;
2108eeeb81eSnorby 				t = &table[i];
2118eeeb81eSnorby 				if (t->value)
2126be5843eStedu 					res->action = t->value;
2138eeeb81eSnorby 			}
2148eeeb81eSnorby 			break;
2158eeeb81eSnorby 
2168eeeb81eSnorby 		case ENDTOKEN:
2178eeeb81eSnorby 			break;
2188eeeb81eSnorby 		}
2198eeeb81eSnorby 	}
2208eeeb81eSnorby 
2218eeeb81eSnorby 	if (match != 1) {
2227500ebd3Sclaudio 		if (word == NULL)
2237500ebd3Sclaudio 			fprintf(stderr, "missing argument:\n");
2247500ebd3Sclaudio 		else if (match > 1)
2258eeeb81eSnorby 			fprintf(stderr, "ambiguous argument: %s\n", word);
2267500ebd3Sclaudio 		else if (match < 1)
2278eeeb81eSnorby 			fprintf(stderr, "unknown argument: %s\n", word);
2288eeeb81eSnorby 		return (NULL);
2298eeeb81eSnorby 	}
2308eeeb81eSnorby 
2318eeeb81eSnorby 	return (t);
2328eeeb81eSnorby }
2338eeeb81eSnorby 
2346be5843eStedu static void
show_valid_args(const struct token * table)235e331d0fcSjsg show_valid_args(const struct token *table)
2368eeeb81eSnorby {
2378eeeb81eSnorby 	int	i;
2388eeeb81eSnorby 
2398eeeb81eSnorby 	for (i = 0; table[i].type != ENDTOKEN; i++) {
2408eeeb81eSnorby 		switch (table[i].type) {
2418eeeb81eSnorby 		case NOTOKEN:
2428eeeb81eSnorby 			fprintf(stderr, "  <cr>\n");
2438eeeb81eSnorby 			break;
2448eeeb81eSnorby 		case KEYWORD:
2458eeeb81eSnorby 		case FLAG:
2468eeeb81eSnorby 			fprintf(stderr, "  %s\n", table[i].keyword);
2478eeeb81eSnorby 			break;
2488eeeb81eSnorby 		case ADDRESS:
2498eeeb81eSnorby 			fprintf(stderr, "  <address>\n");
2508eeeb81eSnorby 			break;
2518eeeb81eSnorby 		case PREFIX:
2528eeeb81eSnorby 			fprintf(stderr, "  <address>[/<len>]\n");
2538eeeb81eSnorby 			break;
2548eeeb81eSnorby 		case IFNAME:
2558eeeb81eSnorby 			fprintf(stderr, "  <interface>\n");
2568eeeb81eSnorby 		case ENDTOKEN:
2578eeeb81eSnorby 			break;
2588eeeb81eSnorby 		}
2598eeeb81eSnorby 	}
2608eeeb81eSnorby }
2618eeeb81eSnorby 
2628eeeb81eSnorby int
parse_addr(const char * word,struct in_addr * addr)2638eeeb81eSnorby parse_addr(const char *word, struct in_addr *addr)
2648eeeb81eSnorby {
2658eeeb81eSnorby 	struct in_addr	ina;
2668eeeb81eSnorby 
2678eeeb81eSnorby 	if (word == NULL)
2688eeeb81eSnorby 		return (0);
2698eeeb81eSnorby 
2708eeeb81eSnorby 	bzero(addr, sizeof(struct in_addr));
2718eeeb81eSnorby 	bzero(&ina, sizeof(ina));
2728eeeb81eSnorby 
2738eeeb81eSnorby 	if (inet_pton(AF_INET, word, &ina)) {
2748eeeb81eSnorby 		addr->s_addr = ina.s_addr;
2758eeeb81eSnorby 		return (1);
2768eeeb81eSnorby 	}
2778eeeb81eSnorby 
2788eeeb81eSnorby 	return (0);
2798eeeb81eSnorby }
2808eeeb81eSnorby 
2818eeeb81eSnorby int
parse_prefix(const char * word,struct in_addr * addr,u_int8_t * prefixlen)2828eeeb81eSnorby parse_prefix(const char *word, struct in_addr *addr, u_int8_t *prefixlen)
2838eeeb81eSnorby {
2848eeeb81eSnorby 	struct in_addr	 ina;
2858eeeb81eSnorby 	int		 bits = 32;
2868eeeb81eSnorby 
2878eeeb81eSnorby 	if (word == NULL)
2888eeeb81eSnorby 		return (0);
2898eeeb81eSnorby 
2908eeeb81eSnorby 	bzero(addr, sizeof(struct in_addr));
2918eeeb81eSnorby 	bzero(&ina, sizeof(ina));
2928eeeb81eSnorby 
2938eeeb81eSnorby 	if (strrchr(word, '/') != NULL) {
2948eeeb81eSnorby 		if ((bits = inet_net_pton(AF_INET, word,
2958eeeb81eSnorby 		    &ina, sizeof(ina))) == -1)
2968eeeb81eSnorby 			return (0);
2978eeeb81eSnorby 		addr->s_addr = ina.s_addr & htonl(prefixlen2mask(bits));
2988eeeb81eSnorby 		*prefixlen = bits;
2998eeeb81eSnorby 		return (1);
3008eeeb81eSnorby 	} else {
3018eeeb81eSnorby 		*prefixlen = 32;
3028eeeb81eSnorby 		return (parse_addr(word, addr));
3038eeeb81eSnorby 	}
3048eeeb81eSnorby 
3058eeeb81eSnorby 	return (0);
3068eeeb81eSnorby }
3078eeeb81eSnorby 
3088eeeb81eSnorby /* XXX local copy from kroute.c, should go to shared file */
3098eeeb81eSnorby in_addr_t
prefixlen2mask(u_int8_t prefixlen)3108eeeb81eSnorby prefixlen2mask(u_int8_t prefixlen)
3118eeeb81eSnorby {
3128eeeb81eSnorby 	if (prefixlen == 0)
3138eeeb81eSnorby 		return (0);
3148eeeb81eSnorby 
3158eeeb81eSnorby 	return (0xffffffff << (32 - prefixlen));
3168eeeb81eSnorby }
317