diff options
author | Nick Hilliard <nick@inex.ie> | 2011-03-23 15:33:17 +0000 |
---|---|---|
committer | Paul Jakma <paul@quagga.net> | 2011-03-23 15:33:17 +0000 |
commit | fa411a212b55bba650d68fd0456686f3e47b7395 (patch) | |
tree | 4d7ef846c2cbc154631a5901747b3384854d497c /bgpd/bgpd.c | |
parent | db07ad7358cb5e26358326332629ffb658f5747a (diff) |
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.
Diffstat (limited to 'bgpd/bgpd.c')
-rw-r--r-- | bgpd/bgpd.c | 157 |
1 files changed, 156 insertions, 1 deletions
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 882fe37c..cc0ea8d4 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1379,6 +1379,7 @@ peer_group_get (struct bgp *bgp, const char *name) 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 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer, /* TTL */ peer->ttl = conf->ttl; + /* GTSM hops */ + peer->gtsm_hops = conf->gtsm_hops; + /* Weight */ peer->weight = conf->weight; @@ -2663,10 +2667,36 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl) { 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 @@ peer_ebgp_multihop_unset (struct peer *peer) 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 @@ peer_maximum_prefix_unset (struct peer *peer, afi_t afi, safi_t safi) 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 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp, 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) || |