1/* $OpenBSD: parser.c,v 1.7 2017/07/28 13:02:35 florian Exp $ */ 2 3/* 4 * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it> 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 "ripd.h" 33 34#include "parser.h" 35 36enum token_type { 37 NOTOKEN, 38 ENDTOKEN, 39 KEYWORD, 40 ADDRESS, 41 FLAG, 42 PREFIX, 43 IFNAME 44}; 45 46struct token { 47 enum token_type type; 48 const char *keyword; 49 int value; 50 const struct token *next; 51}; 52 53static const struct token t_main[]; 54static const struct token t_fib[]; 55static const struct token t_show[]; 56static const struct token t_show_iface[]; 57static const struct token t_show_nbr[]; 58static const struct token t_show_rib[]; 59static const struct token t_show_fib[]; 60static const struct token t_log[]; 61 62static const struct token t_main[] = { 63/* {KEYWORD, "reload", RELOAD, NULL}, */ 64 {KEYWORD, "fib", FIB, t_fib}, 65 {KEYWORD, "show", SHOW, t_show}, 66 {KEYWORD, "log", NONE, t_log}, 67 {ENDTOKEN, "", NONE, NULL} 68}; 69 70static const struct token t_fib[] = { 71 { KEYWORD, "couple", FIB_COUPLE, NULL}, 72 { KEYWORD, "decouple", FIB_DECOUPLE, NULL}, 73 { ENDTOKEN, "", NONE, NULL} 74}; 75 76static const struct token t_show[] = { 77 {NOTOKEN, "", NONE, NULL}, 78 {KEYWORD, "interfaces", SHOW_IFACE, t_show_iface}, 79 {KEYWORD, "neighbor", SHOW_NBR, t_show_nbr}, 80 {KEYWORD, "rib", SHOW_RIB, t_show_rib}, 81 {KEYWORD, "fib", SHOW_FIB, t_show_fib}, 82 {ENDTOKEN, "", NONE, NULL} 83}; 84 85static const struct token t_show_iface[] = { 86 {NOTOKEN, "", NONE, NULL}, 87 {ENDTOKEN, "", NONE, NULL} 88}; 89 90static const struct token t_show_nbr[] = { 91 {NOTOKEN, "", NONE, NULL}, 92 {ENDTOKEN, "", NONE, NULL} 93}; 94 95static const struct token t_show_rib[] = { 96 {NOTOKEN, "", NONE, NULL}, 97 {ENDTOKEN, "", NONE, NULL} 98}; 99 100static const struct token t_show_fib[] = { 101 {NOTOKEN, "", NONE, NULL}, 102 {KEYWORD, "interface", SHOW_FIB_IFACE, t_show_iface}, 103 {FLAG, "connected", F_CONNECTED, t_show_fib}, 104 {FLAG, "static", F_STATIC, t_show_fib}, 105 {FLAG, "rip", F_RIPD_INSERTED, t_show_fib}, 106 {ADDRESS, "", NONE, NULL}, 107 {ENDTOKEN, "", NONE, NULL} 108}; 109 110static const struct token t_log[] = { 111 {KEYWORD, "verbose", LOG_VERBOSE, NULL}, 112 {KEYWORD, "brief", LOG_BRIEF, NULL}, 113 {ENDTOKEN, "", NONE, NULL} 114}; 115 116static const struct token *match_token(const char *, const struct token *, 117 struct parse_result *); 118static void show_valid_args(const struct token *table); 119 120struct parse_result * 121parse(int argc, char *argv[]) 122{ 123 static struct parse_result res; 124 const struct token *table = t_main; 125 const struct token *match; 126 127 bzero(&res, sizeof(res)); 128 129 while (argc >= 0) { 130 if ((match = match_token(argv[0], table, &res)) == NULL) { 131 fprintf(stderr, "valid commands/args:\n"); 132 show_valid_args(table); 133 return (NULL); 134 } 135 136 argc--; 137 argv++; 138 139 if (match->type == NOTOKEN || match->next == NULL) 140 break; 141 142 table = match->next; 143 } 144 145 if (argc > 0) { 146 fprintf(stderr, "superfluous argument: %s\n", argv[0]); 147 return (NULL); 148 } 149 150 return (&res); 151} 152 153static const struct token * 154match_token(const char *word, const struct token *table, 155 struct parse_result *res) 156{ 157 u_int i, match; 158 const struct token *t = NULL; 159 160 match = 0; 161 162 for (i = 0; table[i].type != ENDTOKEN; i++) { 163 switch (table[i].type) { 164 case NOTOKEN: 165 if (word == NULL || strlen(word) == 0) { 166 match++; 167 t = &table[i]; 168 } 169 break; 170 case KEYWORD: 171 if (word != NULL && strncmp(word, table[i].keyword, 172 strlen(word)) == 0) { 173 match++; 174 t = &table[i]; 175 if (t->value) 176 res->action = t->value; 177 } 178 break; 179 case FLAG: 180 if (word != NULL && strncmp(word, table[i].keyword, 181 strlen(word)) == 0) { 182 match++; 183 t = &table[i]; 184 res->flags |= t->value; 185 } 186 break; 187 case ADDRESS: 188 if (parse_addr(word, &res->addr)) { 189 match++; 190 t = &table[i]; 191 if (t->value) 192 res->action = t->value; 193 } 194 break; 195 case PREFIX: 196 if (parse_prefix(word, &res->addr, &res->prefixlen)) { 197 match++; 198 t = &table[i]; 199 if (t->value) 200 res->action = t->value; 201 } 202 break; 203 case IFNAME: 204 if (!match && word != NULL && strlen(word) > 0) { 205 if (strlcpy(res->ifname, word, 206 sizeof(res->ifname)) >= 207 sizeof(res->ifname)) 208 err(1, "interface name too long"); 209 match++; 210 t = &table[i]; 211 if (t->value) 212 res->action = t->value; 213 } 214 break; 215 216 case ENDTOKEN: 217 break; 218 } 219 } 220 221 if (match != 1) { 222 if (word == NULL) 223 fprintf(stderr, "missing argument:\n"); 224 else if (match > 1) 225 fprintf(stderr, "ambiguous argument: %s\n", word); 226 else if (match < 1) 227 fprintf(stderr, "unknown argument: %s\n", word); 228 return (NULL); 229 } 230 231 return (t); 232} 233 234static void 235show_valid_args(const struct token *table) 236{ 237 int i; 238 239 for (i = 0; table[i].type != ENDTOKEN; i++) { 240 switch (table[i].type) { 241 case NOTOKEN: 242 fprintf(stderr, " <cr>\n"); 243 break; 244 case KEYWORD: 245 case FLAG: 246 fprintf(stderr, " %s\n", table[i].keyword); 247 break; 248 case ADDRESS: 249 fprintf(stderr, " <address>\n"); 250 break; 251 case PREFIX: 252 fprintf(stderr, " <address>[/<len>]\n"); 253 break; 254 case IFNAME: 255 fprintf(stderr, " <interface>\n"); 256 case ENDTOKEN: 257 break; 258 } 259 } 260} 261 262int 263parse_addr(const char *word, struct in_addr *addr) 264{ 265 struct in_addr ina; 266 267 if (word == NULL) 268 return (0); 269 270 bzero(addr, sizeof(struct in_addr)); 271 bzero(&ina, sizeof(ina)); 272 273 if (inet_pton(AF_INET, word, &ina)) { 274 addr->s_addr = ina.s_addr; 275 return (1); 276 } 277 278 return (0); 279} 280 281int 282parse_prefix(const char *word, struct in_addr *addr, u_int8_t *prefixlen) 283{ 284 struct in_addr ina; 285 int bits = 32; 286 287 if (word == NULL) 288 return (0); 289 290 bzero(addr, sizeof(struct in_addr)); 291 bzero(&ina, sizeof(ina)); 292 293 if (strrchr(word, '/') != NULL) { 294 if ((bits = inet_net_pton(AF_INET, word, 295 &ina, sizeof(ina))) == -1) 296 return (0); 297 addr->s_addr = ina.s_addr & htonl(prefixlen2mask(bits)); 298 *prefixlen = bits; 299 return (1); 300 } else { 301 *prefixlen = 32; 302 return (parse_addr(word, addr)); 303 } 304 305 return (0); 306} 307 308/* XXX local copy from kroute.c, should go to shared file */ 309in_addr_t 310prefixlen2mask(u_int8_t prefixlen) 311{ 312 if (prefixlen == 0) 313 return (0); 314 315 return (0xffffffff << (32 - prefixlen)); 316} 317