implement or-longer filter op for prefix-sets. Allows one two write rules like
authorbenno <benno@openbsd.org>
Sat, 8 Sep 2018 15:25:27 +0000 (15:25 +0000)
committerbenno <benno@openbsd.org>
Sat, 8 Sep 2018 15:25:27 +0000 (15:25 +0000)
  deny from any prefix-set mynetworks or-longer
ok claudio, feature discussed with job and deraadt

usr.sbin/bgpd/bgpd.conf.5
usr.sbin/bgpd/bgpd.h
usr.sbin/bgpd/parse.y
usr.sbin/bgpd/printconf.c
usr.sbin/bgpd/rde.h
usr.sbin/bgpd/rde_filter.c
usr.sbin/bgpd/rde_trie.c

index 29e97d3..d7fa470 100644 (file)
@@ -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 <claudio@openbsd.org>
 .\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -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
index 4297a67..0f4d1d0 100644 (file)
@@ -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 <henning@openbsd.org>
@@ -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;
index 21fb38b..7a9abf3 100644 (file)
@@ -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 <henning@openbsd.org>
@@ -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);
index d8b7cdd..361ebed 100644 (file)
@@ -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 <henning@openbsd.org>
@@ -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)
index c67e7cf..2d699c2 100644 (file)
@@ -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 <claudio@openbsd.org> 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 *);
 
index 4705cef..04d7f13 100644 (file)
@@ -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 <claudio@openbsd.org>
@@ -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));
index 31d9161..cbbc506 100644 (file)
@@ -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 <claudio@openbsd.org>
@@ -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;