xref: /openbsd-src/usr.sbin/ldpctl/parser.c (revision 3f117ed9c0051c7b2c5c6989afcb51d187e407f8)
1 /*	$OpenBSD: parser.c,v 1.12 2016/05/23 19:06:03 renato Exp $ */
2 
3 /*
4  * Copyright (c) 2009 Michele Marchetto <michele@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 "ldpd.h"
34 
35 #include "parser.h"
36 
37 enum token_type {
38 	NOTOKEN,
39 	ENDTOKEN,
40 	KEYWORD,
41 	FAMILY,
42 	ADDRESS,
43 	FLAG,
44 	IFNAME
45 };
46 
47 struct token {
48 	enum token_type		 type;
49 	const char		*keyword;
50 	int			 value;
51 	const struct token	*next;
52 };
53 
54 static const struct token t_main[];
55 static const struct token t_fib[];
56 static const struct token t_show[];
57 static const struct token t_show_iface[];
58 static const struct token t_show_iface_af[];
59 static const struct token t_show_disc[];
60 static const struct token t_show_disc_af[];
61 static const struct token t_show_nbr[];
62 static const struct token t_show_nbr_af[];
63 static const struct token t_show_lib[];
64 static const struct token t_show_lib_af[];
65 static const struct token t_show_fib[];
66 static const struct token t_show_fib_af[];
67 static const struct token t_show_l2vpn[];
68 static const struct token t_clear[];
69 static const struct token t_clear_nbr[];
70 static const struct token t_log[];
71 
72 static const struct token t_main[] = {
73 	{KEYWORD,	"reload",	RELOAD,		NULL},
74 	{KEYWORD,	"fib",		FIB,		t_fib},
75 	{KEYWORD,	"show",		SHOW,		t_show},
76 	{KEYWORD,	"clear",	CLEAR_NBR,	t_clear},
77 	{KEYWORD,	"log",		NONE,		t_log},
78 	{ENDTOKEN,	"",		NONE,		NULL}
79 };
80 
81 static const struct token t_fib[] = {
82 	{ KEYWORD,	"couple",	FIB_COUPLE,	NULL},
83 	{ KEYWORD,	"decouple",	FIB_DECOUPLE,	NULL},
84 	{ ENDTOKEN,	"",		NONE,		NULL}
85 };
86 
87 static const struct token t_show[] = {
88 	{NOTOKEN,	"",		NONE,		NULL},
89 	{KEYWORD,	"interfaces",	SHOW_IFACE,	t_show_iface},
90 	{KEYWORD,	"discovery",	SHOW_DISC,	t_show_disc},
91 	{KEYWORD,	"neighbor",	SHOW_NBR,	t_show_nbr},
92 	{KEYWORD,	"lib",		SHOW_LIB,	t_show_lib},
93 	{KEYWORD,	"fib",		SHOW_FIB,	t_show_fib},
94 	{KEYWORD,	"l2vpn",	NONE,		t_show_l2vpn},
95 	{ENDTOKEN,	"",		NONE,		NULL}
96 };
97 
98 static const struct token t_show_iface[] = {
99 	{NOTOKEN,	"",		NONE,		NULL},
100 	{KEYWORD,	"family",	NONE,		t_show_iface_af},
101 	{ENDTOKEN,	"",		NONE,		NULL}
102 };
103 
104 static const struct token t_show_iface_af[] = {
105 	{FAMILY,	"",		NONE,		t_show_iface},
106 	{ENDTOKEN,	"",		NONE,		NULL}
107 };
108 
109 static const struct token t_show_disc[] = {
110 	{NOTOKEN,	"",		NONE,		NULL},
111 	{KEYWORD,	"family",	NONE,		t_show_disc_af},
112 	{ENDTOKEN,	"",		NONE,		NULL}
113 };
114 
115 static const struct token t_show_disc_af[] = {
116 	{FAMILY,	"",		NONE,		t_show_disc},
117 	{ENDTOKEN,	"",		NONE,		NULL}
118 };
119 
120 static const struct token t_show_nbr[] = {
121 	{NOTOKEN,	"",		NONE,		NULL},
122 	{KEYWORD,	"family",	NONE,		t_show_nbr_af},
123 	{ENDTOKEN,	"",		NONE,		NULL}
124 };
125 
126 static const struct token t_show_nbr_af[] = {
127 	{FAMILY,	"",		NONE,		t_show_nbr},
128 	{ENDTOKEN,	"",		NONE,		NULL}
129 };
130 
131 static const struct token t_show_lib[] = {
132 	{NOTOKEN,	"",		NONE,		NULL},
133 	{KEYWORD,	"family",	NONE,		t_show_lib_af},
134 	{ENDTOKEN,	"",		NONE,		NULL}
135 };
136 
137 static const struct token t_show_lib_af[] = {
138 	{FAMILY,	"",		NONE,		t_show_lib},
139 	{ENDTOKEN,	"",		NONE,		NULL}
140 };
141 
142 static const struct token t_show_fib[] = {
143 	{NOTOKEN,	"",		NONE,		NULL},
144 	{KEYWORD,	"family",	NONE,		t_show_fib_af},
145 	{KEYWORD,	"interface",	SHOW_FIB_IFACE,	t_show_iface},
146 	{FLAG,		"connected",	F_CONNECTED,	t_show_fib},
147 	{FLAG,		"static",	F_STATIC,	t_show_fib},
148 	{ADDRESS,	"",		NONE,		NULL},
149 	{ENDTOKEN,	"",		NONE,		NULL}
150 };
151 
152 static const struct token t_show_fib_af[] = {
153 	{FAMILY,	"",		NONE,		t_show_fib},
154 	{ENDTOKEN,	"",		NONE,		NULL}
155 };
156 
157 static const struct token t_show_l2vpn[] = {
158 	{KEYWORD,	"bindings",	SHOW_L2VPN_BINDING,	NULL},
159 	{KEYWORD,	"pseudowires",	SHOW_L2VPN_PW,		NULL},
160 	{ENDTOKEN,	"",		NONE,			NULL}
161 };
162 
163 static const struct token t_clear[] = {
164 	{KEYWORD,	"neighbors",	CLEAR_NBR,	t_clear_nbr},
165 	{ENDTOKEN,	"",		NONE,		NULL}
166 };
167 
168 static const struct token t_clear_nbr[] = {
169 	{NOTOKEN,	"",		NONE,		NULL},
170 	{ADDRESS,	"",		NONE,		NULL},
171 	{ENDTOKEN,	"",		NONE,		NULL}
172 };
173 
174 static const struct token t_log[] = {
175 	{KEYWORD,	"verbose",	LOG_VERBOSE,	NULL},
176 	{KEYWORD,	"brief",	LOG_BRIEF,	NULL},
177 	{ENDTOKEN,	"",		NONE,		NULL}
178 };
179 
180 static const struct token *match_token(const char *, const struct token *,
181     struct parse_result *);
182 static void show_valid_args(const struct token *);
183 
184 struct parse_result *
parse(int argc,char * argv[])185 parse(int argc, char *argv[])
186 {
187 	static struct parse_result	res;
188 	const struct token	*table = t_main;
189 	const struct token	*match;
190 
191 	memset(&res, 0, sizeof(res));
192 
193 	while (argc >= 0) {
194 		if ((match = match_token(argv[0], table, &res)) == NULL) {
195 			fprintf(stderr, "valid commands/args:\n");
196 			show_valid_args(table);
197 			return (NULL);
198 		}
199 
200 		argc--;
201 		argv++;
202 
203 		if (match->type == NOTOKEN || match->next == NULL)
204 			break;
205 
206 		table = match->next;
207 	}
208 
209 	if (argc > 0) {
210 		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
211 		return (NULL);
212 	}
213 
214 	return (&res);
215 }
216 
217 static const struct token *
match_token(const char * word,const struct token * table,struct parse_result * res)218 match_token(const char *word, const struct token *table,
219     struct parse_result *res)
220 {
221 	uint			 i, match;
222 	const struct token	*t = NULL;
223 
224 	match = 0;
225 
226 	for (i = 0; table[i].type != ENDTOKEN; i++) {
227 		switch (table[i].type) {
228 		case NOTOKEN:
229 			if (word == NULL || strlen(word) == 0) {
230 				match++;
231 				t = &table[i];
232 			}
233 			break;
234 		case KEYWORD:
235 			if (word != NULL && strncmp(word, table[i].keyword,
236 			    strlen(word)) == 0) {
237 				match++;
238 				t = &table[i];
239 				if (t->value)
240 					res->action = t->value;
241 			}
242 			break;
243 		case FLAG:
244 			if (word != NULL && strncmp(word, table[i].keyword,
245 			    strlen(word)) == 0) {
246 				match++;
247 				t = &table[i];
248 				res->flags |= t->value;
249 			}
250 			break;
251 		case FAMILY:
252 			if (word == NULL)
253 				break;
254 			if (!strcmp(word, "inet") ||
255 			    !strcasecmp(word, "IPv4")) {
256 				match++;
257 				t = &table[i];
258 				res->family = AF_INET;
259 			}
260 			if (!strcmp(word, "inet6") ||
261 			    !strcasecmp(word, "IPv6")) {
262 				match++;
263 				t = &table[i];
264 				res->family = AF_INET6;
265 			}
266 			break;
267 		case ADDRESS:
268 			if (parse_addr(word, &res->family, &res->addr)) {
269 				match++;
270 				t = &table[i];
271 				if (t->value)
272 					res->action = t->value;
273 			}
274 			break;
275 		case IFNAME:
276 			if (!match && word != NULL && strlen(word) > 0) {
277 				if (strlcpy(res->ifname, word,
278 				    sizeof(res->ifname)) >=
279 				    sizeof(res->ifname))
280 					err(1, "interface name too long");
281 				match++;
282 				t = &table[i];
283 				if (t->value)
284 					res->action = t->value;
285 			}
286 			break;
287 
288 		case ENDTOKEN:
289 			break;
290 		}
291 	}
292 
293 	if (match != 1) {
294 		if (word == NULL)
295 			fprintf(stderr, "missing argument:\n");
296 		else if (match > 1)
297 			fprintf(stderr, "ambiguous argument: %s\n", word);
298 		else if (match < 1)
299 			fprintf(stderr, "unknown argument: %s\n", word);
300 		return (NULL);
301 	}
302 
303 	return (t);
304 }
305 
306 static void
show_valid_args(const struct token * table)307 show_valid_args(const struct token *table)
308 {
309 	int	i;
310 
311 	for (i = 0; table[i].type != ENDTOKEN; i++) {
312 		switch (table[i].type) {
313 		case NOTOKEN:
314 			fprintf(stderr, "  <cr>\n");
315 			break;
316 		case KEYWORD:
317 		case FLAG:
318 			fprintf(stderr, "  %s\n", table[i].keyword);
319 			break;
320 		case FAMILY:
321 			fprintf(stderr, "  [ inet | inet6 | IPv4 | IPv6 ]\n");
322 			break;
323 		case ADDRESS:
324 			fprintf(stderr, "  <address>\n");
325 			break;
326 		case IFNAME:
327 			fprintf(stderr, "  <interface>\n");
328 		case ENDTOKEN:
329 			break;
330 		}
331 	}
332 }
333 
334 int
parse_addr(const char * word,int * family,union ldpd_addr * addr)335 parse_addr(const char *word, int *family, union ldpd_addr *addr)
336 {
337 	struct in_addr		 ina;
338 	struct addrinfo		 hints, *r;
339 	struct sockaddr_in6	*sa_in6;
340 
341 	if (word == NULL)
342 		return (0);
343 
344 	memset(addr, 0, sizeof(*addr));
345 	memset(&ina, 0, sizeof(ina));
346 
347 	if (inet_net_pton(AF_INET, word, &ina, sizeof(ina)) != -1) {
348 		*family = AF_INET;
349 		addr->v4.s_addr = ina.s_addr;
350 		return (1);
351 	}
352 
353 	memset(&hints, 0, sizeof(hints));
354 	hints.ai_family = AF_INET6;
355 	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
356 	hints.ai_flags = AI_NUMERICHOST;
357 	if (getaddrinfo(word, "0", &hints, &r) == 0) {
358 		sa_in6 = (struct sockaddr_in6 *)r->ai_addr;
359 		*family = AF_INET6;
360 		addr->v6 = sa_in6->sin6_addr;
361 		freeaddrinfo(r);
362 		return (1);
363 	}
364 
365 	return (0);
366 }
367