From 9dac9fc80e88b0823392bc761ca051df9b4ce23a Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Thu, 7 Feb 2019 10:49:04 +0200 Subject: [PATCH] bgpd: Implement RFC8212 Signed-off-by: Donatas Abraitis --- bgpd/bgp_route.c | 48 +++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_route.h | 2 ++ bgpd/bgp_vty.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgpd.c | 6 ++++++ bgpd/bgpd.h | 5 +++++ 5 files changed, 114 insertions(+) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 59ca223a2d..d02d747361 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1224,6 +1224,20 @@ static int bgp_input_modifier(struct peer *peer, struct prefix *p, } } + /* RFC 8212 to prevent route leaks. + * This specification intends to improve this situation by requiring the + * explicit configuration of both BGP Import and Export Policies for any + * External BGP (EBGP) session such as customers, peers, or + * confederation boundaries for all enabled address families. Through + * codification of the aforementioned requirement, operators will + * benefit from consistent behavior across different BGP + * implementations. + */ + if (peer->bgp->ebgp_requires_policy + == DEFAULT_EBGP_POLICY_ENABLED) + if (!bgp_inbound_policy_exists(peer, filter)) + return RMAP_DENY; + /* Route map apply. */ if (rmap) { memset(&rmap_path, 0, sizeof(struct bgp_path_info)); @@ -1777,6 +1791,20 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, } } + /* RFC 8212 to prevent route leaks. + * This specification intends to improve this situation by requiring the + * explicit configuration of both BGP Import and Export Policies for any + * External BGP (EBGP) session such as customers, peers, or + * confederation boundaries for all enabled address families. Through + * codification of the aforementioned requirement, operators will + * benefit from consistent behavior across different BGP + * implementations. + */ + if (peer->bgp->ebgp_requires_policy + == DEFAULT_EBGP_POLICY_ENABLED) + if (!bgp_outbound_policy_exists(peer, filter)) + return 0; + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) { if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { @@ -4160,6 +4188,26 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) } } +int bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter) +{ + if (peer->sort == BGP_PEER_EBGP + && (ROUTE_MAP_OUT_NAME(filter) || PREFIX_LIST_OUT_NAME(filter) + || FILTER_LIST_OUT_NAME(filter) + || DISTRIBUTE_OUT_NAME(filter))) + return 1; + return 0; +} + +int bgp_inbound_policy_exists(struct peer *peer, struct bgp_filter *filter) +{ + if (peer->sort == BGP_PEER_EBGP + && (ROUTE_MAP_IN_NAME(filter) || PREFIX_LIST_IN_NAME(filter) + || FILTER_LIST_IN_NAME(filter) + || DISTRIBUTE_IN_NAME(filter))) + return 1; + return 0; +} + static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table, safi_t safi) { diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 97d4aaeeba..85325a93cf 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -357,6 +357,8 @@ extern void bgp_clear_route(struct peer *, afi_t, safi_t); extern void bgp_clear_route_all(struct peer *); extern void bgp_clear_adj_in(struct peer *, afi_t, safi_t); extern void bgp_clear_stale_route(struct peer *, afi_t, safi_t); +extern int bgp_outbound_policy_exists(struct peer *, struct bgp_filter *); +extern int bgp_inbound_policy_exists(struct peer *, struct bgp_filter *); extern struct bgp_node *bgp_afi_node_get(struct bgp_table *table, afi_t afi, safi_t safi, struct prefix *p, diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index a6d985ab9f..c3bd6f83b7 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1860,6 +1860,29 @@ DEFUN (no_bgp_always_compare_med, return CMD_SUCCESS; } + +DEFUN(bgp_ebgp_requires_policy, bgp_ebgp_requires_policy_cmd, + "bgp ebgp-requires-policy", + "BGP specific commands\n" + "Require in and out policy for eBGP peers (RFC8212)\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_ENABLED; + return CMD_SUCCESS; +} + +DEFUN(no_bgp_ebgp_requires_policy, no_bgp_ebgp_requires_policy_cmd, + "no bgp ebgp-requires-policy", + NO_STR + "BGP specific commands\n" + "Require in and out policy for eBGP peers (RFC8212)\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_DISABLED; + return CMD_SUCCESS; +} + + /* "bgp deterministic-med" configuration. */ DEFUN (bgp_deterministic_med, bgp_deterministic_med_cmd, @@ -8829,6 +8852,20 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, json_addr, "routeMapForOutgoingAdvertisements", filter->map[RMAP_OUT].name); + /* ebgp-requires-policy (inbound) */ + if (p->bgp->ebgp_requires_policy == DEFAULT_EBGP_POLICY_ENABLED + && !bgp_inbound_policy_exists(p, filter)) + json_object_string_add( + json_addr, "inboundEbgpRequiresPolicy", + "Inbound updates discarded due to missing policy"); + + /* ebgp-requires-policy (outbound) */ + if (p->bgp->ebgp_requires_policy == DEFAULT_EBGP_POLICY_ENABLED + && (!bgp_outbound_policy_exists(p, filter))) + json_object_string_add( + json_addr, "outboundEbgpRequiresPolicy", + "Outbound updates discarded due to missing policy"); + /* unsuppress-map */ if (filter->usmap.name) json_object_string_add(json_addr, @@ -9105,6 +9142,18 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, filter->map[RMAP_OUT].map ? "*" : "", filter->map[RMAP_OUT].name); + /* ebgp-requires-policy (inbound) */ + if (p->bgp->ebgp_requires_policy == DEFAULT_EBGP_POLICY_ENABLED + && !bgp_inbound_policy_exists(p, filter)) + vty_out(vty, + " Inbound updates discarded due to missing policy\n"); + + /* ebgp-requires-policy (outbound) */ + if (p->bgp->ebgp_requires_policy == DEFAULT_EBGP_POLICY_ENABLED + && !bgp_outbound_policy_exists(p, filter)) + vty_out(vty, + " Outbound updates discarded due to missing policy\n"); + /* unsuppress-map */ if (filter->usmap.name) vty_out(vty, @@ -12823,6 +12872,10 @@ void bgp_vty_init(void) install_element(BGP_NODE, &bgp_always_compare_med_cmd); install_element(BGP_NODE, &no_bgp_always_compare_med_cmd); + /* bgp ebgp-requires-policy */ + install_element(BGP_NODE, &bgp_ebgp_requires_policy_cmd); + install_element(BGP_NODE, &no_bgp_ebgp_requires_policy_cmd); + /* "bgp deterministic-med" commands */ install_element(BGP_NODE, &bgp_deterministic_med_cmd); install_element(BGP_NODE, &no_bgp_deterministic_med_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index aceb990534..8032bf59af 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2936,6 +2936,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; bgp->dynamic_neighbors_limit = BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT; bgp->dynamic_neighbors_count = 0; + bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_DISABLED; #if DFLT_BGP_IMPORT_CHECK bgp_flag_set(bgp, BGP_FLAG_IMPORT_CHECK); #endif @@ -7577,6 +7578,11 @@ int bgp_config_write(struct vty *vty) if (bgp_flag_check(bgp, BGP_FLAG_ALWAYS_COMPARE_MED)) vty_out(vty, " bgp always-compare-med\n"); + /* RFC8212 default eBGP policy. */ + if (bgp->ebgp_requires_policy + == DEFAULT_EBGP_POLICY_ENABLED) + vty_out(vty, " bgp ebgp-requires-policy\n"); + /* BGP default ipv4-unicast. */ if (bgp_flag_check(bgp, BGP_FLAG_NO_DEFAULT_IPV4)) vty_out(vty, " no bgp default ipv4-unicast\n"); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index e58c46e240..dde1501d30 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -487,6 +487,11 @@ struct bgp { /* EVPN enable - advertise local VNIs and their MACs etc. */ int advertise_all_vni; + /* RFC 8212 - prevent route leaks. */ + int ebgp_requires_policy; +#define DEFAULT_EBGP_POLICY_DISABLED 0 +#define DEFAULT_EBGP_POLICY_ENABLED 1 + struct bgp_evpn_info *evpn_info; /* EVPN - use RFC 8365 to auto-derive RT */ -- 2.39.5