From bb8f45f7e2c6b04e218e34c60f4e0ea40980287d Mon Sep 17 00:00:00 2001 From: claudio Date: Thu, 9 Aug 2018 21:12:33 +0000 Subject: [PATCH] Improve handling of source-as when an AS_SET is rightmost. In that case 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 | 4 +-- usr.sbin/bgpd/util.c | 67 ++++++++++++++++++++++++-------------------- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index 92ffec8bd16..a36b3667429 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -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 @@ -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 diff --git a/usr.sbin/bgpd/util.c b/usr.sbin/bgpd/util.c index 8ae8272371d..c62e7e15af2 100644 --- a/usr.sbin/bgpd/util.c +++ b/usr.sbin/bgpd/util.c @@ -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 @@ -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. -- 2.20.1