1 /* $OpenBSD: parser.c,v 1.12 2016/05/23 19:06:03 renato 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 #include <netdb.h> 32 33 #include "ldpd.h" 34 35 #include "parser.h" 36 37 enum token_type { 38 NOTOKEN, 39 ENDTOKEN, 40 KEYWORD, 41 FAMILY, 42 ADDRESS, 43 FLAG, 44 IFNAME 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_iface_af[]; 59 static const struct token t_show_disc[]; 60 static const struct token t_show_disc_af[]; 61 static const struct token t_show_nbr[]; 62 static const struct token t_show_nbr_af[]; 63 static const struct token t_show_lib[]; 64 static const struct token t_show_lib_af[]; 65 static const struct token t_show_fib[]; 66 static const struct token t_show_fib_af[]; 67 static const struct token t_show_l2vpn[]; 68 static const struct token t_clear[]; 69 static const struct token t_clear_nbr[]; 70 static const struct token t_log[]; 71 72 static const struct token t_main[] = { 73 {KEYWORD, "reload", RELOAD, NULL}, 74 {KEYWORD, "fib", FIB, t_fib}, 75 {KEYWORD, "show", SHOW, t_show}, 76 {KEYWORD, "clear", CLEAR_NBR, t_clear}, 77 {KEYWORD, "log", NONE, t_log}, 78 {ENDTOKEN, "", NONE, NULL} 79 }; 80 81 static const struct token t_fib[] = { 82 { KEYWORD, "couple", FIB_COUPLE, NULL}, 83 { KEYWORD, "decouple", FIB_DECOUPLE, NULL}, 84 { ENDTOKEN, "", NONE, NULL} 85 }; 86 87 static const struct token t_show[] = { 88 {NOTOKEN, "", NONE, NULL}, 89 {KEYWORD, "interfaces", SHOW_IFACE, t_show_iface}, 90 {KEYWORD, "discovery", SHOW_DISC, t_show_disc}, 91 {KEYWORD, "neighbor", SHOW_NBR, t_show_nbr}, 92 {KEYWORD, "lib", SHOW_LIB, t_show_lib}, 93 {KEYWORD, "fib", SHOW_FIB, t_show_fib}, 94 {KEYWORD, "l2vpn", NONE, t_show_l2vpn}, 95 {ENDTOKEN, "", NONE, NULL} 96 }; 97 98 static const struct token t_show_iface[] = { 99 {NOTOKEN, "", NONE, NULL}, 100 {KEYWORD, "family", NONE, t_show_iface_af}, 101 {ENDTOKEN, "", NONE, NULL} 102 }; 103 104 static const struct token t_show_iface_af[] = { 105 {FAMILY, "", NONE, t_show_iface}, 106 {ENDTOKEN, "", NONE, NULL} 107 }; 108 109 static const struct token t_show_disc[] = { 110 {NOTOKEN, "", NONE, NULL}, 111 {KEYWORD, "family", NONE, t_show_disc_af}, 112 {ENDTOKEN, "", NONE, NULL} 113 }; 114 115 static const struct token t_show_disc_af[] = { 116 {FAMILY, "", NONE, t_show_disc}, 117 {ENDTOKEN, "", NONE, NULL} 118 }; 119 120 static const struct token t_show_nbr[] = { 121 {NOTOKEN, "", NONE, NULL}, 122 {KEYWORD, "family", NONE, t_show_nbr_af}, 123 {ENDTOKEN, "", NONE, NULL} 124 }; 125 126 static const struct token t_show_nbr_af[] = { 127 {FAMILY, "", NONE, t_show_nbr}, 128 {ENDTOKEN, "", NONE, NULL} 129 }; 130 131 static const struct token t_show_lib[] = { 132 {NOTOKEN, "", NONE, NULL}, 133 {KEYWORD, "family", NONE, t_show_lib_af}, 134 {ENDTOKEN, "", NONE, NULL} 135 }; 136 137 static const struct token t_show_lib_af[] = { 138 {FAMILY, "", NONE, t_show_lib}, 139 {ENDTOKEN, "", NONE, NULL} 140 }; 141 142 static const struct token t_show_fib[] = { 143 {NOTOKEN, "", NONE, NULL}, 144 {KEYWORD, "family", NONE, t_show_fib_af}, 145 {KEYWORD, "interface", SHOW_FIB_IFACE, t_show_iface}, 146 {FLAG, "connected", F_CONNECTED, t_show_fib}, 147 {FLAG, "static", F_STATIC, t_show_fib}, 148 {ADDRESS, "", NONE, NULL}, 149 {ENDTOKEN, "", NONE, NULL} 150 }; 151 152 static const struct token t_show_fib_af[] = { 153 {FAMILY, "", NONE, t_show_fib}, 154 {ENDTOKEN, "", NONE, NULL} 155 }; 156 157 static const struct token t_show_l2vpn[] = { 158 {KEYWORD, "bindings", SHOW_L2VPN_BINDING, NULL}, 159 {KEYWORD, "pseudowires", SHOW_L2VPN_PW, NULL}, 160 {ENDTOKEN, "", NONE, NULL} 161 }; 162 163 static const struct token t_clear[] = { 164 {KEYWORD, "neighbors", CLEAR_NBR, t_clear_nbr}, 165 {ENDTOKEN, "", NONE, NULL} 166 }; 167 168 static const struct token t_clear_nbr[] = { 169 {NOTOKEN, "", NONE, NULL}, 170 {ADDRESS, "", NONE, NULL}, 171 {ENDTOKEN, "", NONE, NULL} 172 }; 173 174 static const struct token t_log[] = { 175 {KEYWORD, "verbose", LOG_VERBOSE, NULL}, 176 {KEYWORD, "brief", LOG_BRIEF, NULL}, 177 {ENDTOKEN, "", NONE, NULL} 178 }; 179 180 static const struct token *match_token(const char *, const struct token *, 181 struct parse_result *); 182 static void show_valid_args(const struct token *); 183 184 struct parse_result * 185 parse(int argc, char *argv[]) 186 { 187 static struct parse_result res; 188 const struct token *table = t_main; 189 const struct token *match; 190 191 memset(&res, 0, sizeof(res)); 192 193 while (argc >= 0) { 194 if ((match = match_token(argv[0], table, &res)) == NULL) { 195 fprintf(stderr, "valid commands/args:\n"); 196 show_valid_args(table); 197 return (NULL); 198 } 199 200 argc--; 201 argv++; 202 203 if (match->type == NOTOKEN || match->next == NULL) 204 break; 205 206 table = match->next; 207 } 208 209 if (argc > 0) { 210 fprintf(stderr, "superfluous argument: %s\n", argv[0]); 211 return (NULL); 212 } 213 214 return (&res); 215 } 216 217 static const struct token * 218 match_token(const char *word, const struct token *table, 219 struct parse_result *res) 220 { 221 uint i, match; 222 const struct token *t = NULL; 223 224 match = 0; 225 226 for (i = 0; table[i].type != ENDTOKEN; i++) { 227 switch (table[i].type) { 228 case NOTOKEN: 229 if (word == NULL || strlen(word) == 0) { 230 match++; 231 t = &table[i]; 232 } 233 break; 234 case KEYWORD: 235 if (word != NULL && strncmp(word, table[i].keyword, 236 strlen(word)) == 0) { 237 match++; 238 t = &table[i]; 239 if (t->value) 240 res->action = t->value; 241 } 242 break; 243 case FLAG: 244 if (word != NULL && strncmp(word, table[i].keyword, 245 strlen(word)) == 0) { 246 match++; 247 t = &table[i]; 248 res->flags |= t->value; 249 } 250 break; 251 case FAMILY: 252 if (word == NULL) 253 break; 254 if (!strcmp(word, "inet") || 255 !strcasecmp(word, "IPv4")) { 256 match++; 257 t = &table[i]; 258 res->family = AF_INET; 259 } 260 if (!strcmp(word, "inet6") || 261 !strcasecmp(word, "IPv6")) { 262 match++; 263 t = &table[i]; 264 res->family = AF_INET6; 265 } 266 break; 267 case ADDRESS: 268 if (parse_addr(word, &res->family, &res->addr)) { 269 match++; 270 t = &table[i]; 271 if (t->value) 272 res->action = t->value; 273 } 274 break; 275 case IFNAME: 276 if (!match && word != NULL && strlen(word) > 0) { 277 if (strlcpy(res->ifname, word, 278 sizeof(res->ifname)) >= 279 sizeof(res->ifname)) 280 err(1, "interface name too long"); 281 match++; 282 t = &table[i]; 283 if (t->value) 284 res->action = t->value; 285 } 286 break; 287 288 case ENDTOKEN: 289 break; 290 } 291 } 292 293 if (match != 1) { 294 if (word == NULL) 295 fprintf(stderr, "missing argument:\n"); 296 else if (match > 1) 297 fprintf(stderr, "ambiguous argument: %s\n", word); 298 else if (match < 1) 299 fprintf(stderr, "unknown argument: %s\n", word); 300 return (NULL); 301 } 302 303 return (t); 304 } 305 306 static void 307 show_valid_args(const struct token *table) 308 { 309 int i; 310 311 for (i = 0; table[i].type != ENDTOKEN; i++) { 312 switch (table[i].type) { 313 case NOTOKEN: 314 fprintf(stderr, " <cr>\n"); 315 break; 316 case KEYWORD: 317 case FLAG: 318 fprintf(stderr, " %s\n", table[i].keyword); 319 break; 320 case FAMILY: 321 fprintf(stderr, " [ inet | inet6 | IPv4 | IPv6 ]\n"); 322 break; 323 case ADDRESS: 324 fprintf(stderr, " <address>\n"); 325 break; 326 case IFNAME: 327 fprintf(stderr, " <interface>\n"); 328 case ENDTOKEN: 329 break; 330 } 331 } 332 } 333 334 int 335 parse_addr(const char *word, int *family, union ldpd_addr *addr) 336 { 337 struct in_addr ina; 338 struct addrinfo hints, *r; 339 struct sockaddr_in6 *sa_in6; 340 341 if (word == NULL) 342 return (0); 343 344 memset(addr, 0, sizeof(*addr)); 345 memset(&ina, 0, sizeof(ina)); 346 347 if (inet_net_pton(AF_INET, word, &ina, sizeof(ina)) != -1) { 348 *family = AF_INET; 349 addr->v4.s_addr = ina.s_addr; 350 return (1); 351 } 352 353 memset(&hints, 0, sizeof(hints)); 354 hints.ai_family = AF_INET6; 355 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 356 hints.ai_flags = AI_NUMERICHOST; 357 if (getaddrinfo(word, "0", &hints, &r) == 0) { 358 sa_in6 = (struct sockaddr_in6 *)r->ai_addr; 359 *family = AF_INET6; 360 addr->v6 = sa_in6->sin6_addr; 361 freeaddrinfo(r); 362 return (1); 363 } 364 365 return (0); 366 } 367