1 /* $OpenBSD: parser.c,v 1.7 2017/07/28 13:02:35 florian Exp $ */
2
3 /*
4 * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
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
32 #include "ripd.h"
33
34 #include "parser.h"
35
36 enum token_type {
37 NOTOKEN,
38 ENDTOKEN,
39 KEYWORD,
40 ADDRESS,
41 FLAG,
42 PREFIX,
43 IFNAME
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_nbr[];
58 static const struct token t_show_rib[];
59 static const struct token t_show_fib[];
60 static const struct token t_log[];
61
62 static const struct token t_main[] = {
63 /* {KEYWORD, "reload", RELOAD, NULL}, */
64 {KEYWORD, "fib", FIB, t_fib},
65 {KEYWORD, "show", SHOW, t_show},
66 {KEYWORD, "log", NONE, t_log},
67 {ENDTOKEN, "", NONE, NULL}
68 };
69
70 static const struct token t_fib[] = {
71 { KEYWORD, "couple", FIB_COUPLE, NULL},
72 { KEYWORD, "decouple", FIB_DECOUPLE, NULL},
73 { ENDTOKEN, "", NONE, NULL}
74 };
75
76 static const struct token t_show[] = {
77 {NOTOKEN, "", NONE, NULL},
78 {KEYWORD, "interfaces", SHOW_IFACE, t_show_iface},
79 {KEYWORD, "neighbor", SHOW_NBR, t_show_nbr},
80 {KEYWORD, "rib", SHOW_RIB, t_show_rib},
81 {KEYWORD, "fib", SHOW_FIB, t_show_fib},
82 {ENDTOKEN, "", NONE, NULL}
83 };
84
85 static const struct token t_show_iface[] = {
86 {NOTOKEN, "", NONE, NULL},
87 {ENDTOKEN, "", NONE, NULL}
88 };
89
90 static const struct token t_show_nbr[] = {
91 {NOTOKEN, "", NONE, NULL},
92 {ENDTOKEN, "", NONE, NULL}
93 };
94
95 static const struct token t_show_rib[] = {
96 {NOTOKEN, "", NONE, NULL},
97 {ENDTOKEN, "", NONE, NULL}
98 };
99
100 static const struct token t_show_fib[] = {
101 {NOTOKEN, "", NONE, NULL},
102 {KEYWORD, "interface", SHOW_FIB_IFACE, t_show_iface},
103 {FLAG, "connected", F_CONNECTED, t_show_fib},
104 {FLAG, "static", F_STATIC, t_show_fib},
105 {FLAG, "rip", F_RIPD_INSERTED, t_show_fib},
106 {ADDRESS, "", NONE, NULL},
107 {ENDTOKEN, "", NONE, NULL}
108 };
109
110 static const struct token t_log[] = {
111 {KEYWORD, "verbose", LOG_VERBOSE, NULL},
112 {KEYWORD, "brief", LOG_BRIEF, NULL},
113 {ENDTOKEN, "", NONE, NULL}
114 };
115
116 static const struct token *match_token(const char *, const struct token *,
117 struct parse_result *);
118 static void show_valid_args(const struct token *table);
119
120 struct parse_result *
parse(int argc,char * argv[])121 parse(int argc, char *argv[])
122 {
123 static struct parse_result res;
124 const struct token *table = t_main;
125 const struct token *match;
126
127 bzero(&res, sizeof(res));
128
129 while (argc >= 0) {
130 if ((match = match_token(argv[0], table, &res)) == NULL) {
131 fprintf(stderr, "valid commands/args:\n");
132 show_valid_args(table);
133 return (NULL);
134 }
135
136 argc--;
137 argv++;
138
139 if (match->type == NOTOKEN || match->next == NULL)
140 break;
141
142 table = match->next;
143 }
144
145 if (argc > 0) {
146 fprintf(stderr, "superfluous argument: %s\n", argv[0]);
147 return (NULL);
148 }
149
150 return (&res);
151 }
152
153 static const struct token *
match_token(const char * word,const struct token * table,struct parse_result * res)154 match_token(const char *word, const struct token *table,
155 struct parse_result *res)
156 {
157 u_int i, match;
158 const struct token *t = NULL;
159
160 match = 0;
161
162 for (i = 0; table[i].type != ENDTOKEN; i++) {
163 switch (table[i].type) {
164 case NOTOKEN:
165 if (word == NULL || strlen(word) == 0) {
166 match++;
167 t = &table[i];
168 }
169 break;
170 case KEYWORD:
171 if (word != NULL && strncmp(word, table[i].keyword,
172 strlen(word)) == 0) {
173 match++;
174 t = &table[i];
175 if (t->value)
176 res->action = t->value;
177 }
178 break;
179 case FLAG:
180 if (word != NULL && strncmp(word, table[i].keyword,
181 strlen(word)) == 0) {
182 match++;
183 t = &table[i];
184 res->flags |= t->value;
185 }
186 break;
187 case ADDRESS:
188 if (parse_addr(word, &res->addr)) {
189 match++;
190 t = &table[i];
191 if (t->value)
192 res->action = t->value;
193 }
194 break;
195 case PREFIX:
196 if (parse_prefix(word, &res->addr, &res->prefixlen)) {
197 match++;
198 t = &table[i];
199 if (t->value)
200 res->action = t->value;
201 }
202 break;
203 case IFNAME:
204 if (!match && word != NULL && strlen(word) > 0) {
205 if (strlcpy(res->ifname, word,
206 sizeof(res->ifname)) >=
207 sizeof(res->ifname))
208 err(1, "interface name too long");
209 match++;
210 t = &table[i];
211 if (t->value)
212 res->action = t->value;
213 }
214 break;
215
216 case ENDTOKEN:
217 break;
218 }
219 }
220
221 if (match != 1) {
222 if (word == NULL)
223 fprintf(stderr, "missing argument:\n");
224 else if (match > 1)
225 fprintf(stderr, "ambiguous argument: %s\n", word);
226 else if (match < 1)
227 fprintf(stderr, "unknown argument: %s\n", word);
228 return (NULL);
229 }
230
231 return (t);
232 }
233
234 static void
show_valid_args(const struct token * table)235 show_valid_args(const struct token *table)
236 {
237 int i;
238
239 for (i = 0; table[i].type != ENDTOKEN; i++) {
240 switch (table[i].type) {
241 case NOTOKEN:
242 fprintf(stderr, " <cr>\n");
243 break;
244 case KEYWORD:
245 case FLAG:
246 fprintf(stderr, " %s\n", table[i].keyword);
247 break;
248 case ADDRESS:
249 fprintf(stderr, " <address>\n");
250 break;
251 case PREFIX:
252 fprintf(stderr, " <address>[/<len>]\n");
253 break;
254 case IFNAME:
255 fprintf(stderr, " <interface>\n");
256 case ENDTOKEN:
257 break;
258 }
259 }
260 }
261
262 int
parse_addr(const char * word,struct in_addr * addr)263 parse_addr(const char *word, struct in_addr *addr)
264 {
265 struct in_addr ina;
266
267 if (word == NULL)
268 return (0);
269
270 bzero(addr, sizeof(struct in_addr));
271 bzero(&ina, sizeof(ina));
272
273 if (inet_pton(AF_INET, word, &ina)) {
274 addr->s_addr = ina.s_addr;
275 return (1);
276 }
277
278 return (0);
279 }
280
281 int
parse_prefix(const char * word,struct in_addr * addr,u_int8_t * prefixlen)282 parse_prefix(const char *word, struct in_addr *addr, u_int8_t *prefixlen)
283 {
284 struct in_addr ina;
285 int bits = 32;
286
287 if (word == NULL)
288 return (0);
289
290 bzero(addr, sizeof(struct in_addr));
291 bzero(&ina, sizeof(ina));
292
293 if (strrchr(word, '/') != NULL) {
294 if ((bits = inet_net_pton(AF_INET, word,
295 &ina, sizeof(ina))) == -1)
296 return (0);
297 addr->s_addr = ina.s_addr & htonl(prefixlen2mask(bits));
298 *prefixlen = bits;
299 return (1);
300 } else {
301 *prefixlen = 32;
302 return (parse_addr(word, addr));
303 }
304
305 return (0);
306 }
307
308 /* XXX local copy from kroute.c, should go to shared file */
309 in_addr_t
prefixlen2mask(u_int8_t prefixlen)310 prefixlen2mask(u_int8_t prefixlen)
311 {
312 if (prefixlen == 0)
313 return (0);
314
315 return (0xffffffff << (32 - prefixlen));
316 }
317