From 9ed42aa2b31afb7daccb8e3a9bfa6cc635e8f28d Mon Sep 17 00:00:00 2001 From: benno Date: Sat, 8 Sep 2018 15:25:27 +0000 Subject: [PATCH] implement or-longer filter op for prefix-sets. Allows one two write rules like deny from any prefix-set mynetworks or-longer ok claudio, feature discussed with job and deraadt --- usr.sbin/bgpd/bgpd.conf.5 | 19 ++++++++++--------- usr.sbin/bgpd/bgpd.h | 6 ++++-- usr.sbin/bgpd/parse.y | 27 ++++++++++++++++++++++++--- usr.sbin/bgpd/printconf.c | 4 +++- usr.sbin/bgpd/rde.h | 8 ++++---- usr.sbin/bgpd/rde_filter.c | 7 +++---- usr.sbin/bgpd/rde_trie.c | 23 +++++++++++++++++------ 7 files changed, 65 insertions(+), 29 deletions(-) diff --git a/usr.sbin/bgpd/bgpd.conf.5 b/usr.sbin/bgpd/bgpd.conf.5 index 29e97d37b91..d7fa470ed85 100644 --- a/usr.sbin/bgpd/bgpd.conf.5 +++ b/usr.sbin/bgpd/bgpd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: bgpd.conf.5,v 1.174 2018/09/07 10:59:16 claudio Exp $ +.\" $OpenBSD: bgpd.conf.5,v 1.175 2018/09/08 15:25:27 benno Exp $ .\" .\" Copyright (c) 2004 Claudio Jeker .\" Copyright (c) 2003, 2004 Henning Brauer @@ -16,7 +16,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: September 7 2018 $ +.Dd $Mdocdate: September 8 2018 $ .Dt BGPD.CONF 5 .Os .Sh NAME @@ -291,12 +291,6 @@ Log received and sent updates. .Pq Ic inet Ns | Ns Ic inet6 .Ic priority Ar number Op Ic set ...\& .Xc -.\" NOT IMPLEMENTED. DO WE WANT THIS? -.\" .It Xo -.\" .Ic network prefix-set -.\" .Ar name -.\" .Op Ic set ...\& -.\" .Xc Announce the specified network as belonging to our AS. If set to .Ic connected , @@ -1447,11 +1441,18 @@ is a shorthand for: .Ic prefix Ar address Ns Li / Ns Ar len Ic prexiflen Ic >= Ar len .Ed .Pp -.It Ic prefix-set Ar name +.It Ic prefix-set Ar name Op Ic or-longer This rule applies only to .Em UPDATES that match the given prefix-set .Ar name . +With +.Ic or-longer , +the +.Em UPDATES +will match any prefix in the prefix-set where +.Bd -literal -offset indent +.Ic address Ns Li / Ns Ar len Ic prexiflen Ic >= Ar len .Pp .It Ic quick If an diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index 4297a670d3a..0f4d1d088b4 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.336 2018/09/07 11:50:32 benno Exp $ */ +/* $OpenBSD: bgpd.h,v 1.337 2018/09/08 15:25:27 benno Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -353,7 +353,7 @@ enum network_type { NETWORK_CONNECTED, NETWORK_RTLABEL, NETWORK_MRTCLONE, - NETWORK_PRIORITY + NETWORK_PRIORITY, }; struct network_config { @@ -679,6 +679,8 @@ struct filter_aslen { #define PREFIXSET_FLAG_FILTER 0x01 #define PREFIXSET_FLAG_DIRTY 0x02 /* prefix-set changed at reload */ +#define PREFIXSET_FLAG_OPS 0x04 /* indiv. prefixes have prefixlenops */ +#define PREFIXSET_FLAG_LONGER 0x08 /* filter all prefixes with or-longer */ struct filter_prefixset { int flags; diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index 21fb38b57ca..7a9abf303fb 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.340 2018/09/08 12:29:19 claudio Exp $ */ +/* $OpenBSD: parse.y,v 1.341 2018/09/08 15:25:27 benno Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer @@ -2104,7 +2104,8 @@ filter_elm : filter_prefix_h { } fmopts.m.nexthop.flags = FILTER_NEXTHOP_NEIGHBOR; } - | PREFIXSET STRING { + | PREFIXSET STRING prefixlenop { + struct prefixset *ps; if (fmopts.prefix_l != NULL) { yyerror("\"prefix\" already specified, cannot " "be used with \"prefix-set\" in the same " @@ -2117,7 +2118,8 @@ filter_elm : filter_prefix_h { free($2); YYERROR; } - if ((find_prefixset($2, conf->prefixsets)) == NULL) { + if ((ps = find_prefixset($2, conf->prefixsets)) + == NULL) { yyerror("prefix-set not defined"); free($2); YYERROR; @@ -2129,6 +2131,25 @@ filter_elm : filter_prefix_h { free($2); YYERROR; } + if (!($3.op == OP_NONE || + ($3.op == OP_RANGE && + $3.len_min == -1 && $3.len_max == -1))) { + yyerror("prefix-sets can only use option " + "or-longer"); + free($2); + YYERROR; + } + if ($3.op == OP_RANGE && ps->sflags & PREFIXSET_FLAG_OPS) { + yyerror("prefix-set %s contains prefixlen " + "operators and cannot be used in with a " + "or-longer filter", ps->name); + free($2); + YYERROR; + } + if ($3.op == OP_RANGE && $3.len_min == -1 && + $3.len_min == -1) + fmopts.m.prefixset.flags |= + PREFIXSET_FLAG_LONGER; fmopts.m.prefixset.flags |= PREFIXSET_FLAG_FILTER; fmopts.m.prefixset.ps = NULL; free($2); diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c index d8b7cdde791..361ebed7c28 100644 --- a/usr.sbin/bgpd/printconf.c +++ b/usr.sbin/bgpd/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.113 2018/09/08 09:33:54 claudio Exp $ */ +/* $OpenBSD: printconf.c,v 1.114 2018/09/08 15:25:27 benno Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -685,6 +685,8 @@ print_rule(struct peer *peer_l, struct filter_rule *r) if (r->match.prefixset.flags & PREFIXSET_FLAG_FILTER) printf("prefix-set \"%s\" ", r->match.prefixset.name); + if (r->match.prefixset.flags & PREFIXSET_FLAG_LONGER) + printf("or-longer "); if (r->match.nexthop.flags) { if (r->match.nexthop.flags == FILTER_NEXTHOP_NEIGHBOR) diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h index c67e7cf660f..2d699c2481d 100644 --- a/usr.sbin/bgpd/rde.h +++ b/usr.sbin/bgpd/rde.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.h,v 1.188 2018/09/07 10:49:22 claudio Exp $ */ +/* $OpenBSD: rde.h,v 1.189 2018/09/08 15:25:27 benno Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker and @@ -581,10 +581,10 @@ int up_dump_mp_reach(u_char *, u_int16_t *, struct rde_peer *, u_int8_t); /* rde_trie.c */ -int trie_add(struct trie_head *, struct bgpd_addr *, u_int8_t, - u_int8_t, u_int8_t); +int trie_add(struct trie_head *, struct bgpd_addr *, u_int8_t, u_int8_t, + u_int8_t); void trie_free(struct trie_head *); -int trie_match(struct trie_head *, struct bgpd_addr *, u_int8_t); +int trie_match(struct trie_head *, struct bgpd_addr *, u_int8_t, int); void trie_dump(struct trie_head *); int trie_equal(struct trie_head *, struct trie_head *); diff --git a/usr.sbin/bgpd/rde_filter.c b/usr.sbin/bgpd/rde_filter.c index 4705cef5a55..04d7f13ab94 100644 --- a/usr.sbin/bgpd/rde_filter.c +++ b/usr.sbin/bgpd/rde_filter.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_filter.c,v 1.104 2018/09/07 16:45:23 benno Exp $ */ +/* $OpenBSD: rde_filter.c,v 1.105 2018/09/08 15:25:27 benno Exp $ */ /* * Copyright (c) 2004 Claudio Jeker @@ -478,7 +478,6 @@ rde_filter_match(struct filter_rule *f, struct rde_peer *peer, } /* - * XXX must be second to last because we unconditionally return here. * prefixset and prefix filter rules are mutual exclusive */ if (f->match.prefixset.flags != 0) { @@ -487,9 +486,9 @@ rde_filter_match(struct filter_rule *f, struct rde_peer *peer, pt_getaddr(p->re->prefix, prefix); plen = p->re->prefix->prefixlen; - if (f->match.prefixset.ps == NULL || - !trie_match(&f->match.prefixset.ps->th, prefix, plen)) + !trie_match(&f->match.prefixset.ps->th, prefix, plen, + (f->match.prefixset.flags & PREFIXSET_FLAG_LONGER))) return (0); } else if (f->match.prefix.addr.aid != 0) return (rde_prefix_match(&f->match.prefix, p)); diff --git a/usr.sbin/bgpd/rde_trie.c b/usr.sbin/bgpd/rde_trie.c index 31d9161bd0b..cbbc5060b97 100644 --- a/usr.sbin/bgpd/rde_trie.c +++ b/usr.sbin/bgpd/rde_trie.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_trie.c,v 1.3 2018/09/07 20:26:30 claudio Exp $ */ +/* $OpenBSD: rde_trie.c,v 1.4 2018/09/08 15:25:27 benno Exp $ */ /* * Copyright (c) 2018 Claudio Jeker @@ -397,7 +397,8 @@ trie_free(struct trie_head *th) } static int -trie_match_v4(struct trie_head *th, struct in_addr *prefix, u_int8_t plen) +trie_match_v4(struct trie_head *th, struct in_addr *prefix, u_int8_t plen, + int orlonger) { struct tentry_v4 *n; @@ -417,6 +418,10 @@ trie_match_v4(struct trie_head *th, struct in_addr *prefix, u_int8_t plen) if (n->addr.s_addr != mp.s_addr) break; /* off path, no match possible */ + /* the match covers all larger prefixlens */ + if (n->node && orlonger) + return 1; + /* plen is from 1 - 32 but the bitmask starts with 0 */ if (n->node && inet4isset(&n->plenmask, plen - 1)) return 1; /* prefixlen allowed, match */ @@ -433,7 +438,8 @@ trie_match_v4(struct trie_head *th, struct in_addr *prefix, u_int8_t plen) } static int -trie_match_v6(struct trie_head *th, struct in6_addr *prefix, u_int8_t plen) +trie_match_v6(struct trie_head *th, struct in6_addr *prefix, u_int8_t plen, + int orlonger) { struct tentry_v6 *n; @@ -453,6 +459,10 @@ trie_match_v6(struct trie_head *th, struct in6_addr *prefix, u_int8_t plen) if (memcmp(&n->addr, &mp, sizeof(mp)) != 0) break; /* off path, no match possible */ + /* the match covers all larger prefixlens */ + if (n->node && orlonger) + return 1; + /* plen is from 1 - 128 but the bitmask starts with 0 */ if (n->node && inet6isset(&n->plenmask, plen - 1)) return 1; /* prefixlen allowed, match */ @@ -469,13 +479,14 @@ trie_match_v6(struct trie_head *th, struct in6_addr *prefix, u_int8_t plen) /* find first matching element in the trie for prefix "prefix/plen" */ int -trie_match(struct trie_head *th, struct bgpd_addr *prefix, u_int8_t plen) +trie_match(struct trie_head *th, struct bgpd_addr *prefix, u_int8_t plen, + int orlonger) { switch (prefix->aid) { case AID_INET: - return trie_match_v4(th, &prefix->v4, plen); + return trie_match_v4(th, &prefix->v4, plen, orlonger); case AID_INET6: - return trie_match_v6(th, &prefix->v6, plen); + return trie_match_v6(th, &prefix->v6, plen, orlonger); default: /* anything else is no match */ return 0; -- 2.20.1