xref: /openbsd-src/usr.sbin/bgpctl/parser.c (revision 5738bc6274bbfbba95d07e5dc8d380a26b687449)
1 /*	$OpenBSD: parser.c,v 1.8 2004/08/20 15:49:35 henning 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 <err.h>
20 #include <errno.h>
21 #include <limits.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "parser.h"
27 
28 enum token_type {
29 	NOTOKEN,
30 	ENDTOKEN,
31 	KEYWORD,
32 	ADDRESS,
33 	FLAG,
34 	ASNUM,
35 	ASTYPE,
36 	PREFIX
37 };
38 
39 struct token {
40 	enum token_type		 type;
41 	const char		*keyword;
42 	int			 value;
43 	const struct token	*next;
44 };
45 
46 static const struct token t_main[];
47 static const struct token t_show[];
48 static const struct token t_show_fib[];
49 static const struct token t_show_rib[];
50 static const struct token t_show_neighbor[];
51 static const struct token t_show_neighbor_modifiers[];
52 static const struct token t_fib[];
53 static const struct token t_neighbor[];
54 static const struct token t_neighbor_modifiers[];
55 static const struct token t_show_as[];
56 static const struct token t_show_prefix[];
57 static const struct token t_show_ip[];
58 static const struct token t_nexthop[];
59 static const struct token t_prefix[];
60 
61 static const struct token t_main[] = {
62 	{ KEYWORD,	"reload",	RELOAD,		NULL},
63 	{ KEYWORD,	"show",		SHOW,		t_show},
64 	{ KEYWORD,	"fib",		FIB,		t_fib},
65 	{ KEYWORD,	"neighbor",	NEIGHBOR,	t_neighbor},
66 	{ KEYWORD,	"network",	NONE,		t_nexthop},
67 	{ ENDTOKEN,	"",		NONE,		NULL}
68 };
69 
70 static const struct token t_show[] = {
71 	{ NOTOKEN,	"",		NONE,		NULL},
72 	{ KEYWORD,	"fib",		SHOW_FIB,	t_show_fib},
73 	{ KEYWORD,	"interfaces",	SHOW_INTERFACE,	NULL},
74 	{ KEYWORD,	"neighbor",	SHOW_NEIGHBOR,	t_show_neighbor},
75 	{ KEYWORD,	"nexthop",	SHOW_NEXTHOP,	NULL},
76 	{ KEYWORD,	"rib",		SHOW_RIB,	t_show_rib},
77 	{ KEYWORD,	"ip",		NONE,		t_show_ip},
78 	{ KEYWORD,	"summary",	SHOW_SUMMARY,	NULL},
79 	{ ENDTOKEN,	"",		NONE,		NULL}
80 };
81 
82 static const struct token t_show_fib[] = {
83 	{ NOTOKEN,	"",		NONE,			NULL},
84 	{ FLAG,		"connected",	F_CONNECTED,		t_show_fib},
85 	{ FLAG,		"static",	F_STATIC,		t_show_fib},
86 	{ FLAG,		"bgp",		F_BGPD_INSERTED,	t_show_fib},
87 	{ FLAG,		"nexthop",	F_NEXTHOP,		t_show_fib},
88 	{ ADDRESS,	"",		NONE,			NULL},
89 	{ ENDTOKEN,	"",		NONE,			NULL}
90 };
91 
92 static const struct token t_show_rib[] = {
93 	{ NOTOKEN,	"",		NONE,		NULL},
94 	{ PREFIX,	"",		NONE,		t_show_prefix},
95 	{ ASTYPE,	"as",		AS_ALL,		t_show_as},
96 	{ ASTYPE,	"source-as",	AS_SOURCE,	t_show_as},
97 	{ ASTYPE,	"transit-as",	AS_TRANSIT,	t_show_as},
98 	{ ASTYPE,	"empty-as",	AS_EMPTY,	NULL},
99 	{ KEYWORD,	"summary",	SHOW_SUMMARY,	NULL},
100 	{ ENDTOKEN,	"",		NONE,		NULL}
101 };
102 
103 static const struct token t_show_neighbor[] = {
104 	{ NOTOKEN,	"",		NONE,	NULL},
105 	{ ADDRESS,	"",		NONE,	t_show_neighbor_modifiers},
106 	{ ENDTOKEN,	"",		NONE,	NULL}
107 };
108 
109 static const struct token t_show_neighbor_modifiers[] = {
110 	{ NOTOKEN,	"",		NONE,			NULL},
111 	{ KEYWORD,	"timers",	SHOW_NEIGHBOR_TIMERS,	NULL},
112 	{ KEYWORD,	"messages",	SHOW_NEIGHBOR,		NULL},
113 	{ ENDTOKEN,	"",		NONE,			NULL}
114 };
115 
116 static const struct token t_fib[] = {
117 	{ KEYWORD,	"couple",	FIB_COUPLE,	NULL},
118 	{ KEYWORD,	"decouple",	FIB_DECOUPLE,	NULL},
119 	{ ENDTOKEN,	"",		NONE,		NULL}
120 };
121 
122 static const struct token t_neighbor[] = {
123 	{ ADDRESS,	"",		NONE,		t_neighbor_modifiers},
124 	{ ENDTOKEN,	"",		NONE,		NULL}
125 };
126 
127 static const struct token t_neighbor_modifiers[] = {
128 	{ KEYWORD,	"up",		NEIGHBOR_UP,	NULL},
129 	{ KEYWORD,	"down",		NEIGHBOR_DOWN,	NULL},
130 	{ KEYWORD,	"clear",	NEIGHBOR_CLEAR,	NULL},
131 	{ ENDTOKEN,	"",		NONE,		NULL}
132 };
133 
134 static const struct token t_show_as[] = {
135 	{ ASNUM,	"",		NONE,		NULL},
136 	{ ENDTOKEN,	"",		NONE,		NULL}
137 };
138 
139 static const struct token t_show_prefix[] = {
140 	{ NOTOKEN,	"",		NONE,		NULL},
141 	{ FLAG,		"all",		F_LONGER,	NULL},
142 	{ FLAG,		"longer-prefixes", F_LONGER,	NULL},
143 	{ ENDTOKEN,	"",		NONE,		NULL}
144 };
145 
146 static const struct token t_show_ip[] = {
147 	{ KEYWORD,	"bgp",		SHOW_RIB,	t_show_rib},
148 	{ ENDTOKEN,	"",		NONE,		NULL}
149 };
150 
151 static const struct token t_nexthop[] = {
152 	{ KEYWORD,	"add",		NETWORK_ADD,	t_prefix},
153 	{ KEYWORD,	"delete",	NETWORK_REMOVE,	t_prefix},
154 	{ KEYWORD,	"flush",	NETWORK_FLUSH,	NULL},
155 	{ KEYWORD,	"show",		NETWORK_SHOW,	NULL},
156 	{ ENDTOKEN,	"",		NONE,		NULL}
157 };
158 
159 static const struct token t_prefix[] = {
160 	{ PREFIX,	"",		NONE,		NULL},
161 	{ ENDTOKEN,	"",		NONE,		NULL}
162 };
163 
164 static struct parse_result	res;
165 
166 const struct token	*match_token(const char *, const struct token []);
167 void			 show_valid_args(const struct token []);
168 int			 parse_addr(const char *, struct bgpd_addr *);
169 int			 parse_prefix(const char *, struct bgpd_addr *,
170 			     u_int8_t *);
171 int			 parse_asnum(const char *, u_int16_t *);
172 
173 struct parse_result *
174 parse(int argc, char *argv[])
175 {
176 	int			 curarg = 1;
177 	const struct token	*table = t_main;
178 	const struct token	*match;
179 	char			*word;
180 
181 	bzero(&res, sizeof(res));
182 	if (argc == 1)
183 		return (&res);
184 
185 	for (;;) {
186 		if (argc > curarg)
187 			word = argv[curarg];
188 		else
189 			word = NULL;
190 
191 		if ((match = match_token(word, table)) == NULL) {
192 			fprintf(stderr, "valid commands/args:\n");
193 			show_valid_args(table);
194 			return (NULL);
195 		}
196 
197 		curarg++;
198 
199 		if (match->type == NOTOKEN)
200 			break;
201 
202 		if (match->next == NULL)
203 			break;
204 
205 		table = match->next;
206 	}
207 
208 	if (curarg < argc) {
209 		fprintf(stderr, "superfluous argument: %s\n", argv[curarg]);
210 		return (NULL);
211 	}
212 
213 	return (&res);
214 }
215 
216 const struct token *
217 match_token(const char *word, const struct token table[])
218 {
219 	u_int			 i, match;
220 	const struct token	*t = NULL;
221 
222 	match = 0;
223 
224 	for (i = 0; table[i].type != ENDTOKEN; i++) {
225 		switch (table[i].type) {
226 		case NOTOKEN:
227 			if (word == NULL || strlen(word) == 0) {
228 				match++;
229 				t = &table[i];
230 			}
231 			break;
232 		case KEYWORD:
233 			if (word != NULL && strncmp(word, table[i].keyword,
234 			    strlen(word)) == 0) {
235 				match++;
236 				t = &table[i];
237 				if (t->value)
238 					res.action = t->value;
239 			}
240 			break;
241 		case FLAG:
242 			if (word != NULL && strncmp(word, table[i].keyword,
243 			    strlen(word)) == 0) {
244 				match++;
245 				t = &table[i];
246 				res.flags |= t->value;
247 			}
248 			break;
249 		case ADDRESS:
250 			if (parse_addr(word, &res.addr)) {
251 				match++;
252 				t = &table[i];
253 				if (t->value)
254 					res.action = t->value;
255 			}
256 			break;
257 		case PREFIX:
258 			if (parse_prefix(word, &res.addr, &res.prefixlen)) {
259 				match++;
260 				t = &table[i];
261 				if (t->value)
262 					res.action = t->value;
263 			}
264 			break;
265 		case ASTYPE:
266 			if (word != NULL && strncmp(word, table[i].keyword,
267 			    strlen(word)) == 0) {
268 				match++;
269 				t = &table[i];
270 				res.as.type = t->value;
271 			}
272 			break;
273 		case ASNUM:
274 			if (parse_asnum(word, &res.as.as)) {
275 				match++;
276 				t = &table[i];
277 			}
278 			break;
279 		case ENDTOKEN:
280 			break;
281 		}
282 	}
283 
284 	if (match != 1) {
285 		if (match > 1)
286 			fprintf(stderr, "ambiguous argument: %s\n", word);
287 		if (match < 1)
288 			fprintf(stderr, "unknown argument: %s\n", word);
289 		return (NULL);
290 	}
291 
292 	return (t);
293 }
294 
295 void
296 show_valid_args(const struct token table[])
297 {
298 	int	i;
299 
300 	for (i = 0; table[i].type != ENDTOKEN; i++) {
301 		switch (table[i].type) {
302 		case NOTOKEN:
303 			fprintf(stderr, "  <cr>\n");
304 			break;
305 		case KEYWORD:
306 		case FLAG:
307 		case ASTYPE:
308 			fprintf(stderr, "  %s\n", table[i].keyword);
309 			break;
310 		case ADDRESS:
311 			fprintf(stderr, "  <address>\n");
312 			break;
313 		case PREFIX:
314 			fprintf(stderr, "  <address>[/<len>]\n");
315 			break;
316 		case ASNUM:
317 			fprintf(stderr, "  <asnum>\n");
318 			break;
319 		case ENDTOKEN:
320 			break;
321 		}
322 	}
323 }
324 
325 int
326 parse_addr(const char *word, struct bgpd_addr *addr)
327 {
328 	struct in_addr	ina;
329 
330 	if (word == NULL)
331 		return (0);
332 
333 	bzero(addr, sizeof(struct bgpd_addr));
334 	bzero(&ina, sizeof(ina));
335 
336 	if (inet_pton(AF_INET, word, &ina)) {
337 		addr->af = AF_INET;
338 		addr->v4 = ina;
339 		return (1);
340 	}
341 
342 	return (0);
343 }
344 
345 int
346 parse_prefix(const char *word, struct bgpd_addr *addr, u_int8_t *prefixlen)
347 {
348 	struct in_addr	 ina;
349 	int		 bits = 32;
350 
351 	if (word == NULL)
352 		return (0);
353 
354 	bzero(addr, sizeof(struct bgpd_addr));
355 	bzero(&ina, sizeof(ina));
356 
357 	if (strrchr(word, '/') != NULL) {
358 		if ((bits = inet_net_pton(AF_INET, word,
359 		    &ina, sizeof(ina))) == -1)
360 			return (0);
361 		addr->af = AF_INET;
362 		addr->v4.s_addr = ina.s_addr & htonl(0xffffffff << (32 - bits));
363 		*prefixlen = bits;
364 		return (1);
365 	} else {
366 		*prefixlen = 32;
367 		return (parse_addr(word, addr));
368 	}
369 
370 	return (0);
371 }
372 
373 int
374 parse_asnum(const char *word, u_int16_t *asnum)
375 {
376 	u_long	 ulval;
377 	char	*ep;
378 
379 	if (word == NULL)
380 		return (0);
381 
382 	errno = 0;
383 	ulval = strtoul(word, &ep, 0);
384 	if (word[0] == '\0' || *ep != '\0')
385 		return (0);
386 	if (errno == ERANGE && ulval == ULONG_MAX)
387 		return (0);
388 	if (ulval > USHRT_MAX)
389 		return (0);
390 	*asnum = (u_int16_t)ulval;
391 	return (1);
392 }
393 
394