Improve handling of source-as when an AS_SET is rightmost. In that case
authorclaudio <claudio@openbsd.org>
Thu, 9 Aug 2018 21:12:33 +0000 (21:12 +0000)
committerclaudio <claudio@openbsd.org>
Thu, 9 Aug 2018 21:12:33 +0000 (21:12 +0000)
use the rightmost AS from the previous AS path segment. As suggested in
rfc6472. Also fix a long standing bug of AS 42 >< 4242 matching 43 - 4241
instead of 1-41 and 4243 and upwards. Last but not least pass the filter_as
struct to as_compare since that will make it easier to implement as-sets.
OK benno@, OK job@ on a previous version

usr.sbin/bgpd/bgpd.h
usr.sbin/bgpd/util.c

index 92ffec8..a36b366 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: bgpd.h,v 1.329 2018/08/08 14:29:05 claudio Exp $ */
+/*     $OpenBSD: bgpd.h,v 1.330 2018/08/09 21:12:33 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -1156,8 +1156,6 @@ int                aspath_snprint(char *, size_t, void *, u_int16_t);
 int             aspath_asprint(char **, void *, u_int16_t);
 size_t          aspath_strlen(void *, u_int16_t);
 int             aspath_match(void *, u_int16_t, struct filter_as *, u_int32_t);
-int             as_compare(u_int8_t, u_int32_t, u_int32_t, u_int32_t,
-                   u_int32_t);
 u_int32_t       aspath_extract(const void *, int);
 int             aspath_verify(void *, u_int16_t, int);
 #define                 AS_ERR_LEN     -1
index 8ae8272..c62e7e1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: util.c,v 1.28 2018/07/22 16:52:27 claudio Exp $ */
+/*     $OpenBSD: util.c,v 1.29 2018/08/09 21:12:33 claudio Exp $ */
 
 /*
  * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
@@ -312,6 +312,20 @@ aspath_strlen(void *data, u_int16_t len)
        return (total_size);
 }
 
+static int
+as_compare(struct filter_as *f, u_int32_t as, u_int32_t match)
+{
+       if ((f->op == OP_NONE || f->op == OP_EQ) && as == match)
+               return (1);
+       else if (f->op == OP_NE && as != match)
+               return (1);
+       else if (f->op == OP_RANGE && as >= f->as_min && as <= f->as_max)
+               return (1);
+       else if (f->op == OP_XRANGE && (as < f->as_min || as > f->as_max))
+               return (1);
+       return (0);
+}
+
 /* we need to be able to search more than one as */
 int
 aspath_match(void *data, u_int16_t len, struct filter_as *f, u_int32_t match)
@@ -320,7 +334,7 @@ aspath_match(void *data, u_int16_t len, struct filter_as *f, u_int32_t match)
        int              final;
        u_int16_t        seg_size;
        u_int8_t         i, seg_len;
-       u_int32_t        as;
+       u_int32_t        as = 0, preas;
 
        if (f->type == AS_EMPTY) {
                if (len == 0)
@@ -330,27 +344,35 @@ aspath_match(void *data, u_int16_t len, struct filter_as *f, u_int32_t match)
        }
 
        seg = data;
-       for (; len > 0; len -= seg_size, seg += seg_size) {
+
+       /* just check the leftmost AS */
+       if (f->type == AS_PEER && len >= 6) {
+               as = aspath_extract(seg, 0);
+               if (as_compare(f, as, match))
+                       return (1);
+               else
+                       return (0);
+       }
+
+       for (; len >= 6; len -= seg_size, seg += seg_size) {
                seg_len = seg[1];
                seg_size = 2 + sizeof(u_int32_t) * seg_len;
 
                final = (len == seg_size);
 
-               /* just check the first (leftmost) AS */
-               if (f->type == AS_PEER) {
-                       as = aspath_extract(seg, 0);
-                       if (as_compare(f->op, as, match, f->as_min, f->as_max))
-                               return (1);
-                       else
-                               return (0);
-               }
-               /* just check the final (rightmost) AS */
+               /* just check the rightmost AS */
                if (f->type == AS_SOURCE) {
+                       /* keep previous AS in case an AS_SET is rightmost */
+                       preas = as;
+                       as = aspath_extract(seg, seg_len - 1);
                        /* not yet in the final segment */
                        if (!final)
                                continue;
-                       as = aspath_extract(seg, seg_len - 1);
-                       if (as_compare(f->op, as, match, f->as_min, f->as_max))
+                       if (seg[0] == AS_SET)
+                               /* use aggregator AS per rfc6472 */
+                               if (preas)
+                                       as = preas;
+                       if (as_compare(f, as, match))
                                return (1);
                        else
                                return (0);
@@ -364,28 +386,13 @@ aspath_match(void *data, u_int16_t len, struct filter_as *f, u_int32_t match)
                        if (final && i == seg_len - 1 && f->type == AS_TRANSIT)
                                return (0);
                        as = aspath_extract(seg, i);
-                       if (as_compare(f->op, as, match, f->as_min, f->as_max))
+                       if (as_compare(f, as, match))
                                return (1);
                }
        }
        return (0);
 }
 
-int
-as_compare(u_int8_t op, u_int32_t as, u_int32_t match, u_int32_t as_min,
-    u_int32_t as_max)
-{
-       if ((op == OP_NONE || op == OP_EQ) && as == match)
-               return (1);
-       else if (op == OP_NE && as != match)
-               return (1);
-       else if (op == OP_RANGE && as >= as_min && as <= as_max)
-               return (1);
-       else if (op == OP_XRANGE && as > as_min && as < as_max)
-               return (1);
-       return (0);
-}
-
 /*
  * Extract the asnum out of the as segment at the specified position.
  * Direct access is not possible because of non-aligned reads.