GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/bgpctl/parser.c Lines: 0 338 0.0 %
Date: 2016-12-06 Branches: 0 246 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: parser.c,v 1.73 2015/10/11 19:53:57 sthen Exp $ */
2
3
/*
4
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
21
#include <err.h>
22
#include <errno.h>
23
#include <fcntl.h>
24
#include <limits.h>
25
#include <netdb.h>
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include <unistd.h>
30
31
#include "parser.h"
32
#include "irrfilter.h"
33
34
enum token_type {
35
	NOTOKEN,
36
	ENDTOKEN,
37
	KEYWORD,
38
	ADDRESS,
39
	PEERADDRESS,
40
	FLAG,
41
	ASNUM,
42
	ASTYPE,
43
	PREFIX,
44
	PEERDESC,
45
	RIBNAME,
46
	COMMUNITY,
47
	LOCALPREF,
48
	MED,
49
	NEXTHOP,
50
	PFTABLE,
51
	PREPNBR,
52
	PREPSELF,
53
	WEIGHT,
54
	FAMILY,
55
	GETOPT,
56
	RTABLE,
57
	FILENAME,
58
	BULK
59
};
60
61
enum getopts {
62
	GETOPT_NONE,
63
	GETOPT_IRRFILTER
64
};
65
66
struct token {
67
	enum token_type		 type;
68
	const char		*keyword;
69
	int			 value;
70
	const struct token	*next;
71
};
72
73
static const struct token t_main[];
74
static const struct token t_show[];
75
static const struct token t_show_summary[];
76
static const struct token t_show_fib[];
77
static const struct token t_show_rib[];
78
static const struct token t_show_mrt[];
79
static const struct token t_show_mrt_file[];
80
static const struct token t_show_rib_neigh[];
81
static const struct token t_show_mrt_neigh[];
82
static const struct token t_show_rib_rib[];
83
static const struct token t_show_neighbor[];
84
static const struct token t_show_neighbor_modifiers[];
85
static const struct token t_fib[];
86
static const struct token t_neighbor[];
87
static const struct token t_neighbor_modifiers[];
88
static const struct token t_show_rib_as[];
89
static const struct token t_show_mrt_as[];
90
static const struct token t_show_prefix[];
91
static const struct token t_show_ip[];
92
static const struct token t_show_community[];
93
static const struct token t_network[];
94
static const struct token t_network_show[];
95
static const struct token t_prefix[];
96
static const struct token t_set[];
97
static const struct token t_community[];
98
static const struct token t_localpref[];
99
static const struct token t_med[];
100
static const struct token t_nexthop[];
101
static const struct token t_pftable[];
102
static const struct token t_prepnbr[];
103
static const struct token t_prepself[];
104
static const struct token t_weight[];
105
static const struct token t_irrfilter[];
106
static const struct token t_irrfilter_opts[];
107
static const struct token t_log[];
108
static const struct token t_fib_table[];
109
static const struct token t_show_fib_table[];
110
111
static const struct token t_main[] = {
112
	{ KEYWORD,	"reload",	RELOAD,		NULL},
113
	{ KEYWORD,	"show",		SHOW,		t_show},
114
	{ KEYWORD,	"fib",		FIB,		t_fib},
115
	{ KEYWORD,	"neighbor",	NEIGHBOR,	t_neighbor},
116
	{ KEYWORD,	"network",	NONE,		t_network},
117
	{ KEYWORD,	"irrfilter",	IRRFILTER,	t_irrfilter},
118
	{ KEYWORD,	"log",		NONE,		t_log},
119
	{ ENDTOKEN,	"",		NONE,		NULL}
120
};
121
122
static const struct token t_show[] = {
123
	{ NOTOKEN,	"",		NONE,		NULL},
124
	{ KEYWORD,	"fib",		SHOW_FIB,	t_show_fib},
125
	{ KEYWORD,	"interfaces",	SHOW_INTERFACE,	NULL},
126
	{ KEYWORD,	"neighbor",	SHOW_NEIGHBOR,	t_show_neighbor},
127
	{ KEYWORD,	"network",	NETWORK_SHOW,	t_network_show},
128
	{ KEYWORD,	"nexthop",	SHOW_NEXTHOP,	NULL},
129
	{ KEYWORD,	"rib",		SHOW_RIB,	t_show_rib},
130
	{ KEYWORD,	"tables",	SHOW_FIB_TABLES, NULL},
131
	{ KEYWORD,	"ip",		NONE,		t_show_ip},
132
	{ KEYWORD,	"summary",	SHOW_SUMMARY,	t_show_summary},
133
	{ KEYWORD,	"mrt",		SHOW_MRT,	t_show_mrt},
134
	{ ENDTOKEN,	"",		NONE,		NULL}
135
};
136
137
static const struct token t_show_summary[] = {
138
	{ NOTOKEN,	"",		NONE,			NULL},
139
	{ KEYWORD,	"terse",	SHOW_SUMMARY_TERSE,	NULL},
140
	{ ENDTOKEN,	"",		NONE,			NULL}
141
};
142
143
static const struct token t_show_fib[] = {
144
	{ NOTOKEN,	"",		NONE,		 NULL},
145
	{ FLAG,		"connected",	F_CONNECTED,	 t_show_fib},
146
	{ FLAG,		"static",	F_STATIC,	 t_show_fib},
147
	{ FLAG,		"bgp",		F_BGPD_INSERTED, t_show_fib},
148
	{ FLAG,		"nexthop",	F_NEXTHOP,	 t_show_fib},
149
	{ KEYWORD,	"table",	NONE,		 t_show_fib_table},
150
	{ FAMILY,	"",		NONE,		 t_show_fib},
151
	{ ADDRESS,	"",		NONE,		 NULL},
152
	{ ENDTOKEN,	"",		NONE,		 NULL}
153
};
154
155
static const struct token t_show_rib[] = {
156
	{ NOTOKEN,	"",		NONE,		NULL},
157
	{ ASTYPE,	"as",		AS_ALL,		t_show_rib_as},
158
	{ ASTYPE,	"source-as",	AS_SOURCE,	t_show_rib_as},
159
	{ ASTYPE,	"transit-as",	AS_TRANSIT,	t_show_rib_as},
160
	{ ASTYPE,	"peer-as",	AS_PEER,	t_show_rib_as},
161
	{ ASTYPE,	"empty-as",	AS_EMPTY,	t_show_rib},
162
	{ KEYWORD,	"community",	NONE,		t_show_community},
163
	{ FLAG,		"best",		F_CTL_ACTIVE,	t_show_rib},
164
	{ FLAG,		"selected",	F_CTL_ACTIVE,	t_show_rib},
165
	{ FLAG,		"detail",	F_CTL_DETAIL,	t_show_rib},
166
	{ FLAG,		"in",		F_CTL_ADJ_IN,	t_show_rib},
167
	{ FLAG,		"out",		F_CTL_ADJ_OUT,	t_show_rib},
168
	{ KEYWORD,	"neighbor",	NONE,		t_show_rib_neigh},
169
	{ KEYWORD,	"table",	NONE,		t_show_rib_rib},
170
	{ KEYWORD,	"summary",	SHOW_SUMMARY,	t_show_summary},
171
	{ KEYWORD,	"memory",	SHOW_RIB_MEM,	NULL},
172
	{ FAMILY,	"",		NONE,		t_show_rib},
173
	{ PREFIX,	"",		NONE,		t_show_prefix},
174
	{ ENDTOKEN,	"",		NONE,		NULL}
175
};
176
177
178
static const struct token t_show_mrt[] = {
179
	{ NOTOKEN,	"",		NONE,		NULL},
180
	{ ASTYPE,	"as",		AS_ALL,		t_show_mrt_as},
181
	{ ASTYPE,	"source-as",	AS_SOURCE,	t_show_mrt_as},
182
	{ ASTYPE,	"transit-as",	AS_TRANSIT,	t_show_mrt_as},
183
	{ ASTYPE,	"peer-as",	AS_PEER,	t_show_mrt_as},
184
	{ ASTYPE,	"empty-as",	AS_EMPTY,	t_show_mrt},
185
	{ FLAG,		"detail",	F_CTL_DETAIL,	t_show_mrt},
186
	{ KEYWORD,	"neighbor",	NONE,		t_show_mrt_neigh},
187
	{ KEYWORD,	"file",		NONE,		t_show_mrt_file},
188
	{ FAMILY,	"",		NONE,		t_show_mrt},
189
	{ PREFIX,	"",		NONE,		t_show_prefix},
190
	{ ENDTOKEN,	"",		NONE,		NULL}
191
};
192
193
static const struct token t_show_mrt_file[] = {
194
	{ FILENAME,	"",		NONE,		t_show_mrt},
195
	{ ENDTOKEN,	"",		NONE,	NULL}
196
};
197
198
static const struct token t_show_rib_neigh[] = {
199
	{ PEERADDRESS,	"",		NONE,	t_show_rib},
200
	{ PEERDESC,	"",		NONE,	t_show_rib},
201
	{ ENDTOKEN,	"",		NONE,	NULL}
202
};
203
204
static const struct token t_show_mrt_neigh[] = {
205
	{ PEERADDRESS,	"",		NONE,	t_show_mrt},
206
	{ ENDTOKEN,	"",		NONE,	NULL}
207
};
208
209
static const struct token t_show_rib_rib[] = {
210
	{ RIBNAME,	"",		NONE,	t_show_rib},
211
	{ ENDTOKEN,	"",		NONE,	NULL}
212
};
213
214
static const struct token t_show_neighbor[] = {
215
	{ NOTOKEN,	"",		NONE,	NULL},
216
	{ PEERADDRESS,	"",		NONE,	t_show_neighbor_modifiers},
217
	{ PEERDESC,	"",		NONE,	t_show_neighbor_modifiers},
218
	{ ENDTOKEN,	"",		NONE,	NULL}
219
};
220
221
static const struct token t_show_neighbor_modifiers[] = {
222
	{ NOTOKEN,	"",		NONE,			NULL},
223
	{ KEYWORD,	"timers",	SHOW_NEIGHBOR_TIMERS,	NULL},
224
	{ KEYWORD,	"messages",	SHOW_NEIGHBOR,		NULL},
225
	{ KEYWORD,	"terse",	SHOW_NEIGHBOR_TERSE,	NULL},
226
	{ ENDTOKEN,	"",		NONE,			NULL}
227
};
228
229
static const struct token t_fib[] = {
230
	{ KEYWORD,	"couple",	FIB_COUPLE,	NULL},
231
	{ KEYWORD,	"decouple",	FIB_DECOUPLE,	NULL},
232
	{ KEYWORD,	"table",	NONE,		t_fib_table},
233
	{ ENDTOKEN,	"",		NONE,		NULL}
234
};
235
236
static const struct token t_neighbor[] = {
237
	{ PEERADDRESS,	"",		NONE,		t_neighbor_modifiers},
238
	{ PEERDESC,	"",		NONE,		t_neighbor_modifiers},
239
	{ ENDTOKEN,	"",		NONE,		NULL}
240
};
241
242
static const struct token t_neighbor_modifiers[] = {
243
	{ KEYWORD,	"up",		NEIGHBOR_UP,		NULL},
244
	{ KEYWORD,	"down",		NEIGHBOR_DOWN,		NULL},
245
	{ KEYWORD,	"clear",	NEIGHBOR_CLEAR,		NULL},
246
	{ KEYWORD,	"refresh",	NEIGHBOR_RREFRESH,	NULL},
247
	{ KEYWORD,	"destroy",	NEIGHBOR_DESTROY,	NULL},
248
	{ ENDTOKEN,	"",		NONE,			NULL}
249
};
250
251
static const struct token t_show_rib_as[] = {
252
	{ ASNUM,	"",		NONE,		t_show_rib},
253
	{ ENDTOKEN,	"",		NONE,		NULL}
254
};
255
256
static const struct token t_show_mrt_as[] = {
257
	{ ASNUM,	"",		NONE,		t_show_mrt},
258
	{ ENDTOKEN,	"",		NONE,		NULL}
259
};
260
261
static const struct token t_show_prefix[] = {
262
	{ NOTOKEN,	"",		NONE,		NULL},
263
	{ FLAG,		"all",		F_LONGER,	NULL},
264
	{ FLAG,		"longer-prefixes", F_LONGER,	NULL},
265
	{ ENDTOKEN,	"",		NONE,		NULL}
266
};
267
268
static const struct token t_show_ip[] = {
269
	{ KEYWORD,	"bgp",		SHOW_RIB,	t_show_rib},
270
	{ ENDTOKEN,	"",		NONE,		NULL}
271
};
272
273
static const struct token t_show_community[] = {
274
	{ COMMUNITY,	"",		NONE,		t_show_rib},
275
	{ ENDTOKEN,	"",		NONE,		NULL}
276
};
277
278
static const struct token t_network[] = {
279
	{ KEYWORD,	"add",		NETWORK_ADD,	t_prefix},
280
	{ KEYWORD,	"delete",	NETWORK_REMOVE,	t_prefix},
281
	{ KEYWORD,	"flush",	NETWORK_FLUSH,	NULL},
282
	{ KEYWORD,	"show",		NETWORK_SHOW,	t_network_show},
283
	{ KEYWORD,	"mrt",		NETWORK_MRT,	t_show_mrt},
284
	{ KEYWORD,	"bulk",		NETWORK_BULK_ADD,	t_set},
285
	{ ENDTOKEN,	"",		NONE,		NULL}
286
};
287
288
static const struct token t_prefix[] = {
289
	{ PREFIX,	"",		NONE,		t_set},
290
	{ ENDTOKEN,	"",		NONE,		NULL}
291
};
292
293
static const struct token t_network_show[] = {
294
	{ NOTOKEN,	"",		NONE,			NULL},
295
	{ FAMILY,	"",		NONE,			NULL},
296
	{ ENDTOKEN,	"",		NONE,			NULL}
297
};
298
299
static const struct token t_set[] = {
300
	{ NOTOKEN,	"",			NONE,	NULL},
301
	{ KEYWORD,	"community",		NONE,	t_community},
302
	{ KEYWORD,	"localpref",		NONE,	t_localpref},
303
	{ KEYWORD,	"med",			NONE,	t_med},
304
	{ KEYWORD,	"metric",		NONE,	t_med},
305
	{ KEYWORD,	"nexthop",		NONE,	t_nexthop},
306
	{ KEYWORD,	"pftable",		NONE,	t_pftable},
307
	{ KEYWORD,	"prepend-neighbor",	NONE,	t_prepnbr},
308
	{ KEYWORD,	"prepend-self",		NONE,	t_prepself},
309
	{ KEYWORD,	"weight",		NONE,	t_weight},
310
	{ KEYWORD,	"add",			NETWORK_BULK_ADD,	NULL},
311
	{ KEYWORD,	"delete",		NETWORK_BULK_REMOVE,	NULL},
312
	{ ENDTOKEN,	"",			NONE,	NULL}
313
};
314
315
static const struct token t_community[] = {
316
	{ COMMUNITY,	"",			NONE,	t_set},
317
	{ ENDTOKEN,	"",			NONE,	NULL}
318
};
319
320
static const struct token t_localpref[] = {
321
	{ LOCALPREF,	"",			NONE,	t_set},
322
	{ ENDTOKEN,	"",			NONE,	NULL}
323
};
324
325
static const struct token t_med[] = {
326
	{ MED,		"",			NONE,	t_set},
327
	{ ENDTOKEN,	"",			NONE,	NULL}
328
};
329
330
static const struct token t_nexthop[] = {
331
	{ NEXTHOP,	"",			NONE,	t_set},
332
	{ ENDTOKEN,	"",			NONE,	NULL}
333
};
334
335
static const struct token t_pftable[] = {
336
	{ PFTABLE,	"",			NONE,	t_set},
337
	{ ENDTOKEN,	"",			NONE,	NULL}
338
};
339
340
static const struct token t_prepnbr[] = {
341
	{ PREPNBR,	"",			NONE,	t_set},
342
	{ ENDTOKEN,	"",			NONE,	NULL}
343
};
344
345
static const struct token t_prepself[] = {
346
	{ PREPSELF,	"",			NONE,	t_set},
347
	{ ENDTOKEN,	"",			NONE,	NULL}
348
};
349
350
static const struct token t_weight[] = {
351
	{ WEIGHT,	"",			NONE,	t_set},
352
	{ ENDTOKEN,	"",			NONE,	NULL}
353
};
354
355
static const struct token t_irrfilter[] = {
356
	{ GETOPT,	"",	GETOPT_IRRFILTER,	t_irrfilter},
357
	{ ASNUM,	"",	NONE,			t_irrfilter_opts},
358
	{ ENDTOKEN,	"",	NONE,			NULL}
359
};
360
361
static const struct token t_irrfilter_opts[] = {
362
	{ NOTOKEN,	"",		NONE,			NULL},
363
	{ FLAG,		"importonly",	F_IMPORTONLY,		t_irrfilter_opts},
364
	{ ENDTOKEN,	"",		NONE,			NULL}
365
};
366
367
static const struct token t_log[] = {
368
	{ KEYWORD,	"verbose",	LOG_VERBOSE,	NULL},
369
	{ KEYWORD,	"brief",	LOG_BRIEF,	NULL},
370
	{ ENDTOKEN,	"",		NONE,		NULL}
371
};
372
373
static const struct token t_fib_table[] = {
374
	{ RTABLE,	"",			NONE,	t_fib},
375
	{ ENDTOKEN,	"",			NONE,	NULL}
376
};
377
378
static const struct token t_show_fib_table[] = {
379
	{ RTABLE,	"",			NONE,	t_show_fib},
380
	{ ENDTOKEN,	"",			NONE,	NULL}
381
};
382
383
static struct parse_result	res;
384
385
const struct token	*match_token(int *argc, char **argv[],
386
			    const struct token []);
387
void			 show_valid_args(const struct token []);
388
int			 parse_addr(const char *, struct bgpd_addr *);
389
int			 parse_asnum(const char *, size_t, u_int32_t *);
390
int			 parse_number(const char *, struct parse_result *,
391
			     enum token_type);
392
int			 getcommunity(const char *);
393
int			 parse_community(const char *, struct parse_result *);
394
int			 parse_nexthop(const char *, struct parse_result *);
395
int			 bgpctl_getopt(int *, char **[], int);
396
397
struct parse_result *
398
parse(int argc, char *argv[])
399
{
400
	const struct token	*table = t_main;
401
	const struct token	*match;
402
403
	bzero(&res, sizeof(res));
404
	res.community.as = COMMUNITY_UNSET;
405
	res.community.type = COMMUNITY_UNSET;
406
	TAILQ_INIT(&res.set);
407
	if ((res.irr_outdir = getcwd(NULL, 0)) == NULL) {
408
		fprintf(stderr, "getcwd failed: %s\n", strerror(errno));
409
		return (NULL);
410
	}
411
412
	while (argc >= 0) {
413
		if ((match = match_token(&argc, &argv, table)) == NULL) {
414
			fprintf(stderr, "valid commands/args:\n");
415
			show_valid_args(table);
416
			return (NULL);
417
		}
418
419
		argc--;
420
		argv++;
421
422
		if (match->type == NOTOKEN || match->next == NULL)
423
			break;
424
425
		table = match->next;
426
	}
427
428
	if (argc > 0) {
429
		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
430
		return (NULL);
431
	}
432
433
	return (&res);
434
}
435
436
const struct token *
437
match_token(int *argc, char **argv[], const struct token table[])
438
{
439
	u_int			 i, match;
440
	const struct token	*t = NULL;
441
	struct filter_set	*fs;
442
	const char		*word = *argv[0];
443
	size_t			wordlen = 0;
444
445
	match = 0;
446
	if (word != NULL)
447
		wordlen = strlen(word);
448
	for (i = 0; table[i].type != ENDTOKEN; i++) {
449
		switch (table[i].type) {
450
		case NOTOKEN:
451
			if (word == NULL || wordlen == 0) {
452
				match++;
453
				t = &table[i];
454
			}
455
			break;
456
		case KEYWORD:
457
			if (word != NULL && strncmp(word, table[i].keyword,
458
			    wordlen) == 0) {
459
				match++;
460
				t = &table[i];
461
				if (t->value)
462
					res.action = t->value;
463
			}
464
			break;
465
		case FLAG:
466
			if (word != NULL && strncmp(word, table[i].keyword,
467
			    wordlen) == 0) {
468
				match++;
469
				t = &table[i];
470
				res.flags |= t->value;
471
			}
472
			break;
473
		case FAMILY:
474
			if (word == NULL)
475
				break;
476
			if (!strcmp(word, "inet") ||
477
			    !strcasecmp(word, "IPv4")) {
478
				match++;
479
				t = &table[i];
480
				res.aid = AID_INET;
481
			}
482
			if (!strcmp(word, "inet6") ||
483
			    !strcasecmp(word, "IPv6")) {
484
				match++;
485
				t = &table[i];
486
				res.aid = AID_INET6;
487
			}
488
			if (!strcasecmp(word, "VPNv4")) {
489
				match++;
490
				t = &table[i];
491
				res.aid = AID_VPN_IPv4;
492
			}
493
			break;
494
		case ADDRESS:
495
			if (parse_addr(word, &res.addr)) {
496
				match++;
497
				t = &table[i];
498
				if (t->value)
499
					res.action = t->value;
500
			}
501
			break;
502
		case PEERADDRESS:
503
			if (parse_addr(word, &res.peeraddr)) {
504
				match++;
505
				t = &table[i];
506
				if (t->value)
507
					res.action = t->value;
508
			}
509
			break;
510
		case PREFIX:
511
			if (parse_prefix(word, wordlen, &res.addr, &res.prefixlen)) {
512
				match++;
513
				t = &table[i];
514
				if (t->value)
515
					res.action = t->value;
516
			}
517
			break;
518
		case ASTYPE:
519
			if (word != NULL && strncmp(word, table[i].keyword,
520
			    wordlen) == 0) {
521
				match++;
522
				t = &table[i];
523
				res.as.type = t->value;
524
			}
525
			break;
526
		case ASNUM:
527
			if (parse_asnum(word, wordlen, &res.as.as)) {
528
				match++;
529
				t = &table[i];
530
			}
531
			break;
532
		case PEERDESC:
533
			if (!match && word != NULL && wordlen > 0) {
534
				if (strlcpy(res.peerdesc, word,
535
				    sizeof(res.peerdesc)) >=
536
				    sizeof(res.peerdesc))
537
					errx(1, "neighbor description too "
538
					    "long");
539
				match++;
540
				t = &table[i];
541
			}
542
			break;
543
		case RIBNAME:
544
			if (!match && word != NULL && wordlen > 0) {
545
				if (strlcpy(res.rib, word, sizeof(res.rib)) >=
546
				    sizeof(res.rib))
547
					errx(1, "rib name too long");
548
				match++;
549
				t = &table[i];
550
			}
551
			break;
552
		case COMMUNITY:
553
			if (word != NULL && wordlen > 0 &&
554
			    parse_community(word, &res)) {
555
				match++;
556
				t = &table[i];
557
			}
558
			break;
559
		case LOCALPREF:
560
		case MED:
561
		case PREPNBR:
562
		case PREPSELF:
563
		case WEIGHT:
564
		case RTABLE:
565
			if (word != NULL && wordlen > 0 &&
566
			    parse_number(word, &res, table[i].type)) {
567
				match++;
568
				t = &table[i];
569
			}
570
			break;
571
		case NEXTHOP:
572
			if (word != NULL && wordlen > 0 &&
573
			    parse_nexthop(word, &res)) {
574
				match++;
575
				t = &table[i];
576
			}
577
			break;
578
		case PFTABLE:
579
			if (word != NULL && wordlen > 0) {
580
				if ((fs = calloc(1,
581
				    sizeof(struct filter_set))) == NULL)
582
					err(1, NULL);
583
				if (strlcpy(fs->action.pftable, word,
584
				    sizeof(fs->action.pftable)) >=
585
				    sizeof(fs->action.pftable))
586
					errx(1, "pftable name too long");
587
				TAILQ_INSERT_TAIL(&res.set, fs, entry);
588
				match++;
589
				t = &table[i];
590
			}
591
			break;
592
		case GETOPT:
593
			if (bgpctl_getopt(argc, argv, table[i].value)) {
594
				match++;
595
				t = &table[i];
596
			}
597
			break;
598
		case FILENAME:
599
			if (word != NULL && wordlen > 0) {
600
				if ((res.mrtfd = open(word, O_RDONLY)) == -1) {
601
					/*
602
					 * ignore error if path has no / and
603
					 * does not exist. In hope to print
604
					 * usage.
605
					 */
606
					if (errno == ENOENT &&
607
					    !strchr(word, '/'))
608
						break;
609
					err(1, "mrt open(%s)", word);
610
				}
611
				match++;
612
				t = &table[i];
613
			}
614
			break;
615
		case BULK:
616
			match++;
617
			t = &table[i];
618
			break;
619
		case ENDTOKEN:
620
			break;
621
		}
622
	}
623
624
	if (match != 1) {
625
		if (word == NULL)
626
			fprintf(stderr, "missing argument:\n");
627
		else if (match > 1)
628
			fprintf(stderr, "ambiguous argument: %s\n", word);
629
		else if (match < 1)
630
			fprintf(stderr, "unknown argument: %s\n", word);
631
		return (NULL);
632
	}
633
634
	return (t);
635
}
636
637
void
638
show_valid_args(const struct token table[])
639
{
640
	int	i;
641
642
	for (i = 0; table[i].type != ENDTOKEN; i++) {
643
		switch (table[i].type) {
644
		case NOTOKEN:
645
			fprintf(stderr, "  <cr>\n");
646
			break;
647
		case KEYWORD:
648
		case FLAG:
649
		case ASTYPE:
650
			fprintf(stderr, "  %s\n", table[i].keyword);
651
			break;
652
		case ADDRESS:
653
		case PEERADDRESS:
654
			fprintf(stderr, "  <address>\n");
655
			break;
656
		case PREFIX:
657
			fprintf(stderr, "  <address>[/<len>]\n");
658
			break;
659
		case ASNUM:
660
			fprintf(stderr, "  <asnum>\n");
661
			break;
662
		case PEERDESC:
663
			fprintf(stderr, "  <neighbor description>\n");
664
			break;
665
		case RIBNAME:
666
			fprintf(stderr, "  <rib name>\n");
667
			break;
668
		case COMMUNITY:
669
			fprintf(stderr, "  <community>\n");
670
			break;
671
		case LOCALPREF:
672
		case MED:
673
		case PREPNBR:
674
		case PREPSELF:
675
		case WEIGHT:
676
			fprintf(stderr, "  <number>\n");
677
			break;
678
		case RTABLE:
679
			fprintf(stderr, "  <rtableid>\n");
680
			break;
681
		case NEXTHOP:
682
			fprintf(stderr, "  <address>\n");
683
			break;
684
		case PFTABLE:
685
			fprintf(stderr, "  <pftable>\n");
686
			break;
687
		case FAMILY:
688
			fprintf(stderr, "  [ inet | inet6 | IPv4 | IPv6 | VPNv4 ]\n");
689
			break;
690
		case GETOPT:
691
			fprintf(stderr, "  <options>\n");
692
			break;
693
		case FILENAME:
694
			fprintf(stderr, "  <filename>\n");
695
			break;
696
		case BULK:
697
		case ENDTOKEN:
698
			break;
699
		}
700
	}
701
}
702
703
int
704
parse_addr(const char *word, struct bgpd_addr *addr)
705
{
706
	struct in_addr	ina;
707
	struct addrinfo	hints, *r;
708
709
	if (word == NULL)
710
		return (0);
711
712
	bzero(addr, sizeof(struct bgpd_addr));
713
	bzero(&ina, sizeof(ina));
714
715
	if (inet_net_pton(AF_INET, word, &ina, sizeof(ina)) != -1) {
716
		addr->aid = AID_INET;
717
		addr->v4 = ina;
718
		return (1);
719
	}
720
721
	bzero(&hints, sizeof(hints));
722
	hints.ai_family = AF_INET6;
723
	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
724
	hints.ai_flags = AI_NUMERICHOST;
725
	if (getaddrinfo(word, "0", &hints, &r) == 0) {
726
		sa2addr(r->ai_addr, addr);
727
		freeaddrinfo(r);
728
		return (1);
729
	}
730
731
	return (0);
732
}
733
734
int
735
parse_prefix(const char *word, size_t wordlen, struct bgpd_addr *addr, u_int8_t *prefixlen)
736
{
737
	char		*p, *ps;
738
	const char	*errstr;
739
	int		 mask = -1;
740
741
	if (word == NULL)
742
		return (0);
743
744
	bzero(addr, sizeof(struct bgpd_addr));
745
746
	if ((p = strrchr(word, '/')) != NULL) {
747
		size_t plen = strlen(p);
748
		mask = strtonum(p + 1, 0, 128, &errstr);
749
		if (errstr)
750
			errx(1, "netmask %s", errstr);
751
752
		if ((ps = malloc(wordlen - plen + 1)) == NULL)
753
			err(1, "parse_prefix: malloc");
754
		strlcpy(ps, word, wordlen - plen + 1);
755
756
		if (parse_addr(ps, addr) == 0) {
757
			free(ps);
758
			return (0);
759
		}
760
761
		free(ps);
762
	} else
763
		if (parse_addr(word, addr) == 0)
764
			return (0);
765
766
	switch (addr->aid) {
767
	case AID_INET:
768
		if (mask == -1)
769
			mask = 32;
770
		if (mask > 32)
771
			errx(1, "invalid netmask: too large");
772
		addr->v4.s_addr = addr->v4.s_addr & htonl(prefixlen2mask(mask));
773
		break;
774
	case AID_INET6:
775
		if (mask == -1)
776
			mask = 128;
777
		inet6applymask(&addr->v6, &addr->v6, mask);
778
		break;
779
	default:
780
		return (0);
781
	}
782
783
	*prefixlen = mask;
784
	return (1);
785
}
786
787
int
788
parse_asnum(const char *word, size_t wordlen, u_int32_t *asnum)
789
{
790
	const char	*errstr;
791
	char		*dot;
792
	u_int32_t	 uval, uvalh = 0;
793
794
	if (word == NULL)
795
		return (0);
796
797
	if (wordlen < 1 || word[0] < '0' || word[0] > '9')
798
		return (0);
799
800
	if ((dot = strchr(word,'.')) != NULL) {
801
		*dot++ = '\0';
802
		uvalh = strtonum(word, 0, USHRT_MAX, &errstr);
803
		if (errstr)
804
			errx(1, "AS number is %s: %s", errstr, word);
805
		uval = strtonum(dot, 0, USHRT_MAX, &errstr);
806
		if (errstr)
807
			errx(1, "AS number is %s: %s", errstr, word);
808
	} else {
809
		uval = strtonum(word, 0, UINT_MAX, &errstr);
810
		if (errstr)
811
			errx(1, "AS number is %s: %s", errstr, word);
812
	}
813
814
	*asnum = uval | (uvalh << 16);
815
	return (1);
816
}
817
818
int
819
parse_number(const char *word, struct parse_result *r, enum token_type type)
820
{
821
	struct filter_set	*fs;
822
	const char		*errstr;
823
	u_int			 uval;
824
825
	if (word == NULL)
826
		return (0);
827
828
	uval = strtonum(word, 0, UINT_MAX, &errstr);
829
	if (errstr)
830
		errx(1, "number is %s: %s", errstr, word);
831
832
	/* number was parseable */
833
	if (type == RTABLE) {
834
		r->rtableid = uval;
835
		return (1);
836
	}
837
838
	if ((fs = calloc(1, sizeof(struct filter_set))) == NULL)
839
		err(1, NULL);
840
	switch (type) {
841
	case LOCALPREF:
842
		fs->type = ACTION_SET_LOCALPREF;
843
		fs->action.metric = uval;
844
		break;
845
	case MED:
846
		fs->type = ACTION_SET_MED;
847
		fs->action.metric = uval;
848
		break;
849
	case PREPNBR:
850
		if (uval > 128) {
851
			free(fs);
852
			return (0);
853
		}
854
		fs->type = ACTION_SET_PREPEND_PEER;
855
		fs->action.prepend = uval;
856
		break;
857
	case PREPSELF:
858
		if (uval > 128) {
859
			free(fs);
860
			return (0);
861
		}
862
		fs->type = ACTION_SET_PREPEND_SELF;
863
		fs->action.prepend = uval;
864
		break;
865
	case WEIGHT:
866
		fs->type = ACTION_SET_WEIGHT;
867
		fs->action.metric = uval;
868
		break;
869
	default:
870
		errx(1, "king bula sez bad things happen");
871
	}
872
873
	TAILQ_INSERT_TAIL(&r->set, fs, entry);
874
	return (1);
875
}
876
877
int
878
getcommunity(const char *s)
879
{
880
	const char	*errstr;
881
	u_int16_t	 uval;
882
883
	if (strcmp(s, "*") == 0)
884
		return (COMMUNITY_ANY);
885
886
	uval = strtonum(s, 0, USHRT_MAX, &errstr);
887
	if (errstr)
888
		errx(1, "Community is %s: %s", errstr, s);
889
890
	return (uval);
891
}
892
893
int
894
parse_community(const char *word, struct parse_result *r)
895
{
896
	struct filter_set	*fs;
897
	char			*p;
898
	int			 as, type;
899
900
	/* Well-known communities */
901
	if (strcasecmp(word, "NO_EXPORT") == 0) {
902
		as = COMMUNITY_WELLKNOWN;
903
		type = COMMUNITY_NO_EXPORT;
904
		goto done;
905
	} else if (strcasecmp(word, "NO_ADVERTISE") == 0) {
906
		as = COMMUNITY_WELLKNOWN;
907
		type = COMMUNITY_NO_ADVERTISE;
908
		goto done;
909
	} else if (strcasecmp(word, "NO_EXPORT_SUBCONFED") == 0) {
910
		as = COMMUNITY_WELLKNOWN;
911
		type = COMMUNITY_NO_EXPSUBCONFED;
912
		goto done;
913
	} else if (strcasecmp(word, "NO_PEER") == 0) {
914
		as = COMMUNITY_WELLKNOWN;
915
		type = COMMUNITY_NO_PEER;
916
		goto done;
917
	} else if (strcasecmp(word, "BLACKHOLE") == 0) {
918
		as = COMMUNITY_WELLKNOWN;
919
		type = COMMUNITY_BLACKHOLE;
920
		goto done;
921
	}
922
923
	if ((p = strchr(word, ':')) == NULL) {
924
		fprintf(stderr, "Bad community syntax\n");
925
		return (0);
926
	}
927
	*p++ = 0;
928
929
	as = getcommunity(word);
930
	type = getcommunity(p);
931
932
done:
933
	if (as == 0) {
934
		fprintf(stderr, "Invalid community\n");
935
		return (0);
936
	}
937
	if (as == COMMUNITY_WELLKNOWN)
938
		switch (type) {
939
		case COMMUNITY_NO_EXPORT:
940
		case COMMUNITY_NO_ADVERTISE:
941
		case COMMUNITY_NO_EXPSUBCONFED:
942
		case COMMUNITY_BLACKHOLE:
943
			/* valid */
944
			break;
945
		default:
946
			/* unknown */
947
			fprintf(stderr, "Unknown well-known community\n");
948
			return (0);
949
		}
950
951
	if ((fs = calloc(1, sizeof(struct filter_set))) == NULL)
952
		err(1, NULL);
953
	fs->type = ACTION_SET_COMMUNITY;
954
	fs->action.community.as = as;
955
	fs->action.community.type = type;
956
957
	r->community.as = as;
958
	r->community.type = type;
959
960
	TAILQ_INSERT_TAIL(&r->set, fs, entry);
961
	return (1);
962
}
963
964
int
965
parse_nexthop(const char *word, struct parse_result *r)
966
{
967
	struct filter_set	*fs;
968
969
	if ((fs = calloc(1, sizeof(struct filter_set))) == NULL)
970
		err(1, NULL);
971
972
	if (strcmp(word, "blackhole") == 0)
973
		fs->type = ACTION_SET_NEXTHOP_BLACKHOLE;
974
	else if (strcmp(word, "reject") == 0)
975
		fs->type = ACTION_SET_NEXTHOP_REJECT;
976
	else if (strcmp(word, "no-modify") == 0)
977
		fs->type = ACTION_SET_NEXTHOP_NOMODIFY;
978
	else if (parse_addr(word, &fs->action.nexthop)) {
979
		fs->type = ACTION_SET_NEXTHOP;
980
	} else {
981
		free(fs);
982
		return (0);
983
	}
984
985
	TAILQ_INSERT_TAIL(&r->set, fs, entry);
986
	return (1);
987
}
988
989
int
990
bgpctl_getopt(int *argc, char **argv[], int type)
991
{
992
	int	  ch;
993
994
	optind = optreset = 1;
995
	while ((ch = getopt((*argc) + 1, (*argv) - 1, "46o:")) != -1) {
996
		switch (ch) {
997
		case '4':
998
			res.flags = (res.flags | F_IPV4) & ~F_IPV6;
999
			break;
1000
		case '6':
1001
			res.flags = (res.flags | F_IPV6) & ~F_IPV4;
1002
			break;
1003
		case 'o':
1004
			res.irr_outdir = optarg;
1005
			break;
1006
		default:
1007
			usage();
1008
			/* NOTREACHED */
1009
		}
1010
	}
1011
1012
	if (optind > 1) {
1013
		(*argc) -= (optind - 1);
1014
		(*argv) += (optind - 1);
1015
1016
		/* need to move one backwards as calling code moves forward */
1017
		(*argc)++;
1018
		(*argv)--;
1019
		return (1);
1020
	} else
1021
		return (0);
1022
}