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

Line Branch Exec Source
1
/*	$OpenBSD: parser.c,v 1.4 2016/01/15 12:57:49 renato Exp $ */
2
3
/*
4
 * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
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
#include <netdb.h>
32
33
#include "eigrpd.h"
34
35
#include "parser.h"
36
37
enum token_type {
38
	NOTOKEN,
39
	ENDTOKEN,
40
	KEYWORD,
41
	FAMILY,
42
	ASNUM,
43
	ADDRESS,
44
	FLAG,
45
	PREFIX,
46
	IFNAME
47
};
48
49
struct token {
50
	enum token_type		 type;
51
	const char		*keyword;
52
	int			 value;
53
	const struct token	*next;
54
};
55
56
static const struct token t_main[];
57
static const struct token t_fib[];
58
static const struct token t_show[];
59
static const struct token t_show_iface[];
60
static const struct token t_show_iface_af[];
61
static const struct token t_show_iface_as[];
62
static const struct token t_show_nbr[];
63
static const struct token t_show_nbr_af[];
64
static const struct token t_show_nbr_as[];
65
static const struct token t_show_topology[];
66
static const struct token t_show_topology_af[];
67
static const struct token t_show_topology_as[];
68
static const struct token t_show_fib[];
69
static const struct token t_show_fib_af[];
70
static const struct token t_show_stats[];
71
static const struct token t_show_stats_af[];
72
static const struct token t_show_stats_as[];
73
static const struct token t_log[];
74
static const struct token t_clear[];
75
static const struct token t_clear_nbr[];
76
static const struct token t_clear_nbr_af[];
77
static const struct token t_clear_nbr_as[];
78
79
static const struct token t_main[] = {
80
	{KEYWORD,	"reload",	RELOAD,		NULL},
81
	{KEYWORD,	"fib",		FIB,		t_fib},
82
	{KEYWORD,	"show",		SHOW,		t_show},
83
	{KEYWORD,	"clear",	NONE,		t_clear},
84
	{KEYWORD,	"log",		NONE,		t_log},
85
	{ENDTOKEN,	"",		NONE,		NULL}
86
};
87
88
static const struct token t_fib[] = {
89
	{ KEYWORD,	"couple",	FIB_COUPLE,	NULL},
90
	{ KEYWORD,	"decouple",	FIB_DECOUPLE,	NULL},
91
	{ ENDTOKEN,	"",		NONE,		NULL}
92
};
93
94
static const struct token t_show[] = {
95
	{NOTOKEN,	"",		NONE,		NULL},
96
	{KEYWORD,	"interfaces",	SHOW_IFACE,	t_show_iface},
97
	{KEYWORD,	"neighbor",	SHOW_NBR,	t_show_nbr},
98
	{KEYWORD,	"topology",	SHOW_TOPOLOGY,	t_show_topology},
99
	{KEYWORD,	"fib",		SHOW_FIB,	t_show_fib},
100
	{KEYWORD,	"traffic",	SHOW_STATS,	t_show_stats},
101
	{ENDTOKEN,	"",		NONE,		NULL}
102
};
103
104
static const struct token t_show_iface[] = {
105
	{NOTOKEN,	"",		NONE,			NULL},
106
	{KEYWORD,	"family",	NONE,			t_show_iface_af},
107
	{KEYWORD,	"as",		NONE,			t_show_iface_as},
108
	{KEYWORD,	"detail",	SHOW_IFACE_DTAIL,	NULL},
109
	{IFNAME,	"",		SHOW_IFACE_DTAIL,	NULL},
110
	{ENDTOKEN,	"",		NONE,			NULL}
111
};
112
113
static const struct token t_show_iface_af[] = {
114
	{FAMILY,	"",		NONE,		t_show_iface},
115
	{ENDTOKEN,	"",		NONE,		NULL}
116
};
117
118
static const struct token t_show_iface_as[] = {
119
	{ASNUM,		"",		NONE,		t_show_iface},
120
	{ENDTOKEN,	"",		NONE,		NULL}
121
};
122
123
static const struct token t_show_nbr[] = {
124
	{NOTOKEN,	"",		NONE,		NULL},
125
	{KEYWORD,	"family",	NONE,		t_show_nbr_af},
126
	{KEYWORD,	"as",		NONE,		t_show_nbr_as},
127
	{ENDTOKEN,	"",		NONE,		NULL}
128
};
129
130
static const struct token t_show_nbr_af[] = {
131
	{FAMILY,	"",		NONE,		t_show_nbr},
132
	{ENDTOKEN,	"",		NONE,		NULL}
133
};
134
135
static const struct token t_show_nbr_as[] = {
136
	{ASNUM,		"",		NONE,		t_show_nbr},
137
	{ENDTOKEN,	"",		NONE,		NULL}
138
};
139
140
static const struct token t_show_topology[] = {
141
	{NOTOKEN,	"",		NONE,		NULL},
142
	{KEYWORD,	"family",	NONE,		t_show_topology_af},
143
	{KEYWORD,	"as",		NONE,		t_show_topology_as},
144
	{PREFIX,	"",		NONE,		NULL},
145
	{FLAG,		"active",	F_CTL_ACTIVE,	NULL},
146
	{FLAG,		"all-links",	F_CTL_ALLLINKS,	NULL},
147
	{ENDTOKEN,	"",		NONE,		NULL}
148
};
149
150
static const struct token t_show_topology_af[] = {
151
	{FAMILY,	"",		NONE,		t_show_topology},
152
	{ENDTOKEN,	"",		NONE,		NULL}
153
};
154
155
static const struct token t_show_topology_as[] = {
156
	{ASNUM,		"",		NONE,		t_show_topology},
157
	{ENDTOKEN,	"",		NONE,		NULL}
158
};
159
160
static const struct token t_show_fib[] = {
161
	{NOTOKEN,	"",		NONE,			NULL},
162
	{KEYWORD,	"family",	NONE,			t_show_fib_af},
163
	{KEYWORD,	"interface",	SHOW_FIB_IFACE,		t_show_iface},
164
	{FLAG,		"connected",	F_CONNECTED,		t_show_fib},
165
	{FLAG,		"static",	F_STATIC,		t_show_fib},
166
	{FLAG,		"eigrp",	F_EIGRPD_INSERTED,	t_show_fib},
167
	{ENDTOKEN,	"",		NONE,			NULL}
168
};
169
170
static const struct token t_show_fib_af[] = {
171
	{FAMILY,	"",		NONE,		t_show_fib},
172
	{ENDTOKEN,	"",		NONE,		NULL}
173
};
174
175
176
static const struct token t_show_stats[] = {
177
	{NOTOKEN,	"",		NONE,		NULL},
178
	{KEYWORD,	"family",	NONE,		t_show_stats_af},
179
	{KEYWORD,	"as",		NONE,		t_show_stats_as},
180
	{ENDTOKEN,	"",		NONE,		NULL}
181
};
182
183
static const struct token t_show_stats_af[] = {
184
	{FAMILY,	"",		NONE,		t_show_stats},
185
	{ENDTOKEN,	"",		NONE,		NULL}
186
};
187
188
static const struct token t_show_stats_as[] = {
189
	{ASNUM,		"",		NONE,		t_show_stats},
190
	{ENDTOKEN,	"",		NONE,		NULL}
191
};
192
193
static const struct token t_clear[] = {
194
	{KEYWORD,	"neighbors",	CLEAR_NBR,	t_clear_nbr},
195
	{ENDTOKEN,	"",		NONE,		NULL}
196
};
197
198
static const struct token t_clear_nbr[] = {
199
	{NOTOKEN,	"",		NONE,		NULL},
200
	{KEYWORD,	"as",		NONE,		t_clear_nbr_as},
201
	{KEYWORD,	"family",	NONE,		t_clear_nbr_af},
202
	{ADDRESS,	"",		NONE,		NULL},
203
	{ENDTOKEN,	"",		NONE,		NULL}
204
};
205
206
static const struct token t_clear_nbr_af[] = {
207
	{FAMILY,	"",		NONE,		t_clear_nbr},
208
	{ENDTOKEN,	"",		NONE,		NULL}
209
};
210
211
static const struct token t_clear_nbr_as[] = {
212
	{ASNUM,		"",		NONE,		t_clear_nbr},
213
	{ENDTOKEN,	"",		NONE,		NULL}
214
};
215
216
static const struct token t_log[] = {
217
	{KEYWORD,	"verbose",	LOG_VERBOSE,		NULL},
218
	{KEYWORD,	"brief",	LOG_BRIEF,		NULL},
219
	{ENDTOKEN,	"",		NONE,			NULL}
220
};
221
222
static const struct token *match_token(const char *, const struct token *,
223
    struct parse_result *);
224
static void show_valid_args(const struct token *);
225
226
struct parse_result *
227
parse(int argc, char *argv[])
228
{
229
	static struct parse_result	res;
230
	const struct token	*table = t_main;
231
	const struct token	*match;
232
233
	memset(&res, 0, sizeof(res));
234
235
	while (argc >= 0) {
236
		if ((match = match_token(argv[0], table, &res)) == NULL) {
237
			fprintf(stderr, "valid commands/args:\n");
238
			show_valid_args(table);
239
			return (NULL);
240
		}
241
242
		argc--;
243
		argv++;
244
245
		if (match->type == NOTOKEN || match->next == NULL)
246
			break;
247
248
		table = match->next;
249
	}
250
251
	if (argc > 0) {
252
		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
253
		return (NULL);
254
	}
255
256
	return (&res);
257
}
258
259
static const struct token *
260
match_token(const char *word, const struct token *table,
261
    struct parse_result *res)
262
{
263
	unsigned int		 i, match;
264
	const struct token	*t = NULL;
265
266
	match = 0;
267
268
	for (i = 0; table[i].type != ENDTOKEN; i++) {
269
		switch (table[i].type) {
270
		case NOTOKEN:
271
			if (word == NULL || strlen(word) == 0) {
272
				match++;
273
				t = &table[i];
274
			}
275
			break;
276
		case KEYWORD:
277
			if (word != NULL && strncmp(word, table[i].keyword,
278
			    strlen(word)) == 0) {
279
				match++;
280
				t = &table[i];
281
				if (t->value)
282
					res->action = t->value;
283
			}
284
			break;
285
		case FLAG:
286
			if (word != NULL && strncmp(word, table[i].keyword,
287
			    strlen(word)) == 0) {
288
				match++;
289
				t = &table[i];
290
				res->flags |= t->value;
291
			}
292
			break;
293
		case FAMILY:
294
			if (word == NULL)
295
				break;
296
			if (!strcmp(word, "inet") ||
297
			    !strcasecmp(word, "IPv4")) {
298
				match++;
299
				t = &table[i];
300
				res->family = AF_INET;
301
			}
302
			if (!strcmp(word, "inet6") ||
303
			    !strcasecmp(word, "IPv6")) {
304
				match++;
305
				t = &table[i];
306
				res->family = AF_INET6;
307
			}
308
			break;
309
		case ASNUM:
310
			if (parse_asnum(word, &res->as)) {
311
				match++;
312
				t = &table[i];
313
			}
314
			break;
315
		case ADDRESS:
316
			if (parse_addr(word, &res->family, &res->addr)) {
317
				match++;
318
				t = &table[i];
319
				if (t->value)
320
					res->action = t->value;
321
			}
322
			break;
323
		case PREFIX:
324
			if (parse_prefix(word, &res->family, &res->addr,
325
			    &res->prefixlen)) {
326
				match++;
327
				t = &table[i];
328
				if (t->value)
329
					res->action = t->value;
330
			}
331
			break;
332
		case IFNAME:
333
			if (!match && word != NULL && strlen(word) > 0) {
334
				if (strlcpy(res->ifname, word,
335
				    sizeof(res->ifname)) >=
336
				    sizeof(res->ifname))
337
					err(1, "interface name too long");
338
				match++;
339
				t = &table[i];
340
				if (t->value)
341
					res->action = t->value;
342
			}
343
			break;
344
345
		case ENDTOKEN:
346
			break;
347
		}
348
	}
349
350
	if (match != 1) {
351
		if (word == NULL)
352
			fprintf(stderr, "missing argument:\n");
353
		else if (match > 1)
354
			fprintf(stderr, "ambiguous argument: %s\n", word);
355
		else if (match < 1)
356
			fprintf(stderr, "unknown argument: %s\n", word);
357
		return (NULL);
358
	}
359
360
	return (t);
361
}
362
363
static void
364
show_valid_args(const struct token *table)
365
{
366
	int	i;
367
368
	for (i = 0; table[i].type != ENDTOKEN; i++) {
369
		switch (table[i].type) {
370
		case NOTOKEN:
371
			fprintf(stderr, "  <cr>\n");
372
			break;
373
		case KEYWORD:
374
		case FLAG:
375
			fprintf(stderr, "  %s\n", table[i].keyword);
376
			break;
377
		case FAMILY:
378
			fprintf(stderr, "  [ inet | inet6 | IPv4 | IPv6 ]\n");
379
			break;
380
		case ASNUM:
381
			fprintf(stderr, "  <asnum>\n");
382
			break;
383
		case ADDRESS:
384
			fprintf(stderr, "  <address>\n");
385
			break;
386
		case PREFIX:
387
			fprintf(stderr, "  <address>[/<len>]\n");
388
			break;
389
		case IFNAME:
390
			fprintf(stderr, "  <interface>\n");
391
			break;
392
		case ENDTOKEN:
393
			break;
394
		}
395
	}
396
}
397
398
int
399
parse_asnum(const char *word, uint16_t *asnum)
400
{
401
	const char	*errstr;
402
	uint32_t	 uval;
403
404
	if (word == NULL)
405
		return (0);
406
407
	uval = strtonum(word, EIGRP_MIN_AS, EIGRP_MAX_AS, &errstr);
408
	if (errstr)
409
		errx(1, "AS number is %s: %s", errstr, word);
410
411
	*asnum = uval;
412
	return (1);
413
}
414
415
int
416
parse_addr(const char *word, int *family, union eigrpd_addr *addr)
417
{
418
	struct in_addr		 ina;
419
	struct addrinfo		 hints, *r;
420
	struct sockaddr_in6	*sa_in6;
421
422
	if (word == NULL)
423
		return (0);
424
425
	memset(addr, 0, sizeof(union eigrpd_addr));
426
	memset(&ina, 0, sizeof(ina));
427
428
	if (inet_net_pton(AF_INET, word, &ina, sizeof(ina)) != -1) {
429
		*family = AF_INET;
430
		addr->v4.s_addr = ina.s_addr;
431
		return (1);
432
	}
433
434
	memset(&hints, 0, sizeof(hints));
435
	hints.ai_family = AF_INET6;
436
	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
437
	hints.ai_flags = AI_NUMERICHOST;
438
	if (getaddrinfo(word, "0", &hints, &r) == 0) {
439
		sa_in6 = (struct sockaddr_in6 *)r->ai_addr;
440
		*family = AF_INET6;
441
		addr->v6 = sa_in6->sin6_addr;
442
		freeaddrinfo(r);
443
		return (1);
444
	}
445
446
	return (0);
447
}
448
449
int
450
parse_prefix(const char *word, int *family, union eigrpd_addr *addr,
451
    uint8_t *prefixlen)
452
{
453
	char		*p, *ps;
454
	const char	*errstr;
455
	size_t		 wordlen;
456
	int		 mask = -1;
457
458
	if (word == NULL)
459
		return (0);
460
	wordlen = strlen(word);
461
462
	memset(addr, 0, sizeof(union eigrpd_addr));
463
464
	if ((p = strrchr(word, '/')) != NULL) {
465
		size_t plen = strlen(p);
466
		mask = strtonum(p + 1, 0, 128, &errstr);
467
		if (errstr)
468
			errx(1, "netmask %s", errstr);
469
470
		if ((ps = malloc(wordlen - plen + 1)) == NULL)
471
			err(1, "parse_prefix: malloc");
472
		strlcpy(ps, word, wordlen - plen + 1);
473
474
		if (parse_addr(ps, family, addr) == 0) {
475
			free(ps);
476
			return (0);
477
		}
478
479
		free(ps);
480
	} else
481
		if (parse_addr(word, family, addr) == 0)
482
			return (0);
483
484
	switch (*family) {
485
	case AF_INET:
486
		if (mask == UINT8_MAX)
487
			mask = 32;
488
		if (mask > 32)
489
			errx(1, "invalid netmask: too large");
490
		break;
491
	case AF_INET6:
492
		if (mask == UINT8_MAX)
493
			mask = 128;
494
		if (mask > 128)
495
			errx(1, "invalid netmask: too large");
496
		break;
497
	default:
498
		return (0);
499
	}
500
	eigrp_applymask(*family, addr, addr, mask);
501
	*prefixlen = mask;
502
503
	return (1);
504
}