1 /* $OpenBSD: parser.c,v 1.21 2019/05/16 21:07:33 remi Exp $ */
2
3 /*
4 * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include <err.h>
25 #include <errno.h>
26 #include <limits.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "ospfd.h"
32
33 #include "parser.h"
34
35 enum token_type {
36 NOTOKEN,
37 ENDTOKEN,
38 KEYWORD,
39 ADDRESS,
40 FLAG,
41 PREFIX,
42 IFNAME,
43 AREA
44 };
45
46 struct token {
47 enum token_type type;
48 const char *keyword;
49 int value;
50 const struct token *next;
51 };
52
53 static const struct token t_main[];
54 static const struct token t_fib[];
55 static const struct token t_show[];
56 static const struct token t_show_iface[];
57 static const struct token t_show_db[];
58 static const struct token t_show_area[];
59 static const struct token t_show_nbr[];
60 static const struct token t_show_rib[];
61 static const struct token t_show_fib[];
62 static const struct token t_log[];
63
64 static const struct token t_main[] = {
65 {KEYWORD, "reload", RELOAD, NULL},
66 {KEYWORD, "fib", FIB, t_fib},
67 {KEYWORD, "show", SHOW, t_show},
68 {KEYWORD, "log", NONE, t_log},
69 {ENDTOKEN, "", NONE, NULL}
70 };
71
72 static const struct token t_fib[] = {
73 { KEYWORD, "couple", FIB_COUPLE, NULL},
74 { KEYWORD, "decouple", FIB_DECOUPLE, NULL},
75 { KEYWORD, "reload", FIB_RELOAD, NULL},
76 { ENDTOKEN, "", NONE, NULL}
77 };
78
79 static const struct token t_show[] = {
80 {NOTOKEN, "", NONE, NULL},
81 {KEYWORD, "interfaces", SHOW_IFACE, t_show_iface},
82 {KEYWORD, "database", SHOW_DB, t_show_db},
83 {KEYWORD, "neighbor", SHOW_NBR, t_show_nbr},
84 {KEYWORD, "rib", SHOW_RIB, t_show_rib},
85 {KEYWORD, "fib", SHOW_FIB, t_show_fib},
86 {KEYWORD, "summary", SHOW_SUM, NULL},
87 {ENDTOKEN, "", NONE, NULL}
88 };
89
90 static const struct token t_show_iface[] = {
91 {NOTOKEN, "", NONE, NULL},
92 {KEYWORD, "detail", SHOW_IFACE_DTAIL, NULL},
93 {IFNAME, "", SHOW_IFACE_DTAIL, NULL},
94 {ENDTOKEN, "", NONE, NULL}
95 };
96
97 static const struct token t_show_db[] = {
98 {NOTOKEN, "", NONE, NULL},
99 {KEYWORD, "area", SHOW_DBBYAREA, t_show_area},
100 {KEYWORD, "asbr", SHOW_DBASBR, NULL},
101 {KEYWORD, "external", SHOW_DBEXT, NULL},
102 {KEYWORD, "network", SHOW_DBNET, NULL},
103 {KEYWORD, "router", SHOW_DBRTR, NULL},
104 {KEYWORD, "self-originated", SHOW_DBSELF, NULL},
105 {KEYWORD, "summary", SHOW_DBSUM, NULL},
106 {KEYWORD, "opaque", SHOW_DBOPAQ, NULL},
107 {ENDTOKEN, "", NONE, NULL}
108 };
109
110 static const struct token t_show_area[] = {
111 {AREA, "", NONE, NULL},
112 {ENDTOKEN, "", NONE, NULL}
113 };
114
115 static const struct token t_show_nbr[] = {
116 {NOTOKEN, "", NONE, NULL},
117 {KEYWORD, "detail", SHOW_NBR_DTAIL, NULL},
118 {ENDTOKEN, "", NONE, NULL}
119 };
120
121 static const struct token t_show_rib[] = {
122 {NOTOKEN, "", NONE, NULL},
123 {KEYWORD, "detail", SHOW_RIB_DTAIL, NULL},
124 {ENDTOKEN, "", NONE, NULL}
125 };
126
127 static const struct token t_show_fib[] = {
128 {NOTOKEN, "", NONE, NULL},
129 {KEYWORD, "interface", SHOW_FIB_IFACE, t_show_iface},
130 {FLAG, "connected", F_CONNECTED, t_show_fib},
131 {FLAG, "static", F_STATIC, t_show_fib},
132 {FLAG, "ospf", F_OSPFD_INSERTED, t_show_fib},
133 {ADDRESS, "", NONE, NULL},
134 {ENDTOKEN, "", NONE, NULL}
135 };
136
137 static const struct token t_log[] = {
138 {KEYWORD, "verbose", LOG_VERBOSE, NULL},
139 {KEYWORD, "brief", LOG_BRIEF, NULL},
140 {ENDTOKEN, "", NONE, NULL}
141 };
142
143 static const struct token *match_token(const char *, const struct token *,
144 struct parse_result *);
145 static void show_valid_args(const struct token *);
146
147 struct parse_result *
parse(int argc,char * argv[])148 parse(int argc, char *argv[])
149 {
150 static struct parse_result res;
151 const struct token *table = t_main;
152 const struct token *match;
153
154 bzero(&res, sizeof(res));
155
156 while (argc >= 0) {
157 if ((match = match_token(argv[0], table, &res)) == NULL) {
158 fprintf(stderr, "valid commands/args:\n");
159 show_valid_args(table);
160 return (NULL);
161 }
162
163 argc--;
164 argv++;
165
166 if (match->type == NOTOKEN || match->next == NULL)
167 break;
168
169 table = match->next;
170 }
171
172 if (argc > 0) {
173 fprintf(stderr, "superfluous argument: %s\n", argv[0]);
174 return (NULL);
175 }
176
177 return (&res);
178 }
179
180 static const struct token *
match_token(const char * word,const struct token * table,struct parse_result * res)181 match_token(const char *word, const struct token *table,
182 struct parse_result *res)
183 {
184 u_int i, match;
185 const struct token *t = NULL;
186
187 match = 0;
188
189 for (i = 0; table[i].type != ENDTOKEN; i++) {
190 switch (table[i].type) {
191 case NOTOKEN:
192 if (word == NULL || strlen(word) == 0) {
193 match++;
194 t = &table[i];
195 }
196 break;
197 case KEYWORD:
198 if (word != NULL && strncmp(word, table[i].keyword,
199 strlen(word)) == 0) {
200 match++;
201 t = &table[i];
202 if (t->value)
203 res->action = t->value;
204 }
205 break;
206 case FLAG:
207 if (word != NULL && strncmp(word, table[i].keyword,
208 strlen(word)) == 0) {
209 match++;
210 t = &table[i];
211 res->flags |= t->value;
212 }
213 break;
214 case ADDRESS:
215 if (parse_addr(word, &res->addr)) {
216 match++;
217 t = &table[i];
218 if (t->value)
219 res->action = t->value;
220 }
221 break;
222 case AREA:
223 if (parse_area(word, &res->addr)) {
224 match++;
225 t = &table[i];
226 if (t->value)
227 res->action = t->value;
228 }
229 break;
230 case PREFIX:
231 if (parse_prefix(word, &res->addr, &res->prefixlen)) {
232 match++;
233 t = &table[i];
234 if (t->value)
235 res->action = t->value;
236 }
237 break;
238 case IFNAME:
239 if (!match && word != NULL && strlen(word) > 0) {
240 if (strlcpy(res->ifname, word,
241 sizeof(res->ifname)) >=
242 sizeof(res->ifname))
243 err(1, "interface name too long");
244 match++;
245 t = &table[i];
246 if (t->value)
247 res->action = t->value;
248 }
249 break;
250
251 case ENDTOKEN:
252 break;
253 }
254 }
255
256 if (match != 1) {
257 if (word == NULL)
258 fprintf(stderr, "missing argument:\n");
259 else if (match > 1)
260 fprintf(stderr, "ambiguous argument: %s\n", word);
261 else if (match < 1)
262 fprintf(stderr, "unknown argument: %s\n", word);
263 return (NULL);
264 }
265
266 return (t);
267 }
268
269 static void
show_valid_args(const struct token * table)270 show_valid_args(const struct token *table)
271 {
272 int i;
273
274 for (i = 0; table[i].type != ENDTOKEN; i++) {
275 switch (table[i].type) {
276 case NOTOKEN:
277 fprintf(stderr, " <cr>\n");
278 break;
279 case KEYWORD:
280 case FLAG:
281 fprintf(stderr, " %s\n", table[i].keyword);
282 break;
283 case ADDRESS:
284 fprintf(stderr, " <address>\n");
285 break;
286 case AREA:
287 fprintf(stderr, " <area>\n");
288 break;
289 case PREFIX:
290 fprintf(stderr, " <address>[/<len>]\n");
291 break;
292 case IFNAME:
293 fprintf(stderr, " <interface>\n");
294 break;
295 case ENDTOKEN:
296 break;
297 }
298 }
299 }
300
301 int
parse_addr(const char * word,struct in_addr * addr)302 parse_addr(const char *word, struct in_addr *addr)
303 {
304 struct in_addr ina;
305
306 if (word == NULL)
307 return (0);
308
309 bzero(addr, sizeof(struct in_addr));
310 bzero(&ina, sizeof(ina));
311
312 if (inet_pton(AF_INET, word, &ina)) {
313 addr->s_addr = ina.s_addr;
314 return (1);
315 }
316
317 return (0);
318 }
319
320 int
parse_area(const char * word,struct in_addr * addr)321 parse_area(const char *word, struct in_addr *addr)
322 {
323 struct in_addr ina;
324 const char *errstr;
325
326 if (word == NULL)
327 return (0);
328
329 bzero(addr, sizeof(struct in_addr));
330 bzero(&ina, sizeof(ina));
331
332 if (inet_pton(AF_INET, word, &ina)) {
333 addr->s_addr = ina.s_addr;
334 return (1);
335 }
336
337 ina.s_addr = htonl(strtonum(word, 0, 0xffffffff, &errstr));
338 if (errstr == NULL) {
339 addr->s_addr = ina.s_addr;
340 return (1);
341 }
342
343 return (0);
344 }
345
346 int
parse_prefix(const char * word,struct in_addr * addr,u_int8_t * prefixlen)347 parse_prefix(const char *word, struct in_addr *addr, u_int8_t *prefixlen)
348 {
349 struct in_addr ina;
350 int bits = 32;
351
352 if (word == NULL)
353 return (0);
354
355 bzero(addr, sizeof(struct in_addr));
356 bzero(&ina, sizeof(ina));
357
358 if (strrchr(word, '/') != NULL) {
359 if ((bits = inet_net_pton(AF_INET, word,
360 &ina, sizeof(ina))) == -1)
361 return (0);
362 addr->s_addr = ina.s_addr & htonl(prefixlen2mask(bits));
363 *prefixlen = bits;
364 return (1);
365 }
366 *prefixlen = 32;
367 return (parse_addr(word, addr));
368 }
369
370 /* XXX local copy from kroute.c, should go to shared file */
371 in_addr_t
prefixlen2mask(u_int8_t prefixlen)372 prefixlen2mask(u_int8_t prefixlen)
373 {
374 if (prefixlen == 0)
375 return (0);
376
377 return (0xffffffff << (32 - prefixlen));
378 }
379