expand logic for address class detection, including private and sensitive IP classifi...
authorChristian Grothoff <christian@grothoff.org>
Sun, 27 Nov 2016 22:43:46 +0000 (23:43 +0100)
committerChristian Grothoff <christian@grothoff.org>
Sun, 27 Nov 2016 22:43:46 +0000 (23:43 +0100)
src/include/gnunet_nat_service.h
src/nat/gnunet-service-nat.c

index ad3438538d19f40d5e59906b411997343dacc9f2..a590695452fa017a9b74cfdec8dd75895eee2770 100644 (file)
@@ -64,16 +64,21 @@ enum GNUNET_NAT_AddressClass
   GNUNET_NAT_AC_OTHER = 1,
 
   /**
-   * Addresses that are global and are insensitive
-   * (i.e. IPv4).
+   * Addresses that are highly sensitive
+   * (i.e. IPv6 with our MAC).
+   */
+  GNUNET_NAT_AC_PRIVATE = 2,
+
+  /**
+   * Addresses that are global (i.e. IPv4).
    */
-  GNUNET_NAT_AC_GLOBAL = 2,
+  GNUNET_NAT_AC_GLOBAL = 4,
 
   /**
    * Addresses that are global and are sensitive
    * (i.e. IPv6 with our MAC).
    */
-  GNUNET_NAT_AC_GLOBAL_PRIVATE = 4,
+  GNUNET_NAT_AC_GLOBAL_PRIVATE = 6,
 
   /**
    * Addresses useful in the local wired network,
@@ -81,6 +86,13 @@ enum GNUNET_NAT_AddressClass
    * Useful for broadcasts.
    */
   GNUNET_NAT_AC_LAN = 8,
+  
+  /**
+   * Addresses useful in the local wired network,
+   * i.e. a MAC.  Sensitive, but obvious to people nearby.
+   * Useful for broadcasts.
+   */
+  GNUNET_NAT_AC_LAN_PRIVATE = 10,
 
   /**
    * Addresses useful in the local wireless network,
@@ -95,6 +107,11 @@ enum GNUNET_NAT_AddressClass
    */
   GNUNET_NAT_AC_BT = 32,
 
+  /**
+   * Loopback addresses, only useful under special cirumstances.
+   */
+  GNUNET_NAT_AC_LOOPBACK = 64,
+  
   /**
    * Bitmask for "any" address.
    */
index e42a94ea47144d926eaf42474c114eea6330cf75..a6aa21cd18b4f56c00a721bc160a9c811ccdd8d9 100644 (file)
@@ -603,6 +603,72 @@ struct IfcProcContext
 };
 
 
+/**
+ * Check if @a ip is in @a network with @a bits netmask.
+ *
+ * @param network to test
+ * @param ip IP address to test
+ * @param bits bitmask for the network
+ * @return #GNUNET_YES if @a ip is in @a network
+ */
+static int
+match_ipv4 (const char *network,
+           const struct in_addr *ip,
+           uint8_t bits)
+{
+  struct in_addr net;
+  
+  if (0 == bits)
+    return GNUNET_YES;
+  GNUNET_assert (1 == inet_pton (AF_INET,
+                                network,
+                                &net));
+  return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
+}
+
+
+/**
+ * Check if @a ip is in @a network with @a bits netmask.
+ *
+ * @param network to test
+ * @param ip IP address to test
+ * @param bits bitmask for the network
+ * @return #GNUNET_YES if @a ip is in @a network
+ */
+static int
+match_ipv6 (const char *network,
+           const struct in6_addr *ip,
+           uint8_t bits)
+{
+  struct in6_addr net;
+  struct in6_addr mask;
+  unsigned int off;
+  
+  if (0 == bits)
+    return GNUNET_YES;
+  GNUNET_assert (1 == inet_pton (AF_INET,
+                                network,
+                                &net));
+  memset (&mask, 0, sizeof (mask));
+  off = 0;
+  while (bits > 8)
+  {
+    mask.s6_addr[off++] = 0xFF;
+    bits -= 8;
+  }
+  while (bits > 0)
+  {
+    mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
+    bits--;
+  }
+  for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
+    if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
+       (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
+      return GNUNET_NO;
+  return GNUNET_YES;
+}
+
+
 /**
  * Callback function invoked for each interface found.  Adds them
  * to our new address list.
@@ -629,16 +695,43 @@ ifc_proc (void *cls,
   struct LocalAddressList *lal;
   size_t alen;
   const void *ip;
+  const struct in6_addr *v6;
+  enum GNUNET_NAT_AddressClass ac;
 
   switch (addr->sa_family)
   {
   case AF_INET:
     alen = sizeof (struct in_addr);
     ip = &((const struct sockaddr_in *) addr)->sin_addr;
+    if (match_ipv4 ("127.0.0.0", ip, 8))
+      ac = GNUNET_NAT_AC_LOOPBACK;
+    else if (match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
+            match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
+            match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
+            match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
+            match_ipv4 ("172.16.0.0", ip, 16))  /* RFC 1918 */
+      ac = GNUNET_NAT_AC_LAN;
+    else
+      ac = GNUNET_NAT_AC_GLOBAL;
     break;
   case AF_INET6:
     alen = sizeof (struct in6_addr);
     ip = &((const struct sockaddr_in6 *) addr)->sin6_addr;
+    if (match_ipv6 ("::1", ip, 128))
+      ac = GNUNET_NAT_AC_LOOPBACK;
+    else if (match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
+            match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
+            match_ipv6 ("fe80::", ip, 10)) /* RFC 4291, link-local */
+      ac = GNUNET_NAT_AC_LAN;
+    else
+      ac = GNUNET_NAT_AC_GLOBAL;
+    v6 = ip;
+    if ( (v6->s6_addr[11] == 0xFF) &&
+        (v6->s6_addr[12] == 0xFE) )
+    {
+      /* contains a MAC, be extra careful! */
+      ac |= GNUNET_NAT_AC_PRIVATE;
+    }
     break;
 #if AF_UNIX
   case AF_UNIX:
@@ -652,6 +745,7 @@ ifc_proc (void *cls,
   lal = GNUNET_malloc (sizeof (*lal) + alen);
   lal->af = addr->sa_family;
   lal->addr = &lal[1];
+  lal->ac = ac;
   GNUNET_memcpy (&lal[1],
                 ip,
                 alen);