GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ripctl/parser.c Lines: 0 87 0.0 %
Date: 2017-11-07 Branches: 0 78 0.0 %

Line Branch Exec Source
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
36
enum token_type {
37
	NOTOKEN,
38
	ENDTOKEN,
39
	KEYWORD,
40
	ADDRESS,
41
	FLAG,
42
	PREFIX,
43
	IFNAME
44
};
45
46
struct token {
47
	enum token_type		 type;
48
	const char		*keyword;
49
	int			 value;
50
	const struct token	*next;
51
};
52
53
static const struct token t_main[];
54
static const struct token t_fib[];
55
static const struct token t_show[];
56
static const struct token t_show_iface[];
57
static const struct token t_show_nbr[];
58
static const struct token t_show_rib[];
59
static const struct token t_show_fib[];
60
static const struct token t_log[];
61
62
static 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
70
static const struct token t_fib[] = {
71
	{ KEYWORD,	"couple",	FIB_COUPLE,	NULL},
72
	{ KEYWORD,	"decouple",	FIB_DECOUPLE,	NULL},
73
	{ ENDTOKEN,	"",		NONE,		NULL}
74
};
75
76
static 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
85
static const struct token t_show_iface[] = {
86
	{NOTOKEN,	"",		NONE,			NULL},
87
	{ENDTOKEN,	"",		NONE,			NULL}
88
};
89
90
static const struct token t_show_nbr[] = {
91
	{NOTOKEN,	"",		NONE,		NULL},
92
	{ENDTOKEN,	"",		NONE,		NULL}
93
};
94
95
static const struct token t_show_rib[] = {
96
	{NOTOKEN,	"",		NONE,		NULL},
97
	{ENDTOKEN,	"",		NONE,		NULL}
98
};
99
100
static 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
110
static const struct token t_log[] = {
111
	{KEYWORD,	"verbose",	LOG_VERBOSE,		NULL},
112
	{KEYWORD,	"brief",	LOG_BRIEF,		NULL},
113
	{ENDTOKEN,	"",		NONE,			NULL}
114
};
115
116
static const struct token *match_token(const char *, const struct token *,
117
    struct parse_result *);
118
static void show_valid_args(const struct token *table);
119
120
struct parse_result *
121
parse(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
153
static const struct token *
154
match_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
234
static void
235
show_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
262
int
263
parse_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
281
int
282
parse_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 */
309
in_addr_t
310
prefixlen2mask(u_int8_t prefixlen)
311
{
312
	if (prefixlen == 0)
313
		return (0);
314
315
	return (0xffffffff << (32 - prefixlen));
316
}