1*dd3b9a80Ssthen /* $OpenBSD: parser.c,v 1.15 2023/06/21 09:47:03 sthen Exp $ */
28e709cbdSnorby
38e709cbdSnorby /*
48e709cbdSnorby * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
58e709cbdSnorby * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
68e709cbdSnorby *
78e709cbdSnorby * Permission to use, copy, modify, and distribute this software for any
88e709cbdSnorby * purpose with or without fee is hereby granted, provided that the above
98e709cbdSnorby * copyright notice and this permission notice appear in all copies.
108e709cbdSnorby *
118e709cbdSnorby * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
128e709cbdSnorby * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
138e709cbdSnorby * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
148e709cbdSnorby * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
158e709cbdSnorby * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
168e709cbdSnorby * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
178e709cbdSnorby * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
188e709cbdSnorby */
198e709cbdSnorby
208e709cbdSnorby #include <sys/types.h>
218e709cbdSnorby #include <sys/socket.h>
228e709cbdSnorby #include <netinet/in.h>
238e709cbdSnorby #include <arpa/inet.h>
248e709cbdSnorby #include <err.h>
258e709cbdSnorby #include <errno.h>
268e709cbdSnorby #include <limits.h>
270104e403Sclaudio #include <netdb.h>
288e709cbdSnorby #include <stdio.h>
298e709cbdSnorby #include <stdlib.h>
308e709cbdSnorby #include <string.h>
318e709cbdSnorby
328e709cbdSnorby #include "ospf6d.h"
338e709cbdSnorby
348e709cbdSnorby #include "parser.h"
358e709cbdSnorby
368e709cbdSnorby enum token_type {
378e709cbdSnorby NOTOKEN,
388e709cbdSnorby ENDTOKEN,
398e709cbdSnorby KEYWORD,
408e709cbdSnorby ADDRESS,
418e709cbdSnorby FLAG,
428e709cbdSnorby PREFIX,
4396950f83Sremi IFNAME,
4496950f83Sremi AREA
458e709cbdSnorby };
468e709cbdSnorby
478e709cbdSnorby struct token {
488e709cbdSnorby enum token_type type;
498e709cbdSnorby const char *keyword;
508e709cbdSnorby int value;
518e709cbdSnorby const struct token *next;
528e709cbdSnorby };
538e709cbdSnorby
548e709cbdSnorby static const struct token t_main[];
558e709cbdSnorby static const struct token t_fib[];
568e709cbdSnorby static const struct token t_show[];
578e709cbdSnorby static const struct token t_show_iface[];
588e709cbdSnorby static const struct token t_show_db[];
598e709cbdSnorby static const struct token t_show_area[];
608e709cbdSnorby static const struct token t_show_nbr[];
618e709cbdSnorby static const struct token t_show_rib[];
628e709cbdSnorby static const struct token t_show_fib[];
63c3319070Sclaudio static const struct token t_log[];
648e709cbdSnorby
658e709cbdSnorby static const struct token t_main[] = {
668e709cbdSnorby {KEYWORD, "reload", RELOAD, NULL},
678e709cbdSnorby {KEYWORD, "fib", FIB, t_fib},
688e709cbdSnorby {KEYWORD, "show", SHOW, t_show},
69c3319070Sclaudio {KEYWORD, "log", NONE, t_log},
708e709cbdSnorby {ENDTOKEN, "", NONE, NULL}
718e709cbdSnorby };
728e709cbdSnorby
738e709cbdSnorby static const struct token t_fib[] = {
748e709cbdSnorby { KEYWORD, "couple", FIB_COUPLE, NULL},
758e709cbdSnorby { KEYWORD, "decouple", FIB_DECOUPLE, NULL},
76*dd3b9a80Ssthen { KEYWORD, "reload", FIB_RELOAD, NULL},
778e709cbdSnorby { ENDTOKEN, "", NONE, NULL}
788e709cbdSnorby };
798e709cbdSnorby
808e709cbdSnorby static const struct token t_show[] = {
818e709cbdSnorby {NOTOKEN, "", NONE, NULL},
828e709cbdSnorby {KEYWORD, "interfaces", SHOW_IFACE, t_show_iface},
838e709cbdSnorby {KEYWORD, "database", SHOW_DB, t_show_db},
848e709cbdSnorby {KEYWORD, "neighbor", SHOW_NBR, t_show_nbr},
858e709cbdSnorby {KEYWORD, "rib", SHOW_RIB, t_show_rib},
868e709cbdSnorby {KEYWORD, "fib", SHOW_FIB, t_show_fib},
878e709cbdSnorby {KEYWORD, "summary", SHOW_SUM, NULL},
888e709cbdSnorby {ENDTOKEN, "", NONE, NULL}
898e709cbdSnorby };
908e709cbdSnorby
918e709cbdSnorby static const struct token t_show_iface[] = {
928e709cbdSnorby {NOTOKEN, "", NONE, NULL},
938e709cbdSnorby {KEYWORD, "detail", SHOW_IFACE_DTAIL, NULL},
948e709cbdSnorby {IFNAME, "", SHOW_IFACE_DTAIL, NULL},
958e709cbdSnorby {ENDTOKEN, "", NONE, NULL}
968e709cbdSnorby };
978e709cbdSnorby
988e709cbdSnorby static const struct token t_show_db[] = {
998e709cbdSnorby {NOTOKEN, "", NONE, NULL},
1008e709cbdSnorby {KEYWORD, "area", SHOW_DBBYAREA, t_show_area},
1018e709cbdSnorby {KEYWORD, "asbr", SHOW_DBASBR, NULL},
1028e709cbdSnorby {KEYWORD, "external", SHOW_DBEXT, NULL},
103aeb06b08Sclaudio {KEYWORD, "link", SHOW_DBLINK, NULL},
1048e709cbdSnorby {KEYWORD, "network", SHOW_DBNET, NULL},
1058e709cbdSnorby {KEYWORD, "router", SHOW_DBRTR, NULL},
10641bcac6bSstsp {KEYWORD, "intra", SHOW_DBINTRA, NULL},
1078e709cbdSnorby {KEYWORD, "self-originated", SHOW_DBSELF, NULL},
1088e709cbdSnorby {KEYWORD, "summary", SHOW_DBSUM, NULL},
1098e709cbdSnorby {ENDTOKEN, "", NONE, NULL}
1108e709cbdSnorby };
1118e709cbdSnorby
1128e709cbdSnorby static const struct token t_show_area[] = {
11396950f83Sremi {AREA, "", NONE, NULL},
1148e709cbdSnorby {ENDTOKEN, "", NONE, NULL}
1158e709cbdSnorby };
1168e709cbdSnorby
1178e709cbdSnorby static const struct token t_show_nbr[] = {
1188e709cbdSnorby {NOTOKEN, "", NONE, NULL},
1198e709cbdSnorby {KEYWORD, "detail", SHOW_NBR_DTAIL, NULL},
1208e709cbdSnorby {ENDTOKEN, "", NONE, NULL}
1218e709cbdSnorby };
1228e709cbdSnorby
1238e709cbdSnorby static const struct token t_show_rib[] = {
1248e709cbdSnorby {NOTOKEN, "", NONE, NULL},
1258e709cbdSnorby {KEYWORD, "detail", SHOW_RIB_DTAIL, NULL},
1268e709cbdSnorby {ENDTOKEN, "", NONE, NULL}
1278e709cbdSnorby };
1288e709cbdSnorby
1298e709cbdSnorby static const struct token t_show_fib[] = {
1308e709cbdSnorby {NOTOKEN, "", NONE, NULL},
1318e709cbdSnorby {FLAG, "connected", F_CONNECTED, t_show_fib},
1328e709cbdSnorby {FLAG, "static", F_STATIC, t_show_fib},
1338e709cbdSnorby {FLAG, "ospf", F_OSPFD_INSERTED, t_show_fib},
1348e709cbdSnorby {ADDRESS, "", NONE, NULL},
1358e709cbdSnorby {ENDTOKEN, "", NONE, NULL}
1368e709cbdSnorby };
1378e709cbdSnorby
138c3319070Sclaudio static const struct token t_log[] = {
139c3319070Sclaudio {KEYWORD, "verbose", LOG_VERBOSE, NULL},
140c3319070Sclaudio {KEYWORD, "brief", LOG_BRIEF, NULL},
141c3319070Sclaudio {ENDTOKEN, "", NONE, NULL}
142c3319070Sclaudio };
143c3319070Sclaudio
1446be5843eStedu static const struct token *match_token(const char *, const struct token *,
1456be5843eStedu struct parse_result *);
1466be5843eStedu static void show_valid_args(const struct token *);
1478e709cbdSnorby
1488e709cbdSnorby struct parse_result *
parse(int argc,char * argv[])1498e709cbdSnorby parse(int argc, char *argv[])
1508e709cbdSnorby {
1516be5843eStedu static struct parse_result res;
1528e709cbdSnorby const struct token *table = t_main;
1538e709cbdSnorby const struct token *match;
1548e709cbdSnorby
1558e709cbdSnorby bzero(&res, sizeof(res));
1568e709cbdSnorby
1578e709cbdSnorby while (argc >= 0) {
1586be5843eStedu if ((match = match_token(argv[0], table, &res)) == NULL) {
1598e709cbdSnorby fprintf(stderr, "valid commands/args:\n");
1608e709cbdSnorby show_valid_args(table);
1618e709cbdSnorby return (NULL);
1628e709cbdSnorby }
1638e709cbdSnorby
1648e709cbdSnorby argc--;
1658e709cbdSnorby argv++;
1668e709cbdSnorby
1678e709cbdSnorby if (match->type == NOTOKEN || match->next == NULL)
1688e709cbdSnorby break;
1698e709cbdSnorby
1708e709cbdSnorby table = match->next;
1718e709cbdSnorby }
1728e709cbdSnorby
1738e709cbdSnorby if (argc > 0) {
1748e709cbdSnorby fprintf(stderr, "superfluous argument: %s\n", argv[0]);
1758e709cbdSnorby return (NULL);
1768e709cbdSnorby }
1778e709cbdSnorby
1788e709cbdSnorby return (&res);
1798e709cbdSnorby }
1808e709cbdSnorby
1816be5843eStedu static const struct token *
match_token(const char * word,const struct token * table,struct parse_result * res)1826be5843eStedu match_token(const char *word, const struct token *table,
1836be5843eStedu struct parse_result *res)
1848e709cbdSnorby {
1858e709cbdSnorby u_int i, match;
1868e709cbdSnorby const struct token *t = NULL;
1878e709cbdSnorby
1888e709cbdSnorby match = 0;
1898e709cbdSnorby
1908e709cbdSnorby for (i = 0; table[i].type != ENDTOKEN; i++) {
1918e709cbdSnorby switch (table[i].type) {
1928e709cbdSnorby case NOTOKEN:
1938e709cbdSnorby if (word == NULL || strlen(word) == 0) {
1948e709cbdSnorby match++;
1958e709cbdSnorby t = &table[i];
1968e709cbdSnorby }
1978e709cbdSnorby break;
1988e709cbdSnorby case KEYWORD:
1998e709cbdSnorby if (word != NULL && strncmp(word, table[i].keyword,
2008e709cbdSnorby strlen(word)) == 0) {
2018e709cbdSnorby match++;
2028e709cbdSnorby t = &table[i];
2038e709cbdSnorby if (t->value)
2046be5843eStedu res->action = t->value;
2058e709cbdSnorby }
2068e709cbdSnorby break;
2078e709cbdSnorby case FLAG:
2088e709cbdSnorby if (word != NULL && strncmp(word, table[i].keyword,
2098e709cbdSnorby strlen(word)) == 0) {
2108e709cbdSnorby match++;
2118e709cbdSnorby t = &table[i];
2126be5843eStedu res->flags |= t->value;
2138e709cbdSnorby }
2148e709cbdSnorby break;
2158e709cbdSnorby case ADDRESS:
2166be5843eStedu if (parse_addr(word, &res->addr)) {
2178e709cbdSnorby match++;
2188e709cbdSnorby t = &table[i];
2198e709cbdSnorby if (t->value)
2206be5843eStedu res->action = t->value;
2218e709cbdSnorby }
2228e709cbdSnorby break;
22396950f83Sremi case AREA:
22496950f83Sremi if (parse_area(word, &res->area)) {
22596950f83Sremi match++;
22696950f83Sremi t = &table[i];
22796950f83Sremi if (t->value)
22896950f83Sremi res->action = t->value;
22996950f83Sremi }
23096950f83Sremi break;
2318e709cbdSnorby case PREFIX:
2326be5843eStedu if (parse_prefix(word, &res->addr, &res->prefixlen)) {
2338e709cbdSnorby match++;
2348e709cbdSnorby t = &table[i];
2358e709cbdSnorby if (t->value)
2366be5843eStedu res->action = t->value;
2378e709cbdSnorby }
2388e709cbdSnorby break;
2398e709cbdSnorby case IFNAME:
2408e709cbdSnorby if (!match && word != NULL && strlen(word) > 0) {
2416be5843eStedu if (strlcpy(res->ifname, word,
2426be5843eStedu sizeof(res->ifname)) >=
2436be5843eStedu sizeof(res->ifname))
2448e709cbdSnorby err(1, "interface name too long");
2458e709cbdSnorby match++;
2468e709cbdSnorby t = &table[i];
2478e709cbdSnorby if (t->value)
2486be5843eStedu res->action = t->value;
2498e709cbdSnorby }
2508e709cbdSnorby break;
2518e709cbdSnorby
2528e709cbdSnorby case ENDTOKEN:
2538e709cbdSnorby break;
2548e709cbdSnorby }
2558e709cbdSnorby }
2568e709cbdSnorby
2578e709cbdSnorby if (match != 1) {
2588e709cbdSnorby if (word == NULL)
2598e709cbdSnorby fprintf(stderr, "missing argument:\n");
2608e709cbdSnorby else if (match > 1)
2618e709cbdSnorby fprintf(stderr, "ambiguous argument: %s\n", word);
2628e709cbdSnorby else if (match < 1)
2638e709cbdSnorby fprintf(stderr, "unknown argument: %s\n", word);
2648e709cbdSnorby return (NULL);
2658e709cbdSnorby }
2668e709cbdSnorby
2678e709cbdSnorby return (t);
2688e709cbdSnorby }
2698e709cbdSnorby
2706be5843eStedu static void
show_valid_args(const struct token * table)2714b80bbd0Sjsg show_valid_args(const struct token *table)
2728e709cbdSnorby {
2738e709cbdSnorby int i;
2748e709cbdSnorby
2758e709cbdSnorby for (i = 0; table[i].type != ENDTOKEN; i++) {
2768e709cbdSnorby switch (table[i].type) {
2778e709cbdSnorby case NOTOKEN:
2788e709cbdSnorby fprintf(stderr, " <cr>\n");
2798e709cbdSnorby break;
2808e709cbdSnorby case KEYWORD:
2818e709cbdSnorby case FLAG:
2828e709cbdSnorby fprintf(stderr, " %s\n", table[i].keyword);
2838e709cbdSnorby break;
2848e709cbdSnorby case ADDRESS:
2858e709cbdSnorby fprintf(stderr, " <address>\n");
2868e709cbdSnorby break;
28796950f83Sremi case AREA:
28896950f83Sremi fprintf(stderr, " <area>\n");
28996950f83Sremi break;
2908e709cbdSnorby case PREFIX:
2918e709cbdSnorby fprintf(stderr, " <address>[/<len>]\n");
2928e709cbdSnorby break;
2938e709cbdSnorby case IFNAME:
2948e709cbdSnorby fprintf(stderr, " <interface>\n");
295c5ba8b41Sderaadt break;
2968e709cbdSnorby case ENDTOKEN:
2978e709cbdSnorby break;
2988e709cbdSnorby }
2998e709cbdSnorby }
3008e709cbdSnorby }
3018e709cbdSnorby
3020104e403Sclaudio /* XXX shared with parse.y should be merged */
3038e709cbdSnorby int
parse_addr(const char * word,struct in6_addr * addr)3040104e403Sclaudio parse_addr(const char *word, struct in6_addr *addr)
3058e709cbdSnorby {
3060104e403Sclaudio struct addrinfo hints, *r;
3078e709cbdSnorby
3088e709cbdSnorby if (word == NULL)
3098e709cbdSnorby return (0);
3108e709cbdSnorby
3110104e403Sclaudio bzero(addr, sizeof(struct in6_addr));
3120104e403Sclaudio bzero(&hints, sizeof(hints));
3130104e403Sclaudio hints.ai_family = AF_INET6;
3140104e403Sclaudio hints.ai_socktype = SOCK_DGRAM; /*dummy*/
3150104e403Sclaudio hints.ai_flags = AI_NUMERICHOST;
3160104e403Sclaudio if (getaddrinfo(word, "0", &hints, &r) == 0) {
3170104e403Sclaudio *addr = ((struct sockaddr_in6 *)r->ai_addr)->sin6_addr;
3180104e403Sclaudio /* XXX address scope !!! */
3190104e403Sclaudio /* ((struct sockaddr_in6 *)r->ai_addr)->sin6_scope_id */
3200104e403Sclaudio freeaddrinfo(r);
3218e709cbdSnorby return (1);
3228e709cbdSnorby }
3238e709cbdSnorby return (0);
3248e709cbdSnorby }
3258e709cbdSnorby
32696950f83Sremi int
parse_area(const char * word,struct in_addr * addr)32796950f83Sremi parse_area(const char *word, struct in_addr *addr)
32896950f83Sremi {
32996950f83Sremi struct in_addr ina;
33096950f83Sremi const char *errstr;
33196950f83Sremi
33296950f83Sremi if (word == NULL)
33396950f83Sremi return (0);
33496950f83Sremi
33596950f83Sremi bzero(addr, sizeof(struct in_addr));
33696950f83Sremi bzero(&ina, sizeof(ina));
33796950f83Sremi
33896950f83Sremi if (inet_pton(AF_INET, word, &ina)) {
33996950f83Sremi addr->s_addr = ina.s_addr;
34096950f83Sremi return (1);
34196950f83Sremi }
34296950f83Sremi
34396950f83Sremi ina.s_addr = htonl(strtonum(word, 0, 0xffffffff, &errstr));
34496950f83Sremi if (errstr == NULL) {
34596950f83Sremi addr->s_addr = ina.s_addr;
34696950f83Sremi return (1);
34796950f83Sremi }
34896950f83Sremi return (0);
34996950f83Sremi }
35096950f83Sremi
3510104e403Sclaudio /* XXX shared with parse.y should be merged */
3528e709cbdSnorby int
parse_prefix(const char * word,struct in6_addr * addr,u_int8_t * prefixlen)3530104e403Sclaudio parse_prefix(const char *word, struct in6_addr *addr, u_int8_t *prefixlen)
3548e709cbdSnorby {
3550104e403Sclaudio char *p, *ps;
3560104e403Sclaudio const char *errstr;
3570104e403Sclaudio int mask;
3588e709cbdSnorby
3598e709cbdSnorby if (word == NULL)
3608e709cbdSnorby return (0);
3618e709cbdSnorby
3620104e403Sclaudio if ((p = strrchr(word, '/')) != NULL) {
3630104e403Sclaudio mask = strtonum(p + 1, 0, 128, &errstr);
3640104e403Sclaudio if (errstr)
3650104e403Sclaudio errx(1, "invalid netmask: %s", errstr);
3668e709cbdSnorby
3670104e403Sclaudio if ((ps = malloc(strlen(word) - strlen(p) + 1)) == NULL)
3680104e403Sclaudio err(1, "parse_prefix: malloc");
3690104e403Sclaudio strlcpy(ps, word, strlen(word) - strlen(p) + 1);
3700104e403Sclaudio
3710104e403Sclaudio if (parse_addr(ps, addr) == 0) {
3720104e403Sclaudio free(ps);
3738e709cbdSnorby return (0);
3740104e403Sclaudio }
37523d867c2Stobias free(ps);
3760104e403Sclaudio
3770104e403Sclaudio inet6applymask(addr, addr, mask);
3780104e403Sclaudio *prefixlen = mask;
3798e709cbdSnorby return (1);
380c5ba8b41Sderaadt }
3810104e403Sclaudio *prefixlen = 128;
3828e709cbdSnorby return (parse_addr(word, addr));
3838e709cbdSnorby }
384