xref: /openbsd-src/usr.sbin/ospf6ctl/parser.c (revision dd3b9a80516716eb7d3616a923f2076c1f1589de)
1*dd3b9a80Ssthen /*	$OpenBSD: parser.c,v 1.15 2023/06/21 09:47:03 sthen Exp $ */
28e709cbdSnorby 
38e709cbdSnorby /*
48e709cbdSnorby  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
58e709cbdSnorby  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
68e709cbdSnorby  *
78e709cbdSnorby  * Permission to use, copy, modify, and distribute this software for any
88e709cbdSnorby  * purpose with or without fee is hereby granted, provided that the above
98e709cbdSnorby  * copyright notice and this permission notice appear in all copies.
108e709cbdSnorby  *
118e709cbdSnorby  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
128e709cbdSnorby  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
138e709cbdSnorby  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
148e709cbdSnorby  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
158e709cbdSnorby  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
168e709cbdSnorby  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
178e709cbdSnorby  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
188e709cbdSnorby  */
198e709cbdSnorby 
208e709cbdSnorby #include <sys/types.h>
218e709cbdSnorby #include <sys/socket.h>
228e709cbdSnorby #include <netinet/in.h>
238e709cbdSnorby #include <arpa/inet.h>
248e709cbdSnorby #include <err.h>
258e709cbdSnorby #include <errno.h>
268e709cbdSnorby #include <limits.h>
270104e403Sclaudio #include <netdb.h>
288e709cbdSnorby #include <stdio.h>
298e709cbdSnorby #include <stdlib.h>
308e709cbdSnorby #include <string.h>
318e709cbdSnorby 
328e709cbdSnorby #include "ospf6d.h"
338e709cbdSnorby 
348e709cbdSnorby #include "parser.h"
358e709cbdSnorby 
368e709cbdSnorby enum token_type {
378e709cbdSnorby 	NOTOKEN,
388e709cbdSnorby 	ENDTOKEN,
398e709cbdSnorby 	KEYWORD,
408e709cbdSnorby 	ADDRESS,
418e709cbdSnorby 	FLAG,
428e709cbdSnorby 	PREFIX,
4396950f83Sremi 	IFNAME,
4496950f83Sremi 	AREA
458e709cbdSnorby };
468e709cbdSnorby 
478e709cbdSnorby struct token {
488e709cbdSnorby 	enum token_type		 type;
498e709cbdSnorby 	const char		*keyword;
508e709cbdSnorby 	int			 value;
518e709cbdSnorby 	const struct token	*next;
528e709cbdSnorby };
538e709cbdSnorby 
548e709cbdSnorby static const struct token t_main[];
558e709cbdSnorby static const struct token t_fib[];
568e709cbdSnorby static const struct token t_show[];
578e709cbdSnorby static const struct token t_show_iface[];
588e709cbdSnorby static const struct token t_show_db[];
598e709cbdSnorby static const struct token t_show_area[];
608e709cbdSnorby static const struct token t_show_nbr[];
618e709cbdSnorby static const struct token t_show_rib[];
628e709cbdSnorby static const struct token t_show_fib[];
63c3319070Sclaudio static const struct token t_log[];
648e709cbdSnorby 
658e709cbdSnorby static const struct token t_main[] = {
668e709cbdSnorby 	{KEYWORD,	"reload",	RELOAD,		NULL},
678e709cbdSnorby 	{KEYWORD,	"fib",		FIB,		t_fib},
688e709cbdSnorby 	{KEYWORD,	"show",		SHOW,		t_show},
69c3319070Sclaudio 	{KEYWORD,	"log",		NONE,		t_log},
708e709cbdSnorby 	{ENDTOKEN,	"",		NONE,		NULL}
718e709cbdSnorby };
728e709cbdSnorby 
738e709cbdSnorby static const struct token t_fib[] = {
748e709cbdSnorby 	{ KEYWORD,	"couple",	FIB_COUPLE,	NULL},
758e709cbdSnorby 	{ KEYWORD,	"decouple",	FIB_DECOUPLE,	NULL},
76*dd3b9a80Ssthen 	{ KEYWORD,	"reload",	FIB_RELOAD,	NULL},
778e709cbdSnorby 	{ ENDTOKEN,	"",		NONE,		NULL}
788e709cbdSnorby };
798e709cbdSnorby 
808e709cbdSnorby static const struct token t_show[] = {
818e709cbdSnorby 	{NOTOKEN,	"",		NONE,		NULL},
828e709cbdSnorby 	{KEYWORD,	"interfaces",	SHOW_IFACE,	t_show_iface},
838e709cbdSnorby 	{KEYWORD,	"database",	SHOW_DB,	t_show_db},
848e709cbdSnorby 	{KEYWORD,	"neighbor",	SHOW_NBR,	t_show_nbr},
858e709cbdSnorby 	{KEYWORD,	"rib",		SHOW_RIB,	t_show_rib},
868e709cbdSnorby 	{KEYWORD,	"fib",		SHOW_FIB,	t_show_fib},
878e709cbdSnorby 	{KEYWORD,	"summary",	SHOW_SUM,	NULL},
888e709cbdSnorby 	{ENDTOKEN,	"",		NONE,		NULL}
898e709cbdSnorby };
908e709cbdSnorby 
918e709cbdSnorby static const struct token t_show_iface[] = {
928e709cbdSnorby 	{NOTOKEN,	"",		NONE,			NULL},
938e709cbdSnorby 	{KEYWORD,	"detail",	SHOW_IFACE_DTAIL,	NULL},
948e709cbdSnorby 	{IFNAME,	"",		SHOW_IFACE_DTAIL,	NULL},
958e709cbdSnorby 	{ENDTOKEN,	"",		NONE,			NULL}
968e709cbdSnorby };
978e709cbdSnorby 
988e709cbdSnorby static const struct token t_show_db[] = {
998e709cbdSnorby 	{NOTOKEN,	"",			NONE,		NULL},
1008e709cbdSnorby 	{KEYWORD,	"area",			SHOW_DBBYAREA,	t_show_area},
1018e709cbdSnorby 	{KEYWORD,	"asbr",			SHOW_DBASBR,	NULL},
1028e709cbdSnorby 	{KEYWORD,	"external",		SHOW_DBEXT,	NULL},
103aeb06b08Sclaudio 	{KEYWORD,	"link",			SHOW_DBLINK,	NULL},
1048e709cbdSnorby 	{KEYWORD,	"network",		SHOW_DBNET,	NULL},
1058e709cbdSnorby 	{KEYWORD,	"router",		SHOW_DBRTR,	NULL},
10641bcac6bSstsp 	{KEYWORD,	"intra",		SHOW_DBINTRA,	NULL},
1078e709cbdSnorby 	{KEYWORD,	"self-originated",	SHOW_DBSELF,	NULL},
1088e709cbdSnorby 	{KEYWORD,	"summary",		SHOW_DBSUM,	NULL},
1098e709cbdSnorby 	{ENDTOKEN,	"",			NONE,		NULL}
1108e709cbdSnorby };
1118e709cbdSnorby 
1128e709cbdSnorby static const struct token t_show_area[] = {
11396950f83Sremi 	{AREA,		"",		NONE,		NULL},
1148e709cbdSnorby 	{ENDTOKEN,	"",		NONE,		NULL}
1158e709cbdSnorby };
1168e709cbdSnorby 
1178e709cbdSnorby static const struct token t_show_nbr[] = {
1188e709cbdSnorby 	{NOTOKEN,	"",		NONE,		NULL},
1198e709cbdSnorby 	{KEYWORD,	"detail",	SHOW_NBR_DTAIL,	NULL},
1208e709cbdSnorby 	{ENDTOKEN,	"",		NONE,		NULL}
1218e709cbdSnorby };
1228e709cbdSnorby 
1238e709cbdSnorby static const struct token t_show_rib[] = {
1248e709cbdSnorby 	{NOTOKEN,	"",		NONE,		NULL},
1258e709cbdSnorby 	{KEYWORD,	"detail",	SHOW_RIB_DTAIL,	NULL},
1268e709cbdSnorby 	{ENDTOKEN,	"",		NONE,		NULL}
1278e709cbdSnorby };
1288e709cbdSnorby 
1298e709cbdSnorby static const struct token t_show_fib[] = {
1308e709cbdSnorby 	{NOTOKEN,	"",		NONE,			NULL},
1318e709cbdSnorby 	{FLAG,		"connected",	F_CONNECTED,		t_show_fib},
1328e709cbdSnorby 	{FLAG,		"static",	F_STATIC,		t_show_fib},
1338e709cbdSnorby 	{FLAG,		"ospf",		F_OSPFD_INSERTED,	t_show_fib},
1348e709cbdSnorby 	{ADDRESS,	"",		NONE,			NULL},
1358e709cbdSnorby 	{ENDTOKEN,	"",		NONE,			NULL}
1368e709cbdSnorby };
1378e709cbdSnorby 
138c3319070Sclaudio static const struct token t_log[] = {
139c3319070Sclaudio 	{KEYWORD,	"verbose",	LOG_VERBOSE,		NULL},
140c3319070Sclaudio 	{KEYWORD,	"brief",	LOG_BRIEF,		NULL},
141c3319070Sclaudio 	{ENDTOKEN,	"",		NONE,			NULL}
142c3319070Sclaudio };
143c3319070Sclaudio 
1446be5843eStedu static const struct token *match_token(const char *, const struct token *,
1456be5843eStedu     struct parse_result *);
1466be5843eStedu static void show_valid_args(const struct token *);
1478e709cbdSnorby 
1488e709cbdSnorby struct parse_result *
parse(int argc,char * argv[])1498e709cbdSnorby parse(int argc, char *argv[])
1508e709cbdSnorby {
1516be5843eStedu 	static struct parse_result	res;
1528e709cbdSnorby 	const struct token	*table = t_main;
1538e709cbdSnorby 	const struct token	*match;
1548e709cbdSnorby 
1558e709cbdSnorby 	bzero(&res, sizeof(res));
1568e709cbdSnorby 
1578e709cbdSnorby 	while (argc >= 0) {
1586be5843eStedu 		if ((match = match_token(argv[0], table, &res)) == NULL) {
1598e709cbdSnorby 			fprintf(stderr, "valid commands/args:\n");
1608e709cbdSnorby 			show_valid_args(table);
1618e709cbdSnorby 			return (NULL);
1628e709cbdSnorby 		}
1638e709cbdSnorby 
1648e709cbdSnorby 		argc--;
1658e709cbdSnorby 		argv++;
1668e709cbdSnorby 
1678e709cbdSnorby 		if (match->type == NOTOKEN || match->next == NULL)
1688e709cbdSnorby 			break;
1698e709cbdSnorby 
1708e709cbdSnorby 		table = match->next;
1718e709cbdSnorby 	}
1728e709cbdSnorby 
1738e709cbdSnorby 	if (argc > 0) {
1748e709cbdSnorby 		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
1758e709cbdSnorby 		return (NULL);
1768e709cbdSnorby 	}
1778e709cbdSnorby 
1788e709cbdSnorby 	return (&res);
1798e709cbdSnorby }
1808e709cbdSnorby 
1816be5843eStedu static const struct token *
match_token(const char * word,const struct token * table,struct parse_result * res)1826be5843eStedu match_token(const char *word, const struct token *table,
1836be5843eStedu     struct parse_result *res)
1848e709cbdSnorby {
1858e709cbdSnorby 	u_int			 i, match;
1868e709cbdSnorby 	const struct token	*t = NULL;
1878e709cbdSnorby 
1888e709cbdSnorby 	match = 0;
1898e709cbdSnorby 
1908e709cbdSnorby 	for (i = 0; table[i].type != ENDTOKEN; i++) {
1918e709cbdSnorby 		switch (table[i].type) {
1928e709cbdSnorby 		case NOTOKEN:
1938e709cbdSnorby 			if (word == NULL || strlen(word) == 0) {
1948e709cbdSnorby 				match++;
1958e709cbdSnorby 				t = &table[i];
1968e709cbdSnorby 			}
1978e709cbdSnorby 			break;
1988e709cbdSnorby 		case KEYWORD:
1998e709cbdSnorby 			if (word != NULL && strncmp(word, table[i].keyword,
2008e709cbdSnorby 			    strlen(word)) == 0) {
2018e709cbdSnorby 				match++;
2028e709cbdSnorby 				t = &table[i];
2038e709cbdSnorby 				if (t->value)
2046be5843eStedu 					res->action = t->value;
2058e709cbdSnorby 			}
2068e709cbdSnorby 			break;
2078e709cbdSnorby 		case FLAG:
2088e709cbdSnorby 			if (word != NULL && strncmp(word, table[i].keyword,
2098e709cbdSnorby 			    strlen(word)) == 0) {
2108e709cbdSnorby 				match++;
2118e709cbdSnorby 				t = &table[i];
2126be5843eStedu 				res->flags |= t->value;
2138e709cbdSnorby 			}
2148e709cbdSnorby 			break;
2158e709cbdSnorby 		case ADDRESS:
2166be5843eStedu 			if (parse_addr(word, &res->addr)) {
2178e709cbdSnorby 				match++;
2188e709cbdSnorby 				t = &table[i];
2198e709cbdSnorby 				if (t->value)
2206be5843eStedu 					res->action = t->value;
2218e709cbdSnorby 			}
2228e709cbdSnorby 			break;
22396950f83Sremi 		case AREA:
22496950f83Sremi 			if (parse_area(word, &res->area)) {
22596950f83Sremi 				match++;
22696950f83Sremi 				t = &table[i];
22796950f83Sremi 				if (t->value)
22896950f83Sremi 					res->action = t->value;
22996950f83Sremi 			}
23096950f83Sremi 			break;
2318e709cbdSnorby 		case PREFIX:
2326be5843eStedu 			if (parse_prefix(word, &res->addr, &res->prefixlen)) {
2338e709cbdSnorby 				match++;
2348e709cbdSnorby 				t = &table[i];
2358e709cbdSnorby 				if (t->value)
2366be5843eStedu 					res->action = t->value;
2378e709cbdSnorby 			}
2388e709cbdSnorby 			break;
2398e709cbdSnorby 		case IFNAME:
2408e709cbdSnorby 			if (!match && word != NULL && strlen(word) > 0) {
2416be5843eStedu 				if (strlcpy(res->ifname, word,
2426be5843eStedu 				    sizeof(res->ifname)) >=
2436be5843eStedu 				    sizeof(res->ifname))
2448e709cbdSnorby 					err(1, "interface name too long");
2458e709cbdSnorby 				match++;
2468e709cbdSnorby 				t = &table[i];
2478e709cbdSnorby 				if (t->value)
2486be5843eStedu 					res->action = t->value;
2498e709cbdSnorby 			}
2508e709cbdSnorby 			break;
2518e709cbdSnorby 
2528e709cbdSnorby 		case ENDTOKEN:
2538e709cbdSnorby 			break;
2548e709cbdSnorby 		}
2558e709cbdSnorby 	}
2568e709cbdSnorby 
2578e709cbdSnorby 	if (match != 1) {
2588e709cbdSnorby 		if (word == NULL)
2598e709cbdSnorby 			fprintf(stderr, "missing argument:\n");
2608e709cbdSnorby 		else if (match > 1)
2618e709cbdSnorby 			fprintf(stderr, "ambiguous argument: %s\n", word);
2628e709cbdSnorby 		else if (match < 1)
2638e709cbdSnorby 			fprintf(stderr, "unknown argument: %s\n", word);
2648e709cbdSnorby 		return (NULL);
2658e709cbdSnorby 	}
2668e709cbdSnorby 
2678e709cbdSnorby 	return (t);
2688e709cbdSnorby }
2698e709cbdSnorby 
2706be5843eStedu static void
show_valid_args(const struct token * table)2714b80bbd0Sjsg show_valid_args(const struct token *table)
2728e709cbdSnorby {
2738e709cbdSnorby 	int	i;
2748e709cbdSnorby 
2758e709cbdSnorby 	for (i = 0; table[i].type != ENDTOKEN; i++) {
2768e709cbdSnorby 		switch (table[i].type) {
2778e709cbdSnorby 		case NOTOKEN:
2788e709cbdSnorby 			fprintf(stderr, "  <cr>\n");
2798e709cbdSnorby 			break;
2808e709cbdSnorby 		case KEYWORD:
2818e709cbdSnorby 		case FLAG:
2828e709cbdSnorby 			fprintf(stderr, "  %s\n", table[i].keyword);
2838e709cbdSnorby 			break;
2848e709cbdSnorby 		case ADDRESS:
2858e709cbdSnorby 			fprintf(stderr, "  <address>\n");
2868e709cbdSnorby 			break;
28796950f83Sremi 		case AREA:
28896950f83Sremi 			fprintf(stderr, "  <area>\n");
28996950f83Sremi 			break;
2908e709cbdSnorby 		case PREFIX:
2918e709cbdSnorby 			fprintf(stderr, "  <address>[/<len>]\n");
2928e709cbdSnorby 			break;
2938e709cbdSnorby 		case IFNAME:
2948e709cbdSnorby 			fprintf(stderr, "  <interface>\n");
295c5ba8b41Sderaadt 			break;
2968e709cbdSnorby 		case ENDTOKEN:
2978e709cbdSnorby 			break;
2988e709cbdSnorby 		}
2998e709cbdSnorby 	}
3008e709cbdSnorby }
3018e709cbdSnorby 
3020104e403Sclaudio /* XXX shared with parse.y should be merged */
3038e709cbdSnorby int
parse_addr(const char * word,struct in6_addr * addr)3040104e403Sclaudio parse_addr(const char *word, struct in6_addr *addr)
3058e709cbdSnorby {
3060104e403Sclaudio 	struct addrinfo	hints, *r;
3078e709cbdSnorby 
3088e709cbdSnorby 	if (word == NULL)
3098e709cbdSnorby 		return (0);
3108e709cbdSnorby 
3110104e403Sclaudio 	bzero(addr, sizeof(struct in6_addr));
3120104e403Sclaudio 	bzero(&hints, sizeof(hints));
3130104e403Sclaudio 	hints.ai_family = AF_INET6;
3140104e403Sclaudio 	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
3150104e403Sclaudio 	hints.ai_flags = AI_NUMERICHOST;
3160104e403Sclaudio 	if (getaddrinfo(word, "0", &hints, &r) == 0) {
3170104e403Sclaudio 		*addr = ((struct sockaddr_in6 *)r->ai_addr)->sin6_addr;
3180104e403Sclaudio 		/* XXX address scope !!! */
3190104e403Sclaudio 		/* ((struct sockaddr_in6 *)r->ai_addr)->sin6_scope_id */
3200104e403Sclaudio 		freeaddrinfo(r);
3218e709cbdSnorby 		return (1);
3228e709cbdSnorby 	}
3238e709cbdSnorby 	return (0);
3248e709cbdSnorby }
3258e709cbdSnorby 
32696950f83Sremi int
parse_area(const char * word,struct in_addr * addr)32796950f83Sremi parse_area(const char *word, struct in_addr *addr)
32896950f83Sremi {
32996950f83Sremi 	struct in_addr	 ina;
33096950f83Sremi 	const char	*errstr;
33196950f83Sremi 
33296950f83Sremi 	if (word == NULL)
33396950f83Sremi 		return (0);
33496950f83Sremi 
33596950f83Sremi 	bzero(addr, sizeof(struct in_addr));
33696950f83Sremi 	bzero(&ina, sizeof(ina));
33796950f83Sremi 
33896950f83Sremi 	if (inet_pton(AF_INET, word, &ina)) {
33996950f83Sremi 		addr->s_addr = ina.s_addr;
34096950f83Sremi 		return (1);
34196950f83Sremi 	}
34296950f83Sremi 
34396950f83Sremi 	ina.s_addr = htonl(strtonum(word, 0, 0xffffffff, &errstr));
34496950f83Sremi 	if (errstr == NULL) {
34596950f83Sremi 		addr->s_addr = ina.s_addr;
34696950f83Sremi 		return (1);
34796950f83Sremi 	}
34896950f83Sremi 	return (0);
34996950f83Sremi }
35096950f83Sremi 
3510104e403Sclaudio /* XXX shared with parse.y should be merged */
3528e709cbdSnorby int
parse_prefix(const char * word,struct in6_addr * addr,u_int8_t * prefixlen)3530104e403Sclaudio parse_prefix(const char *word, struct in6_addr *addr, u_int8_t *prefixlen)
3548e709cbdSnorby {
3550104e403Sclaudio 	char		*p, *ps;
3560104e403Sclaudio 	const char	*errstr;
3570104e403Sclaudio 	int		 mask;
3588e709cbdSnorby 
3598e709cbdSnorby 	if (word == NULL)
3608e709cbdSnorby 		return (0);
3618e709cbdSnorby 
3620104e403Sclaudio 	if ((p = strrchr(word, '/')) != NULL) {
3630104e403Sclaudio 		mask = strtonum(p + 1, 0, 128, &errstr);
3640104e403Sclaudio 		if (errstr)
3650104e403Sclaudio 			errx(1, "invalid netmask: %s", errstr);
3668e709cbdSnorby 
3670104e403Sclaudio 		if ((ps = malloc(strlen(word) - strlen(p) + 1)) == NULL)
3680104e403Sclaudio 			err(1, "parse_prefix: malloc");
3690104e403Sclaudio 		strlcpy(ps, word, strlen(word) - strlen(p) + 1);
3700104e403Sclaudio 
3710104e403Sclaudio 		if (parse_addr(ps, addr) == 0) {
3720104e403Sclaudio 			free(ps);
3738e709cbdSnorby 			return (0);
3740104e403Sclaudio 		}
37523d867c2Stobias 		free(ps);
3760104e403Sclaudio 
3770104e403Sclaudio 		inet6applymask(addr, addr, mask);
3780104e403Sclaudio 		*prefixlen = mask;
3798e709cbdSnorby 		return (1);
380c5ba8b41Sderaadt 	}
3810104e403Sclaudio 	*prefixlen = 128;
3828e709cbdSnorby 	return (parse_addr(word, addr));
3838e709cbdSnorby }
384