This diff adds 'reject as-set yes' as an option to filter out AS paths with AS_SET segement elements. In bgpctl they show up with {} elements, e.g. 174 6762 24835 { 36893 }.
This diff uses the soft-error path from RFC7606 and because of this prefixes that have such an AS_SET segment will be removed via treat-as-withdraw. These prefixes can be seen in `bgpctl show rib in error`. By default this is turned off. -- :wq Claudio Index: bgpctl/output.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpctl/output.c,v retrieving revision 1.11 diff -u -p -r1.11 output.c --- bgpctl/output.c 30 Dec 2020 07:31:19 -0000 1.11 +++ bgpctl/output.c 14 Jan 2021 14:31:45 -0000 @@ -647,8 +647,8 @@ show_attr(u_char *data, size_t len, stru case ATTR_ASPATH: case ATTR_AS4_PATH: /* prefer 4-byte AS here */ - e4 = aspath_verify(data, alen, 1); - e2 = aspath_verify(data, alen, 0); + e4 = aspath_verify(data, alen, 1, 0); + e2 = aspath_verify(data, alen, 0, 0); if (e4 == 0 || e4 == AS_ERR_SOFT) { path = data; } else if (e2 == 0 || e2 == AS_ERR_SOFT) { Index: bgpctl/output_json.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpctl/output_json.c,v retrieving revision 1.5 diff -u -p -r1.5 output_json.c --- bgpctl/output_json.c 30 Dec 2020 07:31:19 -0000 1.5 +++ bgpctl/output_json.c 14 Jan 2021 14:31:57 -0000 @@ -598,8 +598,8 @@ json_attr(u_char *data, size_t len, stru case ATTR_ASPATH: case ATTR_AS4_PATH: /* prefer 4-byte AS here */ - e4 = aspath_verify(data, alen, 1); - e2 = aspath_verify(data, alen, 0); + e4 = aspath_verify(data, alen, 1, 0); + e2 = aspath_verify(data, alen, 0, 0); if (e4 == 0 || e4 == AS_ERR_SOFT) { path = data; } else if (e2 == 0 || e2 == AS_ERR_SOFT) { Index: bgpd/bgpd.conf.5 =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/bgpd.conf.5,v retrieving revision 1.205 diff -u -p -r1.205 bgpd.conf.5 --- bgpd/bgpd.conf.5 16 May 2020 16:58:11 -0000 1.205 +++ bgpd/bgpd.conf.5 14 Jan 2021 14:30:43 -0000 @@ -330,6 +330,20 @@ This renders the decision process nondet The default is .Ic ignore . .Pp +.It Xo +.Ic reject Ic as-set +.Pq Ic yes Ns | Ns Ic no +.Xc +If set to +.Ic yes , +.Em AS paths +attributes containing +.Em AS_SET +path segements will be rejected and +all prefixes will be treated as withdraws. +The default is +.Ic no . +.Pp .It Ic router-id Ar dotted-quad Set the BGP router ID, which must be non-zero and should be unique within the AS. @@ -1086,6 +1100,21 @@ statement defines the maximum hops the n .Pp .It Ic passive Do not attempt to actively open a TCP connection to the neighbor system. +.Pp +.It Xo +.Ic reject Ic as-set +.Pq Ic yes Ns | Ns Ic no +.Xc +If set to +.Ic yes , +.Em AS paths +attributes containing +.Em AS_SET +path segements will be rejected and +all prefixes will be treated as withdraws. +The default is inherited from the global +.Ic reject Ic as-set +setting. .Pp .It Ic remote-as Ar as-number Set the AS number of the remote system. Index: bgpd/bgpd.h =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v retrieving revision 1.409 diff -u -p -r1.409 bgpd.h --- bgpd/bgpd.h 4 Jan 2021 13:40:32 -0000 1.409 +++ bgpd/bgpd.h 14 Jan 2021 14:05:58 -0000 @@ -65,6 +65,7 @@ #define BGPD_FLAG_DECISION_ROUTEAGE 0x0100 #define BGPD_FLAG_DECISION_TRANS_AS 0x0200 #define BGPD_FLAG_DECISION_MED_ALWAYS 0x0400 +#define BGPD_FLAG_NO_AS_SET 0x0800 #define BGPD_LOG_UPDATES 0x0001 @@ -427,6 +428,7 @@ struct peer_config { #define PEERFLAG_TRANS_AS 0x01 #define PEERFLAG_LOG_UPDATES 0x02 +#define PEERFLAG_NO_AS_SET 0x04 enum network_type { NETWORK_DEFAULT, /* from network statements */ @@ -1346,7 +1348,7 @@ int aspath_snprint(char *, size_t, voi int aspath_asprint(char **, void *, u_int16_t); size_t aspath_strlen(void *, u_int16_t); u_int32_t aspath_extract(const void *, int); -int aspath_verify(void *, u_int16_t, int); +int aspath_verify(void *, u_int16_t, int, int); #define AS_ERR_LEN -1 #define AS_ERR_TYPE -2 #define AS_ERR_BAD -3 Index: bgpd/parse.y =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v retrieving revision 1.411 diff -u -p -r1.411 parse.y --- bgpd/parse.y 29 Dec 2020 15:30:34 -0000 1.411 +++ bgpd/parse.y 14 Jan 2021 14:17:19 -0000 @@ -623,6 +623,12 @@ conf_main : AS as4number { else conf->flags &= ~BGPD_FLAG_DECISION_TRANS_AS; } + | REJECT ASSET yesno { + if ($3 == 1) + conf->flags |= BGPD_FLAG_NO_AS_SET; + else + conf->flags &= ~BGPD_FLAG_NO_AS_SET; + } | LOG STRING { if (!strcmp($2, "updates")) conf->log |= BGPD_LOG_UPDATES; @@ -1657,6 +1663,12 @@ peeropts : REMOTEAS as4number { } free($2); } + | REJECT ASSET yesno { + if ($3 == 1) + curpeer->conf.flags |= PEERFLAG_NO_AS_SET; + else + curpeer->conf.flags &= ~PEERFLAG_NO_AS_SET; + } ; restart : /* nada */ { $$ = 0; } @@ -3815,6 +3827,8 @@ alloc_peer(void) if (conf->flags & BGPD_FLAG_DECISION_TRANS_AS) p->conf.flags |= PEERFLAG_TRANS_AS; + if (conf->flags & BGPD_FLAG_NO_AS_SET) + p->conf.flags |= PEERFLAG_NO_AS_SET; return (p); } Index: bgpd/rde.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v retrieving revision 1.512 diff -u -p -r1.512 rde.c --- bgpd/rde.c 13 Jan 2021 11:34:01 -0000 1.512 +++ bgpd/rde.c 14 Jan 2021 14:00:03 -0000 @@ -79,6 +79,7 @@ static void rde_softreconfig_in(struct static void rde_softreconfig_sync_reeval(struct rib_entry *, void *); static void rde_softreconfig_sync_fib(struct rib_entry *, void *); static void rde_softreconfig_sync_done(void *, u_int8_t); +static int rde_no_as_set(struct rde_peer *); int rde_update_queue_pending(void); void rde_update_queue_runner(void); void rde_update6_queue_runner(u_int8_t); @@ -1591,7 +1592,8 @@ 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)); + error = aspath_verify(p, attr_len, rde_as4byte(peer), + rde_no_as_set(peer)); if (error == AS_ERR_SOFT) { /* * soft errors like unexpected segment types are @@ -1599,8 +1601,6 @@ bad_flags: * marked invalid. */ a->flags |= F_ATTR_PARSE_ERR; - log_peer_warnx(&peer->conf, "bad ASPATH, " - "path invalidated and prefix withdrawn"); } else if (error != 0) { rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH, NULL, 0); @@ -1616,6 +1616,15 @@ bad_flags: if (npath == NULL) fatal("aspath_inflate"); } + if (error == AS_ERR_SOFT) { + char *str; + + aspath_asprint(&str, npath, nlen); + log_peer_warnx(&peer->conf, "bad ASPATH %s, " + "path invalidated and prefix withdrawn", + str ? str : "(bad aspath)"); + free(str); + } a->flags |= F_ATTR_ASPATH; a->aspath = aspath_get(npath, nlen); if (npath != p) @@ -1842,7 +1851,8 @@ 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, 1, + rde_no_as_set(peer))) != 0) { /* * XXX RFC does not specify how to handle errors. * XXX Instead of dropping the session because of a @@ -3583,6 +3593,12 @@ int rde_as4byte(struct rde_peer *peer) { return (peer->capa.as4byte); +} + +static int +rde_no_as_set(struct rde_peer *peer) +{ + return (peer->conf.flags & PEERFLAG_NO_AS_SET); } /* End-of-RIB marker, RFC 4724 */ Index: bgpd/util.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/util.c,v retrieving revision 1.58 diff -u -p -r1.58 util.c --- bgpd/util.c 5 Jan 2021 10:00:28 -0000 1.58 +++ bgpd/util.c 14 Jan 2021 13:54:48 -0000 @@ -331,7 +331,7 @@ aspath_extract(const void *seg, int pos) * Verify that the aspath is correctly encoded. */ int -aspath_verify(void *data, u_int16_t len, int as4byte) +aspath_verify(void *data, u_int16_t len, int as4byte, int noset) { u_int8_t *seg = data; u_int16_t seg_size, as_size = 2; @@ -364,6 +364,12 @@ aspath_verify(void *data, u_int16_t len, * bgp session running. */ if (seg_type == AS_CONFED_SEQUENCE || seg_type == AS_CONFED_SET) + error = AS_ERR_SOFT; + /* + * If AS_SET filtering (RFC6472) is on, error out on AS_SET + * as well. + */ + if (noset && seg_type == AS_SET) error = AS_ERR_SOFT; if (seg_type != AS_SET && seg_type != AS_SEQUENCE && seg_type != AS_CONFED_SEQUENCE && seg_type != AS_CONFED_SET)