1 |
|
|
/* $OpenBSD: parser.c,v 1.41 2017/07/31 16:38:33 gilles Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2013 Eric Faurot <eric@openbsd.org> |
5 |
|
|
* |
6 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
7 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
8 |
|
|
* copyright notice and this permission notice appear in all copies. |
9 |
|
|
* |
10 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 |
|
|
*/ |
18 |
|
|
|
19 |
|
|
#include <sys/types.h> |
20 |
|
|
#include <sys/queue.h> |
21 |
|
|
#include <sys/socket.h> |
22 |
|
|
|
23 |
|
|
#include <netinet/in.h> |
24 |
|
|
#include <net/if.h> |
25 |
|
|
#include <arpa/inet.h> |
26 |
|
|
|
27 |
|
|
#include <err.h> |
28 |
|
|
#include <inttypes.h> |
29 |
|
|
#include <limits.h> |
30 |
|
|
#include <netdb.h> |
31 |
|
|
#include <stdio.h> |
32 |
|
|
#include <stdlib.h> |
33 |
|
|
#include <string.h> |
34 |
|
|
|
35 |
|
|
#include "parser.h" |
36 |
|
|
|
37 |
|
|
uint64_t text_to_evpid(const char *); |
38 |
|
|
uint32_t text_to_msgid(const char *); |
39 |
|
|
|
40 |
|
|
struct node { |
41 |
|
|
int type; |
42 |
|
|
const char *token; |
43 |
|
|
struct node *parent; |
44 |
|
|
TAILQ_ENTRY(node) entry; |
45 |
|
|
TAILQ_HEAD(, node) children; |
46 |
|
|
int (*cmd)(int, struct parameter*); |
47 |
|
|
}; |
48 |
|
|
|
49 |
|
|
static struct node *root; |
50 |
|
|
|
51 |
|
|
static int text_to_sockaddr(struct sockaddr *, int, const char *); |
52 |
|
|
|
53 |
|
|
#define ARGVMAX 64 |
54 |
|
|
|
55 |
|
|
int |
56 |
|
|
cmd_install(const char *pattern, int (*cmd)(int, struct parameter*)) |
57 |
|
|
{ |
58 |
|
|
struct node *node, *tmp; |
59 |
|
|
char *s, *str, *argv[ARGVMAX], **ap; |
60 |
|
|
int i, n; |
61 |
|
|
|
62 |
|
|
/* Tokenize */ |
63 |
|
|
str = s = strdup(pattern); |
64 |
|
|
if (str == NULL) |
65 |
|
|
err(1, "strdup"); |
66 |
|
|
n = 0; |
67 |
|
|
for (ap = argv; n < ARGVMAX && (*ap = strsep(&str, " \t")) != NULL;) { |
68 |
|
|
if (**ap != '\0') { |
69 |
|
|
ap++; |
70 |
|
|
n++; |
71 |
|
|
} |
72 |
|
|
} |
73 |
|
|
*ap = NULL; |
74 |
|
|
|
75 |
|
|
if (root == NULL) { |
76 |
|
|
root = calloc(1, sizeof (*root)); |
77 |
|
|
TAILQ_INIT(&root->children); |
78 |
|
|
} |
79 |
|
|
node = root; |
80 |
|
|
|
81 |
|
|
for (i = 0; i < n; i++) { |
82 |
|
|
TAILQ_FOREACH(tmp, &node->children, entry) { |
83 |
|
|
if (!strcmp(tmp->token, argv[i])) { |
84 |
|
|
node = tmp; |
85 |
|
|
break; |
86 |
|
|
} |
87 |
|
|
} |
88 |
|
|
if (tmp == NULL) { |
89 |
|
|
tmp = calloc(1, sizeof (*tmp)); |
90 |
|
|
TAILQ_INIT(&tmp->children); |
91 |
|
|
if (!strcmp(argv[i], "<str>")) |
92 |
|
|
tmp->type = P_STR; |
93 |
|
|
else if (!strcmp(argv[i], "<int>")) |
94 |
|
|
tmp->type = P_INT; |
95 |
|
|
else if (!strcmp(argv[i], "<msgid>")) |
96 |
|
|
tmp->type = P_MSGID; |
97 |
|
|
else if (!strcmp(argv[i], "<evpid>")) |
98 |
|
|
tmp->type = P_EVPID; |
99 |
|
|
else if (!strcmp(argv[i], "<routeid>")) |
100 |
|
|
tmp->type = P_ROUTEID; |
101 |
|
|
else if (!strcmp(argv[i], "<addr>")) |
102 |
|
|
tmp->type = P_ADDR; |
103 |
|
|
else |
104 |
|
|
tmp->type = P_TOKEN; |
105 |
|
|
tmp->token = strdup(argv[i]); |
106 |
|
|
tmp->parent = node; |
107 |
|
|
TAILQ_INSERT_TAIL(&node->children, tmp, entry); |
108 |
|
|
node = tmp; |
109 |
|
|
} |
110 |
|
|
} |
111 |
|
|
|
112 |
|
|
if (node->cmd) |
113 |
|
|
errx(1, "duplicate pattern: %s", pattern); |
114 |
|
|
node->cmd = cmd; |
115 |
|
|
|
116 |
|
|
free(s); |
117 |
|
|
return (n); |
118 |
|
|
} |
119 |
|
|
|
120 |
|
|
static int |
121 |
|
|
cmd_check(const char *str, struct node *node, struct parameter *res) |
122 |
|
|
{ |
123 |
|
|
const char *e; |
124 |
|
|
|
125 |
|
|
switch (node->type) { |
126 |
|
|
case P_TOKEN: |
127 |
|
|
if (!strcmp(str, node->token)) |
128 |
|
|
return (1); |
129 |
|
|
return (0); |
130 |
|
|
|
131 |
|
|
case P_STR: |
132 |
|
|
res->u.u_str = str; |
133 |
|
|
return (1); |
134 |
|
|
|
135 |
|
|
case P_INT: |
136 |
|
|
res->u.u_int = strtonum(str, INT_MIN, INT_MAX, &e); |
137 |
|
|
if (e) |
138 |
|
|
return (0); |
139 |
|
|
return (1); |
140 |
|
|
|
141 |
|
|
case P_MSGID: |
142 |
|
|
if (strlen(str) != 8) |
143 |
|
|
return (0); |
144 |
|
|
res->u.u_msgid = text_to_msgid(str); |
145 |
|
|
if (res->u.u_msgid == 0) |
146 |
|
|
return (0); |
147 |
|
|
return (1); |
148 |
|
|
|
149 |
|
|
case P_EVPID: |
150 |
|
|
if (strlen(str) != 16) |
151 |
|
|
return (0); |
152 |
|
|
res->u.u_evpid = text_to_evpid(str); |
153 |
|
|
if (res->u.u_evpid == 0) |
154 |
|
|
return (0); |
155 |
|
|
return (1); |
156 |
|
|
|
157 |
|
|
case P_ROUTEID: |
158 |
|
|
res->u.u_routeid = strtonum(str, 1, LLONG_MAX, &e); |
159 |
|
|
if (e) |
160 |
|
|
return (0); |
161 |
|
|
return (1); |
162 |
|
|
|
163 |
|
|
case P_ADDR: |
164 |
|
|
if (text_to_sockaddr((struct sockaddr *)&res->u.u_ss, PF_UNSPEC, str) == 0) |
165 |
|
|
return (1); |
166 |
|
|
return (0); |
167 |
|
|
|
168 |
|
|
default: |
169 |
|
|
errx(1, "bad token type: %d", node->type); |
170 |
|
|
return (0); |
171 |
|
|
} |
172 |
|
|
} |
173 |
|
|
|
174 |
|
|
int |
175 |
|
|
cmd_run(int argc, char **argv) |
176 |
|
|
{ |
177 |
|
|
struct parameter param[ARGVMAX]; |
178 |
|
|
struct node *node, *tmp, *stack[ARGVMAX], *best; |
179 |
|
|
int i, j, np; |
180 |
|
|
|
181 |
|
|
node = root; |
182 |
|
|
np = 0; |
183 |
|
|
|
184 |
|
|
for (i = 0; i < argc; i++) { |
185 |
|
|
TAILQ_FOREACH(tmp, &node->children, entry) { |
186 |
|
|
if (cmd_check(argv[i], tmp, ¶m[np])) { |
187 |
|
|
stack[i] = tmp; |
188 |
|
|
node = tmp; |
189 |
|
|
param[np].type = node->type; |
190 |
|
|
if (node->type != P_TOKEN) |
191 |
|
|
np++; |
192 |
|
|
break; |
193 |
|
|
} |
194 |
|
|
} |
195 |
|
|
if (tmp == NULL) { |
196 |
|
|
best = NULL; |
197 |
|
|
TAILQ_FOREACH(tmp, &node->children, entry) { |
198 |
|
|
if (tmp->type != P_TOKEN) |
199 |
|
|
continue; |
200 |
|
|
if (strstr(tmp->token, argv[i]) != tmp->token) |
201 |
|
|
continue; |
202 |
|
|
if (best) |
203 |
|
|
goto fail; |
204 |
|
|
best = tmp; |
205 |
|
|
} |
206 |
|
|
if (best == NULL) |
207 |
|
|
goto fail; |
208 |
|
|
stack[i] = best; |
209 |
|
|
node = best; |
210 |
|
|
param[np].type = node->type; |
211 |
|
|
if (node->type != P_TOKEN) |
212 |
|
|
np++; |
213 |
|
|
} |
214 |
|
|
} |
215 |
|
|
|
216 |
|
|
if (node->cmd == NULL) |
217 |
|
|
goto fail; |
218 |
|
|
|
219 |
|
|
return (node->cmd(np, np ? param : NULL)); |
220 |
|
|
|
221 |
|
|
fail: |
222 |
|
|
fprintf(stderr, "possibilities are:\n"); |
223 |
|
|
TAILQ_FOREACH(tmp, &node->children, entry) { |
224 |
|
|
for (j = 0; j < i; j++) |
225 |
|
|
fprintf(stderr, "%s%s", j?" ":"", stack[j]->token); |
226 |
|
|
fprintf(stderr, "%s%s\n", i?" ":"", tmp->token); |
227 |
|
|
} |
228 |
|
|
|
229 |
|
|
return (-1); |
230 |
|
|
} |
231 |
|
|
|
232 |
|
|
int |
233 |
|
|
cmd_show_params(int argc, struct parameter *argv) |
234 |
|
|
{ |
235 |
|
|
int i; |
236 |
|
|
|
237 |
|
|
for (i = 0; i < argc; i++) { |
238 |
|
|
switch(argv[i].type) { |
239 |
|
|
case P_STR: |
240 |
|
|
printf(" str:\"%s\"", argv[i].u.u_str); |
241 |
|
|
break; |
242 |
|
|
case P_INT: |
243 |
|
|
printf(" int:%d", argv[i].u.u_int); |
244 |
|
|
break; |
245 |
|
|
case P_MSGID: |
246 |
|
|
printf(" msgid:%08"PRIx32, argv[i].u.u_msgid); |
247 |
|
|
break; |
248 |
|
|
case P_EVPID: |
249 |
|
|
printf(" evpid:%016"PRIx64, argv[i].u.u_evpid); |
250 |
|
|
break; |
251 |
|
|
case P_ROUTEID: |
252 |
|
|
printf(" routeid:%016"PRIx64, argv[i].u.u_routeid); |
253 |
|
|
break; |
254 |
|
|
default: |
255 |
|
|
printf(" ???:%d", argv[i].type); |
256 |
|
|
} |
257 |
|
|
} |
258 |
|
|
printf ("\n"); |
259 |
|
|
return (1); |
260 |
|
|
} |
261 |
|
|
|
262 |
|
|
static int |
263 |
|
|
text_to_sockaddr(struct sockaddr *sa, int family, const char *str) |
264 |
|
|
{ |
265 |
|
|
struct in_addr ina; |
266 |
|
|
struct in6_addr in6a; |
267 |
|
|
struct sockaddr_in *in; |
268 |
|
|
struct sockaddr_in6 *in6; |
269 |
|
|
char *cp, *str2; |
270 |
|
|
const char *errstr; |
271 |
|
|
|
272 |
|
|
switch (family) { |
273 |
|
|
case PF_UNSPEC: |
274 |
|
|
if (text_to_sockaddr(sa, PF_INET, str) == 0) |
275 |
|
|
return (0); |
276 |
|
|
return text_to_sockaddr(sa, PF_INET6, str); |
277 |
|
|
|
278 |
|
|
case PF_INET: |
279 |
|
|
if (inet_pton(PF_INET, str, &ina) != 1) |
280 |
|
|
return (-1); |
281 |
|
|
|
282 |
|
|
in = (struct sockaddr_in *)sa; |
283 |
|
|
memset(in, 0, sizeof *in); |
284 |
|
|
in->sin_len = sizeof(struct sockaddr_in); |
285 |
|
|
in->sin_family = PF_INET; |
286 |
|
|
in->sin_addr.s_addr = ina.s_addr; |
287 |
|
|
return (0); |
288 |
|
|
|
289 |
|
|
case PF_INET6: |
290 |
|
|
cp = strchr(str, SCOPE_DELIMITER); |
291 |
|
|
if (cp) { |
292 |
|
|
str2 = strdup(str); |
293 |
|
|
if (str2 == NULL) |
294 |
|
|
return (-1); |
295 |
|
|
str2[cp - str] = '\0'; |
296 |
|
|
if (inet_pton(PF_INET6, str2, &in6a) != 1) { |
297 |
|
|
free(str2); |
298 |
|
|
return (-1); |
299 |
|
|
} |
300 |
|
|
cp++; |
301 |
|
|
free(str2); |
302 |
|
|
} else if (inet_pton(PF_INET6, str, &in6a) != 1) |
303 |
|
|
return (-1); |
304 |
|
|
|
305 |
|
|
in6 = (struct sockaddr_in6 *)sa; |
306 |
|
|
memset(in6, 0, sizeof *in6); |
307 |
|
|
in6->sin6_len = sizeof(struct sockaddr_in6); |
308 |
|
|
in6->sin6_family = PF_INET6; |
309 |
|
|
in6->sin6_addr = in6a; |
310 |
|
|
|
311 |
|
|
if (cp == NULL) |
312 |
|
|
return (0); |
313 |
|
|
|
314 |
|
|
if (IN6_IS_ADDR_LINKLOCAL(&in6a) || |
315 |
|
|
IN6_IS_ADDR_MC_LINKLOCAL(&in6a) || |
316 |
|
|
IN6_IS_ADDR_MC_INTFACELOCAL(&in6a)) |
317 |
|
|
if ((in6->sin6_scope_id = if_nametoindex(cp))) |
318 |
|
|
return (0); |
319 |
|
|
|
320 |
|
|
in6->sin6_scope_id = strtonum(cp, 0, UINT32_MAX, &errstr); |
321 |
|
|
if (errstr) |
322 |
|
|
return (-1); |
323 |
|
|
return (0); |
324 |
|
|
|
325 |
|
|
default: |
326 |
|
|
break; |
327 |
|
|
} |
328 |
|
|
|
329 |
|
|
return (-1); |
330 |
|
|
} |