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 } 331