1 /* $OpenBSD: parser.c,v 1.9 2016/05/23 19:01:08 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 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_disc[]; 58 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_show_l2vpn[]; 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 { ENDTOKEN, "", NONE, NULL} 77 }; 78 79 static const struct token t_show[] = { 80 {NOTOKEN, "", NONE, NULL}, 81 {KEYWORD, "interfaces", SHOW_IFACE, t_show_iface}, 82 {KEYWORD, "discovery", SHOW_DISC, t_show_disc}, 83 {KEYWORD, "neighbor", SHOW_NBR, t_show_nbr}, 84 {KEYWORD, "lib", SHOW_LIB, t_show_lib}, 85 {KEYWORD, "fib", SHOW_FIB, t_show_fib}, 86 {KEYWORD, "l2vpn", NONE, t_show_l2vpn}, 87 {ENDTOKEN, "", NONE, NULL} 88 }; 89 90 static const struct token t_show_iface[] = { 91 {NOTOKEN, "", NONE, NULL}, 92 {ENDTOKEN, "", NONE, NULL} 93 }; 94 95 static const struct token t_show_disc[] = { 96 {NOTOKEN, "", NONE, NULL}, 97 {ENDTOKEN, "", NONE, NULL} 98 }; 99 100 static const struct token t_show_nbr[] = { 101 {NOTOKEN, "", NONE, NULL}, 102 {ENDTOKEN, "", NONE, NULL} 103 }; 104 105 static const struct token t_show_lib[] = { 106 {NOTOKEN, "", NONE, NULL}, 107 {ENDTOKEN, "", NONE, NULL} 108 }; 109 110 static const struct token t_log[] = { 111 {KEYWORD, "verbose", LOG_VERBOSE, NULL}, 112 {KEYWORD, "brief", LOG_BRIEF, NULL}, 113 {ENDTOKEN, "", NONE, NULL} 114 }; 115 116 static const struct token t_show_fib[] = { 117 {NOTOKEN, "", NONE, NULL}, 118 {KEYWORD, "interface", SHOW_FIB_IFACE, t_show_iface}, 119 {FLAG, "connected", F_CONNECTED, t_show_fib}, 120 {FLAG, "static", F_STATIC, t_show_fib}, 121 {ADDRESS, "", NONE, NULL}, 122 {ENDTOKEN, "", NONE, NULL} 123 }; 124 125 static const struct token t_show_l2vpn[] = { 126 {KEYWORD, "bindings", SHOW_L2VPN_BINDING, NULL}, 127 {KEYWORD, "pseudowires", SHOW_L2VPN_PW, NULL}, 128 {ENDTOKEN, "", NONE, NULL} 129 }; 130 131 static const struct token *match_token(const char *, const struct token *, 132 struct parse_result *); 133 static void show_valid_args(const struct token *); 134 135 struct parse_result * 136 parse(int argc, char *argv[]) 137 { 138 static struct parse_result res; 139 const struct token *table = t_main; 140 const struct token *match; 141 142 bzero(&res, sizeof(res)); 143 144 while (argc >= 0) { 145 if ((match = match_token(argv[0], table, &res)) == NULL) { 146 fprintf(stderr, "valid commands/args:\n"); 147 show_valid_args(table); 148 return (NULL); 149 } 150 151 argc--; 152 argv++; 153 154 if (match->type == NOTOKEN || match->next == NULL) 155 break; 156 157 table = match->next; 158 } 159 160 if (argc > 0) { 161 fprintf(stderr, "superfluous argument: %s\n", argv[0]); 162 return (NULL); 163 } 164 165 return (&res); 166 } 167 168 static const struct token * 169 match_token(const char *word, const struct token *table, 170 struct parse_result *res) 171 { 172 uint i, match; 173 const struct token *t = NULL; 174 175 match = 0; 176 177 for (i = 0; table[i].type != ENDTOKEN; i++) { 178 switch (table[i].type) { 179 case NOTOKEN: 180 if (word == NULL || strlen(word) == 0) { 181 match++; 182 t = &table[i]; 183 } 184 break; 185 case KEYWORD: 186 if (word != NULL && strncmp(word, table[i].keyword, 187 strlen(word)) == 0) { 188 match++; 189 t = &table[i]; 190 if (t->value) 191 res->action = t->value; 192 } 193 break; 194 case FLAG: 195 if (word != NULL && strncmp(word, table[i].keyword, 196 strlen(word)) == 0) { 197 match++; 198 t = &table[i]; 199 res->flags |= t->value; 200 } 201 break; 202 case ADDRESS: 203 if (parse_addr(word, &res->addr)) { 204 match++; 205 t = &table[i]; 206 if (t->value) 207 res->action = t->value; 208 } 209 break; 210 case PREFIX: 211 if (parse_prefix(word, &res->addr, &res->prefixlen)) { 212 match++; 213 t = &table[i]; 214 if (t->value) 215 res->action = t->value; 216 } 217 break; 218 case IFNAME: 219 if (!match && word != NULL && strlen(word) > 0) { 220 if (strlcpy(res->ifname, word, 221 sizeof(res->ifname)) >= 222 sizeof(res->ifname)) 223 err(1, "interface name too long"); 224 match++; 225 t = &table[i]; 226 if (t->value) 227 res->action = t->value; 228 } 229 break; 230 231 case ENDTOKEN: 232 break; 233 } 234 } 235 236 if (match != 1) { 237 if (word == NULL) 238 fprintf(stderr, "missing argument:\n"); 239 else if (match > 1) 240 fprintf(stderr, "ambiguous argument: %s\n", word); 241 else if (match < 1) 242 fprintf(stderr, "unknown argument: %s\n", word); 243 return (NULL); 244 } 245 246 return (t); 247 } 248 249 static void 250 show_valid_args(const struct token *table) 251 { 252 int i; 253 254 for (i = 0; table[i].type != ENDTOKEN; i++) { 255 switch (table[i].type) { 256 case NOTOKEN: 257 fprintf(stderr, " <cr>\n"); 258 break; 259 case KEYWORD: 260 case FLAG: 261 fprintf(stderr, " %s\n", table[i].keyword); 262 break; 263 case ADDRESS: 264 fprintf(stderr, " <address>\n"); 265 break; 266 case PREFIX: 267 fprintf(stderr, " <address>[/<len>]\n"); 268 break; 269 case IFNAME: 270 fprintf(stderr, " <interface>\n"); 271 case ENDTOKEN: 272 break; 273 } 274 } 275 } 276 277 int 278 parse_addr(const char *word, struct in_addr *addr) 279 { 280 struct in_addr ina; 281 282 if (word == NULL) 283 return (0); 284 285 bzero(addr, sizeof(struct in_addr)); 286 bzero(&ina, sizeof(ina)); 287 288 if (inet_pton(AF_INET, word, &ina)) { 289 addr->s_addr = ina.s_addr; 290 return (1); 291 } 292 293 return (0); 294 } 295 296 int 297 parse_prefix(const char *word, struct in_addr *addr, uint8_t *prefixlen) 298 { 299 struct in_addr ina; 300 int bits = 32; 301 302 if (word == NULL) 303 return (0); 304 305 bzero(addr, sizeof(struct in_addr)); 306 bzero(&ina, sizeof(ina)); 307 308 if (strrchr(word, '/') != NULL) { 309 if ((bits = inet_net_pton(AF_INET, word, 310 &ina, sizeof(ina))) == -1) 311 return (0); 312 addr->s_addr = ina.s_addr & htonl(prefixlen2mask(bits)); 313 *prefixlen = bits; 314 return (1); 315 } else { 316 *prefixlen = 32; 317 return (parse_addr(word, addr)); 318 } 319 320 return (0); 321 } 322 323 /* XXX local copy from kroute.c, should go to shared file */ 324 in_addr_t 325 prefixlen2mask(uint8_t prefixlen) 326 { 327 if (prefixlen == 0) 328 return (0); 329 330 return (0xffffffff << (32 - prefixlen)); 331 } 332