1 /* $OpenBSD: parser.c,v 1.8 2004/08/20 15:49:35 henning Exp $ */ 2 3 /* 4 * Copyright (c) 2003, 2004 Henning Brauer <henning@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 <err.h> 20 #include <errno.h> 21 #include <limits.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 26 #include "parser.h" 27 28 enum token_type { 29 NOTOKEN, 30 ENDTOKEN, 31 KEYWORD, 32 ADDRESS, 33 FLAG, 34 ASNUM, 35 ASTYPE, 36 PREFIX 37 }; 38 39 struct token { 40 enum token_type type; 41 const char *keyword; 42 int value; 43 const struct token *next; 44 }; 45 46 static const struct token t_main[]; 47 static const struct token t_show[]; 48 static const struct token t_show_fib[]; 49 static const struct token t_show_rib[]; 50 static const struct token t_show_neighbor[]; 51 static const struct token t_show_neighbor_modifiers[]; 52 static const struct token t_fib[]; 53 static const struct token t_neighbor[]; 54 static const struct token t_neighbor_modifiers[]; 55 static const struct token t_show_as[]; 56 static const struct token t_show_prefix[]; 57 static const struct token t_show_ip[]; 58 static const struct token t_nexthop[]; 59 static const struct token t_prefix[]; 60 61 static const struct token t_main[] = { 62 { KEYWORD, "reload", RELOAD, NULL}, 63 { KEYWORD, "show", SHOW, t_show}, 64 { KEYWORD, "fib", FIB, t_fib}, 65 { KEYWORD, "neighbor", NEIGHBOR, t_neighbor}, 66 { KEYWORD, "network", NONE, t_nexthop}, 67 { ENDTOKEN, "", NONE, NULL} 68 }; 69 70 static const struct token t_show[] = { 71 { NOTOKEN, "", NONE, NULL}, 72 { KEYWORD, "fib", SHOW_FIB, t_show_fib}, 73 { KEYWORD, "interfaces", SHOW_INTERFACE, NULL}, 74 { KEYWORD, "neighbor", SHOW_NEIGHBOR, t_show_neighbor}, 75 { KEYWORD, "nexthop", SHOW_NEXTHOP, NULL}, 76 { KEYWORD, "rib", SHOW_RIB, t_show_rib}, 77 { KEYWORD, "ip", NONE, t_show_ip}, 78 { KEYWORD, "summary", SHOW_SUMMARY, NULL}, 79 { ENDTOKEN, "", NONE, NULL} 80 }; 81 82 static const struct token t_show_fib[] = { 83 { NOTOKEN, "", NONE, NULL}, 84 { FLAG, "connected", F_CONNECTED, t_show_fib}, 85 { FLAG, "static", F_STATIC, t_show_fib}, 86 { FLAG, "bgp", F_BGPD_INSERTED, t_show_fib}, 87 { FLAG, "nexthop", F_NEXTHOP, t_show_fib}, 88 { ADDRESS, "", NONE, NULL}, 89 { ENDTOKEN, "", NONE, NULL} 90 }; 91 92 static const struct token t_show_rib[] = { 93 { NOTOKEN, "", NONE, NULL}, 94 { PREFIX, "", NONE, t_show_prefix}, 95 { ASTYPE, "as", AS_ALL, t_show_as}, 96 { ASTYPE, "source-as", AS_SOURCE, t_show_as}, 97 { ASTYPE, "transit-as", AS_TRANSIT, t_show_as}, 98 { ASTYPE, "empty-as", AS_EMPTY, NULL}, 99 { KEYWORD, "summary", SHOW_SUMMARY, NULL}, 100 { ENDTOKEN, "", NONE, NULL} 101 }; 102 103 static const struct token t_show_neighbor[] = { 104 { NOTOKEN, "", NONE, NULL}, 105 { ADDRESS, "", NONE, t_show_neighbor_modifiers}, 106 { ENDTOKEN, "", NONE, NULL} 107 }; 108 109 static const struct token t_show_neighbor_modifiers[] = { 110 { NOTOKEN, "", NONE, NULL}, 111 { KEYWORD, "timers", SHOW_NEIGHBOR_TIMERS, NULL}, 112 { KEYWORD, "messages", SHOW_NEIGHBOR, NULL}, 113 { ENDTOKEN, "", NONE, NULL} 114 }; 115 116 static const struct token t_fib[] = { 117 { KEYWORD, "couple", FIB_COUPLE, NULL}, 118 { KEYWORD, "decouple", FIB_DECOUPLE, NULL}, 119 { ENDTOKEN, "", NONE, NULL} 120 }; 121 122 static const struct token t_neighbor[] = { 123 { ADDRESS, "", NONE, t_neighbor_modifiers}, 124 { ENDTOKEN, "", NONE, NULL} 125 }; 126 127 static const struct token t_neighbor_modifiers[] = { 128 { KEYWORD, "up", NEIGHBOR_UP, NULL}, 129 { KEYWORD, "down", NEIGHBOR_DOWN, NULL}, 130 { KEYWORD, "clear", NEIGHBOR_CLEAR, NULL}, 131 { ENDTOKEN, "", NONE, NULL} 132 }; 133 134 static const struct token t_show_as[] = { 135 { ASNUM, "", NONE, NULL}, 136 { ENDTOKEN, "", NONE, NULL} 137 }; 138 139 static const struct token t_show_prefix[] = { 140 { NOTOKEN, "", NONE, NULL}, 141 { FLAG, "all", F_LONGER, NULL}, 142 { FLAG, "longer-prefixes", F_LONGER, NULL}, 143 { ENDTOKEN, "", NONE, NULL} 144 }; 145 146 static const struct token t_show_ip[] = { 147 { KEYWORD, "bgp", SHOW_RIB, t_show_rib}, 148 { ENDTOKEN, "", NONE, NULL} 149 }; 150 151 static const struct token t_nexthop[] = { 152 { KEYWORD, "add", NETWORK_ADD, t_prefix}, 153 { KEYWORD, "delete", NETWORK_REMOVE, t_prefix}, 154 { KEYWORD, "flush", NETWORK_FLUSH, NULL}, 155 { KEYWORD, "show", NETWORK_SHOW, NULL}, 156 { ENDTOKEN, "", NONE, NULL} 157 }; 158 159 static const struct token t_prefix[] = { 160 { PREFIX, "", NONE, NULL}, 161 { ENDTOKEN, "", NONE, NULL} 162 }; 163 164 static struct parse_result res; 165 166 const struct token *match_token(const char *, const struct token []); 167 void show_valid_args(const struct token []); 168 int parse_addr(const char *, struct bgpd_addr *); 169 int parse_prefix(const char *, struct bgpd_addr *, 170 u_int8_t *); 171 int parse_asnum(const char *, u_int16_t *); 172 173 struct parse_result * 174 parse(int argc, char *argv[]) 175 { 176 int curarg = 1; 177 const struct token *table = t_main; 178 const struct token *match; 179 char *word; 180 181 bzero(&res, sizeof(res)); 182 if (argc == 1) 183 return (&res); 184 185 for (;;) { 186 if (argc > curarg) 187 word = argv[curarg]; 188 else 189 word = NULL; 190 191 if ((match = match_token(word, table)) == NULL) { 192 fprintf(stderr, "valid commands/args:\n"); 193 show_valid_args(table); 194 return (NULL); 195 } 196 197 curarg++; 198 199 if (match->type == NOTOKEN) 200 break; 201 202 if (match->next == NULL) 203 break; 204 205 table = match->next; 206 } 207 208 if (curarg < argc) { 209 fprintf(stderr, "superfluous argument: %s\n", argv[curarg]); 210 return (NULL); 211 } 212 213 return (&res); 214 } 215 216 const struct token * 217 match_token(const char *word, const struct token table[]) 218 { 219 u_int i, match; 220 const struct token *t = NULL; 221 222 match = 0; 223 224 for (i = 0; table[i].type != ENDTOKEN; i++) { 225 switch (table[i].type) { 226 case NOTOKEN: 227 if (word == NULL || strlen(word) == 0) { 228 match++; 229 t = &table[i]; 230 } 231 break; 232 case KEYWORD: 233 if (word != NULL && strncmp(word, table[i].keyword, 234 strlen(word)) == 0) { 235 match++; 236 t = &table[i]; 237 if (t->value) 238 res.action = t->value; 239 } 240 break; 241 case FLAG: 242 if (word != NULL && strncmp(word, table[i].keyword, 243 strlen(word)) == 0) { 244 match++; 245 t = &table[i]; 246 res.flags |= t->value; 247 } 248 break; 249 case ADDRESS: 250 if (parse_addr(word, &res.addr)) { 251 match++; 252 t = &table[i]; 253 if (t->value) 254 res.action = t->value; 255 } 256 break; 257 case PREFIX: 258 if (parse_prefix(word, &res.addr, &res.prefixlen)) { 259 match++; 260 t = &table[i]; 261 if (t->value) 262 res.action = t->value; 263 } 264 break; 265 case ASTYPE: 266 if (word != NULL && strncmp(word, table[i].keyword, 267 strlen(word)) == 0) { 268 match++; 269 t = &table[i]; 270 res.as.type = t->value; 271 } 272 break; 273 case ASNUM: 274 if (parse_asnum(word, &res.as.as)) { 275 match++; 276 t = &table[i]; 277 } 278 break; 279 case ENDTOKEN: 280 break; 281 } 282 } 283 284 if (match != 1) { 285 if (match > 1) 286 fprintf(stderr, "ambiguous argument: %s\n", word); 287 if (match < 1) 288 fprintf(stderr, "unknown argument: %s\n", word); 289 return (NULL); 290 } 291 292 return (t); 293 } 294 295 void 296 show_valid_args(const struct token table[]) 297 { 298 int i; 299 300 for (i = 0; table[i].type != ENDTOKEN; i++) { 301 switch (table[i].type) { 302 case NOTOKEN: 303 fprintf(stderr, " <cr>\n"); 304 break; 305 case KEYWORD: 306 case FLAG: 307 case ASTYPE: 308 fprintf(stderr, " %s\n", table[i].keyword); 309 break; 310 case ADDRESS: 311 fprintf(stderr, " <address>\n"); 312 break; 313 case PREFIX: 314 fprintf(stderr, " <address>[/<len>]\n"); 315 break; 316 case ASNUM: 317 fprintf(stderr, " <asnum>\n"); 318 break; 319 case ENDTOKEN: 320 break; 321 } 322 } 323 } 324 325 int 326 parse_addr(const char *word, struct bgpd_addr *addr) 327 { 328 struct in_addr ina; 329 330 if (word == NULL) 331 return (0); 332 333 bzero(addr, sizeof(struct bgpd_addr)); 334 bzero(&ina, sizeof(ina)); 335 336 if (inet_pton(AF_INET, word, &ina)) { 337 addr->af = AF_INET; 338 addr->v4 = ina; 339 return (1); 340 } 341 342 return (0); 343 } 344 345 int 346 parse_prefix(const char *word, struct bgpd_addr *addr, u_int8_t *prefixlen) 347 { 348 struct in_addr ina; 349 int bits = 32; 350 351 if (word == NULL) 352 return (0); 353 354 bzero(addr, sizeof(struct bgpd_addr)); 355 bzero(&ina, sizeof(ina)); 356 357 if (strrchr(word, '/') != NULL) { 358 if ((bits = inet_net_pton(AF_INET, word, 359 &ina, sizeof(ina))) == -1) 360 return (0); 361 addr->af = AF_INET; 362 addr->v4.s_addr = ina.s_addr & htonl(0xffffffff << (32 - bits)); 363 *prefixlen = bits; 364 return (1); 365 } else { 366 *prefixlen = 32; 367 return (parse_addr(word, addr)); 368 } 369 370 return (0); 371 } 372 373 int 374 parse_asnum(const char *word, u_int16_t *asnum) 375 { 376 u_long ulval; 377 char *ep; 378 379 if (word == NULL) 380 return (0); 381 382 errno = 0; 383 ulval = strtoul(word, &ep, 0); 384 if (word[0] == '\0' || *ep != '\0') 385 return (0); 386 if (errno == ERANGE && ulval == ULONG_MAX) 387 return (0); 388 if (ulval > USHRT_MAX) 389 return (0); 390 *asnum = (u_int16_t)ulval; 391 return (1); 392 } 393 394