bgpd: RFC 5082 Generalized TTL Security Mechanism support
* bgpd: Add support for RFC 5082 GTSM, which allows the TTL field to be used
to verify that incoming packets have been sent from neighbours no more
than X IP hops away. In other words, this allows packets that were sent from
further away (i.e. not by the neighbour with known distance, and so possibly
a miscreant) to be filtered out.
* lib/sockunion.{c,h}: (sockopt_minttl) new function, to set a minimum TTL
using the IP_MINTTL socket opt.
* bgpd.h: (BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK) define for command
error for minttl.
(struct peer) add a config variable, to store the configured minttl.
(peer_ttl_security_hops_{set,unset}) configuration handlers
* bgpd.c: (peer_group_get) init gtsm_hops
(peer_ebgp_multihop_{un,}set) check for conflicts with GTSM. Multihop and
GTSM can't both be active for a peer at the same time.
(peer_ttl_security_hops_set) set minttl, taking care to avoid conflicts with
ebgp_multihop.
(bgp_config_write_peer) write out minttl as "neighbor .. ttl-security hops X".
* bgp_vty.c: (bgp_vty_return) message for
BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK
(peer_ebgp_multihop_{un,}set_vty)
* bgp_network.c: (bgp_accept) set minttl on accepted sockets if appropriate.
(bgp_connect) ditto for outbound.
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 882fe37..cc0ea8d 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1379,6 +1379,7 @@
group->conf->group = group;
group->conf->as = 0;
group->conf->ttl = 1;
+ group->conf->gtsm_hops = 0;
group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
UNSET_FLAG (group->conf->config, PEER_CONFIG_TIMER);
UNSET_FLAG (group->conf->config, PEER_CONFIG_CONNECT);
@@ -1416,6 +1417,9 @@
/* TTL */
peer->ttl = conf->ttl;
+ /* GTSM hops */
+ peer->gtsm_hops = conf->gtsm_hops;
+
/* Weight */
peer->weight = conf->weight;
@@ -2663,10 +2667,36 @@
{
struct peer_group *group;
struct listnode *node, *nnode;
+ struct peer *peer1;
if (peer_sort (peer) == BGP_PEER_IBGP)
return 0;
+ /* see comment in peer_ttl_security_hops_set() */
+ if (ttl != MAXTTL)
+ {
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+ {
+ group = peer->group;
+ if (group->conf->gtsm_hops != 0)
+ return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+
+ for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1))
+ {
+ if (peer_sort (peer1) == BGP_PEER_IBGP)
+ continue;
+
+ if (peer1->gtsm_hops != 0)
+ return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+ }
+ }
+ else
+ {
+ if (peer->gtsm_hops != 0)
+ return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+ }
+ }
+
peer->ttl = ttl;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
@@ -2700,6 +2730,9 @@
if (peer_sort (peer) == BGP_PEER_IBGP)
return 0;
+ if (peer->gtsm_hops != 0 && peer->ttl != MAXTTL)
+ return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+
if (peer_group_active (peer))
peer->ttl = peer->group->conf->ttl;
else
@@ -4331,6 +4364,121 @@
return 0;
}
+/* Set # of hops between us and BGP peer. */
+int
+peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+ struct peer *peer1;
+ int ret;
+
+ zlog_debug ("peer_ttl_security_hops_set: set gtsm_hops to %d for %s", gtsm_hops, peer->host);
+
+ if (peer_sort (peer) == BGP_PEER_IBGP)
+ return 0;
+
+ /* We cannot configure ttl-security hops when ebgp-multihop is already
+ set. For non peer-groups, the check is simple. For peer-groups, it's
+ slightly messy, because we need to check both the peer-group structure
+ and all peer-group members for any trace of ebgp-multihop configuration
+ before actually applying the ttl-security rules. Cisco really made a
+ mess of this configuration parameter, and OpenBGPD got it right.
+ */
+
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+ {
+ group = peer->group;
+ if (group->conf->ttl != 1)
+ return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+
+ for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1))
+ {
+ if (peer_sort (peer1) == BGP_PEER_IBGP)
+ continue;
+
+ if (peer1->ttl != 1)
+ return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+ }
+ }
+ else
+ {
+ if (peer->ttl != 1)
+ return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+ }
+
+ peer->gtsm_hops = gtsm_hops;
+
+ /* specify MAXTTL on outgoing packets */
+ ret = peer_ebgp_multihop_set (peer, MAXTTL);
+ if (ret != 0)
+ return ret;
+
+ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+ {
+ if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP)
+ sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - gtsm_hops);
+ }
+ else
+ {
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
+ {
+ if (peer_sort (peer) == BGP_PEER_IBGP)
+ continue;
+
+ peer->gtsm_hops = group->conf->gtsm_hops;
+
+ if (peer->fd >= 0 && peer->gtsm_hops != 0)
+ sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - peer->gtsm_hops);
+ }
+ }
+
+ return 0;
+}
+
+int
+peer_ttl_security_hops_unset (struct peer *peer)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+ struct peer *opeer;
+
+ zlog_debug ("peer_ttl_security_hops_unset: set gtsm_hops to zero for %s", peer->host);
+
+ if (peer_sort (peer) == BGP_PEER_IBGP)
+ return 0;
+
+ /* if a peer-group member, then reset to peer-group default rather than 0 */
+ if (peer_group_active (peer))
+ peer->gtsm_hops = peer->group->conf->gtsm_hops;
+ else
+ peer->gtsm_hops = 0;
+
+ opeer = peer;
+ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+ {
+ if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP)
+ sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0);
+ }
+ else
+ {
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
+ {
+ if (peer_sort (peer) == BGP_PEER_IBGP)
+ continue;
+
+ peer->gtsm_hops = 0;
+
+ if (peer->fd >= 0)
+ sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0);
+ }
+ }
+
+ return peer_ebgp_multihop_unset (opeer);
+}
+
int
peer_clear (struct peer *peer)
{
@@ -4635,12 +4783,19 @@
vty_out (vty, " neighbor %s passive%s", addr, VTY_NEWLINE);
/* EBGP multihop. */
- if (peer_sort (peer) != BGP_PEER_IBGP && peer->ttl != 1)
+ if (peer_sort (peer) != BGP_PEER_IBGP && peer->ttl != 1 &&
+ !(peer->gtsm_hops != 0 && peer->ttl == MAXTTL))
if (! peer_group_active (peer) ||
g_peer->ttl != peer->ttl)
vty_out (vty, " neighbor %s ebgp-multihop %d%s", addr, peer->ttl,
VTY_NEWLINE);
+ /* ttl-security hops */
+ if (peer_sort (peer) != BGP_PEER_IBGP && peer->gtsm_hops != 0)
+ if (! peer_group_active (peer) || g_peer->gtsm_hops != peer->gtsm_hops)
+ vty_out (vty, " neighbor %s ttl-security hops %d%s", addr,
+ peer->gtsm_hops, VTY_NEWLINE);
+
/* disable-connected-check. */
if (CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
if (! peer_group_active (peer) ||