The generalized TTL security mechanism (RFC 5082) support.
Thanks to Alexander V. Chernikov for the patch.
This commit is contained in:
parent
a52d52fa91
commit
b1b1943360
9 changed files with 174 additions and 21 deletions
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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_* */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in a new issue