]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
The generalized TTL security mechanism (RFC 5082) support.
authorOndrej Zajicek <santiago@crfreenet.org>
Tue, 16 Aug 2011 21:05:35 +0000 (23:05 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Tue, 16 Aug 2011 21:13:05 +0000 (23:13 +0200)
Thanks to Alexander V. Chernikov for the patch.

doc/bird.sgml
lib/socket.h
proto/bgp/bgp.c
proto/bgp/bgp.h
proto/bgp/config.Y
sysdep/bsd/sysio.h
sysdep/linux/sysio.h
sysdep/unix/io.c
sysdep/unix/main.c

index 406adc69eaa10b78f47da54e3e1c516165b8ebc1..2435d1cb71f5121123c707ce314bc2fb53f2e848 100644 (file)
@@ -1120,9 +1120,11 @@ for each neighbor using the following configuration parameters:
        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
@@ -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
        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.
index 348295f5bf48da07d3aa18a200a59e202bb43b9d..9b9452c65123fd985ec85ff6ff2c011f33671c9c 100644 (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 */
 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);
index 70c9b2f99beb668f79798fd3b31787c4e0c6f602..d26b4817651956682ff9d6588572fb287b7411cf 100644 (file)
@@ -92,6 +92,8 @@ static int
 bgp_open(struct bgp_proto *p)
 {
   struct config *cfg = p->cf->c.global;
+  int errcode;
+
   bgp_counter++;
 
   if (!bgp_listen_sk)
@@ -100,10 +102,8 @@ bgp_open(struct bgp_proto *p)
   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)
@@ -115,14 +115,18 @@ bgp_open(struct bgp_proto *p)
       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
@@ -567,6 +571,7 @@ bgp_connect(struct bgp_proto *p)    /* Enter Connect state and start establishing c
 {
   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);
@@ -574,7 +579,7 @@ bgp_connect(struct bgp_proto *p)    /* Enter Connect state and start establishing c
   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;
@@ -584,11 +589,25 @@ bgp_connect(struct bgp_proto *p)  /* Enter Connect state and start establishing c
   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);
 }
@@ -627,9 +646,22 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED)
            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;
          }
@@ -656,6 +688,7 @@ bgp_setup_listen_sk(ip_addr addr, unsigned port, u32 flags)
   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;
@@ -664,14 +697,15 @@ bgp_setup_listen_sk(ip_addr addr, unsigned port, u32 flags)
   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
index 12478709dce1c1551937fc0a70280122ba02ce5f..16e8ea89d31cc91f903ef4d8acd2f94a2ea72e5b 100644 (file)
@@ -20,6 +20,7 @@ struct bgp_config {
   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_* */
index 93cc85f659da072be69859554f20ce8d172da35c..19d757a526956d49417216dad5efada7f29e3ed7 100644 (file)
@@ -25,7 +25,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY,
        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
 
@@ -71,7 +71,7 @@ bgp_proto:
  | 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; }
@@ -98,6 +98,7 @@ bgp_proto:
  | 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
index 847ce2612e58701bc20820ce9f477d4e65c13317..95f7dcf467ada1b88021b774007e91244622270c 100644 (file)
@@ -237,3 +237,34 @@ sk_set_md5_auth_int(sock *s, sockaddr *sa, char *passwd)
 
   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
+
index 9c10333ad989622c2ef320e8b7f45b0fa682c2fe..bb522804285016c247b1ffc74b811c529a10c7df 100644 (file)
@@ -309,3 +309,51 @@ sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
 */
 
 #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
index b6c1b86c0fa16a3236234178d70ff1f98f4c77cc..815989f88c772d7b37e4381dca1c320a0c0b84de 100644 (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
  * @ttl: TTL value
  *
@@ -828,6 +828,28 @@ sk_set_ttl(sock *s, int ttl)
   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.
index 610d207d5c48d36054373a917e9a34e210aaf3ea..55477913bc63441a4da1153e7497dd18262fe6b0 100644 (file)
@@ -17,6 +17,7 @@
 #include <signal.h>
 #include <pwd.h>
 #include <grp.h>
+#include <sys/stat.h>
 
 #include "nest/bird.h"
 #include "lib/lists.h"