Thanks to Alexander V. Chernikov for the patch.
subnets. Such IP address have to be reachable through system
routing table. For multihop BGP it is recommended to
explicitly configure <cf/source address/ to have it
- stable. Optional <cf/number/ argument can be used to limit TTL
- (the number of hops).
- Default: switched off.
+ stable. Optional <cf/number/ argument can be used to specify
+ the number of hops (used for TTL). Note that the number of
+ 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
should use for next hop calculation and as a source address
as an IGP routing table. Default: the same as the table BGP is
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
of BGP sessions. Default: no authentication. Password has to be set by
external utility (e.g. setkey(8)) on BSD systems.
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_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 */
int sk_set_md5_auth(sock *s, ip_addr a, char *passwd);
bgp_open(struct bgp_proto *p)
{
struct config *cfg = p->cf->c.global;
+ int errcode;
+
bgp_counter++;
if (!bgp_listen_sk)
if (!bgp_listen_sk)
{
bgp_counter--;
- p->p.disabled = 1;
- bgp_store_error(p, NULL, BE_MISC, BEM_NO_SOCKET);
- proto_notify_state(&p->p, PS_DOWN);
- return -1;
+ errcode = BEM_NO_SOCKET;
+ goto err;
}
if (!bgp_linpool)
if (rv < 0)
{
bgp_close(p, 0);
- p->p.disabled = 1;
- bgp_store_error(p, NULL, BE_MISC, BEM_INVALID_MD5);
- proto_notify_state(&p->p, PS_DOWN);
- return -1;
+ errcode = BEM_INVALID_MD5;
+ goto err;
}
}
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
{
sock *s;
struct bgp_conn *conn = &p->outgoing_conn;
+ int hops = p->cf->multihop ? : 1;
DBG("BGP: Connecting\n");
s = sk_new(p->p.pool);
s->saddr = p->source_addr;
s->daddr = p->cf->remote_ip;
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->tbsize = BGP_TX_BUFFER_SIZE;
s->tos = IP_PREC_INTERNET_CONTROL;
bgp_setup_conn(p, conn);
bgp_setup_sk(conn, s);
bgp_conn_set_state(conn, BS_CONNECT);
- if (sk_open(s))
+
+ if (sk_open(s) < 0)
{
bgp_sock_err(s, 0);
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");
bgp_start_timer(conn->connect_retry_timer, p->cf->connect_retry_time);
}
if (!acc)
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_sk(&p->incoming_conn, sk);
- sk_set_ttl(sk, p->cf->multihop ? : 1);
bgp_send_open(&p->incoming_conn);
return 0;
}
sock *s = sk_new(&root_pool);
DBG("BGP: Creating listening socket\n");
s->type = SK_TCP_PASSIVE;
+ s->ttl = 255;
s->saddr = addr;
s->sport = port ? port : BGP_PORT;
s->flags = flags ? 0 : SKF_V6ONLY;
s->tbsize = BGP_TX_BUFFER_SIZE;
s->rx_hook = bgp_incoming_connection;
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");
rfree(s);
return NULL;
}
- else
- return s;
+
+ return s;
}
static void
u32 local_as, remote_as;
ip_addr remote_ip;
int multihop; /* Number of hops if multihop */
+ int ttl_security; /* Enable TTL security [RFC5082] */
ip_addr source_addr; /* Source address to use */
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_* */
CLUSTER, ID, AS4, ADVERTISE, IPV4, CAPABILITIES, LIMIT, PASSIVE,
PREFER, OLDER, MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH,
INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP,
- TABLE, GATEWAY, DIRECT, RECURSIVE, MED)
+ TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL, SECURITY)
CF_GRAMMAR
| bgp_proto CONNECT RETRY TIME expr ';' { BGP_CFG->connect_retry_time = $5; }
| bgp_proto KEEPALIVE TIME expr ';' { BGP_CFG->keepalive_time = $4; }
| 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 MISSING LLADDR SELF ';' { BGP_CFG->missing_lladdr = MLL_SELF; }
| bgp_proto MISSING LLADDR DROP ';' { BGP_CFG->missing_lladdr = MLL_DROP; }
| bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; }
| bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $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
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
+
*/
#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
}
/**
- * sk_set_ttl - set TTL for given socket.
+ * sk_set_ttl - set transmit TTL for given socket.
* @s: socket
* @ttl: TTL value
*
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.
#include <signal.h>
#include <pwd.h>
#include <grp.h>
+#include <sys/stat.h>
#include "nest/bird.h"
#include "lib/lists.h"