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);