diff options
Diffstat (limited to 'usr.sbin/bgpctl/irr_parser.c')
-rw-r--r-- | usr.sbin/bgpctl/irr_parser.c | 395 |
1 files changed, 395 insertions, 0 deletions
diff --git a/usr.sbin/bgpctl/irr_parser.c b/usr.sbin/bgpctl/irr_parser.c new file mode 100644 index 00000000000..8d9e34a9e45 --- /dev/null +++ b/usr.sbin/bgpctl/irr_parser.c @@ -0,0 +1,395 @@ +/* $OpenBSD: irr_parser.c,v 1.1 2007/03/03 11:45:30 henning Exp $ */ + +/* + * Copyright (c) 2007 Henning Brauer <henning@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "irrfilter.h" + +#define PARSEBUF_INCREMENT 4096 + +int lineno; +char *parsebuf = NULL; +size_t parsebuflen = 0; + +void grow_parsebuf(void); +char *irr_getln(FILE *f); +int parse_policy(char *, char *); +int policy_additem(char *, struct policy_item *); +int parse_asset(char *, char *); +int parse_route(char *, char *); + +int +parse_response(FILE *f, enum qtype qtype) +{ + char *key, *val; + int cnt, n; + + lineno = 1; + cnt = 0; + while ((val = irr_getln(f)) != NULL) { + if (!strncmp(val, "%ERROR:101:", 11)) /* no entries found */ + return (0); + + if (val[0] == '%') { + warnx("message from whois server: %s", val); + return (-1); + } + + key = strsep(&val, ":"); + if (val == NULL) { + warnx("%u: %s", lineno, key); + warnx("no \":\" found!"); + return (-1); + } + while (ISWS(*val)) + val++; + + switch (qtype) { + case QTYPE_OWNAS: + if ((n = parse_policy(key, val)) == -1) + return (-1); + break; + case QTYPE_ASSET: + if ((n = parse_asset(key, val)) == -1) + return (-1); + break; + case QTYPE_ROUTE: + if ((n = parse_route(key, val)) == -1) + return (-1); + break; + default: + err(1, "king bula suffers from dementia"); + } + cnt += n; + } + + return (cnt); +} + +void +grow_parsebuf(void) +{ + char *p; + size_t newlen; + + newlen = parsebuflen + PARSEBUF_INCREMENT; + if ((p = realloc(parsebuf, newlen)) == NULL) + err(1, "grow_parsebuf realloc"); + parsebuf = p; + parsebuflen = newlen; + + if (0) + fprintf(stderr, "parsebuf now %lu bytes\n", (ulong)parsebuflen); +} + +char * +irr_getln(FILE *f) +{ + int c, next, last; + char *p; + + if (parsebuf == NULL) + grow_parsebuf(); + p = parsebuf; + last = -1; + + do { + c = getc(f); + + if (p == parsebuf) { /* beginning of new line */ + if (c == '%') { + next = getc(f); + switch (next) { + case ' ': /* comment. skip over */ + while ((c = getc(f)) != '\n' && + c != EOF) + ; /* nothing */ + break; + case '\n': + case EOF: + c = next; + break; + default: + ungetc(next, f); + break; + } + } + } + + if (c == '#') /* skip until \n */ + while ((c = getc(f)) != '\n' && c != EOF) + ; /* nothing */ + + if (c == '\n') { + lineno++; + next = getc(f); + if (next == '+') /* continuation, skip the + */ + c = getc(f); + else if (ISWS(next)) /* continuation */ + c = next; + else + ungetc(next, f); + } + + + if (c == '\n' || c == EOF) { + if (c == EOF) + if (ferror(f)) + err(1, "ferror"); + if (p > parsebuf) { + *p = '\0'; + return (parsebuf); + } + } else { + if (!(ISWS(c) && ISWS(last))) { + if (p + 1 >= parsebuf + parsebuflen - 1) { + size_t offset; + + offset = p - parsebuf; + grow_parsebuf(); + p = parsebuf + offset; + } + if (ISWS(c)) /* equal opportunity whitespace */ + *p++ = ' '; + else + *p++ = (char)c; + } + last = c; + } + } while (c != EOF); + + return (NULL); +} + +/* + * parse the policy from an aut-num object + */ + +enum policy_parser_st { + PO_NONE, + PO_PEER_KEY, + PO_PEER_AS, + PO_PEER_ADDR, + PO_RTR_KEY, + PO_RTR_ADDR, + PO_ACTION_KEY, + PO_ACTION_SPEC, + PO_FILTER_KEY, + PO_FILTER_SPEC +}; + +int +parse_policy(char *key, char *val) +{ + struct policy_item *pi; + enum pdir dir; + enum policy_parser_st st = PO_NONE, nextst; + char *tok, *router = NULL, *p; + + if (!strcmp(key, "import")) + dir = IMPORT; + else if (!strcmp(key, "export")) + dir = EXPORT; + else /* ignore! */ + return (0); + + if (dir == EXPORT && (irrflags & F_IMPORTONLY)) + return (0); + + if ((pi = calloc(1, sizeof(*pi))) == NULL) + err(1, "parse_policy calloc"); + pi->dir = dir; + + while ((tok = strsep(&val, " ")) != NULL) { + nextst = PO_NONE; + if (dir == IMPORT) { + if (!strcmp(tok, "from")) + nextst = PO_PEER_KEY; + else if (!strcmp(tok, "at")) + nextst = PO_RTR_KEY; + else if (!strcmp(tok, "action")) + nextst = PO_ACTION_KEY; + else if (!strcmp(tok, "accept")) + nextst = PO_FILTER_KEY; + } else if (dir == EXPORT) { + if (!strcmp(tok, "to")) + nextst = PO_PEER_KEY; + else if (!strcmp(tok, "at")) + nextst = PO_RTR_KEY; + else if (!strcmp(tok, "announce")) + nextst = PO_FILTER_KEY; + } + + if (nextst == PO_FILTER_KEY) /* rest is filter spec */ + if ((pi->filter = strdup(val)) == NULL) + err(1, NULL); + + if (nextst == PO_ACTION_KEY) { + /* action list. ends after last ; */ + p = strrchr(val, ';'); + if (p == NULL || !ISWS(*++p)) + errx(1, "syntax error in action spec"); + *p = '\0'; + if ((pi->action = strdup(val)) == NULL) + err(1, NULL); + val = ++p; + while (ISWS(*p)) + p++; + } + + switch (st) { + case PO_NONE: + if (nextst != PO_PEER_KEY) + goto ppoerr; + st = nextst; + break; + case PO_PEER_KEY: + if (pi->peer_as == NULL) { + if (nextst != PO_NONE) + goto ppoerr; + if ((pi->peer_as = strdup(tok)) == NULL) + err(1, NULL); + } else { + switch (nextst) { + case PO_NONE: + if (!strcasecmp(tok, "and") || + !strcasecmp(tok, "or") || + !strcasecmp(tok, "not")) + fprintf(stderr, "compound peering " + "statements are not supported"); + else /* peer address */ + if ((pi->peer_addr = strdup(tok)) == NULL) + err(1, NULL); + break; + case PO_RTR_KEY: + case PO_ACTION_KEY: + case PO_FILTER_KEY: + st = nextst; + break; + default: + goto ppoerr; + } + } + break; + case PO_PEER_AS: + case PO_PEER_ADDR: + err(1, "state error"); + break; + case PO_RTR_KEY: + if (nextst != PO_NONE) + goto ppoerr; + /* rtr address */ + if ((router = strdup(tok)) == NULL) + err(1, NULL); + st = PO_RTR_ADDR; + break; + case PO_RTR_ADDR: + if (nextst != PO_ACTION_KEY && + nextst != PO_FILTER_KEY) + goto ppoerr; + st = nextst; + break; + case PO_ACTION_KEY: + /* already handled, next must be FILTER_KEY */ + if (nextst != PO_FILTER_KEY) + goto ppoerr; + st = nextst; + break; + case PO_FILTER_KEY: + /* already handled */ + break; + case PO_ACTION_SPEC: + case PO_FILTER_SPEC: + err(1, "state error"); + break; + } + } + + if (st != PO_FILTER_KEY) + err(1, "state error"); + + if (policy_additem(router, pi) == -1) + return (-1); + + return (1); + +ppoerr: + free(pi); + fprintf(stderr, "%u: parse error\n", lineno); + return (-1); +} + +int +policy_additem(char *router, struct policy_item *pi) +{ + struct router *r; + + for (r = TAILQ_FIRST(&router_head); r != NULL && + strcmp(r->address, router); r = TAILQ_NEXT(r, entry)) + ; /* nothing */ + + if (r == NULL) { + if ((r = calloc(1, sizeof(*r))) == NULL || + (r->address = strdup(router)) == NULL) + err(1, NULL); + TAILQ_INIT(&r->policy_h); + TAILQ_INSERT_TAIL(&router_head, r, entry); + } + + TAILQ_INSERT_TAIL(&r->policy_h, pi, entry); + + return (0); +} + +/* + * parse as-set: get members + */ + +int +parse_asset(char *key, char *val) +{ + char *tok; + + if (strcmp(key, "members")) /* ignore everything else */ + return (0); + + while ((tok = strsep(&val, ",")) != NULL) { + EATWS(tok); + asset_addmember(tok); + } + + return (1); +} + +/* + * parse route obj: just get the prefix + */ +int +parse_route(char *key, char *val) +{ + if (strcmp(key, "route")) /* ignore everything else */ + return (0); + + return(prefixset_addmember(val)); +} |