1 /* $OpenBSD: parser.c,v 1.4 2010/09/01 13:59:17 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> 5 * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 6 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/types.h> 22 #include <sys/socket.h> 23 #include <netinet/in.h> 24 #include <arpa/inet.h> 25 #include <err.h> 26 #include <errno.h> 27 #include <limits.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 32 #include "ldpd.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_lib[]; 61 static const struct token t_show_fib[]; 62 static const struct token t_log[]; 63 64 static const struct token t_main[] = { 65 /* {KEYWORD, "reload", RELOAD, NULL}, */ 66 {KEYWORD, "fib", FIB, t_fib}, 67 {KEYWORD, "show", SHOW, t_show}, 68 {KEYWORD, "log", NONE, t_log}, 69 {ENDTOKEN, "", NONE, NULL} 70 }; 71 72 static const struct token t_fib[] = { 73 { KEYWORD, "couple", FIB_COUPLE, NULL}, 74 { KEYWORD, "decouple", FIB_DECOUPLE, NULL}, 75 { ENDTOKEN, "", NONE, NULL} 76 }; 77 78 static const struct token t_show[] = { 79 {NOTOKEN, "", NONE, NULL}, 80 {KEYWORD, "interfaces", SHOW_IFACE, t_show_iface}, 81 {KEYWORD, "neighbor", SHOW_NBR, t_show_nbr}, 82 {KEYWORD, "lib", SHOW_LIB, t_show_lib}, 83 {KEYWORD, "fib", SHOW_FIB, t_show_fib}, 84 {ENDTOKEN, "", NONE, NULL} 85 }; 86 87 static const struct token t_show_iface[] = { 88 {NOTOKEN, "", NONE, NULL}, 89 {ENDTOKEN, "", NONE, NULL} 90 }; 91 92 static const struct token t_show_nbr[] = { 93 {NOTOKEN, "", NONE, NULL}, 94 {ENDTOKEN, "", NONE, NULL} 95 }; 96 97 static const struct token t_show_lib[] = { 98 {NOTOKEN, "", NONE, NULL}, 99 {ENDTOKEN, "", NONE, NULL} 100 }; 101 102 static const struct token t_log[] = { 103 {KEYWORD, "verbose", LOG_VERBOSE, NULL}, 104 {KEYWORD, "brief", LOG_BRIEF, NULL}, 105 {ENDTOKEN, "", NONE, NULL} 106 }; 107 108 static const struct token t_show_fib[] = { 109 {NOTOKEN, "", NONE, NULL}, 110 {KEYWORD, "interface", SHOW_FIB_IFACE, t_show_iface}, 111 {FLAG, "connected", F_CONNECTED, t_show_fib}, 112 {FLAG, "static", F_STATIC, t_show_fib}, 113 {ADDRESS, "", NONE, NULL}, 114 {ENDTOKEN, "", NONE, NULL} 115 }; 116 117 static struct parse_result res; 118 119 struct parse_result * 120 parse(int argc, char *argv[]) 121 { 122 const struct token *table = t_main; 123 const struct token *match; 124 125 bzero(&res, sizeof(res)); 126 127 while (argc >= 0) { 128 if ((match = match_token(argv[0], table)) == NULL) { 129 fprintf(stderr, "valid commands/args:\n"); 130 show_valid_args(table); 131 return (NULL); 132 } 133 134 argc--; 135 argv++; 136 137 if (match->type == NOTOKEN || match->next == NULL) 138 break; 139 140 table = match->next; 141 } 142 143 if (argc > 0) { 144 fprintf(stderr, "superfluous argument: %s\n", argv[0]); 145 return (NULL); 146 } 147 148 return (&res); 149 } 150 151 const struct token * 152 match_token(const char *word, const struct token *table) 153 { 154 u_int i, match; 155 const struct token *t = NULL; 156 157 match = 0; 158 159 for (i = 0; table[i].type != ENDTOKEN; i++) { 160 switch (table[i].type) { 161 case NOTOKEN: 162 if (word == NULL || strlen(word) == 0) { 163 match++; 164 t = &table[i]; 165 } 166 break; 167 case KEYWORD: 168 if (word != NULL && strncmp(word, table[i].keyword, 169 strlen(word)) == 0) { 170 match++; 171 t = &table[i]; 172 if (t->value) 173 res.action = t->value; 174 } 175 break; 176 case FLAG: 177 if (word != NULL && strncmp(word, table[i].keyword, 178 strlen(word)) == 0) { 179 match++; 180 t = &table[i]; 181 res.flags |= t->value; 182 } 183 break; 184 case ADDRESS: 185 if (parse_addr(word, &res.addr)) { 186 match++; 187 t = &table[i]; 188 if (t->value) 189 res.action = t->value; 190 } 191 break; 192 case PREFIX: 193 if (parse_prefix(word, &res.addr, &res.prefixlen)) { 194 match++; 195 t = &table[i]; 196 if (t->value) 197 res.action = t->value; 198 } 199 break; 200 case IFNAME: 201 if (!match && word != NULL && strlen(word) > 0) { 202 if (strlcpy(res.ifname, word, 203 sizeof(res.ifname)) >= 204 sizeof(res.ifname)) 205 err(1, "interface name too long"); 206 match++; 207 t = &table[i]; 208 if (t->value) 209 res.action = t->value; 210 } 211 break; 212 213 case ENDTOKEN: 214 break; 215 } 216 } 217 218 if (match != 1) { 219 if (word == NULL) 220 fprintf(stderr, "missing argument:\n"); 221 else if (match > 1) 222 fprintf(stderr, "ambiguous argument: %s\n", word); 223 else if (match < 1) 224 fprintf(stderr, "unknown argument: %s\n", word); 225 return (NULL); 226 } 227 228 return (t); 229 } 230 231 void 232 show_valid_args(const struct token *table) 233 { 234 int i; 235 236 for (i = 0; table[i].type != ENDTOKEN; i++) { 237 switch (table[i].type) { 238 case NOTOKEN: 239 fprintf(stderr, " <cr>\n"); 240 break; 241 case KEYWORD: 242 case FLAG: 243 fprintf(stderr, " %s\n", table[i].keyword); 244 break; 245 case ADDRESS: 246 fprintf(stderr, " <address>\n"); 247 break; 248 case PREFIX: 249 fprintf(stderr, " <address>[/<len>]\n"); 250 break; 251 case IFNAME: 252 fprintf(stderr, " <interface>\n"); 253 case ENDTOKEN: 254 break; 255 } 256 } 257 } 258 259 int 260 parse_addr(const char *word, struct in_addr *addr) 261 { 262 struct in_addr ina; 263 264 if (word == NULL) 265 return (0); 266 267 bzero(addr, sizeof(struct in_addr)); 268 bzero(&ina, sizeof(ina)); 269 270 if (inet_pton(AF_INET, word, &ina)) { 271 addr->s_addr = ina.s_addr; 272 return (1); 273 } 274 275 return (0); 276 } 277 278 int 279 parse_prefix(const char *word, struct in_addr *addr, u_int8_t *prefixlen) 280 { 281 struct in_addr ina; 282 int bits = 32; 283 284 if (word == NULL) 285 return (0); 286 287 bzero(addr, sizeof(struct in_addr)); 288 bzero(&ina, sizeof(ina)); 289 290 if (strrchr(word, '/') != NULL) { 291 if ((bits = inet_net_pton(AF_INET, word, 292 &ina, sizeof(ina))) == -1) 293 return (0); 294 addr->s_addr = ina.s_addr & htonl(prefixlen2mask(bits)); 295 *prefixlen = bits; 296 return (1); 297 } else { 298 *prefixlen = 32; 299 return (parse_addr(word, addr)); 300 } 301 302 return (0); 303 } 304 305 /* XXX local copy from kroute.c, should go to shared file */ 306 in_addr_t 307 prefixlen2mask(u_int8_t prefixlen) 308 { 309 if (prefixlen == 0) 310 return (0); 311 312 return (0xffffffff << (32 - prefixlen)); 313 } 314