1 /* $OpenBSD: parser.c,v 1.4 2007/12/13 08:57:32 claudio 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 }; 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_db[]; 58 static const struct token t_show_area[]; 59 static const struct token t_show_nbr[]; 60 static const struct token t_show_rib[]; 61 static const struct token t_show_fib[]; 62 63 static const struct token t_main[] = { 64 {KEYWORD, "reload", RELOAD, NULL}, 65 {KEYWORD, "fib", FIB, t_fib}, 66 {KEYWORD, "show", SHOW, t_show}, 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, "database", SHOW_DB, t_show_db}, 80 {KEYWORD, "neighbor", SHOW_NBR, t_show_nbr}, 81 {KEYWORD, "rib", SHOW_RIB, t_show_rib}, 82 {KEYWORD, "fib", SHOW_FIB, t_show_fib}, 83 {KEYWORD, "summary", SHOW_SUM, NULL}, 84 {ENDTOKEN, "", NONE, NULL} 85 }; 86 87 static const struct token t_show_iface[] = { 88 {NOTOKEN, "", NONE, NULL}, 89 {KEYWORD, "detail", SHOW_IFACE_DTAIL, NULL}, 90 {IFNAME, "", SHOW_IFACE_DTAIL, NULL}, 91 {ENDTOKEN, "", NONE, NULL} 92 }; 93 94 static const struct token t_show_db[] = { 95 {NOTOKEN, "", NONE, NULL}, 96 {KEYWORD, "area", SHOW_DBBYAREA, t_show_area}, 97 {KEYWORD, "asbr", SHOW_DBASBR, NULL}, 98 {KEYWORD, "external", SHOW_DBEXT, NULL}, 99 {KEYWORD, "network", SHOW_DBNET, NULL}, 100 {KEYWORD, "router", SHOW_DBRTR, NULL}, 101 {KEYWORD, "self-originated", SHOW_DBSELF, NULL}, 102 {KEYWORD, "summary", SHOW_DBSUM, NULL}, 103 {ENDTOKEN, "", NONE, NULL} 104 }; 105 106 static const struct token t_show_area[] = { 107 {ADDRESS, "", NONE, NULL}, 108 {ENDTOKEN, "", NONE, NULL} 109 }; 110 111 static const struct token t_show_nbr[] = { 112 {NOTOKEN, "", NONE, NULL}, 113 {KEYWORD, "detail", SHOW_NBR_DTAIL, NULL}, 114 {ENDTOKEN, "", NONE, NULL} 115 }; 116 117 static const struct token t_show_rib[] = { 118 {NOTOKEN, "", NONE, NULL}, 119 {KEYWORD, "detail", SHOW_RIB_DTAIL, NULL}, 120 {ENDTOKEN, "", NONE, NULL} 121 }; 122 123 static const struct token t_show_fib[] = { 124 {NOTOKEN, "", NONE, NULL}, 125 {FLAG, "connected", F_CONNECTED, t_show_fib}, 126 {FLAG, "static", F_STATIC, t_show_fib}, 127 {FLAG, "ospf", F_OSPFD_INSERTED, t_show_fib}, 128 {ADDRESS, "", NONE, NULL}, 129 {ENDTOKEN, "", NONE, NULL} 130 }; 131 132 static struct parse_result res; 133 134 struct parse_result * 135 parse(int argc, char *argv[]) 136 { 137 const struct token *table = t_main; 138 const struct token *match; 139 140 bzero(&res, sizeof(res)); 141 142 while (argc >= 0) { 143 if ((match = match_token(argv[0], table)) == NULL) { 144 fprintf(stderr, "valid commands/args:\n"); 145 show_valid_args(table); 146 return (NULL); 147 } 148 149 argc--; 150 argv++; 151 152 if (match->type == NOTOKEN || match->next == NULL) 153 break; 154 155 table = match->next; 156 } 157 158 if (argc > 0) { 159 fprintf(stderr, "superfluous argument: %s\n", argv[0]); 160 return (NULL); 161 } 162 163 return (&res); 164 } 165 166 const struct token * 167 match_token(const char *word, const struct token table[]) 168 { 169 u_int i, match; 170 const struct token *t = NULL; 171 172 match = 0; 173 174 for (i = 0; table[i].type != ENDTOKEN; i++) { 175 switch (table[i].type) { 176 case NOTOKEN: 177 if (word == NULL || strlen(word) == 0) { 178 match++; 179 t = &table[i]; 180 } 181 break; 182 case KEYWORD: 183 if (word != NULL && strncmp(word, table[i].keyword, 184 strlen(word)) == 0) { 185 match++; 186 t = &table[i]; 187 if (t->value) 188 res.action = t->value; 189 } 190 break; 191 case FLAG: 192 if (word != NULL && strncmp(word, table[i].keyword, 193 strlen(word)) == 0) { 194 match++; 195 t = &table[i]; 196 res.flags |= t->value; 197 } 198 break; 199 case ADDRESS: 200 if (parse_addr(word, &res.addr)) { 201 match++; 202 t = &table[i]; 203 if (t->value) 204 res.action = t->value; 205 } 206 break; 207 case PREFIX: 208 if (parse_prefix(word, &res.addr, &res.prefixlen)) { 209 match++; 210 t = &table[i]; 211 if (t->value) 212 res.action = t->value; 213 } 214 break; 215 case IFNAME: 216 if (!match && word != NULL && strlen(word) > 0) { 217 if (strlcpy(res.ifname, word, 218 sizeof(res.ifname)) >= 219 sizeof(res.ifname)) 220 err(1, "interface name too long"); 221 match++; 222 t = &table[i]; 223 if (t->value) 224 res.action = t->value; 225 } 226 break; 227 228 case ENDTOKEN: 229 break; 230 } 231 } 232 233 if (match != 1) { 234 if (word == NULL) 235 fprintf(stderr, "missing argument:\n"); 236 else if (match > 1) 237 fprintf(stderr, "ambiguous argument: %s\n", word); 238 else if (match < 1) 239 fprintf(stderr, "unknown argument: %s\n", word); 240 return (NULL); 241 } 242 243 return (t); 244 } 245 246 void 247 show_valid_args(const struct token table[]) 248 { 249 int i; 250 251 for (i = 0; table[i].type != ENDTOKEN; i++) { 252 switch (table[i].type) { 253 case NOTOKEN: 254 fprintf(stderr, " <cr>\n"); 255 break; 256 case KEYWORD: 257 case FLAG: 258 fprintf(stderr, " %s\n", table[i].keyword); 259 break; 260 case ADDRESS: 261 fprintf(stderr, " <address>\n"); 262 break; 263 case PREFIX: 264 fprintf(stderr, " <address>[/<len>]\n"); 265 break; 266 case IFNAME: 267 fprintf(stderr, " <interface>\n"); 268 break; 269 case ENDTOKEN: 270 break; 271 } 272 } 273 } 274 275 /* XXX shared with parse.y should be merged */ 276 int 277 parse_addr(const char *word, struct in6_addr *addr) 278 { 279 struct addrinfo hints, *r; 280 281 if (word == NULL) 282 return (0); 283 284 bzero(addr, sizeof(struct in6_addr)); 285 bzero(&hints, sizeof(hints)); 286 hints.ai_family = AF_INET6; 287 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 288 hints.ai_flags = AI_NUMERICHOST; 289 if (getaddrinfo(word, "0", &hints, &r) == 0) { 290 *addr = ((struct sockaddr_in6 *)r->ai_addr)->sin6_addr; 291 /* XXX address scope !!! */ 292 /* ((struct sockaddr_in6 *)r->ai_addr)->sin6_scope_id */ 293 freeaddrinfo(r); 294 return (1); 295 } 296 return (0); 297 } 298 299 /* XXX shared with parse.y should be merged */ 300 int 301 parse_prefix(const char *word, struct in6_addr *addr, u_int8_t *prefixlen) 302 { 303 char *p, *ps; 304 const char *errstr; 305 int mask; 306 307 if (word == NULL) 308 return (0); 309 310 if ((p = strrchr(word, '/')) != NULL) { 311 mask = strtonum(p + 1, 0, 128, &errstr); 312 if (errstr) 313 errx(1, "invalid netmask: %s", errstr); 314 315 if ((ps = malloc(strlen(word) - strlen(p) + 1)) == NULL) 316 err(1, "parse_prefix: malloc"); 317 strlcpy(ps, word, strlen(word) - strlen(p) + 1); 318 319 if (parse_addr(ps, addr) == 0) { 320 free(ps); 321 return (0); 322 } 323 324 inet6applymask(addr, addr, mask); 325 *prefixlen = mask; 326 return (1); 327 } 328 *prefixlen = 128; 329 return (parse_addr(word, addr)); 330 } 331 332 /* XXX prototype defined in ospfd.h and shared with the kroute.c version */ 333 u_int8_t 334 mask2prefixlen(struct sockaddr_in6 *sa_in6) 335 { 336 u_int8_t l = 0, i, len; 337 338 /* 339 * sin6_len is the size of the sockaddr so substract the offset of 340 * the possibly truncated sin6_addr struct. 341 */ 342 len = sa_in6->sin6_len - 343 (u_int8_t)(&((struct sockaddr_in6 *)NULL)->sin6_addr); 344 for (i = 0; i < len; i++) { 345 /* this "beauty" is adopted from sbin/route/show.c ... */ 346 switch (sa_in6->sin6_addr.s6_addr[i]) { 347 case 0xff: 348 l += 8; 349 break; 350 case 0xfe: 351 l += 7; 352 return (l); 353 case 0xfc: 354 l += 6; 355 return (l); 356 case 0xf8: 357 l += 5; 358 return (l); 359 case 0xf0: 360 l += 4; 361 return (l); 362 case 0xe0: 363 l += 3; 364 return (l); 365 case 0xc0: 366 l += 2; 367 return (l); 368 case 0x80: 369 l += 1; 370 return (l); 371 case 0x00: 372 return (l); 373 default: 374 errx(1, "non continguous inet6 netmask"); 375 } 376 } 377 378 return (l); 379 } 380 381 /* XXX local copy from kroute.c, should go to shared file */ 382 struct in6_addr * 383 prefixlen2mask(u_int8_t prefixlen) 384 { 385 static struct in6_addr mask; 386 int i; 387 388 bzero(&mask, sizeof(mask)); 389 for (i = 0; i < prefixlen / 8; i++) 390 mask.s6_addr[i] = 0xff; 391 i = prefixlen % 8; 392 if (i) 393 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 394 395 return (&mask); 396 } 397 398 /* XXX local copy from kroute.c, should go to shared file */ 399 void 400 inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) 401 { 402 struct in6_addr mask; 403 int i; 404 405 bzero(&mask, sizeof(mask)); 406 for (i = 0; i < prefixlen / 8; i++) 407 mask.s6_addr[i] = 0xff; 408 i = prefixlen % 8; 409 if (i) 410 mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 411 412 for (i = 0; i < 16; i++) 413 dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; 414 } 415