1/*	$OpenBSD: parser.c,v 1.7 2017/07/28 13:02:35 florian Exp $ */
2
3/*
4 * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
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
32#include "ripd.h"
33
34#include "parser.h"
35
36enum token_type {
37	NOTOKEN,
38	ENDTOKEN,
39	KEYWORD,
40	ADDRESS,
41	FLAG,
42	PREFIX,
43	IFNAME
44};
45
46struct token {
47	enum token_type		 type;
48	const char		*keyword;
49	int			 value;
50	const struct token	*next;
51};
52
53static const struct token t_main[];
54static const struct token t_fib[];
55static const struct token t_show[];
56static const struct token t_show_iface[];
57static const struct token t_show_nbr[];
58static const struct token t_show_rib[];
59static const struct token t_show_fib[];
60static const struct token t_log[];
61
62static const struct token t_main[] = {
63/*	{KEYWORD,	"reload",	RELOAD,		NULL}, */
64	{KEYWORD,	"fib",		FIB,		t_fib},
65	{KEYWORD,	"show",		SHOW,		t_show},
66	{KEYWORD,	"log",		NONE,		t_log},
67	{ENDTOKEN,	"",		NONE,		NULL}
68};
69
70static const struct token t_fib[] = {
71	{ KEYWORD,	"couple",	FIB_COUPLE,	NULL},
72	{ KEYWORD,	"decouple",	FIB_DECOUPLE,	NULL},
73	{ ENDTOKEN,	"",		NONE,		NULL}
74};
75
76static const struct token t_show[] = {
77	{NOTOKEN,	"",		NONE,		NULL},
78	{KEYWORD,	"interfaces",	SHOW_IFACE,	t_show_iface},
79	{KEYWORD,	"neighbor",	SHOW_NBR,	t_show_nbr},
80	{KEYWORD,	"rib",		SHOW_RIB,	t_show_rib},
81	{KEYWORD,	"fib",		SHOW_FIB,	t_show_fib},
82	{ENDTOKEN,	"",		NONE,		NULL}
83};
84
85static const struct token t_show_iface[] = {
86	{NOTOKEN,	"",		NONE,			NULL},
87	{ENDTOKEN,	"",		NONE,			NULL}
88};
89
90static const struct token t_show_nbr[] = {
91	{NOTOKEN,	"",		NONE,		NULL},
92	{ENDTOKEN,	"",		NONE,		NULL}
93};
94
95static const struct token t_show_rib[] = {
96	{NOTOKEN,	"",		NONE,		NULL},
97	{ENDTOKEN,	"",		NONE,		NULL}
98};
99
100static const struct token t_show_fib[] = {
101	{NOTOKEN,	"",		NONE,			NULL},
102	{KEYWORD,	"interface",	SHOW_FIB_IFACE,		t_show_iface},
103	{FLAG,		"connected",	F_CONNECTED,		t_show_fib},
104	{FLAG,		"static",	F_STATIC,		t_show_fib},
105	{FLAG,		"rip",		F_RIPD_INSERTED,	t_show_fib},
106	{ADDRESS,	"",		NONE,			NULL},
107	{ENDTOKEN,	"",		NONE,			NULL}
108};
109
110static const struct token t_log[] = {
111	{KEYWORD,	"verbose",	LOG_VERBOSE,		NULL},
112	{KEYWORD,	"brief",	LOG_BRIEF,		NULL},
113	{ENDTOKEN,	"",		NONE,			NULL}
114};
115
116static const struct token *match_token(const char *, const struct token *,
117    struct parse_result *);
118static void show_valid_args(const struct token *table);
119
120struct parse_result *
121parse(int argc, char *argv[])
122{
123	static struct parse_result res;
124	const struct token	*table = t_main;
125	const struct token	*match;
126
127	bzero(&res, sizeof(res));
128
129	while (argc >= 0) {
130		if ((match = match_token(argv[0], table, &res)) == NULL) {
131			fprintf(stderr, "valid commands/args:\n");
132			show_valid_args(table);
133			return (NULL);
134		}
135
136		argc--;
137		argv++;
138
139		if (match->type == NOTOKEN || match->next == NULL)
140			break;
141
142		table = match->next;
143	}
144
145	if (argc > 0) {
146		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
147		return (NULL);
148	}
149
150	return (&res);
151}
152
153static const struct token *
154match_token(const char *word, const struct token *table,
155    struct parse_result *res)
156{
157	u_int			 i, match;
158	const struct token	*t = NULL;
159
160	match = 0;
161
162	for (i = 0; table[i].type != ENDTOKEN; i++) {
163		switch (table[i].type) {
164		case NOTOKEN:
165			if (word == NULL || strlen(word) == 0) {
166				match++;
167				t = &table[i];
168			}
169			break;
170		case KEYWORD:
171			if (word != NULL && strncmp(word, table[i].keyword,
172			    strlen(word)) == 0) {
173				match++;
174				t = &table[i];
175				if (t->value)
176					res->action = t->value;
177			}
178			break;
179		case FLAG:
180			if (word != NULL && strncmp(word, table[i].keyword,
181			    strlen(word)) == 0) {
182				match++;
183				t = &table[i];
184				res->flags |= t->value;
185			}
186			break;
187		case ADDRESS:
188			if (parse_addr(word, &res->addr)) {
189				match++;
190				t = &table[i];
191				if (t->value)
192					res->action = t->value;
193			}
194			break;
195		case PREFIX:
196			if (parse_prefix(word, &res->addr, &res->prefixlen)) {
197				match++;
198				t = &table[i];
199				if (t->value)
200					res->action = t->value;
201			}
202			break;
203		case IFNAME:
204			if (!match && word != NULL && strlen(word) > 0) {
205				if (strlcpy(res->ifname, word,
206				    sizeof(res->ifname)) >=
207				    sizeof(res->ifname))
208					err(1, "interface name too long");
209				match++;
210				t = &table[i];
211				if (t->value)
212					res->action = t->value;
213			}
214			break;
215
216		case ENDTOKEN:
217			break;
218		}
219	}
220
221	if (match != 1) {
222		if (word == NULL)
223			fprintf(stderr, "missing argument:\n");
224		else if (match > 1)
225			fprintf(stderr, "ambiguous argument: %s\n", word);
226		else if (match < 1)
227			fprintf(stderr, "unknown argument: %s\n", word);
228		return (NULL);
229	}
230
231	return (t);
232}
233
234static void
235show_valid_args(const struct token *table)
236{
237	int	i;
238
239	for (i = 0; table[i].type != ENDTOKEN; i++) {
240		switch (table[i].type) {
241		case NOTOKEN:
242			fprintf(stderr, "  <cr>\n");
243			break;
244		case KEYWORD:
245		case FLAG:
246			fprintf(stderr, "  %s\n", table[i].keyword);
247			break;
248		case ADDRESS:
249			fprintf(stderr, "  <address>\n");
250			break;
251		case PREFIX:
252			fprintf(stderr, "  <address>[/<len>]\n");
253			break;
254		case IFNAME:
255			fprintf(stderr, "  <interface>\n");
256		case ENDTOKEN:
257			break;
258		}
259	}
260}
261
262int
263parse_addr(const char *word, struct in_addr *addr)
264{
265	struct in_addr	ina;
266
267	if (word == NULL)
268		return (0);
269
270	bzero(addr, sizeof(struct in_addr));
271	bzero(&ina, sizeof(ina));
272
273	if (inet_pton(AF_INET, word, &ina)) {
274		addr->s_addr = ina.s_addr;
275		return (1);
276	}
277
278	return (0);
279}
280
281int
282parse_prefix(const char *word, struct in_addr *addr, u_int8_t *prefixlen)
283{
284	struct in_addr	 ina;
285	int		 bits = 32;
286
287	if (word == NULL)
288		return (0);
289
290	bzero(addr, sizeof(struct in_addr));
291	bzero(&ina, sizeof(ina));
292
293	if (strrchr(word, '/') != NULL) {
294		if ((bits = inet_net_pton(AF_INET, word,
295		    &ina, sizeof(ina))) == -1)
296			return (0);
297		addr->s_addr = ina.s_addr & htonl(prefixlen2mask(bits));
298		*prefixlen = bits;
299		return (1);
300	} else {
301		*prefixlen = 32;
302		return (parse_addr(word, addr));
303	}
304
305	return (0);
306}
307
308/* XXX local copy from kroute.c, should go to shared file */
309in_addr_t
310prefixlen2mask(u_int8_t prefixlen)
311{
312	if (prefixlen == 0)
313		return (0);
314
315	return (0xffffffff << (32 - prefixlen));
316}
317