]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Implements TTL security for OSPF and RIP.
authorOndrej Zajicek <santiago@crfreenet.org>
Tue, 25 Jun 2013 13:33:00 +0000 (15:33 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Tue, 25 Jun 2013 13:39:44 +0000 (15:39 +0200)
Interfaces for OSPF and RIP could be configured to use (and request)
TTL 255 for traffic to direct neighbors.

Thanks to Simon Dickhoven for the original patch for RIPng.

lib/socket.h
proto/ospf/config.Y
proto/ospf/iface.c
proto/ospf/ospf.h
proto/ospf/packet.c
proto/rip/config.Y
proto/rip/rip.c
proto/rip/rip.h
sysdep/bsd/sysio.h
sysdep/linux/sysio.h
sysdep/unix/io.c

index fbddfb4c667edf214717dd5f77cbcf1418b25cd9..6e0a769bb08058bcadbb6da12b5fed15773ba562 100644 (file)
@@ -89,6 +89,7 @@ extern int sk_priority_control;       /* Suggested priority for control traffic, shoul
 #define SKF_V6ONLY     1       /* Use IPV6_V6ONLY socket option */
 #define SKF_LADDR_RX   2       /* Report local address for RX packets */
 #define SKF_LADDR_TX   4       /* Allow to specify local address for TX packets */
+#define SKF_TTL_RX     8       /* Report TTL / Hop Limit for RX packets */
 
 
 /*
index d9379a7cf25e1725d7efb63edb8302afad77dbfb..f042e1aa26a3251e9728980f8d8c3a44510a4ebc 100644 (file)
@@ -127,8 +127,8 @@ CF_KEYWORDS(OSPF, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG, OSPF_ROUTER_ID)
 CF_KEYWORDS(NEIGHBORS, RFC1583COMPAT, STUB, TICK, COST, COST2, RETRANSMIT)
 CF_KEYWORDS(HELLO, TRANSMIT, PRIORITY, DEAD, TYPE, BROADCAST, BCAST)
 CF_KEYWORDS(NONBROADCAST, NBMA, POINTOPOINT, PTP, POINTOMULTIPOINT, PTMP)
-CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, STRICT, CRYPTOGRAPHIC)
-CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK)
+CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, STRICT, CRYPTOGRAPHIC, TTL, SECURITY)
+CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK, ONLY)
 CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL)
 CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY)
 CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY)
@@ -307,6 +307,8 @@ ospf_iface_item:
  | RX BUFFER expr { OSPF_PATT->rxbuf = $3 ; if (($3 < OSPF_RXBUF_MINSIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); } 
  | TX tos { OSPF_PATT->tx_tos = $2; }
  | TX PRIORITY expr { OSPF_PATT->tx_priority = $3; }
+ | TTL SECURITY bool { OSPF_PATT->ttl_security = $3; }
+ | TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; }
  | password_list
  ;
 
index bc3b1ef601b429689b9d74b536855870539955fb..698ef6208aa50028f71e905ce0abc1dbcfc2eef0 100644 (file)
@@ -86,7 +86,7 @@ ospf_sk_open(struct ospf_iface *ifa)
   sk->rbsize = rxbufsize(ifa);
   sk->tbsize = rxbufsize(ifa);
   sk->data = (void *) ifa;
-  sk->flags = SKF_LADDR_RX;
+  sk->flags = SKF_LADDR_RX | (ifa->check_ttl ? SKF_TTL_RX : 0);
 
   if (sk_open(sk) != 0)
     goto err;
@@ -131,7 +131,7 @@ ospf_sk_open(struct ospf_iface *ifa)
     else
     {
       ifa->all_routers = AllSPFRouters;
-      sk->ttl = 1;     /* Hack, this will affect just multicast packets */
+      sk->ttl = ifa->cf->ttl_security ? 255 : 1;
 
       if (sk_setup_multicast(sk) < 0)
         goto err;
@@ -534,6 +534,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
   ifa->rxbuf = ip->rxbuf;
   ifa->check_link = ip->check_link;
   ifa->ecmp_weight = ip->ecmp_weight;
+  ifa->check_ttl = (ip->ttl_security == 1);
 
 #ifdef OSPFv2
   ifa->autype = ip->autype;
index 56ebcd31fd80fd1a5660292e2b8a5f77b4095e94..f1409af342a372f0a1352803b17ce5caed1c2407 100644 (file)
@@ -275,6 +275,7 @@ struct ospf_iface
   u8 check_link;               /* Whether iface link change is used */
   u8 ecmp_weight;              /* Weight used for ECMP */
   u8 ptp_netmask;              /* Send real netmask for P2P */
+  u8 check_ttl;                        /* Check incoming packets for TTL 255 */
 };
 
 struct ospf_md5
@@ -815,7 +816,8 @@ struct ospf_iface_patt
   u8 check_link;
   u8 ecmp_weight;
   u8 real_bcast;               /* Not really used in OSPFv3 */
-  u8 ptp_netmask;              /* bool but 2 for unspecified */
+  u8 ptp_netmask;              /* bool + 2 for unspecified */
+  u8 ttl_security;             /* bool + 2 for TX only */
 
 #ifdef OSPFv2
   list *passwords;
index 241a58f73831309f6080e5be6db4ed249132418e..4338bc1a8ba347ead4f574ba14c17bc305bd695c 100644 (file)
@@ -309,6 +309,12 @@ ospf_rx_hook(sock *sk, int size)
     return 1;
   }
 
+  if (ifa->check_ttl && (sk->ttl < 255))
+  {
+    log(L_ERR "%s%I - TTL %d (< 255)", mesg, sk->faddr, sk->ttl);
+    return 1;
+  }
+
   if ((unsigned) size < sizeof(struct ospf_packet))
   {
     log(L_ERR "%s%I - too short (%u bytes)", mesg, sk->faddr, size);
index ec82aa3d40c3425a155a47cd0a69a63175b8784a..791c43a2cdbdb2942eff622feb49bb7514114867 100644 (file)
@@ -22,12 +22,18 @@ CF_DEFINES
 #define RIP_CFG ((struct rip_proto_config *) this_proto)
 #define RIP_IPATT ((struct rip_patt *) this_ipatt)
 
+#ifdef IPV6
+#define RIP_DEFAULT_TTL_SECURITY 2
+#else
+#define RIP_DEFAULT_TTL_SECURITY 0
+#endif
+
 CF_DECLS
 
 CF_KEYWORDS(RIP, INFINITY, METRIC, PORT, PERIOD, GARBAGE, TIMEOUT,
            MODE, BROADCAST, MULTICAST, QUIET, NOLISTEN, VERSION1, 
-           AUTHENTICATION, NONE, PLAINTEXT, MD5,
-           HONOR, NEVER, NEIGHBOR, ALWAYS, TX, PRIORITY,
+           AUTHENTICATION, NONE, PLAINTEXT, MD5, TTL, SECURITY,
+           HONOR, NEVER, NEIGHBOR, ALWAYS, TX, PRIORITY, ONLY,
            RIP_METRIC, RIP_TAG)
 
 %type <i> rip_mode rip_auth
@@ -78,6 +84,8 @@ rip_iface_item:
  | MODE rip_mode { RIP_IPATT->mode |= $2; }
  | TX tos { RIP_IPATT->tx_tos = $2; }
  | TX PRIORITY expr { RIP_IPATT->tx_priority = $3; }
+ | TTL SECURITY bool { RIP_IPATT->ttl_security = $3; }
+ | TTL SECURITY TX ONLY { RIP_IPATT->ttl_security = 2; }
  ;
 
 rip_iface_opts: 
@@ -98,6 +106,7 @@ rip_iface_init:
      RIP_IPATT->metric = 1;
      RIP_IPATT->tx_tos = IP_PREC_INTERNET_CONTROL;
      RIP_IPATT->tx_priority = sk_priority_control;
+     RIP_IPATT->ttl_security = RIP_DEFAULT_TTL_SECURITY;
    }
  ;
 
index c09eae79f5e821244563083ecbb0c3057b71ee5f..3ec070b3e8ef686e6131b98ba7db254c58fad2ea 100644 (file)
@@ -480,6 +480,14 @@ rip_rx(sock *s, int size)
   iface = i->iface;
 #endif
 
+  if (i->check_ttl && (s->ttl < 255))
+  {
+    log( L_REMOTE "%s: Discarding packet with TTL %d (< 255) from %I on %s",
+        p->name, s->ttl, s->faddr, i->iface->name);
+    return 1;
+  }
+
+
   CHK_MAGIC;
   DBG( "RIP: message came: %d bytes from %I via %s\n", size, s->faddr, i->iface ? i->iface->name : "(dummy)" );
   size -= sizeof( struct rip_packet_heading );
@@ -686,6 +694,7 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_
     rif->mode = PATT->mode;
     rif->metric = PATT->metric;
     rif->multicast = (!(PATT->mode & IM_BROADCAST)) && (flags & IF_MULTICAST);
+    rif->check_ttl = (PATT->ttl_security == 1);
   }
   /* lookup multicasts over unnumbered links - no: rip is not defined over unnumbered links */
 
@@ -706,10 +715,10 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_
   rif->sock->dport = P_CF->port;
   if (new)
     {
-      rif->sock->ttl = 1;
       rif->sock->tos = PATT->tx_tos;
       rif->sock->priority = PATT->tx_priority;
-      rif->sock->flags = SKF_LADDR_RX;
+      rif->sock->ttl = PATT->ttl_security ? 255 : 1;
+      rif->sock->flags = SKF_LADDR_RX | (rif->check_ttl ? SKF_TTL_RX : 0);
     }
 
   if (new) {
index 2cce8c81f504d50638800f1e58d0ff6156620323..6e0d5aad8ec828163d805a424b66b510ef1b472a 100644 (file)
@@ -114,6 +114,7 @@ struct rip_interface {
   struct rip_connection *busy;
   int metric;                  /* You don't want to put struct rip_patt *patt here -- think about reconfigure */
   int mode;
+  int check_ttl;               /* Check incoming packets for TTL 255 */
   int triggered;
   struct object_lock *lock;
   int multicast;
@@ -130,6 +131,7 @@ struct rip_patt {
 #define IM_VERSION1 16
   int tx_tos;
   int tx_priority;
+  int ttl_security;    /* bool + 2 for TX only (send, but do not check on RX) */
 };
 
 struct rip_proto_config {
index 085f16fad13692411f870769fd116191ef46ccd7..031eac9af92f6a6aee8a2959a737fbf697737acd 100644 (file)
@@ -113,7 +113,9 @@ sysio_leave_group(sock *s, ip_addr maddr)
 /* BSD RX/TX packet info handling for IPv4 */
 /* it uses IP_RECVDSTADDR / IP_RECVIF socket options instead of IP_PKTINFO */
 
-#define CMSG_RX_SPACE (CMSG_SPACE(sizeof(struct in_addr)) + CMSG_SPACE(sizeof(struct sockaddr_dl)))
+#define CMSG_RX_SPACE (CMSG_SPACE(sizeof(struct in_addr)) + \
+                      CMSG_SPACE(sizeof(struct sockaddr_dl)) + \
+                      CMSG_SPACE(sizeof(char)))
 #define CMSG_TX_SPACE CMSG_SPACE(sizeof(struct in_addr))
 
 static char *
@@ -121,13 +123,18 @@ sysio_register_cmsgs(sock *s)
 {
   int ok = 1;
   if (s->flags & SKF_LADDR_RX)
-    {
-      if (setsockopt(s->fd, IPPROTO_IP, IP_RECVDSTADDR, &ok, sizeof(ok)) < 0)
-       return "IP_RECVDSTADDR";
+  {
+    if (setsockopt(s->fd, IPPROTO_IP, IP_RECVDSTADDR, &ok, sizeof(ok)) < 0)
+      return "IP_RECVDSTADDR";
+
+    if (setsockopt(s->fd, IPPROTO_IP, IP_RECVIF, &ok, sizeof(ok)) < 0)
+      return "IP_RECVIF";
+  }
+
+  if ((s->flags & SKF_TTL_RX) &&
+      (setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0))
+    return "IP_RECVTTL";
 
-      if (setsockopt(s->fd, IPPROTO_IP, IP_RECVIF, &ok, sizeof(ok)) < 0)
-       return "IP_RECVIF";
-    }
 
   return NULL;
 }
@@ -136,27 +143,35 @@ static void
 sysio_process_rx_cmsgs(sock *s, struct msghdr *msg)
 {
   struct cmsghdr *cm;
+  struct in_addr *ra = NULL;
+  struct sockaddr_dl *ri = NULL;
+  unsigned char *ttl = NULL;
 
-  if (!(s->flags & SKF_LADDR_RX))
-    return;
+  for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
+  {
+    if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVDSTADDR)
+      ra = (struct in_addr *) CMSG_DATA(cm);
 
-  s->laddr = IPA_NONE;
-  s->lifindex = 0;
+    if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVIF)
+      ri = (struct sockaddr_dl *) CMSG_DATA(cm);
 
-  for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
-    {
-      if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVDSTADDR)
-       {
-         struct in_addr *ra = (struct in_addr *) CMSG_DATA(cm);
-         get_inaddr(&s->laddr, ra);
-       }
+    if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVTTL)
+      ttl = (unsigned char *) CMSG_DATA(cm);
+  }
 
-      if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVIF)
-       {
-         struct sockaddr_dl *ri = (struct sockaddr_dl *) CMSG_DATA(cm);
-         s->lifindex = ri->sdl_index;
-       }
-    }
+  if (s->flags & SKF_LADDR_RX)
+  {
+    s->laddr = IPA_NONE;
+    s->lifindex = 0;
+
+    if (ra)
+      get_inaddr(&s->laddr, ra);
+    if (ri)
+      s->lifindex = ri->sdl_index;
+  }
+
+  if (s->flags & SKF_TTL_RX)
+    s->ttl = ttl ? *ttl : -1;
 
   // log(L_WARN "RX %I %d", s->laddr, s->lifindex);
 }
index 41287e7121eeda6a51ac0d189f158db99025aa3f..250ed5866370773d8a57d0b6101ee5587d3b8ecd 100644 (file)
@@ -194,17 +194,22 @@ sk_set_md5_auth_int(sock *s, sockaddr *sa, char *passwd)
 /* RX/TX packet info handling for IPv4 */
 /* Mostly similar to standardized IPv6 code */
 
-#define CMSG_RX_SPACE CMSG_SPACE(sizeof(struct in_pktinfo))
+#define CMSG_RX_SPACE (CMSG_SPACE(sizeof(struct in_pktinfo)) + CMSG_SPACE(sizeof(int)))
 #define CMSG_TX_SPACE CMSG_SPACE(sizeof(struct in_pktinfo))
 
 static char *
 sysio_register_cmsgs(sock *s)
 {
   int ok = 1;
+
   if ((s->flags & SKF_LADDR_RX) &&
-      setsockopt(s->fd, IPPROTO_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0)
+      (setsockopt(s->fd, IPPROTO_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0))
     return "IP_PKTINFO";
 
+  if ((s->flags & SKF_TTL_RX) &&
+      (setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0))
+    return "IP_RECVTTL";
+
   return NULL;
 }
 
@@ -213,25 +218,34 @@ sysio_process_rx_cmsgs(sock *s, struct msghdr *msg)
 {
   struct cmsghdr *cm;
   struct in_pktinfo *pi = NULL;
-
-  if (!(s->flags & SKF_LADDR_RX))
-    return;
+  int *ttl = NULL;
 
   for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
+  {
+    if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_PKTINFO)
+      pi = (struct in_pktinfo *) CMSG_DATA(cm);
+
+    if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_TTL)
+      ttl = (int *) CMSG_DATA(cm);
+  }
+
+  if (s->flags & SKF_LADDR_RX)
+  {
+    if (pi)
     {
-      if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_PKTINFO)
-       pi = (struct in_pktinfo *) CMSG_DATA(cm);
+      get_inaddr(&s->laddr, &pi->ipi_addr);
+      s->lifindex = pi->ipi_ifindex;
     }
-
-  if (!pi)
+    else
     {
       s->laddr = IPA_NONE;
       s->lifindex = 0;
-      return;
     }
+  }
+
+  if (s->flags & SKF_TTL_RX)
+    s->ttl = ttl ? *ttl : -1;
 
-  get_inaddr(&s->laddr, &pi->ipi_addr);
-  s->lifindex = pi->ipi_ifindex;
   return;
 }
 
index 434a05bed53883b394a57659fb6fa26e46b0aa79..9386388538f4361d3abb04e6c988f0d364c347a0 100644 (file)
@@ -673,7 +673,7 @@ get_sockaddr(struct sockaddr_in *sa, ip_addr *a, struct iface **ifa, unsigned *p
 #ifdef IPV6
 
 /* PKTINFO handling is also standardized in IPv6 */
-#define CMSG_RX_SPACE CMSG_SPACE(sizeof(struct in6_pktinfo))
+#define CMSG_RX_SPACE (CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)))
 #define CMSG_TX_SPACE CMSG_SPACE(sizeof(struct in6_pktinfo))
 
 /*
@@ -685,15 +685,26 @@ get_sockaddr(struct sockaddr_in *sa, ip_addr *a, struct iface **ifa, unsigned *p
 #ifndef IPV6_RECVPKTINFO
 #define IPV6_RECVPKTINFO IPV6_PKTINFO
 #endif
+/*
+ * Same goes for IPV6_HOPLIMIT -> IPV6_RECVHOPLIMIT.
+ */
+#ifndef IPV6_RECVHOPLIMIT
+#define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
+#endif
 
 static char *
 sysio_register_cmsgs(sock *s)
 {
   int ok = 1;
+
   if ((s->flags & SKF_LADDR_RX) &&
-      setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0)
+      (setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0))
     return "IPV6_RECVPKTINFO";
 
+  if ((s->flags & SKF_TTL_RX) &&
+      (setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &ok, sizeof(ok)) < 0))
+    return "IPV6_RECVHOPLIMIT";
+
   return NULL;
 }
 
@@ -702,25 +713,34 @@ sysio_process_rx_cmsgs(sock *s, struct msghdr *msg)
 {
   struct cmsghdr *cm;
   struct in6_pktinfo *pi = NULL;
-
-  if (!(s->flags & SKF_LADDR_RX))
-    return;
+  int *hlim = NULL;
 
   for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
+  {
+    if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO)
+      pi = (struct in6_pktinfo *) CMSG_DATA(cm);
+
+    if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_HOPLIMIT)
+      hlim = (int *) CMSG_DATA(cm);
+  }
+
+  if (s->flags & SKF_LADDR_RX)
+  {
+    if (pi)
     {
-      if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO)
-       pi = (struct in6_pktinfo *) CMSG_DATA(cm);
+      get_inaddr(&s->laddr, &pi->ipi6_addr);
+      s->lifindex = pi->ipi6_ifindex;
     }
-
-  if (!pi)
+    else
     {
       s->laddr = IPA_NONE;
       s->lifindex = 0;
-      return;
     }
+  }
+
+  if (s->flags & SKF_TTL_RX)
+    s->ttl = hlim ? *hlim : -1;
 
-  get_inaddr(&s->laddr, &pi->ipi6_addr);
-  s->lifindex = pi->ipi6_ifindex;
   return;
 }