The generalized TTL security mechanism (RFC 5082) support.

Thanks to Alexander V. Chernikov for the patch.
This commit is contained in:
Ondrej Zajicek 2011-08-16 23:05:35 +02:00
parent a52d52fa91
commit b1b1943360
9 changed files with 174 additions and 21 deletions

View file

@ -1120,9 +1120,11 @@ for each neighbor using the following configuration parameters:
subnets. Such IP address have to be reachable through system subnets. Such IP address have to be reachable through system
routing table. For multihop BGP it is recommended to routing table. For multihop BGP it is recommended to
explicitly configure <cf/source address/ to have it explicitly configure <cf/source address/ to have it
stable. Optional <cf/number/ argument can be used to limit TTL stable. Optional <cf/number/ argument can be used to specify
(the number of hops). the number of hops (used for TTL). Note that the number of
Default: switched off. networks (edges) in a path is counted, i.e. if two BGP
speakers are separated by one router, the number of hops is
2. Default: switched off.
<tag>source address <m/ip/</tag> Define local address we <tag>source address <m/ip/</tag> Define local address we
should use for next hop calculation and as a source address should use for next hop calculation and as a source address
@ -1169,6 +1171,18 @@ for each neighbor using the following configuration parameters:
as an IGP routing table. Default: the same as the table BGP is as an IGP routing table. Default: the same as the table BGP is
connected to. connected to.
<tag>ttl security <m/switch/</tag> Use GTSM (RFC 5082 - the
generalized TTL security mechanism). GTSM protects against
spoofed packets by ignoring received packets with a smaller
than expected TTL. To work properly, GTSM have to be enabled
on both sides of a BGP session. If both <cf/ttl security/ and
<cf/multihop/ options are enabled, <cf/multihop/ option should
specify proper hop value to compute expected TTL. Kernel
support required: Linux: 2.6.34+ (IPv4), 2.6.35+ (IPv6), BSD:
since long ago, IPv4 only. Note that full (ICMP protection,
for example) RFC 5082 support is provided by Linux
only. Default: disabled.
<tag>password <m/string/</tag> Use this password for MD5 authentication <tag>password <m/string/</tag> Use this password for MD5 authentication
of BGP sessions. Default: no authentication. Password has to be set by of BGP sessions. Default: no authentication. Password has to be set by
external utility (e.g. setkey(8)) on BSD systems. external utility (e.g. setkey(8)) on BSD systems.

View file

@ -54,7 +54,8 @@ int sk_send(sock *, unsigned len); /* Send data, <0=err, >0=ok, 0=sleep */
int sk_send_to(sock *, unsigned len, ip_addr to, unsigned port); /* sk_send to given destination */ int sk_send_to(sock *, unsigned len, ip_addr to, unsigned port); /* sk_send to given destination */
void sk_reallocate(sock *); /* Free and allocate tbuf & rbuf */ void sk_reallocate(sock *); /* Free and allocate tbuf & rbuf */
void sk_dump_all(void); void sk_dump_all(void);
int sk_set_ttl(sock *s, int ttl); /* Set TTL for given socket */ int sk_set_ttl(sock *s, int ttl); /* Set transmit TTL for given socket */
int sk_set_min_ttl(sock *s, int ttl); /* Set minimal accepted TTL for given socket */
/* Add or remove security associations for given passive socket */ /* Add or remove security associations for given passive socket */
int sk_set_md5_auth(sock *s, ip_addr a, char *passwd); int sk_set_md5_auth(sock *s, ip_addr a, char *passwd);

View file

@ -92,6 +92,8 @@ static int
bgp_open(struct bgp_proto *p) bgp_open(struct bgp_proto *p)
{ {
struct config *cfg = p->cf->c.global; struct config *cfg = p->cf->c.global;
int errcode;
bgp_counter++; bgp_counter++;
if (!bgp_listen_sk) if (!bgp_listen_sk)
@ -100,10 +102,8 @@ bgp_open(struct bgp_proto *p)
if (!bgp_listen_sk) if (!bgp_listen_sk)
{ {
bgp_counter--; bgp_counter--;
p->p.disabled = 1; errcode = BEM_NO_SOCKET;
bgp_store_error(p, NULL, BE_MISC, BEM_NO_SOCKET); goto err;
proto_notify_state(&p->p, PS_DOWN);
return -1;
} }
if (!bgp_linpool) if (!bgp_linpool)
@ -115,14 +115,18 @@ bgp_open(struct bgp_proto *p)
if (rv < 0) if (rv < 0)
{ {
bgp_close(p, 0); bgp_close(p, 0);
p->p.disabled = 1; errcode = BEM_INVALID_MD5;
bgp_store_error(p, NULL, BE_MISC, BEM_INVALID_MD5); goto err;
proto_notify_state(&p->p, PS_DOWN);
return -1;
} }
} }
return 0; return 0;
err:
p->p.disabled = 1;
bgp_store_error(p, NULL, BE_MISC, errcode);
proto_notify_state(&p->p, PS_DOWN);
return -1;
} }
static void static void
@ -567,6 +571,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
{ {
sock *s; sock *s;
struct bgp_conn *conn = &p->outgoing_conn; struct bgp_conn *conn = &p->outgoing_conn;
int hops = p->cf->multihop ? : 1;
DBG("BGP: Connecting\n"); DBG("BGP: Connecting\n");
s = sk_new(p->p.pool); s = sk_new(p->p.pool);
@ -574,7 +579,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
s->saddr = p->source_addr; s->saddr = p->source_addr;
s->daddr = p->cf->remote_ip; s->daddr = p->cf->remote_ip;
s->dport = BGP_PORT; s->dport = BGP_PORT;
s->ttl = p->cf->multihop ? : 1; s->ttl = p->cf->ttl_security ? 255 : hops;
s->rbsize = BGP_RX_BUFFER_SIZE; s->rbsize = BGP_RX_BUFFER_SIZE;
s->tbsize = BGP_TX_BUFFER_SIZE; s->tbsize = BGP_TX_BUFFER_SIZE;
s->tos = IP_PREC_INTERNET_CONTROL; s->tos = IP_PREC_INTERNET_CONTROL;
@ -584,11 +589,25 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
bgp_setup_conn(p, conn); bgp_setup_conn(p, conn);
bgp_setup_sk(conn, s); bgp_setup_sk(conn, s);
bgp_conn_set_state(conn, BS_CONNECT); bgp_conn_set_state(conn, BS_CONNECT);
if (sk_open(s))
if (sk_open(s) < 0)
{ {
bgp_sock_err(s, 0); bgp_sock_err(s, 0);
return; return;
} }
/* Set minimal receive TTL if needed */
if (p->cf->ttl_security)
{
DBG("Setting minimum received TTL to %d", 256 - hops);
if (sk_set_min_ttl(s, 256 - hops) < 0)
{
log(L_ERR "TTL security configuration failed, closing session");
bgp_sock_err(s, 0);
return;
}
}
DBG("BGP: Waiting for connect success\n"); DBG("BGP: Waiting for connect success\n");
bgp_start_timer(conn->connect_retry_timer, p->cf->connect_retry_time); bgp_start_timer(conn->connect_retry_timer, p->cf->connect_retry_time);
} }
@ -627,9 +646,22 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED)
if (!acc) if (!acc)
goto err; goto err;
int hops = p->cf->multihop ? : 1;
if (p->cf->ttl_security)
{
/* TTL security support */
if ((sk_set_ttl(sk, 255) < 0) ||
(sk_set_min_ttl(sk, 256 - hops) < 0))
{
log(L_ERR "TTL security configuration failed, closing session");
goto err;
}
}
else
sk_set_ttl(sk, hops);
bgp_setup_conn(p, &p->incoming_conn); bgp_setup_conn(p, &p->incoming_conn);
bgp_setup_sk(&p->incoming_conn, sk); bgp_setup_sk(&p->incoming_conn, sk);
sk_set_ttl(sk, p->cf->multihop ? : 1);
bgp_send_open(&p->incoming_conn); bgp_send_open(&p->incoming_conn);
return 0; return 0;
} }
@ -656,6 +688,7 @@ bgp_setup_listen_sk(ip_addr addr, unsigned port, u32 flags)
sock *s = sk_new(&root_pool); sock *s = sk_new(&root_pool);
DBG("BGP: Creating listening socket\n"); DBG("BGP: Creating listening socket\n");
s->type = SK_TCP_PASSIVE; s->type = SK_TCP_PASSIVE;
s->ttl = 255;
s->saddr = addr; s->saddr = addr;
s->sport = port ? port : BGP_PORT; s->sport = port ? port : BGP_PORT;
s->flags = flags ? 0 : SKF_V6ONLY; s->flags = flags ? 0 : SKF_V6ONLY;
@ -664,14 +697,15 @@ bgp_setup_listen_sk(ip_addr addr, unsigned port, u32 flags)
s->tbsize = BGP_TX_BUFFER_SIZE; s->tbsize = BGP_TX_BUFFER_SIZE;
s->rx_hook = bgp_incoming_connection; s->rx_hook = bgp_incoming_connection;
s->err_hook = bgp_listen_sock_err; s->err_hook = bgp_listen_sock_err;
if (sk_open(s))
if (sk_open(s) < 0)
{ {
log(L_ERR "BGP: Unable to open listening socket"); log(L_ERR "BGP: Unable to open listening socket");
rfree(s); rfree(s);
return NULL; return NULL;
} }
else
return s; return s;
} }
static void static void

View file

@ -20,6 +20,7 @@ struct bgp_config {
u32 local_as, remote_as; u32 local_as, remote_as;
ip_addr remote_ip; ip_addr remote_ip;
int multihop; /* Number of hops if multihop */ int multihop; /* Number of hops if multihop */
int ttl_security; /* Enable TTL security [RFC5082] */
ip_addr source_addr; /* Source address to use */ ip_addr source_addr; /* Source address to use */
int next_hop_self; /* Always set next hop to local IP address */ int next_hop_self; /* Always set next hop to local IP address */
int missing_lladdr; /* What we will do when we don' know link-local addr, see MLL_* */ int missing_lladdr; /* What we will do when we don' know link-local addr, see MLL_* */

View file

@ -25,7 +25,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY,
CLUSTER, ID, AS4, ADVERTISE, IPV4, CAPABILITIES, LIMIT, PASSIVE, CLUSTER, ID, AS4, ADVERTISE, IPV4, CAPABILITIES, LIMIT, PASSIVE,
PREFER, OLDER, MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH, PREFER, OLDER, MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH,
INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP, INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP,
TABLE, GATEWAY, DIRECT, RECURSIVE, MED) TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL, SECURITY)
CF_GRAMMAR CF_GRAMMAR
@ -71,7 +71,7 @@ bgp_proto:
| bgp_proto CONNECT RETRY TIME expr ';' { BGP_CFG->connect_retry_time = $5; } | bgp_proto CONNECT RETRY TIME expr ';' { BGP_CFG->connect_retry_time = $5; }
| bgp_proto KEEPALIVE TIME expr ';' { BGP_CFG->keepalive_time = $4; } | bgp_proto KEEPALIVE TIME expr ';' { BGP_CFG->keepalive_time = $4; }
| bgp_proto MULTIHOP ';' { BGP_CFG->multihop = 64; } | bgp_proto MULTIHOP ';' { BGP_CFG->multihop = 64; }
| bgp_proto MULTIHOP expr ';' { BGP_CFG->multihop = $3; } | bgp_proto MULTIHOP expr ';' { BGP_CFG->multihop = $3; if (($3<1) || ($3>255)) cf_error("Multihop must be in range 1-255"); }
| bgp_proto NEXT HOP SELF ';' { BGP_CFG->next_hop_self = 1; } | bgp_proto NEXT HOP SELF ';' { BGP_CFG->next_hop_self = 1; }
| bgp_proto MISSING LLADDR SELF ';' { BGP_CFG->missing_lladdr = MLL_SELF; } | bgp_proto MISSING LLADDR SELF ';' { BGP_CFG->missing_lladdr = MLL_SELF; }
| bgp_proto MISSING LLADDR DROP ';' { BGP_CFG->missing_lladdr = MLL_DROP; } | bgp_proto MISSING LLADDR DROP ';' { BGP_CFG->missing_lladdr = MLL_DROP; }
@ -98,6 +98,7 @@ bgp_proto:
| bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; } | bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; }
| bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; } | bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; }
| bgp_proto IGP TABLE rtable ';' { BGP_CFG->igp_table = $4; } | bgp_proto IGP TABLE rtable ';' { BGP_CFG->igp_table = $4; }
| bgp_proto TTL SECURITY bool ';' { BGP_CFG->ttl_security = $4; }
; ;
CF_ADDTO(dynamic_attr, BGP_ORIGIN CF_ADDTO(dynamic_attr, BGP_ORIGIN

View file

@ -237,3 +237,34 @@ sk_set_md5_auth_int(sock *s, sockaddr *sa, char *passwd)
return rv; return rv;
} }
#ifndef IPV6
static int
sk_set_min_ttl4(sock *s, int ttl)
{
if (setsockopt(s->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0)
{
if (errno == ENOPROTOOPT)
log(L_ERR "Kernel does not support IPv4 TTL security");
else
log(L_ERR "sk_set_min_ttl4: setsockopt: %m");
return -1;
}
return 0;
}
#else
static int
sk_set_min_ttl6(sock *s, int ttl)
{
log(L_ERR "IPv6 TTL security not supported");
return -1;
}
#endif

View file

@ -309,3 +309,51 @@ sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
*/ */
#endif #endif
#ifndef IP_MINTTL
#define IP_MINTTL 21
#endif
#ifndef IPV6_MINHOPCOUNT
#define IPV6_MINHOPCOUNT 73
#endif
#ifndef IPV6
static int
sk_set_min_ttl4(sock *s, int ttl)
{
if (setsockopt(s->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0)
{
if (errno == ENOPROTOOPT)
log(L_ERR "Kernel does not support IPv4 TTL security");
else
log(L_ERR "sk_set_min_ttl4: setsockopt: %m");
return -1;
}
return 0;
}
#else
static int
sk_set_min_ttl6(sock *s, int ttl)
{
if (setsockopt(s->fd, IPPROTO_IPV6, IPV6_MINHOPCOUNT, &ttl, sizeof(ttl)) < 0)
{
if (errno == ENOPROTOOPT)
log(L_ERR "Kernel does not support IPv6 TTL security");
else
log(L_ERR "sk_set_min_ttl4: setsockopt: %m");
return -1;
}
return 0;
}
#endif

View file

@ -805,7 +805,7 @@ bad:
} }
/** /**
* sk_set_ttl - set TTL for given socket. * sk_set_ttl - set transmit TTL for given socket.
* @s: socket * @s: socket
* @ttl: TTL value * @ttl: TTL value
* *
@ -828,6 +828,28 @@ sk_set_ttl(sock *s, int ttl)
return (err ? -1 : 0); return (err ? -1 : 0);
} }
/**
* sk_set_min_ttl - set minimal accepted TTL for given socket.
* @s: socket
* @ttl: TTL value
*
* Can be used in TTL security implementation
*
* Result: 0 for success, -1 for an error.
*/
int
sk_set_min_ttl(sock *s, int ttl)
{
int err;
#ifdef IPV6
err = sk_set_min_ttl6(s, ttl);
#else
err = sk_set_min_ttl4(s, ttl);
#endif
return err;
}
/** /**
* sk_set_md5_auth - add / remove MD5 security association for given socket. * sk_set_md5_auth - add / remove MD5 security association for given socket.

View file

@ -17,6 +17,7 @@
#include <signal.h> #include <signal.h>
#include <pwd.h> #include <pwd.h>
#include <grp.h> #include <grp.h>
#include <sys/stat.h>
#include "nest/bird.h" #include "nest/bird.h"
#include "lib/lists.h" #include "lib/lists.h"