1 /* $OpenBSD: parser.c,v 1.15 2023/06/21 09:47:03 sthen 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 <netdb.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 32 #include "ospf6d.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 AREA 45 }; 46 47 struct token { 48 enum token_type type; 49 const char *keyword; 50 int value; 51 const struct token *next; 52 }; 53 54 static const struct token t_main[]; 55 static const struct token t_fib[]; 56 static const struct token t_show[]; 57 static const struct token t_show_iface[]; 58 static const struct token t_show_db[]; 59 static const struct token t_show_area[]; 60 static const struct token t_show_nbr[]; 61 static const struct token t_show_rib[]; 62 static const struct token t_show_fib[]; 63 static const struct token t_log[]; 64 65 static const struct token t_main[] = { 66 {KEYWORD, "reload", RELOAD, NULL}, 67 {KEYWORD, "fib", FIB, t_fib}, 68 {KEYWORD, "show", SHOW, t_show}, 69 {KEYWORD, "log", NONE, t_log}, 70 {ENDTOKEN, "", NONE, NULL} 71 }; 72 73 static const struct token t_fib[] = { 74 { KEYWORD, "couple", FIB_COUPLE, NULL}, 75 { KEYWORD, "decouple", FIB_DECOUPLE, NULL}, 76 { KEYWORD, "reload", FIB_RELOAD, NULL}, 77 { ENDTOKEN, "", NONE, NULL} 78 }; 79 80 static const struct token t_show[] = { 81 {NOTOKEN, "", NONE, NULL}, 82 {KEYWORD, "interfaces", SHOW_IFACE, t_show_iface}, 83 {KEYWORD, "database", SHOW_DB, t_show_db}, 84 {KEYWORD, "neighbor", SHOW_NBR, t_show_nbr}, 85 {KEYWORD, "rib", SHOW_RIB, t_show_rib}, 86 {KEYWORD, "fib", SHOW_FIB, t_show_fib}, 87 {KEYWORD, "summary", SHOW_SUM, NULL}, 88 {ENDTOKEN, "", NONE, NULL} 89 }; 90 91 static const struct token t_show_iface[] = { 92 {NOTOKEN, "", NONE, NULL}, 93 {KEYWORD, "detail", SHOW_IFACE_DTAIL, NULL}, 94 {IFNAME, "", SHOW_IFACE_DTAIL, NULL}, 95 {ENDTOKEN, "", NONE, NULL} 96 }; 97 98 static const struct token t_show_db[] = { 99 {NOTOKEN, "", NONE, NULL}, 100 {KEYWORD, "area", SHOW_DBBYAREA, t_show_area}, 101 {KEYWORD, "asbr", SHOW_DBASBR, NULL}, 102 {KEYWORD, "external", SHOW_DBEXT, NULL}, 103 {KEYWORD, "link", SHOW_DBLINK, NULL}, 104 {KEYWORD, "network", SHOW_DBNET, NULL}, 105 {KEYWORD, "router", SHOW_DBRTR, NULL}, 106 {KEYWORD, "intra", SHOW_DBINTRA, NULL}, 107 {KEYWORD, "self-originated", SHOW_DBSELF, NULL}, 108 {KEYWORD, "summary", SHOW_DBSUM, NULL}, 109 {ENDTOKEN, "", NONE, NULL} 110 }; 111 112 static const struct token t_show_area[] = { 113 {AREA, "", NONE, NULL}, 114 {ENDTOKEN, "", NONE, NULL} 115 }; 116 117 static const struct token t_show_nbr[] = { 118 {NOTOKEN, "", NONE, NULL}, 119 {KEYWORD, "detail", SHOW_NBR_DTAIL, NULL}, 120 {ENDTOKEN, "", NONE, NULL} 121 }; 122 123 static const struct token t_show_rib[] = { 124 {NOTOKEN, "", NONE, NULL}, 125 {KEYWORD, "detail", SHOW_RIB_DTAIL, NULL}, 126 {ENDTOKEN, "", NONE, NULL} 127 }; 128 129 static const struct token t_show_fib[] = { 130 {NOTOKEN, "", NONE, NULL}, 131 {FLAG, "connected", F_CONNECTED, t_show_fib}, 132 {FLAG, "static", F_STATIC, t_show_fib}, 133 {FLAG, "ospf", F_OSPFD_INSERTED, t_show_fib}, 134 {ADDRESS, "", NONE, NULL}, 135 {ENDTOKEN, "", NONE, NULL} 136 }; 137 138 static const struct token t_log[] = { 139 {KEYWORD, "verbose", LOG_VERBOSE, NULL}, 140 {KEYWORD, "brief", LOG_BRIEF, NULL}, 141 {ENDTOKEN, "", NONE, NULL} 142 }; 143 144 static const struct token *match_token(const char *, const struct token *, 145 struct parse_result *); 146 static void show_valid_args(const struct token *); 147 148 struct parse_result * 149 parse(int argc, char *argv[]) 150 { 151 static struct parse_result res; 152 const struct token *table = t_main; 153 const struct token *match; 154 155 bzero(&res, sizeof(res)); 156 157 while (argc >= 0) { 158 if ((match = match_token(argv[0], table, &res)) == NULL) { 159 fprintf(stderr, "valid commands/args:\n"); 160 show_valid_args(table); 161 return (NULL); 162 } 163 164 argc--; 165 argv++; 166 167 if (match->type == NOTOKEN || match->next == NULL) 168 break; 169 170 table = match->next; 171 } 172 173 if (argc > 0) { 174 fprintf(stderr, "superfluous argument: %s\n", argv[0]); 175 return (NULL); 176 } 177 178 return (&res); 179 } 180 181 static const struct token * 182 match_token(const char *word, const struct token *table, 183 struct parse_result *res) 184 { 185 u_int i, match; 186 const struct token *t = NULL; 187 188 match = 0; 189 190 for (i = 0; table[i].type != ENDTOKEN; i++) { 191 switch (table[i].type) { 192 case NOTOKEN: 193 if (word == NULL || strlen(word) == 0) { 194 match++; 195 t = &table[i]; 196 } 197 break; 198 case KEYWORD: 199 if (word != NULL && strncmp(word, table[i].keyword, 200 strlen(word)) == 0) { 201 match++; 202 t = &table[i]; 203 if (t->value) 204 res->action = t->value; 205 } 206 break; 207 case FLAG: 208 if (word != NULL && strncmp(word, table[i].keyword, 209 strlen(word)) == 0) { 210 match++; 211 t = &table[i]; 212 res->flags |= t->value; 213 } 214 break; 215 case ADDRESS: 216 if (parse_addr(word, &res->addr)) { 217 match++; 218 t = &table[i]; 219 if (t->value) 220 res->action = t->value; 221 } 222 break; 223 case AREA: 224 if (parse_area(word, &res->area)) { 225 match++; 226 t = &table[i]; 227 if (t->value) 228 res->action = t->value; 229 } 230 break; 231 case PREFIX: 232 if (parse_prefix(word, &res->addr, &res->prefixlen)) { 233 match++; 234 t = &table[i]; 235 if (t->value) 236 res->action = t->value; 237 } 238 break; 239 case IFNAME: 240 if (!match && word != NULL && strlen(word) > 0) { 241 if (strlcpy(res->ifname, word, 242 sizeof(res->ifname)) >= 243 sizeof(res->ifname)) 244 err(1, "interface name too long"); 245 match++; 246 t = &table[i]; 247 if (t->value) 248 res->action = t->value; 249 } 250 break; 251 252 case ENDTOKEN: 253 break; 254 } 255 } 256 257 if (match != 1) { 258 if (word == NULL) 259 fprintf(stderr, "missing argument:\n"); 260 else if (match > 1) 261 fprintf(stderr, "ambiguous argument: %s\n", word); 262 else if (match < 1) 263 fprintf(stderr, "unknown argument: %s\n", word); 264 return (NULL); 265 } 266 267 return (t); 268 } 269 270 static void 271 show_valid_args(const struct token *table) 272 { 273 int i; 274 275 for (i = 0; table[i].type != ENDTOKEN; i++) { 276 switch (table[i].type) { 277 case NOTOKEN: 278 fprintf(stderr, " <cr>\n"); 279 break; 280 case KEYWORD: 281 case FLAG: 282 fprintf(stderr, " %s\n", table[i].keyword); 283 break; 284 case ADDRESS: 285 fprintf(stderr, " <address>\n"); 286 break; 287 case AREA: 288 fprintf(stderr, " <area>\n"); 289 break; 290 case PREFIX: 291 fprintf(stderr, " <address>[/<len>]\n"); 292 break; 293 case IFNAME: 294 fprintf(stderr, " <interface>\n"); 295 break; 296 case ENDTOKEN: 297 break; 298 } 299 } 300 } 301 302 /* XXX shared with parse.y should be merged */ 303 int 304 parse_addr(const char *word, struct in6_addr *addr) 305 { 306 struct addrinfo hints, *r; 307 308 if (word == NULL) 309 return (0); 310 311 bzero(addr, sizeof(struct in6_addr)); 312 bzero(&hints, sizeof(hints)); 313 hints.ai_family = AF_INET6; 314 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 315 hints.ai_flags = AI_NUMERICHOST; 316 if (getaddrinfo(word, "0", &hints, &r) == 0) { 317 *addr = ((struct sockaddr_in6 *)r->ai_addr)->sin6_addr; 318 /* XXX address scope !!! */ 319 /* ((struct sockaddr_in6 *)r->ai_addr)->sin6_scope_id */ 320 freeaddrinfo(r); 321 return (1); 322 } 323 return (0); 324 } 325 326 int 327 parse_area(const char *word, struct in_addr *addr) 328 { 329 struct in_addr ina; 330 const char *errstr; 331 332 if (word == NULL) 333 return (0); 334 335 bzero(addr, sizeof(struct in_addr)); 336 bzero(&ina, sizeof(ina)); 337 338 if (inet_pton(AF_INET, word, &ina)) { 339 addr->s_addr = ina.s_addr; 340 return (1); 341 } 342 343 ina.s_addr = htonl(strtonum(word, 0, 0xffffffff, &errstr)); 344 if (errstr == NULL) { 345 addr->s_addr = ina.s_addr; 346 return (1); 347 } 348 return (0); 349 } 350 351 /* XXX shared with parse.y should be merged */ 352 int 353 parse_prefix(const char *word, struct in6_addr *addr, u_int8_t *prefixlen) 354 { 355 char *p, *ps; 356 const char *errstr; 357 int mask; 358 359 if (word == NULL) 360 return (0); 361 362 if ((p = strrchr(word, '/')) != NULL) { 363 mask = strtonum(p + 1, 0, 128, &errstr); 364 if (errstr) 365 errx(1, "invalid netmask: %s", errstr); 366 367 if ((ps = malloc(strlen(word) - strlen(p) + 1)) == NULL) 368 err(1, "parse_prefix: malloc"); 369 strlcpy(ps, word, strlen(word) - strlen(p) + 1); 370 371 if (parse_addr(ps, addr) == 0) { 372 free(ps); 373 return (0); 374 } 375 free(ps); 376 377 inet6applymask(addr, addr, mask); 378 *prefixlen = mask; 379 return (1); 380 } 381 *prefixlen = 128; 382 return (parse_addr(word, addr)); 383 } 384