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