1*33a9ef42Sflorian /* $OpenBSD: parser.c,v 1.7 2017/07/28 13:02:35 florian Exp $ */
28eeeb81eSnorby
38eeeb81eSnorby /*
48eeeb81eSnorby * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
58eeeb81eSnorby * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
68eeeb81eSnorby * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
78eeeb81eSnorby *
88eeeb81eSnorby * Permission to use, copy, modify, and distribute this software for any
98eeeb81eSnorby * purpose with or without fee is hereby granted, provided that the above
108eeeb81eSnorby * copyright notice and this permission notice appear in all copies.
118eeeb81eSnorby *
128eeeb81eSnorby * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
138eeeb81eSnorby * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
148eeeb81eSnorby * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
158eeeb81eSnorby * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
168eeeb81eSnorby * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
178eeeb81eSnorby * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
188eeeb81eSnorby * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
198eeeb81eSnorby */
208eeeb81eSnorby
218eeeb81eSnorby #include <sys/types.h>
228eeeb81eSnorby #include <sys/socket.h>
238eeeb81eSnorby #include <netinet/in.h>
248eeeb81eSnorby #include <arpa/inet.h>
258eeeb81eSnorby #include <err.h>
268eeeb81eSnorby #include <errno.h>
278eeeb81eSnorby #include <limits.h>
288eeeb81eSnorby #include <stdio.h>
298eeeb81eSnorby #include <stdlib.h>
308eeeb81eSnorby #include <string.h>
318eeeb81eSnorby
328eeeb81eSnorby #include "ripd.h"
338eeeb81eSnorby
348eeeb81eSnorby #include "parser.h"
358eeeb81eSnorby
368eeeb81eSnorby enum token_type {
378eeeb81eSnorby NOTOKEN,
388eeeb81eSnorby ENDTOKEN,
398eeeb81eSnorby KEYWORD,
408eeeb81eSnorby ADDRESS,
418eeeb81eSnorby FLAG,
428eeeb81eSnorby PREFIX,
438eeeb81eSnorby IFNAME
448eeeb81eSnorby };
458eeeb81eSnorby
468eeeb81eSnorby struct token {
478eeeb81eSnorby enum token_type type;
488eeeb81eSnorby const char *keyword;
498eeeb81eSnorby int value;
508eeeb81eSnorby const struct token *next;
518eeeb81eSnorby };
528eeeb81eSnorby
538eeeb81eSnorby static const struct token t_main[];
548eeeb81eSnorby static const struct token t_fib[];
558eeeb81eSnorby static const struct token t_show[];
568eeeb81eSnorby static const struct token t_show_iface[];
578eeeb81eSnorby static const struct token t_show_nbr[];
588eeeb81eSnorby static const struct token t_show_rib[];
598eeeb81eSnorby static const struct token t_show_fib[];
60c3319070Sclaudio static const struct token t_log[];
618eeeb81eSnorby
628eeeb81eSnorby static const struct token t_main[] = {
638eeeb81eSnorby /* {KEYWORD, "reload", RELOAD, NULL}, */
648eeeb81eSnorby {KEYWORD, "fib", FIB, t_fib},
658eeeb81eSnorby {KEYWORD, "show", SHOW, t_show},
66c3319070Sclaudio {KEYWORD, "log", NONE, t_log},
678eeeb81eSnorby {ENDTOKEN, "", NONE, NULL}
688eeeb81eSnorby };
698eeeb81eSnorby
708eeeb81eSnorby static const struct token t_fib[] = {
718eeeb81eSnorby { KEYWORD, "couple", FIB_COUPLE, NULL},
728eeeb81eSnorby { KEYWORD, "decouple", FIB_DECOUPLE, NULL},
738eeeb81eSnorby { ENDTOKEN, "", NONE, NULL}
748eeeb81eSnorby };
758eeeb81eSnorby
768eeeb81eSnorby static const struct token t_show[] = {
778eeeb81eSnorby {NOTOKEN, "", NONE, NULL},
788eeeb81eSnorby {KEYWORD, "interfaces", SHOW_IFACE, t_show_iface},
798eeeb81eSnorby {KEYWORD, "neighbor", SHOW_NBR, t_show_nbr},
808eeeb81eSnorby {KEYWORD, "rib", SHOW_RIB, t_show_rib},
818eeeb81eSnorby {KEYWORD, "fib", SHOW_FIB, t_show_fib},
828eeeb81eSnorby {ENDTOKEN, "", NONE, NULL}
838eeeb81eSnorby };
848eeeb81eSnorby
858eeeb81eSnorby static const struct token t_show_iface[] = {
868eeeb81eSnorby {NOTOKEN, "", NONE, NULL},
878eeeb81eSnorby {ENDTOKEN, "", NONE, NULL}
888eeeb81eSnorby };
898eeeb81eSnorby
908eeeb81eSnorby static const struct token t_show_nbr[] = {
918eeeb81eSnorby {NOTOKEN, "", NONE, NULL},
928eeeb81eSnorby {ENDTOKEN, "", NONE, NULL}
938eeeb81eSnorby };
948eeeb81eSnorby
958eeeb81eSnorby static const struct token t_show_rib[] = {
968eeeb81eSnorby {NOTOKEN, "", NONE, NULL},
978eeeb81eSnorby {ENDTOKEN, "", NONE, NULL}
988eeeb81eSnorby };
998eeeb81eSnorby
1008eeeb81eSnorby static const struct token t_show_fib[] = {
1018eeeb81eSnorby {NOTOKEN, "", NONE, NULL},
1028eeeb81eSnorby {KEYWORD, "interface", SHOW_FIB_IFACE, t_show_iface},
1038eeeb81eSnorby {FLAG, "connected", F_CONNECTED, t_show_fib},
1048eeeb81eSnorby {FLAG, "static", F_STATIC, t_show_fib},
1058eeeb81eSnorby {FLAG, "rip", F_RIPD_INSERTED, t_show_fib},
1068eeeb81eSnorby {ADDRESS, "", NONE, NULL},
1078eeeb81eSnorby {ENDTOKEN, "", NONE, NULL}
1088eeeb81eSnorby };
1098eeeb81eSnorby
110c3319070Sclaudio static const struct token t_log[] = {
111c3319070Sclaudio {KEYWORD, "verbose", LOG_VERBOSE, NULL},
112c3319070Sclaudio {KEYWORD, "brief", LOG_BRIEF, NULL},
113c3319070Sclaudio {ENDTOKEN, "", NONE, NULL}
114c3319070Sclaudio };
115c3319070Sclaudio
1166be5843eStedu static const struct token *match_token(const char *, const struct token *,
1176be5843eStedu struct parse_result *);
1186c9c7f05Skettenis static void show_valid_args(const struct token *table);
1198eeeb81eSnorby
1208eeeb81eSnorby struct parse_result *
parse(int argc,char * argv[])1218eeeb81eSnorby parse(int argc, char *argv[])
1228eeeb81eSnorby {
1236be5843eStedu static struct parse_result res;
1248eeeb81eSnorby const struct token *table = t_main;
1258eeeb81eSnorby const struct token *match;
1268eeeb81eSnorby
1278eeeb81eSnorby bzero(&res, sizeof(res));
1288eeeb81eSnorby
1297500ebd3Sclaudio while (argc >= 0) {
1306be5843eStedu if ((match = match_token(argv[0], table, &res)) == NULL) {
1318eeeb81eSnorby fprintf(stderr, "valid commands/args:\n");
1328eeeb81eSnorby show_valid_args(table);
1338eeeb81eSnorby return (NULL);
1348eeeb81eSnorby }
1358eeeb81eSnorby
1368eeeb81eSnorby argc--;
1378eeeb81eSnorby argv++;
1388eeeb81eSnorby
1398eeeb81eSnorby if (match->type == NOTOKEN || match->next == NULL)
1408eeeb81eSnorby break;
1418eeeb81eSnorby
1428eeeb81eSnorby table = match->next;
1438eeeb81eSnorby }
1448eeeb81eSnorby
1458eeeb81eSnorby if (argc > 0) {
1468eeeb81eSnorby fprintf(stderr, "superfluous argument: %s\n", argv[0]);
1478eeeb81eSnorby return (NULL);
1488eeeb81eSnorby }
1498eeeb81eSnorby
1508eeeb81eSnorby return (&res);
1518eeeb81eSnorby }
1528eeeb81eSnorby
1536be5843eStedu static const struct token *
match_token(const char * word,const struct token * table,struct parse_result * res)1546be5843eStedu match_token(const char *word, const struct token *table,
1556be5843eStedu struct parse_result *res)
1568eeeb81eSnorby {
1578eeeb81eSnorby u_int i, match;
1588eeeb81eSnorby const struct token *t = NULL;
1598eeeb81eSnorby
1608eeeb81eSnorby match = 0;
1618eeeb81eSnorby
1628eeeb81eSnorby for (i = 0; table[i].type != ENDTOKEN; i++) {
1638eeeb81eSnorby switch (table[i].type) {
1648eeeb81eSnorby case NOTOKEN:
1658eeeb81eSnorby if (word == NULL || strlen(word) == 0) {
1668eeeb81eSnorby match++;
1678eeeb81eSnorby t = &table[i];
1688eeeb81eSnorby }
1698eeeb81eSnorby break;
1708eeeb81eSnorby case KEYWORD:
1718eeeb81eSnorby if (word != NULL && strncmp(word, table[i].keyword,
1728eeeb81eSnorby strlen(word)) == 0) {
1738eeeb81eSnorby match++;
1748eeeb81eSnorby t = &table[i];
1758eeeb81eSnorby if (t->value)
1766be5843eStedu res->action = t->value;
1778eeeb81eSnorby }
1788eeeb81eSnorby break;
1798eeeb81eSnorby case FLAG:
1808eeeb81eSnorby if (word != NULL && strncmp(word, table[i].keyword,
1818eeeb81eSnorby strlen(word)) == 0) {
1828eeeb81eSnorby match++;
1838eeeb81eSnorby t = &table[i];
1846be5843eStedu res->flags |= t->value;
1858eeeb81eSnorby }
1868eeeb81eSnorby break;
1878eeeb81eSnorby case ADDRESS:
1886be5843eStedu if (parse_addr(word, &res->addr)) {
1898eeeb81eSnorby match++;
1908eeeb81eSnorby t = &table[i];
1918eeeb81eSnorby if (t->value)
1926be5843eStedu res->action = t->value;
1938eeeb81eSnorby }
1948eeeb81eSnorby break;
1958eeeb81eSnorby case PREFIX:
1966be5843eStedu if (parse_prefix(word, &res->addr, &res->prefixlen)) {
1978eeeb81eSnorby match++;
1988eeeb81eSnorby t = &table[i];
1998eeeb81eSnorby if (t->value)
2006be5843eStedu res->action = t->value;
2018eeeb81eSnorby }
2028eeeb81eSnorby break;
2038eeeb81eSnorby case IFNAME:
2048eeeb81eSnorby if (!match && word != NULL && strlen(word) > 0) {
2056be5843eStedu if (strlcpy(res->ifname, word,
2066be5843eStedu sizeof(res->ifname)) >=
2076be5843eStedu sizeof(res->ifname))
2088eeeb81eSnorby err(1, "interface name too long");
2098eeeb81eSnorby match++;
2108eeeb81eSnorby t = &table[i];
2118eeeb81eSnorby if (t->value)
2126be5843eStedu res->action = t->value;
2138eeeb81eSnorby }
2148eeeb81eSnorby break;
2158eeeb81eSnorby
2168eeeb81eSnorby case ENDTOKEN:
2178eeeb81eSnorby break;
2188eeeb81eSnorby }
2198eeeb81eSnorby }
2208eeeb81eSnorby
2218eeeb81eSnorby if (match != 1) {
2227500ebd3Sclaudio if (word == NULL)
2237500ebd3Sclaudio fprintf(stderr, "missing argument:\n");
2247500ebd3Sclaudio else if (match > 1)
2258eeeb81eSnorby fprintf(stderr, "ambiguous argument: %s\n", word);
2267500ebd3Sclaudio else if (match < 1)
2278eeeb81eSnorby fprintf(stderr, "unknown argument: %s\n", word);
2288eeeb81eSnorby return (NULL);
2298eeeb81eSnorby }
2308eeeb81eSnorby
2318eeeb81eSnorby return (t);
2328eeeb81eSnorby }
2338eeeb81eSnorby
2346be5843eStedu static void
show_valid_args(const struct token * table)235e331d0fcSjsg show_valid_args(const struct token *table)
2368eeeb81eSnorby {
2378eeeb81eSnorby int i;
2388eeeb81eSnorby
2398eeeb81eSnorby for (i = 0; table[i].type != ENDTOKEN; i++) {
2408eeeb81eSnorby switch (table[i].type) {
2418eeeb81eSnorby case NOTOKEN:
2428eeeb81eSnorby fprintf(stderr, " <cr>\n");
2438eeeb81eSnorby break;
2448eeeb81eSnorby case KEYWORD:
2458eeeb81eSnorby case FLAG:
2468eeeb81eSnorby fprintf(stderr, " %s\n", table[i].keyword);
2478eeeb81eSnorby break;
2488eeeb81eSnorby case ADDRESS:
2498eeeb81eSnorby fprintf(stderr, " <address>\n");
2508eeeb81eSnorby break;
2518eeeb81eSnorby case PREFIX:
2528eeeb81eSnorby fprintf(stderr, " <address>[/<len>]\n");
2538eeeb81eSnorby break;
2548eeeb81eSnorby case IFNAME:
2558eeeb81eSnorby fprintf(stderr, " <interface>\n");
2568eeeb81eSnorby case ENDTOKEN:
2578eeeb81eSnorby break;
2588eeeb81eSnorby }
2598eeeb81eSnorby }
2608eeeb81eSnorby }
2618eeeb81eSnorby
2628eeeb81eSnorby int
parse_addr(const char * word,struct in_addr * addr)2638eeeb81eSnorby parse_addr(const char *word, struct in_addr *addr)
2648eeeb81eSnorby {
2658eeeb81eSnorby struct in_addr ina;
2668eeeb81eSnorby
2678eeeb81eSnorby if (word == NULL)
2688eeeb81eSnorby return (0);
2698eeeb81eSnorby
2708eeeb81eSnorby bzero(addr, sizeof(struct in_addr));
2718eeeb81eSnorby bzero(&ina, sizeof(ina));
2728eeeb81eSnorby
2738eeeb81eSnorby if (inet_pton(AF_INET, word, &ina)) {
2748eeeb81eSnorby addr->s_addr = ina.s_addr;
2758eeeb81eSnorby return (1);
2768eeeb81eSnorby }
2778eeeb81eSnorby
2788eeeb81eSnorby return (0);
2798eeeb81eSnorby }
2808eeeb81eSnorby
2818eeeb81eSnorby int
parse_prefix(const char * word,struct in_addr * addr,u_int8_t * prefixlen)2828eeeb81eSnorby parse_prefix(const char *word, struct in_addr *addr, u_int8_t *prefixlen)
2838eeeb81eSnorby {
2848eeeb81eSnorby struct in_addr ina;
2858eeeb81eSnorby int bits = 32;
2868eeeb81eSnorby
2878eeeb81eSnorby if (word == NULL)
2888eeeb81eSnorby return (0);
2898eeeb81eSnorby
2908eeeb81eSnorby bzero(addr, sizeof(struct in_addr));
2918eeeb81eSnorby bzero(&ina, sizeof(ina));
2928eeeb81eSnorby
2938eeeb81eSnorby if (strrchr(word, '/') != NULL) {
2948eeeb81eSnorby if ((bits = inet_net_pton(AF_INET, word,
2958eeeb81eSnorby &ina, sizeof(ina))) == -1)
2968eeeb81eSnorby return (0);
2978eeeb81eSnorby addr->s_addr = ina.s_addr & htonl(prefixlen2mask(bits));
2988eeeb81eSnorby *prefixlen = bits;
2998eeeb81eSnorby return (1);
3008eeeb81eSnorby } else {
3018eeeb81eSnorby *prefixlen = 32;
3028eeeb81eSnorby return (parse_addr(word, addr));
3038eeeb81eSnorby }
3048eeeb81eSnorby
3058eeeb81eSnorby return (0);
3068eeeb81eSnorby }
3078eeeb81eSnorby
3088eeeb81eSnorby /* XXX local copy from kroute.c, should go to shared file */
3098eeeb81eSnorby in_addr_t
prefixlen2mask(u_int8_t prefixlen)3108eeeb81eSnorby prefixlen2mask(u_int8_t prefixlen)
3118eeeb81eSnorby {
3128eeeb81eSnorby if (prefixlen == 0)
3138eeeb81eSnorby return (0);
3148eeeb81eSnorby
3158eeeb81eSnorby return (0xffffffff << (32 - prefixlen));
3168eeeb81eSnorby }
317