1/*	$OpenBSD: parser.c,v 1.21 2019/05/16 21:07:33 remi Exp $ */
2
3/*
4 * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <sys/types.h>
21#include <sys/socket.h>
22#include <netinet/in.h>
23#include <arpa/inet.h>
24#include <err.h>
25#include <errno.h>
26#include <limits.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include "ospfd.h"
32
33#include "parser.h"
34
35enum token_type {
36	NOTOKEN,
37	ENDTOKEN,
38	KEYWORD,
39	ADDRESS,
40	FLAG,
41	PREFIX,
42	IFNAME,
43	AREA
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_db[];
58static const struct token t_show_area[];
59static const struct token t_show_nbr[];
60static const struct token t_show_rib[];
61static const struct token t_show_fib[];
62static const struct token t_log[];
63
64static const struct token t_main[] = {
65	{KEYWORD,	"reload",	RELOAD,		NULL},
66	{KEYWORD,	"fib",		FIB,		t_fib},
67	{KEYWORD,	"show",		SHOW,		t_show},
68	{KEYWORD,	"log",		NONE,		t_log},
69	{ENDTOKEN,	"",		NONE,		NULL}
70};
71
72static const struct token t_fib[] = {
73	{ KEYWORD,	"couple",	FIB_COUPLE,	NULL},
74	{ KEYWORD,	"decouple",	FIB_DECOUPLE,	NULL},
75	{ KEYWORD,	"reload",	FIB_RELOAD,	NULL},
76	{ ENDTOKEN,	"",		NONE,		NULL}
77};
78
79static const struct token t_show[] = {
80	{NOTOKEN,	"",		NONE,		NULL},
81	{KEYWORD,	"interfaces",	SHOW_IFACE,	t_show_iface},
82	{KEYWORD,	"database",	SHOW_DB,	t_show_db},
83	{KEYWORD,	"neighbor",	SHOW_NBR,	t_show_nbr},
84	{KEYWORD,	"rib",		SHOW_RIB,	t_show_rib},
85	{KEYWORD,	"fib",		SHOW_FIB,	t_show_fib},
86	{KEYWORD,	"summary",	SHOW_SUM,	NULL},
87	{ENDTOKEN,	"",		NONE,		NULL}
88};
89
90static const struct token t_show_iface[] = {
91	{NOTOKEN,	"",		NONE,			NULL},
92	{KEYWORD,	"detail",	SHOW_IFACE_DTAIL,	NULL},
93	{IFNAME,	"",		SHOW_IFACE_DTAIL,	NULL},
94	{ENDTOKEN,	"",		NONE,			NULL}
95};
96
97static const struct token t_show_db[] = {
98	{NOTOKEN,	"",			NONE,		NULL},
99	{KEYWORD,	"area",			SHOW_DBBYAREA,	t_show_area},
100	{KEYWORD,	"asbr",			SHOW_DBASBR,	NULL},
101	{KEYWORD,	"external",		SHOW_DBEXT,	NULL},
102	{KEYWORD,	"network",		SHOW_DBNET,	NULL},
103	{KEYWORD,	"router",		SHOW_DBRTR,	NULL},
104	{KEYWORD,	"self-originated",	SHOW_DBSELF,	NULL},
105	{KEYWORD,	"summary",		SHOW_DBSUM,	NULL},
106	{KEYWORD,	"opaque",		SHOW_DBOPAQ,	NULL},
107	{ENDTOKEN,	"",			NONE,		NULL}
108};
109
110static const struct token t_show_area[] = {
111	{AREA,		"",		NONE,		NULL},
112	{ENDTOKEN,	"",		NONE,		NULL}
113};
114
115static const struct token t_show_nbr[] = {
116	{NOTOKEN,	"",		NONE,		NULL},
117	{KEYWORD,	"detail",	SHOW_NBR_DTAIL,	NULL},
118	{ENDTOKEN,	"",		NONE,		NULL}
119};
120
121static const struct token t_show_rib[] = {
122	{NOTOKEN,	"",		NONE,		NULL},
123	{KEYWORD,	"detail",	SHOW_RIB_DTAIL,	NULL},
124	{ENDTOKEN,	"",		NONE,		NULL}
125};
126
127static const struct token t_show_fib[] = {
128	{NOTOKEN,	"",		NONE,			NULL},
129	{KEYWORD,	"interface",	SHOW_FIB_IFACE,		t_show_iface},
130	{FLAG,		"connected",	F_CONNECTED,		t_show_fib},
131	{FLAG,		"static",	F_STATIC,		t_show_fib},
132	{FLAG,		"ospf",		F_OSPFD_INSERTED,	t_show_fib},
133	{ADDRESS,	"",		NONE,			NULL},
134	{ENDTOKEN,	"",		NONE,			NULL}
135};
136
137static const struct token t_log[] = {
138	{KEYWORD,	"verbose",	LOG_VERBOSE,		NULL},
139	{KEYWORD,	"brief",	LOG_BRIEF,		NULL},
140	{ENDTOKEN,	"",		NONE,			NULL}
141};
142
143static const struct token *match_token(const char *, const struct token *,
144    struct parse_result *);
145static void show_valid_args(const struct token *);
146
147struct parse_result *
148parse(int argc, char *argv[])
149{
150	static struct parse_result	res;
151	const struct token	*table = t_main;
152	const struct token	*match;
153
154	bzero(&res, sizeof(res));
155
156	while (argc >= 0) {
157		if ((match = match_token(argv[0], table, &res)) == NULL) {
158			fprintf(stderr, "valid commands/args:\n");
159			show_valid_args(table);
160			return (NULL);
161		}
162
163		argc--;
164		argv++;
165
166		if (match->type == NOTOKEN || match->next == NULL)
167			break;
168
169		table = match->next;
170	}
171
172	if (argc > 0) {
173		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
174		return (NULL);
175	}
176
177	return (&res);
178}
179
180static const struct token *
181match_token(const char *word, const struct token *table,
182    struct parse_result *res)
183{
184	u_int			 i, match;
185	const struct token	*t = NULL;
186
187	match = 0;
188
189	for (i = 0; table[i].type != ENDTOKEN; i++) {
190		switch (table[i].type) {
191		case NOTOKEN:
192			if (word == NULL || strlen(word) == 0) {
193				match++;
194				t = &table[i];
195			}
196			break;
197		case KEYWORD:
198			if (word != NULL && strncmp(word, table[i].keyword,
199			    strlen(word)) == 0) {
200				match++;
201				t = &table[i];
202				if (t->value)
203					res->action = t->value;
204			}
205			break;
206		case FLAG:
207			if (word != NULL && strncmp(word, table[i].keyword,
208			    strlen(word)) == 0) {
209				match++;
210				t = &table[i];
211				res->flags |= t->value;
212			}
213			break;
214		case ADDRESS:
215			if (parse_addr(word, &res->addr)) {
216				match++;
217				t = &table[i];
218				if (t->value)
219					res->action = t->value;
220			}
221			break;
222		case AREA:
223			if (parse_area(word, &res->addr)) {
224				match++;
225				t = &table[i];
226				if (t->value)
227					res->action = t->value;
228			}
229			break;
230		case PREFIX:
231			if (parse_prefix(word, &res->addr, &res->prefixlen)) {
232				match++;
233				t = &table[i];
234				if (t->value)
235					res->action = t->value;
236			}
237			break;
238		case IFNAME:
239			if (!match && word != NULL && strlen(word) > 0) {
240				if (strlcpy(res->ifname, word,
241				    sizeof(res->ifname)) >=
242				    sizeof(res->ifname))
243					err(1, "interface name too long");
244				match++;
245				t = &table[i];
246				if (t->value)
247					res->action = t->value;
248			}
249			break;
250
251		case ENDTOKEN:
252			break;
253		}
254	}
255
256	if (match != 1) {
257		if (word == NULL)
258			fprintf(stderr, "missing argument:\n");
259		else if (match > 1)
260			fprintf(stderr, "ambiguous argument: %s\n", word);
261		else if (match < 1)
262			fprintf(stderr, "unknown argument: %s\n", word);
263		return (NULL);
264	}
265
266	return (t);
267}
268
269static void
270show_valid_args(const struct token *table)
271{
272	int	i;
273
274	for (i = 0; table[i].type != ENDTOKEN; i++) {
275		switch (table[i].type) {
276		case NOTOKEN:
277			fprintf(stderr, "  <cr>\n");
278			break;
279		case KEYWORD:
280		case FLAG:
281			fprintf(stderr, "  %s\n", table[i].keyword);
282			break;
283		case ADDRESS:
284			fprintf(stderr, "  <address>\n");
285			break;
286		case AREA:
287			fprintf(stderr, "  <area>\n");
288			break;
289		case PREFIX:
290			fprintf(stderr, "  <address>[/<len>]\n");
291			break;
292		case IFNAME:
293			fprintf(stderr, "  <interface>\n");
294			break;
295		case ENDTOKEN:
296			break;
297		}
298	}
299}
300
301int
302parse_addr(const char *word, struct in_addr *addr)
303{
304	struct in_addr	ina;
305
306	if (word == NULL)
307		return (0);
308
309	bzero(addr, sizeof(struct in_addr));
310	bzero(&ina, sizeof(ina));
311
312	if (inet_pton(AF_INET, word, &ina)) {
313		addr->s_addr = ina.s_addr;
314		return (1);
315	}
316
317	return (0);
318}
319
320int
321parse_area(const char *word, struct in_addr *addr)
322{
323	struct in_addr	 ina;
324	const char	*errstr;
325
326	if (word == NULL)
327		return (0);
328
329	bzero(addr, sizeof(struct in_addr));
330	bzero(&ina, sizeof(ina));
331
332	if (inet_pton(AF_INET, word, &ina)) {
333		addr->s_addr = ina.s_addr;
334		return (1);
335	}
336
337	ina.s_addr = htonl(strtonum(word, 0, 0xffffffff, &errstr));
338	if (errstr == NULL) {
339		addr->s_addr = ina.s_addr;
340		return (1);
341	}
342
343	return (0);
344}
345
346int
347parse_prefix(const char *word, struct in_addr *addr, u_int8_t *prefixlen)
348{
349	struct in_addr	 ina;
350	int		 bits = 32;
351
352	if (word == NULL)
353		return (0);
354
355	bzero(addr, sizeof(struct in_addr));
356	bzero(&ina, sizeof(ina));
357
358	if (strrchr(word, '/') != NULL) {
359		if ((bits = inet_net_pton(AF_INET, word,
360		    &ina, sizeof(ina))) == -1)
361			return (0);
362		addr->s_addr = ina.s_addr & htonl(prefixlen2mask(bits));
363		*prefixlen = bits;
364		return (1);
365	}
366	*prefixlen = 32;
367	return (parse_addr(word, addr));
368}
369
370/* XXX local copy from kroute.c, should go to shared file */
371in_addr_t
372prefixlen2mask(u_int8_t prefixlen)
373{
374	if (prefixlen == 0)
375		return (0);
376
377	return (0xffffffff << (32 - prefixlen));
378}
379