Flowspec RFC 8955 and 8956 allows to propegate traffic filtering rules to other routers. The main use case is to drop DDoS traffic further upstream and by that reducing the impact of such denial of service attacks.
This diff only adds the needed plumbing to announce the MP capability for flowspec. Any flowspec UPDATE received will be silently ignored and there is no way to send anything. Still this is a first small step and more changes will follow to send flowspec rules. The diff includes all the defines needed for flowspec. On top of this there is a small fix in rde_update_dispatch() to properly jump over unknown MP attributes (2 hunks). In rde_get_mp_nexthop() I moved the AID_VPN_IPv6 case around and used the same error message for lenght check in all cases. This is why the diff is a bit larger. I successfully tested this against exabgp. -- :wq Claudio Index: bgpd.8 =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/bgpd.8,v retrieving revision 1.77 diff -u -p -r1.77 bgpd.8 --- bgpd.8 2 Mar 2023 17:09:53 -0000 1.77 +++ bgpd.8 3 Apr 2023 08:26:45 -0000 @@ -478,6 +478,26 @@ has been started. .Re .Pp .Rs +.%A C. Loibl +.%A S. Hares +.%A R. Raszuk +.%A D. McPherson +.%A M. Bacher +.%D December 2020 +.%R RFC 8955 +.%T Dissemination of Flow Specification Rules +.Re +.Pp +.Rs +.%A C. Loibl +.%A R. Raszuk +.%A S. Hares +.%D December 2020 +.%R RFC 8956 +.%T Dissemination of Flow Specification Rules for IPv6 +.Re +.Pp +.Rs .%A E. Chen .%A J. Scudder .%D July 2021 Index: bgpd.conf.5 =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/bgpd.conf.5,v retrieving revision 1.233 diff -u -p -r1.233 bgpd.conf.5 --- bgpd.conf.5 13 Mar 2023 18:31:54 -0000 1.233 +++ bgpd.conf.5 3 Apr 2023 08:26:45 -0000 @@ -839,7 +839,7 @@ The neighbor properties are as follows: .It Xo .Ic announce .Pq Ic IPv4 Ns | Ns Ic IPv6 -.Pq Ic none Ns | Ns Ic unicast Ns | Ns Ic vpn +.Pq Ic none Ns | Ns Ic unicast Ns | Ns Ic vpn | Ns Ic flowspec .Xc For the given address family, control which .Em subsequent address families @@ -851,9 +851,11 @@ At the moment, only .Ic none , which disables the announcement of that address family, .Ic unicast , -and .Ic vpn , -which allows the distribution of BGP MPLS VPNs, are supported. +which allows the distribution of BGP MPLS VPNs, and +.Ic flowspec , +which allows the distribution of Flow Specification Rules, +are supported. .Pp The default is .Ic unicast Index: bgpd.h =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v retrieving revision 1.469 diff -u -p -r1.469 bgpd.h --- bgpd.h 29 Mar 2023 14:35:38 -0000 1.469 +++ bgpd.h 3 Apr 2023 08:26:45 -0000 @@ -152,11 +152,13 @@ enum reconf_action { #define AFI_IPv6 2 /* Subsequent Address Family Identifier as per RFC 4760 */ -#define SAFI_NONE 0 -#define SAFI_UNICAST 1 -#define SAFI_MULTICAST 2 -#define SAFI_MPLS 4 -#define SAFI_MPLSVPN 128 +#define SAFI_NONE 0 +#define SAFI_UNICAST 1 +#define SAFI_MULTICAST 2 +#define SAFI_MPLS 4 +#define SAFI_MPLSVPN 128 +#define SAFI_FLOWSPEC 133 +#define SAFI_VPNFLOWSPEC 134 struct aid { uint16_t afi; @@ -172,7 +174,9 @@ extern const struct aid aid_vals[]; #define AID_INET6 2 #define AID_VPN_IPv4 3 #define AID_VPN_IPv6 4 -#define AID_MAX 5 +#define AID_FLOWSPECv4 5 +#define AID_FLOWSPECv6 6 +#define AID_MAX 7 #define AID_MIN 1 /* skip AID_UNSPEC since that is a dummy */ #define AID_VALS { \ @@ -181,7 +185,9 @@ extern const struct aid aid_vals[]; { AFI_IPv4, AF_INET, SAFI_UNICAST, "IPv4 unicast" }, \ { AFI_IPv6, AF_INET6, SAFI_UNICAST, "IPv6 unicast" }, \ { AFI_IPv4, AF_INET, SAFI_MPLSVPN, "IPv4 vpn" }, \ - { AFI_IPv6, AF_INET6, SAFI_MPLSVPN, "IPv6 vpn" } \ + { AFI_IPv6, AF_INET6, SAFI_MPLSVPN, "IPv6 vpn" }, \ + { AFI_IPv4, AF_INET, SAFI_FLOWSPEC, "IPv4 flowspec" }, \ + { AFI_IPv6, AF_INET6, SAFI_FLOWSPEC, "IPv6 flowspec" }, \ } #define BGP_MPLS_BOS 0x01 @@ -1004,18 +1010,22 @@ struct filter_peers { #define EXT_COMMUNITY_IANA 0x80 #define EXT_COMMUNITY_NON_TRANSITIVE 0x40 #define EXT_COMMUNITY_VALUE 0x3f -/* extended types transitive */ +/* extended transitive types */ #define EXT_COMMUNITY_TRANS_TWO_AS 0x00 /* 2 octet AS specific */ #define EXT_COMMUNITY_TRANS_IPV4 0x01 /* IPv4 specific */ #define EXT_COMMUNITY_TRANS_FOUR_AS 0x02 /* 4 octet AS specific */ #define EXT_COMMUNITY_TRANS_OPAQUE 0x03 /* opaque ext community */ #define EXT_COMMUNITY_TRANS_EVPN 0x06 /* EVPN RFC 7432 */ -/* extended types non-transitive */ +/* extended non-transitive types */ #define EXT_COMMUNITY_NON_TRANS_TWO_AS 0x40 /* 2 octet AS specific */ #define EXT_COMMUNITY_NON_TRANS_IPV4 0x41 /* IPv4 specific */ #define EXT_COMMUNITY_NON_TRANS_FOUR_AS 0x42 /* 4 octet AS specific */ #define EXT_COMMUNITY_NON_TRANS_OPAQUE 0x43 /* opaque ext community */ #define EXT_COMMUNITY_UNKNOWN -1 +/* generic transitive types */ +#define EXT_COMMUNITY_GEN_TWO_AS 0x80 /* 2 octet AS specific */ +#define EXT_COMMUNITY_GEN_IPV4 0x81 /* IPv4 specific */ +#define EXT_COMMUNITY_GEN_FOUR_AS 0x82 /* 4 octet AS specific */ /* BGP Origin Validation State Extended Community RFC 8097 */ #define EXT_COMMUNITY_SUBTYPE_OVS 0 @@ -1063,10 +1073,47 @@ struct ext_comm_pairs { { EXT_COMMUNITY_TRANS_EVPN, 0x01, "esi-lab" }, \ { EXT_COMMUNITY_TRANS_EVPN, 0x02, "esi-rt" }, \ \ + { EXT_COMMUNITY_GEN_TWO_AS, 0x06, "flow-rate" }, \ + { EXT_COMMUNITY_GEN_TWO_AS, 0x0c, "flow-pps" }, \ + { EXT_COMMUNITY_GEN_TWO_AS, 0x07, "flow-action" }, \ + { EXT_COMMUNITY_GEN_TWO_AS, 0x08, "flow-rt-redir" }, \ + { EXT_COMMUNITY_GEN_IPV4, 0x08, "flow-rt-redir" }, \ + { EXT_COMMUNITY_GEN_FOUR_AS, 0x08, "flow-rt-redir" }, \ + { EXT_COMMUNITY_GEN_TWO_AS, 0x09, "flow-dscp" }, \ { 0 } \ } extern const struct ext_comm_pairs iana_ext_comms[]; + +/* BGP flowspec defines RFC 8955 */ +#define FLOWSPEC_LEN_LIMIT 0xf0 +#define FLOWSPEC_OP_EOL 0x80 +#define FLOWSPEC_OP_AND 0x40 +#define FLOWSPEC_OP_LEN_MASK 0x30 +#define FLOWSPEC_OP_LEN_SHIFT 4 +#define FLOWSPEC_OP_LEN(op) \ + (1 << (((op) & FLOWSPEC_OP_LEN_MASK) >> FLOWSPEC_OP_LEN_SHIFT)) +#define FLOWSPEC_OP_NUM_LT 0x04 +#define FLOWSPEC_OP_NUM_GT 0x02 +#define FLOWSPEC_OP_NUM_EQ 0x01 +#define FLOWSPEC_OP_BIT_NOT 0x02 +#define FLOWSPEC_OP_BIT_MATCH 0x01 + +#define FLOWSPEC_TYPE_MIN 1 +#define FLOWSPEC_TYPE_DEST 1 +#define FLOWSPEC_TYPE_SOURCE 2 +#define FLOWSPEC_TYPE_PROTO 3 +#define FLOWSPEC_TYPE_PORT 4 +#define FLOWSPEC_TYPE_DST_PORT 5 +#define FLOWSPEC_TYPE_SRC_PORT 6 +#define FLOWSPEC_TYPE_ICMP_TYPE 7 +#define FLOWSPEC_TYPE_ICMP_CODE 8 +#define FLOWSPEC_TYPE_TCP_FLAGS 9 +#define FLOWSPEC_TYPE_PKT_LEN 10 +#define FLOWSPEC_TYPE_DSCP 11 +#define FLOWSPEC_TYPE_FRAG 12 +#define FLOWSPEC_TYPE_FLOW 13 +#define FLOWSPEC_TYPE_MAX 13 struct filter_prefix { struct bgpd_addr addr; Index: parse.y =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v retrieving revision 1.442 diff -u -p -r1.442 parse.y --- parse.y 9 Mar 2023 13:12:19 -0000 1.442 +++ parse.y 3 Apr 2023 08:26:45 -0000 @@ -213,7 +213,7 @@ typedef struct { %} %token AS ROUTERID HOLDTIME YMIN LISTEN ON FIBUPDATE FIBPRIORITY RTABLE -%token NONE UNICAST VPN RD EXPORT EXPORTTRGT IMPORTTRGT DEFAULTROUTE +%token NONE UNICAST VPN FLOWSPEC RD EXPORT EXPORTTRGT IMPORTTRGT DEFAULTROUTE %token RDE RIB EVALUATE IGNORE COMPARE RTR PORT %token GROUP NEIGHBOR NETWORK %token EBGP IBGP @@ -1995,6 +1995,7 @@ family : IPV4 { $$ = AFI_IPv4; } safi : NONE { $$ = SAFI_NONE; } | UNICAST { $$ = SAFI_UNICAST; } | VPN { $$ = SAFI_MPLSVPN; } + | FLOWSPEC { $$ = SAFI_FLOWSPEC; } ; nettype : STATIC { $$ = 1; } @@ -3200,6 +3201,7 @@ lookup(char *s) { "ext-community", EXTCOMMUNITY}, { "fib-priority", FIBPRIORITY}, { "fib-update", FIBUPDATE}, + { "flowspec", FLOWSPEC}, { "from", FROM}, { "group", GROUP}, { "holdtime", HOLDTIME}, Index: rde.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v retrieving revision 1.598 diff -u -p -r1.598 rde.c --- rde.c 28 Mar 2023 08:32:42 -0000 1.598 +++ rde.c 3 Apr 2023 08:26:45 -0000 @@ -1474,9 +1474,14 @@ rde_update_dispatch(struct rde_peer *pee goto done; } break; + case AID_FLOWSPECv4: + case AID_FLOWSPECv6: + /* ignore flowspec for now */ default: /* ignore unsupported multiprotocol AF */ - break; + mpp += mplen; + mplen = 0; + continue; } mpp += pos; @@ -1674,9 +1679,14 @@ rde_update_dispatch(struct rde_peer *pee goto done; } break; + case AID_FLOWSPECv4: + case AID_FLOWSPECv6: + /* ignore flowspec for now */ default: /* ignore unsupported multiprotocol AF */ - break; + mpp += mplen; + mplen = 0; + continue; } mpp += pos; @@ -2314,7 +2324,6 @@ rde_get_mp_nexthop(u_char *data, uint16_ return (-1); memset(&nexthop, 0, sizeof(nexthop)); - nexthop.aid = aid; switch (aid) { case AID_INET6: /* @@ -2326,19 +2335,11 @@ rde_get_mp_nexthop(u_char *data, uint16_ * traffic. */ if (nhlen != 16 && nhlen != 32) { - log_warnx("bad multiprotocol nexthop, bad size"); - return (-1); - } - memcpy(&nexthop.v6.s6_addr, data, 16); - break; - case AID_VPN_IPv6: - if (nhlen != 24) { - log_warnx("bad multiprotocol nexthop, bad size %d", + log_warnx("bad %s nexthop, bad size %d", aid2str(aid), nhlen); return (-1); } - memcpy(&nexthop.v6, data + sizeof(uint64_t), - sizeof(nexthop.v6)); + memcpy(&nexthop.v6.s6_addr, data, 16); nexthop.aid = AID_INET6; break; case AID_VPN_IPv4: @@ -2356,24 +2357,43 @@ rde_get_mp_nexthop(u_char *data, uint16_ * AID_VPN_IPv4 in nexthop and kroute. */ if (nhlen != 12) { - log_warnx("bad multiprotocol nexthop, bad size"); + log_warnx("bad %s nexthop, bad size %d", aid2str(aid), + nhlen); return (-1); } nexthop.aid = AID_INET; memcpy(&nexthop.v4, data + sizeof(uint64_t), sizeof(nexthop.v4)); break; + case AID_VPN_IPv6: + if (nhlen != 24) { + log_warnx("bad %s nexthop, bad size %d", aid2str(aid), + nhlen); + return (-1); + } + memcpy(&nexthop.v6, data + sizeof(uint64_t), + sizeof(nexthop.v6)); + nexthop.aid = AID_INET6; + break; + case AID_FLOWSPECv4: + case AID_FLOWSPECv6: + /* nexthop must be 0 and ignored for flowspec */ + if (nhlen != 0) { + log_warnx("bad %s nexthop, bad size %d", aid2str(aid), + nhlen); + return (-1); + } + totlen += nhlen + 1; + return (totlen); default: log_warnx("bad multiprotocol nexthop, bad AID"); return (-1); } - nexthop_unref(state->nexthop); /* just to be sure */ state->nexthop = nexthop_get(&nexthop); /* ignore reserved (old SNPA) field as per RFC4760 */ totlen += nhlen + 1; - data += nhlen + 1; return (totlen); } Index: util.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/util.c,v retrieving revision 1.75 diff -u -p -r1.75 util.c --- util.c 30 Mar 2023 14:47:25 -0000 1.75 +++ util.c 3 Apr 2023 08:26:45 -0000 @@ -918,6 +918,9 @@ addr2sa(const struct bgpd_addr *addr, ui sa_in6->sin6_scope_id = addr->scope_id; *len = sizeof(struct sockaddr_in6); break; + case AID_FLOWSPECv4: + case AID_FLOWSPECv6: + return (NULL); } return ((struct sockaddr *)&ss);