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