From 502ece1df2ec10e9b6a48a1eeb249d0e0e2b83c5 Mon Sep 17 00:00:00 2001 From: claudio Date: Fri, 21 Sep 2018 04:55:27 +0000 Subject: [PATCH] Implement code to parse, print and reload roa-set tables. This is sharing a lot of code with prefixset which makes all a bit easier. A roa-set is defined like this: roa-set "test2" { 1.2.3.0/24 source-as 1, 1.2.8.0/22 maxlen 24 source-as 3 } No support for acting on this data yet. Put it in deraadt@, OK benno@, input and OK denis@ --- usr.sbin/bgpd/bgpd.c | 30 +++++++++- usr.sbin/bgpd/bgpd.h | 7 ++- usr.sbin/bgpd/config.c | 12 +++- usr.sbin/bgpd/parse.y | 112 ++++++++++++++++++++++++++++++++------ usr.sbin/bgpd/printconf.c | 33 ++++++++++- usr.sbin/bgpd/rde.c | 51 ++++++++++++++--- 6 files changed, 216 insertions(+), 29 deletions(-) diff --git a/usr.sbin/bgpd/bgpd.c b/usr.sbin/bgpd/bgpd.c index d422fe98467..108f636b48d 100644 --- a/usr.sbin/bgpd/bgpd.c +++ b/usr.sbin/bgpd/bgpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.c,v 1.200 2018/09/20 11:45:59 claudio Exp $ */ +/* $OpenBSD: bgpd.c,v 1.201 2018/09/21 04:55:27 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -516,6 +516,34 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct peer **peer_l) if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIXSETITEM, 0, 0, -1, psi, sizeof(*psi)) == -1) return (-1); + set_free(psi->set); + free(psi); + } + free(ps); + } + + /* roasets for filters in the RDE */ + while ((ps = SIMPLEQ_FIRST(conf->roasets)) != NULL) { + SIMPLEQ_REMOVE_HEAD(conf->roasets, entry); + if (imsg_compose(ibuf_rde, IMSG_RECONF_ROA_SET, 0, 0, -1, + ps->name, sizeof(ps->name)) == -1) + return (-1); + RB_FOREACH_SAFE(psi, prefixset_tree, &ps->psitems, npsi) { + u_int32_t *as; + size_t i, l, n; + RB_REMOVE(prefixset_tree, &ps->psitems, psi); + as = set_get(psi->set, &n); + for (i = 0; i < n; i += l) { + l = (n - i > 1024 ? 1024 : n - i); + if (imsg_compose(ibuf_rde, + IMSG_RECONF_ROA_AS_SET_ITEMS, + 0, 0, -1, as + i, l) == -1) + return -1; + } + if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIXSETITEM, 0, + 0, -1, psi, sizeof(*psi)) == -1) + return (-1); + set_free(psi->set); free(psi); } free(ps); diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index 509589bb66b..3f7e61ffcd7 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.343 2018/09/20 11:45:59 claudio Exp $ */ +/* $OpenBSD: bgpd.h,v 1.344 2018/09/21 04:55:27 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -229,7 +229,9 @@ struct bgpd_config { struct listen_addrs *listen_addrs; struct mrt_head *mrt; struct prefixset_head *prefixsets; + struct prefixset_head *roasets; struct rde_prefixset_head *rde_prefixsets; + struct rde_prefixset_head *rde_roasets; struct as_set_head *as_sets; char *csock; char *rcsock; @@ -431,6 +433,8 @@ enum imsg_type { IMSG_RECONF_AS_SET, IMSG_RECONF_AS_SET_ITEMS, IMSG_RECONF_AS_SET_DONE, + IMSG_RECONF_ROA_SET, + IMSG_RECONF_ROA_AS_SET_ITEMS, IMSG_RECONF_DONE, IMSG_UPDATE, IMSG_UPDATE_ERR, @@ -961,6 +965,7 @@ struct roa_set { struct prefixset_item { struct filter_prefix p; RB_ENTRY(prefixset_item) entry; + struct set_table *set; }; RB_HEAD(prefixset_tree, prefixset_item); diff --git a/usr.sbin/bgpd/config.c b/usr.sbin/bgpd/config.c index b34d7aaec5e..60c2d86d08f 100644 --- a/usr.sbin/bgpd/config.c +++ b/usr.sbin/bgpd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.74 2018/09/20 07:46:39 claudio Exp $ */ +/* $OpenBSD: config.c,v 1.75 2018/09/21 04:55:27 claudio Exp $ */ /* * Copyright (c) 2003, 2004, 2005 Henning Brauer @@ -67,6 +67,8 @@ new_config(void) if ((conf->prefixsets = calloc(1, sizeof(struct prefixset_head))) == NULL) fatal(NULL); + if ((conf->roasets = calloc(1, sizeof(struct prefixset_head))) == NULL) + fatal(NULL); if ((conf->as_sets = calloc(1, sizeof(struct as_set_head))) == NULL) fatal(NULL); if ((conf->filters = calloc(1, sizeof(struct filter_head))) == NULL) @@ -81,6 +83,7 @@ new_config(void) TAILQ_INIT(&conf->networks); SIMPLEQ_INIT(&conf->rdomains); SIMPLEQ_INIT(conf->prefixsets); + SIMPLEQ_INIT(conf->roasets); SIMPLEQ_INIT(conf->as_sets); TAILQ_INIT(conf->filters); @@ -129,6 +132,7 @@ free_prefixsets(struct prefixset_head *psh) ps = SIMPLEQ_FIRST(psh); RB_FOREACH_SAFE(psi, prefixset_tree, &ps->psitems, npsi) { RB_REMOVE(prefixset_tree, &ps->psitems, psi); + set_free(psi->set); free(psi); } SIMPLEQ_REMOVE_HEAD(psh, entry); @@ -147,6 +151,7 @@ free_config(struct bgpd_config *conf) free_networks(&conf->networks); filterlist_free(conf->filters); free_prefixsets(conf->prefixsets); + free_prefixsets(conf->roasets); as_sets_free(conf->as_sets); while ((la = TAILQ_FIRST(conf->listen_addrs)) != NULL) { @@ -225,6 +230,11 @@ merge_config(struct bgpd_config *xconf, struct bgpd_config *conf, xconf->prefixsets = conf->prefixsets; conf->prefixsets = NULL; + /* switch the roasets, first remove the old ones */ + free_prefixsets(xconf->roasets); + xconf->roasets = conf->roasets; + conf->roasets = NULL; + /* switch the as_sets, first remove the old ones */ as_sets_free(xconf->as_sets); xconf->as_sets = conf->as_sets; diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index 91b1e4796c6..931fa057468 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.355 2018/09/20 11:45:59 claudio Exp $ */ +/* $OpenBSD: parse.y,v 1.356 2018/09/21 04:55:27 claudio Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer @@ -93,6 +93,7 @@ static struct peer *curpeer; static struct peer *curgroup; static struct rdomain *currdom; static struct prefixset *curpset; +static struct prefixset *curroaset; static struct filter_head *filter_l; static struct filter_head *peerfilter_l; static struct filter_head *groupfilter_l; @@ -162,7 +163,8 @@ int parseextcommunity(struct filter_extcommunity *, char *, static int new_as_set(char *); static void add_as_set(u_int32_t); static void done_as_set(void); -static int new_prefix_set(char *); +static struct prefixset *new_prefix_set(char *, int); +static void add_roa_set(struct prefixset_item *, u_int32_t, u_int8_t); typedef struct { union { @@ -211,7 +213,7 @@ typedef struct { %token FROM TO ANY %token CONNECTED STATIC %token COMMUNITY EXTCOMMUNITY LARGECOMMUNITY DELETE -%token PREFIX PREFIXLEN PREFIXSET +%token PREFIX PREFIXLEN PREFIXSET ROASET %token ASSET SOURCEAS TRANSITAS PEERAS MAXASLEN MAXASSEQ %token SET LOCALPREF MED METRIC NEXTHOP REJECT BLACKHOLE NOMODIFY SELF %token PREPEND_SELF PREPEND_PEER PFTABLE WEIGHT RTLABEL ORIGIN PRIORITY @@ -250,6 +252,7 @@ grammar : /* empty */ | grammar include '\n' | grammar as_set '\n' | grammar prefixset '\n' + | grammar roa_set '\n' | grammar conf_main '\n' | grammar rdomain '\n' | grammar neighbor '\n' @@ -423,7 +426,7 @@ as_set_l : as4number_any { add_as_set($1); } | as_set_l comma as4number_any { add_as_set($3); } prefixset : PREFIXSET STRING '{' optnl { - if (new_prefix_set($2) != 0) { + if ((curpset = new_prefix_set($2, 0)) == NULL) { free($2); YYERROR; } @@ -433,7 +436,7 @@ prefixset : PREFIXSET STRING '{' optnl { curpset = NULL; } | PREFIXSET STRING '{' optnl '}' { - if (new_prefix_set($2) != 0) { + if ((curpset = new_prefix_set($2, 0)) == NULL) { free($2); YYERROR; } @@ -487,6 +490,47 @@ prefixset_item : prefix prefixlenop { } ; +roa_set : ROASET STRING '{' optnl { + if ((curroaset = new_prefix_set($2, 1)) == NULL) { + free($2); + YYERROR; + } + free($2); + } roa_set_l optnl '}' { + SIMPLEQ_INSERT_TAIL(conf->roasets, curroaset, entry); + curroaset = NULL; + } + | ROASET STRING '{' optnl '}' { + if ((curroaset = new_prefix_set($2, 1)) == NULL) { + free($2); + YYERROR; + } + free($2); + SIMPLEQ_INSERT_TAIL(conf->roasets, curroaset, entry); + curroaset = NULL; + } + ; + +roa_set_l : prefixset_item SOURCEAS as4number_any { + if ($1->p.len_min != $1->p.len) { + yyerror("unsupported prefixlen operation in " + "roa-set"); + free($1); + YYERROR; + } + add_roa_set($1, $3, $1->p.len_max); + } + | roa_set_l comma prefixset_item SOURCEAS as4number_any { + if ($3->p.len_min != $3->p.len) { + yyerror("unsupported prefixlen operation in " + "roa-set"); + free($3); + YYERROR; + } + add_roa_set($3, $5, $3->p.len_max); + } + ; + conf_main : AS as4number { conf->as = $2; if ($2 > USHRT_MAX) @@ -2768,6 +2812,7 @@ lookup(char *s) { "restart", RESTART}, { "restricted", RESTRICTED}, { "rib", RIB}, + { "roa-set", ROASET }, { "route-collector", ROUTECOLL}, { "route-reflector", REFLECTOR}, { "router-id", ROUTERID}, @@ -4230,21 +4275,52 @@ done_as_set(void) curset = NULL; } -static int -new_prefix_set(char *name) +static struct prefixset * +new_prefix_set(char *name, int is_roa) { - if (find_prefixset(name, conf->prefixsets) != NULL) { - yyerror("prefix-set \"%s\" already exists", name); - return -1; + const char *type = "prefix-set"; + struct prefixset_head *sets = conf->prefixsets; + struct prefixset *pset; + + if (is_roa) { + type = "roa-set"; + sets = conf->roasets; + } + + if (find_prefixset(name, sets) != NULL) { + yyerror("%s \"%s\" already exists", type, name); + return NULL; } - if ((curpset = calloc(1, sizeof(*curpset))) == NULL) + if ((pset = calloc(1, sizeof(*pset))) == NULL) fatal("prefixset"); - if (strlcpy(curpset->name, name, sizeof(curpset->name)) >= - sizeof(curpset->name)) { - yyerror("prefix-set \"%s\" too long: max %zu", - name, sizeof(curpset->name) - 1); - return -1; + if (strlcpy(pset->name, name, sizeof(pset->name)) >= + sizeof(pset->name)) { + yyerror("%s \"%s\" too long: max %zu", type, + name, sizeof(pset->name) - 1); + free(pset); + return NULL; } - RB_INIT(&curpset->psitems); - return 0; + RB_INIT(&pset->psitems); + return pset; +} + +static void +add_roa_set(struct prefixset_item *npsi, u_int32_t as, u_int8_t max) +{ + struct prefixset_item *psi; + struct roa_set rs; + + /* no prefixlen option on this tree */ + npsi->p.len_max = npsi->p.len_min = npsi->p.len; + psi = RB_INSERT(prefixset_tree, &curroaset->psitems, npsi); + if (psi == NULL) + psi = npsi; + + if (psi->set == NULL) + if ((psi->set = set_new(1, sizeof(rs))) == NULL) + fatal("set_new"); + rs.as = as; + rs.maxlen = max; + if (set_add(psi->set, &rs, 1) != 0) + fatal("as_set_new"); } diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c index d4648c1b4a7..451a50bf686 100644 --- a/usr.sbin/bgpd/printconf.c +++ b/usr.sbin/bgpd/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.121 2018/09/20 11:45:59 claudio Exp $ */ +/* $OpenBSD: printconf.c,v 1.122 2018/09/21 04:55:27 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -42,6 +42,7 @@ const char *print_af(u_int8_t); void print_network(struct network_config *, const char *); void print_as_sets(struct as_set_head *); void print_prefixsets(struct prefixset_head *); +void print_roasets(struct prefixset_head *); void print_peer(struct peer_config *, struct bgpd_config *, const char *); const char *print_auth_alg(u_int8_t); @@ -485,6 +486,35 @@ print_prefixsets(struct prefixset_head *psh) } } +void +print_roasets(struct prefixset_head *psh) +{ + struct prefixset *ps; + struct prefixset_item *psi; + struct roa_set *rs; + size_t i, n; + + SIMPLEQ_FOREACH(ps, psh, entry) { + int count = 0; + printf("roa-set \"%s\" {", ps->name); + RB_FOREACH(psi, prefixset_tree, &ps->psitems) { + rs = set_get(psi->set, &n); + for (i = 0; i < n; i++) { + if (count++ % 2 == 0) + printf("\n\t"); + else + printf(", "); + + print_prefix(&psi->p); + if (psi->p.len != rs[i].maxlen) + printf(" maxlen %u", rs[i].maxlen); + printf(" source-as %u", rs[i].as); + } + } + printf("\n}\n\n"); + } +} + void print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c) { @@ -891,6 +921,7 @@ print_config(struct bgpd_config *conf, struct rib_names *rib_l, print_mainconf(conf); print_prefixsets(conf->prefixsets); print_as_sets(conf->as_sets); + print_roasets(conf->roasets); TAILQ_FOREACH(n, net_l, entry) print_network(&n->net, ""); if (!SIMPLEQ_EMPTY(rdom_l)) diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c index 39ccae7a0d2..23081362d3f 100644 --- a/usr.sbin/bgpd/rde.c +++ b/usr.sbin/bgpd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.425 2018/09/20 11:45:59 claudio Exp $ */ +/* $OpenBSD: rde.c,v 1.426 2018/09/21 04:55:27 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -131,6 +131,7 @@ time_t reloadtime; struct rde_peer_head peerlist; struct rde_peer *peerself; struct rde_prefixset_head *prefixsets_tmp, *prefixsets_old; +struct rde_prefixset_head *roasets_tmp, *roasets_old; struct as_set_head *as_sets_tmp, *as_sets_old; struct filter_head *out_rules, *out_rules_tmp; struct rdomain_head *rdomains_l, *newdomains; @@ -689,6 +690,7 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf) { static struct rde_prefixset *last_prefixset; static struct as_set *last_as_set; + static struct set_table *last_set; static struct rdomain *rd; struct imsg imsg; struct mrt xmrt; @@ -702,7 +704,7 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf) struct prefixset_item psi; char *name; size_t nmemb; - int n, fd; + int n, fd, rv; u_int16_t rid; while (ibuf) { @@ -774,6 +776,11 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf) if (prefixsets_tmp == NULL) fatal(NULL); SIMPLEQ_INIT(prefixsets_tmp); + roasets_tmp = calloc(1, + sizeof(struct rde_prefixset_head)); + if (roasets_tmp == NULL) + fatal(NULL); + SIMPLEQ_INIT(roasets_tmp); as_sets_tmp = calloc(1, sizeof(struct as_set_head)); if (as_sets_tmp == NULL) @@ -877,6 +884,7 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf) TAILQ_INSERT_TAIL(out_rules_tmp, r, entry); break; case IMSG_RECONF_PREFIXSET: + case IMSG_RECONF_ROA_SET: if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(ps->name)) fatalx("IMSG_RECONF_PREFIXSET bad len"); @@ -884,9 +892,22 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf) if (ps == NULL) fatal(NULL); memcpy(ps->name, imsg.data, sizeof(ps->name)); - SIMPLEQ_INSERT_TAIL(prefixsets_tmp, ps, entry); + if (imsg.hdr.type == IMSG_RECONF_ROA_SET) { + SIMPLEQ_INSERT_TAIL(roasets_tmp, ps, entry); + ps->roa = 1; + last_set = set_new(1, sizeof(struct roa_set)); + if (last_set == NULL) + fatal(NULL); + } else + SIMPLEQ_INSERT_TAIL(prefixsets_tmp, ps, entry); last_prefixset = ps; break; + case IMSG_RECONF_ROA_AS_SET_ITEMS: + nmemb = imsg.hdr.len - IMSG_HEADER_SIZE; + nmemb /= sizeof(struct roa_set); + if (set_add(last_set, imsg.data, nmemb) != 0) + fatal(NULL); + break; case IMSG_RECONF_PREFIXSETITEM: if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(psi)) @@ -894,11 +915,19 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf) memcpy(&psi, imsg.data, sizeof(psi)); if (last_prefixset == NULL) fatalx("King Bula has no prefixset"); - if (trie_add(&last_prefixset->th, &psi.p.addr, - psi.p.len, psi.p.len_min, psi.p.len_max) == -1) - log_warnx("trie_add(%s) %s/%u, %u-%u) failed", + if (last_prefixset->roa) { + set_prep(last_set); + rv = trie_roa_add(&last_prefixset->th, + &psi.p.addr, psi.p.len, last_set); + } else { + rv = trie_add(&last_prefixset->th, + &psi.p.addr, psi.p.len, + psi.p.len_min, psi.p.len_max); + } + if (rv == -1) + log_warnx("trie_add(%s) %s/%u) failed", last_prefixset->name, log_addr(&psi.p.addr), - psi.p.len, psi.p.len_min, psi.p.len_max); + psi.p.len); break; case IMSG_RECONF_AS_SET: if (imsg.hdr.len - IMSG_HEADER_SIZE != @@ -2795,6 +2824,7 @@ rde_reload_done(void) } prefixsets_old = conf->rde_prefixsets; + roasets_old = conf->rde_roasets; as_sets_old = conf->as_sets; memcpy(conf, nconf, sizeof(struct bgpd_config)); @@ -2802,6 +2832,7 @@ rde_reload_done(void) conf->csock = NULL; conf->rcsock = NULL; conf->prefixsets = NULL; + conf->roasets = NULL; free(nconf); nconf = NULL; @@ -2826,11 +2857,15 @@ rde_reload_done(void) /* XXX WHERE IS THE SYNC ??? */ rde_mark_prefixsets_dirty(prefixsets_old, prefixsets_tmp); + rde_mark_prefixsets_dirty(roasets_old, roasets_tmp); as_sets_mark_dirty(as_sets_old, as_sets_tmp); /* swap the prefixsets */ conf->rde_prefixsets = prefixsets_tmp; prefixsets_tmp = NULL; + /* the roa-sets */ + conf->rde_roasets = roasets_tmp; + roasets_tmp = NULL; /* and the as_sets */ conf->as_sets = as_sets_tmp; as_sets_tmp = NULL; @@ -3022,6 +3057,8 @@ rde_softreconfig_done(void) rde_free_prefixsets(prefixsets_old); prefixsets_old = NULL; + rde_free_prefixsets(roasets_old); + roasets_old = NULL; as_sets_free(as_sets_old); as_sets_old = NULL; -- 2.20.1