diff options
-rw-r--r-- | usr.sbin/bgpctl/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/bgpctl/bgpctl.c | 11 | ||||
-rw-r--r-- | usr.sbin/bgpctl/irr_asset.c | 234 | ||||
-rw-r--r-- | usr.sbin/bgpctl/irr_output.c | 183 | ||||
-rw-r--r-- | usr.sbin/bgpctl/irr_parser.c | 395 | ||||
-rw-r--r-- | usr.sbin/bgpctl/irr_prefix.c | 102 | ||||
-rw-r--r-- | usr.sbin/bgpctl/irrfilter.c | 52 | ||||
-rw-r--r-- | usr.sbin/bgpctl/irrfilter.h | 96 | ||||
-rw-r--r-- | usr.sbin/bgpctl/parser.c | 16 | ||||
-rw-r--r-- | usr.sbin/bgpctl/parser.h | 5 | ||||
-rw-r--r-- | usr.sbin/bgpctl/whois.c | 149 |
11 files changed, 1241 insertions, 6 deletions
diff --git a/usr.sbin/bgpctl/Makefile b/usr.sbin/bgpctl/Makefile index 0ed3be67547..71ace1ba13f 100644 --- a/usr.sbin/bgpctl/Makefile +++ b/usr.sbin/bgpctl/Makefile @@ -1,9 +1,11 @@ -# $OpenBSD: Makefile,v 1.8 2006/11/26 11:31:12 deraadt Exp $ +# $OpenBSD: Makefile,v 1.9 2007/03/03 11:45:30 henning Exp $ .PATH: ${.CURDIR}/../bgpd PROG= bgpctl SRCS= bgpctl.c parser.c buffer.c imsg.c util.c +SRCS+= irrfilter.c whois.c irr_asset.c irr_prefix.c irr_output.c +SRCS+= irr_parser.c CFLAGS+= -Wall CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes CFLAGS+= -Wmissing-declarations diff --git a/usr.sbin/bgpctl/bgpctl.c b/usr.sbin/bgpctl/bgpctl.c index adfb300fc51..768c4e680d8 100644 --- a/usr.sbin/bgpctl/bgpctl.c +++ b/usr.sbin/bgpctl/bgpctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpctl.c,v 1.115 2007/02/22 08:38:19 henning Exp $ */ +/* $OpenBSD: bgpctl.c,v 1.116 2007/03/03 11:45:30 henning Exp $ */ /* * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> @@ -36,6 +36,7 @@ #include "rde.h" #include "log.h" #include "parser.h" +#include "irrfilter.h" enum neighbor_views { NV_DEFAULT, @@ -102,10 +103,11 @@ main(int argc, char *argv[]) struct parse_result *res; struct ctl_neighbor neighbor; struct ctl_show_rib_request ribreq; - char *sockname; + char *sockname, *outdir; enum imsg_type type; sockname = SOCKET_NAME; + outdir = getcwd(NULL, 0); while ((ch = getopt(argc, argv, "ns:")) != -1) { switch (ch) { case 'n': @@ -126,6 +128,9 @@ main(int argc, char *argv[]) if ((res = parse(argc, argv)) == NULL) exit(1); + if (res->action == IRRFILTER) + irr_main(res->as.as, res->flags, outdir); + memcpy(&neighbor.addr, &res->peeraddr, sizeof(neighbor.addr)); strlcpy(neighbor.descr, res->peerdesc, sizeof(neighbor.descr)); @@ -147,6 +152,7 @@ main(int argc, char *argv[]) switch (res->action) { case NONE: + case IRRFILTER: usage(); /* not reached */ case SHOW: @@ -352,6 +358,7 @@ main(int argc, char *argv[]) case NETWORK_ADD: case NETWORK_REMOVE: case NETWORK_FLUSH: + case IRRFILTER: break; } imsg_free(&imsg); diff --git a/usr.sbin/bgpctl/irr_asset.c b/usr.sbin/bgpctl/irr_asset.c new file mode 100644 index 00000000000..0cf54557a49 --- /dev/null +++ b/usr.sbin/bgpctl/irr_asset.c @@ -0,0 +1,234 @@ +/* $OpenBSD: irr_asset.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" + +int as_set_compare(struct as_set *, struct as_set *); +struct as_set *as_set_find(char *); + +RB_HEAD(as_set_h, as_set) as_set_h; +RB_PROTOTYPE(as_set_h, as_set, entry, as_set_compare) +RB_GENERATE(as_set_h, as_set, entry, as_set_compare) + +struct as_set *curass; + +struct as_set *asset_get(char *); +void asset_resolve(struct as_set *); +int asset_merge(struct as_set *, struct as_set *); +int asset_add_as(struct as_set *, char *); +int asset_add_asset(struct as_set *, char *); + +struct as_set * +asset_expand(char *name) +{ + struct as_set *ass; + + ass = asset_get(name); + asset_resolve(ass); + + return (ass); +} + +struct as_set * +asset_get(char *name) +{ + struct as_set *ass, *mas; + u_int i; + int r; + + + /* + * the caching prevents the endless recursion. + * MUST have the RB_INSERT before calling self again. + */ + + /* cached? then things are easy */ + if ((ass = as_set_find(name)) != NULL) + return ass; + + if ((ass = calloc(1, sizeof(*ass))) == NULL) + err(1, "expand_as_set calloc"); + if ((ass->name = strdup(name)) == NULL) + err(1, "expand_as_set strdup"); + RB_INSERT(as_set_h, &as_set_h, ass); + + curass = ass; + if ((r = whois(name, QTYPE_ASSET)) == -1) + errx(1, "whois error, asset_get %s", name); + curass = NULL; + + /* + * if there are no members, this is an aut-num. + * if thsi was specified directly in the policy, + * make a dummy as-set with the the AS as name + * and its only member */ + if (ass->n_members == 0) + asset_add_as(ass, name); + + for (i = 0; i < ass->n_members; i++) { + mas = asset_get(ass->members[i]); + if (mas->n_members == 0) + asset_add_as(ass, ass->members[i]); + else + asset_add_asset(ass, ass->members[i]); + } + + return (ass); +} + +void +asset_resolve(struct as_set *ass) +{ + struct as_set *mas; + u_int i; + + /* + * traverse all as_set members and fold their + * members as into this as_set. + * ass->n_as_set is a moving target, it grows + * as member as-sets' member as-sets are beeing + * added. + * remove processed member as-sets (all!) only + * after we are done, they're needed for dupe + * detection + */ + + for (i = 0; i < ass->n_as_set; i++) { + if ((mas = as_set_find(ass->as_set[i])) == NULL) + errx(1, "asset_get %s: %s unresolved?!?", + ass->name, ass->as_set[i]); + if (asset_merge(ass, mas) == -1) + errx(1, "asset_merge failed"); + } + + for (i = 0; i < ass->n_as_set; i++) { + free(ass->as_set[i]); + ass->as_set[i] = NULL; + } + free(ass->as_set); + ass->as_set = NULL; + ass->n_as_set = 0; +} + +int +asset_merge(struct as_set *ass, struct as_set *mas) +{ + u_int i, j; + + /* merge ASes from the member into the parent */ + for (i = 0; i < mas->n_as; i++) { + for (j = 0; j < ass->n_as && strcmp(ass->as[j], + mas->as[i]); j++) + ; /* nothing */ + if (j == ass->n_as) + if (asset_add_as(ass, mas->as[i]) == -1) + return (-1); + } + + /* merge as-set members from the member into the parent */ + for (i = 0; i < mas->n_as_set; i++) { + if (!strcmp(ass->name, mas->as_set[i])) /* skip self! */ + continue; + for (j = 0; j < ass->n_as_set && strcmp(ass->as_set[j], + mas->as_set[i]); j++) + ; /* nothing */ + if (j == ass->n_as_set) + if (asset_add_asset(ass, mas->as_set[i]) == -1) + return (-1); + } + + return (0); +} + +int +asset_addmember(char *s) +{ + void *p; + + if ((p = realloc(curass->members, + (curass->n_members + 1) * sizeof(char *))) == NULL) + err(1, "asset_addmember strdup"); + curass->members = p; + curass->n_members++; + + if ((curass->members[curass->n_members - 1] = + strdup(s)) == NULL) + err(1, "asset_addmember strdup"); + + return (0); +} + +int +asset_add_as(struct as_set *ass, char *s) +{ + void *p; + + if ((p = realloc(ass->as, + (ass->n_as + 1) * sizeof(char *))) == NULL) + err(1, "asset_add_as strdup"); + ass->as = p; + ass->n_as++; + + if ((ass->as[ass->n_as - 1] = + strdup(s)) == NULL) + err(1, "asset_add_as strdup"); + + return (0); +} + +int +asset_add_asset(struct as_set *ass, char *s) +{ + void *p; + + if ((p = realloc(ass->as_set, + (ass->n_as_set + 1) * sizeof(char *))) == NULL) + err(1, "asset_add_asset strdup"); + ass->as_set = p; + ass->n_as_set++; + + if ((ass->as_set[ass->n_as_set - 1] = + strdup(s)) == NULL) + err(1, "asset_add_asset strdup"); + + return (0); +} + +/* RB helpers */ +int +as_set_compare(struct as_set *a, struct as_set *b) +{ + return (strcmp(a->name, b->name)); +} + +struct as_set * +as_set_find(char *name) +{ + struct as_set s; + + s.name = name; + return (RB_FIND(as_set_h, &as_set_h, &s)); +} diff --git a/usr.sbin/bgpctl/irr_output.c b/usr.sbin/bgpctl/irr_output.c new file mode 100644 index 00000000000..b0503ca2d4a --- /dev/null +++ b/usr.sbin/bgpctl/irr_output.c @@ -0,0 +1,183 @@ +/* $OpenBSD: irr_output.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" + +int process_policies(struct policy_head *, char *); +void policy_prettyprint(FILE *, struct policy_item *); +void policy_torule(FILE *, struct policy_item *); +char *action_torule(char *); +void print_rule(FILE *, enum pdir, char *, char *, char *); + +int +write_filters(char *outpath) +{ + struct router *r; + int ret = 0; + + while ((r = TAILQ_FIRST(&router_head)) != NULL) { + TAILQ_REMOVE(&router_head, r, entry); + printf("\nRouter %s\n", r->address); + + if (process_policies(&r->policy_h, + r->address) == -1) + ret = -1; + + free(r->address); + free(r); + } + + return (ret); +} + +int +process_policies(struct policy_head *head, char *router) +{ + struct policy_item *pi; + + while ((pi = TAILQ_FIRST(head)) != NULL) { + TAILQ_REMOVE(head, pi, entry); + + policy_prettyprint(stdout, pi); + policy_torule(stdout, pi); + + free(pi->peer_as); + free(pi->peer_addr); + free(pi->action); + free(pi->filter); + free(pi); + } + + return (0); +} + +void +policy_prettyprint(FILE *fh, struct policy_item *pi) +{ + if (pi->dir == IMPORT) + fprintf(fh, "# import: from "); + else + fprintf(fh, "# export: to "); + fprintf(fh, "%s ", pi->peer_as); + if (pi->peer_addr) + fprintf(fh, "%s ", pi->peer_addr); + if (pi->action) + fprintf(fh, "action %s ", pi->action); + fprintf(fh, "%s %s\n", pi->dir == IMPORT ? "accept" : "announce", + pi->filter); +} + +void +policy_torule(FILE *fh, struct policy_item *pi) +{ + struct as_set *ass; + struct prefix_set *pfxs; + u_int i, j; + + if (pi->filter == NULL || !strcasecmp(pi->filter, "any")) + print_rule(fh, pi->dir, pi->peer_addr, pi->action, NULL); + else { + ass = asset_expand(pi->filter); + + for (i = 0; i < ass->n_as; i++) { + pfxs = prefixset_get(ass->as[i]); + printf("# prefixes from %s\n", ass->as[i]); + for (j = 0; j < pfxs->prefixcnt; j++) + print_rule(fh, pi->dir, pi->peer_addr, + pi->action, pfxs->prefix[j]); + } + } +} + +/* XXX should really be parsed earlier! */ +char * +action_torule(char *s) +{ + int cnt = 0; + char *key, *val, *pre, *buf, *tmp; + static char abuf[8192]; + char ebuf[2048]; + + if ((tmp = strdup(s)) == NULL) + err(1, "foo"); + abuf[0] = '\0'; + buf = abuf; + while ((val = strsep(&tmp, ";")) != NULL && *val) { + key = strsep(&val, "="); + if (key == NULL || val == NULL) + err(1, "format error in action spec\n"); + + EATWS(key); + EATWS(val); + + if (cnt++ == 0) + pre = " set {"; + else + pre = ","; + + if (!strcmp(key, "pref")) + snprintf(ebuf, sizeof(ebuf), + "%s localpref=%s", pre, val); + else if (!strcmp(key, "med")) + snprintf(ebuf, sizeof(ebuf), + "%s med=%s", pre, val); + else + warnx("unknown action key \"%s\"", key); + + strlcat(abuf, ebuf, sizeof(abuf)); + } + if (cnt > 0) + strlcat(abuf, " }", sizeof(abuf)); + + free(tmp); + return (abuf); +} + +void +print_rule(FILE *fh, enum pdir pdir, char *peerspec, char *actspec, + char *prefix) +{ + char *fmt = "allow quick %s %s%s%s%s\n"; + char *peer = "any"; + char *action = ""; + char *dir; + + if (pdir == IMPORT) + dir = "from"; + else + dir = "to"; + + if (peerspec) + peer = peerspec; + + if (actspec) + action = action_torule(actspec); + + if (prefix == NULL) + fprintf(fh, fmt, dir, peer, action, "", ""); + else + fprintf(fh, fmt, dir, peer, action, " prefix ", prefix); +} 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)); +} diff --git a/usr.sbin/bgpctl/irr_prefix.c b/usr.sbin/bgpctl/irr_prefix.c new file mode 100644 index 00000000000..d694ae09cf7 --- /dev/null +++ b/usr.sbin/bgpctl/irr_prefix.c @@ -0,0 +1,102 @@ +/* $OpenBSD: irr_prefix.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" + +int prefix_set_compare(struct prefix_set *, struct prefix_set *); +struct prefix_set + *prefix_set_find(char *); + +RB_HEAD(prefix_set_h, prefix_set) prefix_set_h; +RB_PROTOTYPE(prefix_set_h, prefix_set, entry, prefix_set_compare) +RB_GENERATE(prefix_set_h, prefix_set, entry, prefix_set_compare) + +struct prefix_set *curpfxs = NULL; + +struct prefix_set * +prefixset_get(char *as) +{ + struct prefix_set *pfxs; + int r; + + if ((pfxs = prefix_set_find(as)) != NULL) + return (pfxs); + + /* nothing found, resolve and store */ + if ((pfxs = calloc(1, sizeof(*pfxs))) == NULL) + err(1, "get_prefixset calloc"); + if ((pfxs->as = strdup(as)) == NULL) + err(1, "get_prefixset strdup"); + RB_INSERT(prefix_set_h, &prefix_set_h, pfxs); + + curpfxs = pfxs; + if ((r = whois(as, QTYPE_ROUTE)) == -1) + errx(1, "whois error, prefixset_get %s", as); + curpfxs = NULL; + + return (pfxs); +} + +int +prefixset_addmember(char *s) +{ + void *p; + u_int i; + + /* yes, there are dupes... e. g. from multiple sources */ + for (i = 0; i < curpfxs->prefixcnt; i++) + if (!strcmp(curpfxs->prefix[i], s)) + return (0); + + if ((p = realloc(curpfxs->prefix, + (curpfxs->prefixcnt + 1) * sizeof(char *))) == NULL) + err(1, "prefixset_addmember strdup"); + curpfxs->prefix = p; + curpfxs->prefixcnt++; + + if ((curpfxs->prefix[curpfxs->prefixcnt - 1] = + strdup(s)) == NULL) + err(1, "prefixset_addmember strdup"); + + return (1); +} + + +/* RB helpers */ +int +prefix_set_compare(struct prefix_set *a, struct prefix_set *b) +{ + return (strcmp(a->as, b->as)); +} + +struct prefix_set * +prefix_set_find(char *as) +{ + struct prefix_set s; + + s.as = as; + return (RB_FIND(prefix_set_h, &prefix_set_h, &s)); +} diff --git a/usr.sbin/bgpctl/irrfilter.c b/usr.sbin/bgpctl/irrfilter.c new file mode 100644 index 00000000000..203411d2d7c --- /dev/null +++ b/usr.sbin/bgpctl/irrfilter.c @@ -0,0 +1,52 @@ +/* $OpenBSD: irrfilter.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" + +__dead void +irr_main(u_int32_t AS, int flags, char *outdir) +{ + char *query; + int r; + + fprintf(stderr, "irrfilter for: %u\n", AS); + + irrflags = flags; + TAILQ_INIT(&router_head); + + /* send query for own AS, parse policy */ + if (asprintf(&query, "AS%u", AS) == -1) + err(1, "parse_policy asprintf"); + if ((r = whois(query, QTYPE_OWNAS)) == -1) + exit (1); + if (r == 0) + errx(1, "aut-num object %s not found", query); + free(query); + + write_filters(outdir); + + exit (0); +} diff --git a/usr.sbin/bgpctl/irrfilter.h b/usr.sbin/bgpctl/irrfilter.h new file mode 100644 index 00000000000..1cd55f7dce5 --- /dev/null +++ b/usr.sbin/bgpctl/irrfilter.h @@ -0,0 +1,96 @@ +/* $OpenBSD: irrfilter.h,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/queue.h> +#include <sys/tree.h> + +#define F_IMPORTONLY 0x01 /* skip export: items */ + +int irrflags; + +enum pdir { + PDIR_NONE, + IMPORT, + EXPORT +}; + +struct policy_item { + TAILQ_ENTRY(policy_item) entry; + enum pdir dir; + char *peer_as; + char *peer_addr; + char *action; + char *filter; +}; + +TAILQ_HEAD(policy_head, policy_item); + +struct router { + TAILQ_ENTRY(router) entry; + char *address; + struct policy_head policy_h; +}; + +TAILQ_HEAD(router_head, router) router_head; + +/* keep qtype and qtype_objs in whois.c in sync! */ +enum qtype { + QTYPE_NONE, + QTYPE_OWNAS, + QTYPE_ASSET, + QTYPE_ROUTE +}; + +struct as_set { + RB_ENTRY(as_set) entry; + char *name; + char **members; /* direct members */ + char **as_set; /* members as-set */ + char **as; /* members aut-num */ + u_int n_members; + u_int n_as_set; + u_int n_as; +}; + +struct prefix_set { + RB_ENTRY(prefix_set) entry; + char *as; + char **prefix; + u_int prefixcnt; +}; + +/* eat trailing and leading whitespace */ +#define ISWS(x) (x == ' ' || x == '\t') +#define EATWS(s) \ + do { \ + char *ps; \ + while (ISWS(*s)) \ + s++; \ + ps = s + strlen(s) - 1; \ + while (ps && ps >= s && ISWS(*ps)) \ + *ps-- = '\0'; \ + } while (0); + +__dead void irr_main(u_int32_t, int, char *); +int whois(const char *, enum qtype); +int parse_response(FILE *, enum qtype); +int write_filters(char *); +struct as_set *asset_expand(char *); +int asset_addmember(char *); +struct prefix_set *prefixset_get(char *); +int prefixset_addmember(char *); diff --git a/usr.sbin/bgpctl/parser.c b/usr.sbin/bgpctl/parser.c index caec5342bc0..1a066909c2e 100644 --- a/usr.sbin/bgpctl/parser.c +++ b/usr.sbin/bgpctl/parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.c,v 1.38 2007/02/22 08:38:19 henning Exp $ */ +/* $OpenBSD: parser.c,v 1.39 2007/03/03 11:45:30 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -28,6 +28,7 @@ #include <string.h> #include "parser.h" +#include "irrfilter.h" enum token_type { NOTOKEN, @@ -84,6 +85,8 @@ static const struct token t_pftable[]; static const struct token t_prepnbr[]; static const struct token t_prepself[]; static const struct token t_weight[]; +static const struct token t_irrfilter[]; +static const struct token t_irrfilter_opts[]; static const struct token t_main[] = { { KEYWORD, "reload", RELOAD, NULL}, @@ -91,6 +94,7 @@ static const struct token t_main[] = { { KEYWORD, "fib", FIB, t_fib}, { KEYWORD, "neighbor", NEIGHBOR, t_neighbor}, { KEYWORD, "network", NONE, t_network}, + { KEYWORD, "irrfilter", IRRFILTER, t_irrfilter}, { ENDTOKEN, "", NONE, NULL} }; @@ -271,6 +275,16 @@ static const struct token t_weight[] = { { ENDTOKEN, "", NONE, NULL} }; +static const struct token t_irrfilter[] = { + { ASNUM, "", NONE, t_irrfilter_opts}, + { ENDTOKEN, "", NONE, NULL} +}; + +static const struct token t_irrfilter_opts[] = { + { NOTOKEN, "", NONE, NULL}, + { FLAG, "importonly", F_IMPORTONLY, t_irrfilter_opts}, + { ENDTOKEN, "", NONE, NULL} +}; static struct parse_result res; diff --git a/usr.sbin/bgpctl/parser.h b/usr.sbin/bgpctl/parser.h index a2732c8d9b4..fa92508744b 100644 --- a/usr.sbin/bgpctl/parser.h +++ b/usr.sbin/bgpctl/parser.h @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.h,v 1.14 2006/08/23 08:21:11 claudio Exp $ */ +/* $OpenBSD: parser.h,v 1.15 2007/03/03 11:45:30 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -44,7 +44,8 @@ enum actions { NETWORK_ADD, NETWORK_REMOVE, NETWORK_FLUSH, - NETWORK_SHOW + NETWORK_SHOW, + IRRFILTER }; struct parse_result { diff --git a/usr.sbin/bgpctl/whois.c b/usr.sbin/bgpctl/whois.c new file mode 100644 index 00000000000..cecbf53e092 --- /dev/null +++ b/usr.sbin/bgpctl/whois.c @@ -0,0 +1,149 @@ +/* $OpenBSD: whois.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. + */ + +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "irrfilter.h" + +#define WHOIS_STDOPTS "-r -a" + +char *qtype_opts[] = { + "", + "-T aut-num", + "-K -T as-set", + "-K -T route -i origin" +}; + +char *server = "whois.ripe.net"; +char *port = "whois"; + +int +whois(const char *query, enum qtype qtype) +{ + FILE *sfw, *sfr; + int s, r = -1, error = 0, attempt, ret; + struct addrinfo hints, *res, *ai; + const char *reason = NULL; + char *fmt; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = 0; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(server, port, &hints, &res); + if (error) { + if (error == EAI_SERVICE) + warnx("%s: bad port", port); + else + warnx("%s: %s", server, gai_strerror(error)); + return (1); + } + + for (s = -1, ai = res; ai != NULL; ai = ai->ai_next) { + attempt = 0; + do { + attempt++; + if (s != -1) + close (s); + s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (s == -1) { + error = errno; + reason = "socket"; + } else + r = connect(s, ai->ai_addr, ai->ai_addrlen); + } while (r == -1 && errno == ETIMEDOUT && attempt <= 3); + + if (r == -1) { + error = errno; + reason = "connect"; + close(s); + s = -1; + continue; + } + if (s != -1) + break; /*okay*/ + } + freeaddrinfo(res); + + if (s == -1) { + if (reason) { + errno = error; + warn("%s: %s", server, reason); + } else + warn("unknown error in connection attempt"); + return (1); + } + + sfr = fdopen(s, "r"); + sfw = fdopen(s, "w"); + if (sfr == NULL || sfw == NULL) + err(1, "fdopen"); + fmt = "%s %s %s\r\n"; + fprintf(sfw, fmt, WHOIS_STDOPTS, qtype_opts[qtype], query); + fflush(sfw); + + if ((ret = parse_response(sfr, qtype)) == -1) + warnx("parse error, query=\"%s %s\"", qtype_opts[qtype], query); + + fclose(sfw); + fclose(sfr); + close(s); + return (ret); +} |