The commit below to bgpd/rde_attr.c introduced a check for AS0 in the AS-PATH received in an UPDATE message:

revision 1.98
date: 2017/05/26 20:55:30; author: phessler; state: Exp; lines: +8 -2; commitid: p82SYNnm0pVdbRCn;
AS 0 is special and should be considered an error.

Drop the session if it shows during OPEN or CAPA, or mark as invalid if it is part of an Update.

required by RFC 7607

This works fine if the peer has 4-byte AS capability but fails if not.

aspath_verify() happens before aspath_inflate() fixes up the 2-byte AS path. As a result when iterating over the path in aspath_verify(), aspath_extract() is returning incorrect AS number values, sometimes this will return a 0 causing aspath_verify() to drop the update with message "bad ASPATH, path invalidated and prefix withdrawn".

The patch below flips the order so that aspath_inflate() for a peer without 4-byte capability happens before aspath_verify(). This also means there is no need to pass the 4-byte capability indicator to aspath_verify() as it’ll only ever be looking at a path containing 4 byte AS numbers.

Appreciate the work on bgpd. Hope this is of some use.

Index: rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.372
diff -u -p -r1.372 rde.c
--- rde.c       14 Sep 2017 18:16:28 -0000      1.372
+++ rde.c       30 Mar 2018 19:17:14 -0000
@@ -1465,7 +1465,12 @@ bad_flags:
        case ATTR_ASPATH:
                if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
                        goto bad_flags;
-               error = aspath_verify(p, attr_len, rde_as4byte(peer));
+               if (rde_as4byte(peer)) {
+                       npath = p;
+                       nlen = attr_len;
+               } else
+                       npath = aspath_inflate(p, attr_len, &nlen);
+               error = aspath_verify(npath, nlen);
                if (error == AS_ERR_SOFT) {
                        /*
                         * soft errors like unexpected segment types are
@@ -1482,11 +1487,6 @@ bad_flags:
                }
                if (a->flags & F_ATTR_ASPATH)
                        goto bad_list;
-               if (rde_as4byte(peer)) {
-                       npath = p;
-                       nlen = attr_len;
-               } else
-                       npath = aspath_inflate(p, attr_len, &nlen);
                a->flags |= F_ATTR_ASPATH;
                a->aspath = aspath_get(npath, nlen);
                if (npath != p)
@@ -1687,7 +1687,7 @@ bad_flags:
                if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
                    ATTR_PARTIAL))
                        goto bad_flags;
-               if ((error = aspath_verify(p, attr_len, 1)) != 0) {
+               if ((error = aspath_verify(p, attr_len)) != 0) {
                        /*
                         * XXX RFC does not specify how to handle errors.
                         * XXX Instead of dropping the session because of a
Index: rde.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
retrieving revision 1.162
diff -u -p -r1.162 rde.h
--- rde.h       30 May 2017 18:08:15 -0000      1.162
+++ rde.h       30 Mar 2018 19:17:14 -0000
@@ -349,7 +349,7 @@ void                 attr_free(struct rde_aspath *, st
 #define                 attr_optlen(x) \
     ((x)->len > 255 ? (x)->len + 4 : (x)->len + 3)

-int             aspath_verify(void *, u_int16_t, int);
+int             aspath_verify(void *, u_int16_t);
 #define                 AS_ERR_LEN     -1
 #define                 AS_ERR_TYPE    -2
 #define                 AS_ERR_BAD     -3
Index: rde_attr.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_attr.c,v
retrieving revision 1.100
diff -u -p -r1.100 rde_attr.c
--- rde_attr.c  31 May 2017 10:44:00 -0000      1.100
+++ rde_attr.c  30 Mar 2018 19:17:14 -0000
@@ -421,10 +421,10 @@ SIPHASH_KEY astablekey;
        &astable.hashtbl[(x) & astable.hashmask]

 int
-aspath_verify(void *data, u_int16_t len, int as4byte)
+aspath_verify(void *data, u_int16_t len)
 {
        u_int8_t        *seg = data;
-       u_int16_t        seg_size, as_size = 2;
+       u_int16_t        seg_size;
        u_int8_t         seg_len, seg_type;
        int              i, error = 0;

@@ -432,9 +432,6 @@ aspath_verify(void *data, u_int16_t len,
                /* odd length aspath are invalid */
                return (AS_ERR_BAD);

-       if (as4byte)
-               as_size = 4;
-
        for (; len > 0; len -= seg_size, seg += seg_size) {
                if (len < 2)    /* header length check */
                        return (AS_ERR_BAD);
@@ -452,7 +449,7 @@ aspath_verify(void *data, u_int16_t len,
                    seg_type != AS_CONFED_SEQUENCE && seg_type != AS_CONFED_SET)
                        return (AS_ERR_TYPE);

-               seg_size = 2 + as_size * seg_len;
+               seg_size = 2 + 4 * seg_len;

                if (seg_size > len)
                        return (AS_ERR_LEN);


Reply via email to