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)

Reply via email to