improve/fix handling of NAT server logic for ICMP-based autonomous NAT traversal
authorChristian Grothoff <christian@grothoff.org>
Mon, 2 Jan 2017 08:47:37 +0000 (09:47 +0100)
committerChristian Grothoff <christian@grothoff.org>
Mon, 2 Jan 2017 08:47:37 +0000 (09:47 +0100)
src/include/gnunet_nat_service.h
src/nat/gnunet-nat.c
src/nat/gnunet-service-nat.c
src/nat/gnunet-service-nat_helper.c
src/nat/gnunet-service-nat_helper.h
src/nat/nat.h
src/nat/nat_api.c

index 4df17b53168480419c280260ee3d9cd7e90a0692..d9ce0e6f9dedd8c4b7fdc8a840995e39d39e6146 100644 (file)
@@ -155,15 +155,11 @@ typedef void
  * reversal.
  *
  * @param cls closure
- * @param local_addr address where we received the request
- * @param local_addrlen actual length of the @a local_addr
  * @param remote_addr public IP address of the other peer
  * @param remote_addrlen actual length of the @a remote_addr
  */
 typedef void
 (*GNUNET_NAT_ReversalCallback) (void *cls,
-                                const struct sockaddr *local_addr,
-                                socklen_t local_addrlen,
                                const struct sockaddr *remote_addr,
                                 socklen_t remote_addrlen);
 
index 4d0ed572371dca0499bc09f4cb7c0a80f0bb2eba..a145dc800363b2bb7c3e92504216bad125d4d557 100644 (file)
@@ -338,15 +338,11 @@ address_cb (void *cls,
  * reversal.
  *
  * @param cls closure, NULL
- * @param local_addr address where we received the request
- * @param local_addrlen actual length of the @a local_addr
  * @param remote_addr public IP address of the other peer
  * @param remote_addrlen actual length of the @a remote_addr
  */
 static void
 reversal_cb (void *cls,
-            const struct sockaddr *local_addr,
-            socklen_t local_addrlen,
             const struct sockaddr *remote_addr,
             socklen_t remote_addrlen)
 {
@@ -580,6 +576,14 @@ run (void *cls,
                              (listen_reversal) ? &reversal_cb : NULL,
                              NULL);
   }
+  else if (listen_reversal)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+               "Use of `-W` only effective in combination with `-i`\n");    
+    global_ret = 1;
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
 
   if (NULL != remote_addr)
   {
index 762175437e3afca883a18197e8bffcfed78d1c2f..b547e773a131a2ad274b531280b27dda0e42897a 100644 (file)
@@ -1,6 +1,6 @@
 /*
   This file is part of GNUnet.
-  Copyright (C) 2016 GNUnet e.V.
+  Copyright (C) 2016, 2017 GNUnet e.V.
 
   GNUnet is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published
@@ -175,6 +175,12 @@ struct LocalAddressList
    */
   struct LocalAddressList *prev;
 
+  /**
+   * Context for a gnunet-helper-nat-server used to listen
+   * for ICMP messages to this client for connection reversal.
+   */
+  struct HelperContext *hc;
+  
   /**
    * The address itself (i.e. `struct sockaddr_in` or `struct
    * sockaddr_in6`, in the respective byte order).
@@ -395,6 +401,11 @@ destroy_lal ()
     GNUNET_CONTAINER_DLL_remove (lal_head,
                                 lal_tail,
                                 lal);
+    if (NULL != lal->hc)
+    {
+      GN_stop_gnunet_nat_server_ (lal->hc);
+      lal->hc = NULL;
+    }
     GNUNET_free (lal);
   }
 }
@@ -718,10 +729,12 @@ check_notify_client (struct LocalAddressList *delta,
     GNUNET_memcpy (&v4,
                   &delta->addr,
                   alen);
+    
+    /* Check for client notifications */
     for (unsigned int i=0;i<ch->num_caddrs;i++)
     {
       const struct sockaddr_in *c4;
-      
+
       if (AF_INET != ch->caddrs[i].ss.ss_family)
        return; /* IPv4 not relevant */
       c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
@@ -890,7 +903,7 @@ check_notify_client_external_ipv4_change (const struct in_addr *v4,
   
   /* (3) notify client of change */
   notify_client (is_nat_v4 (v4)
-                ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN_PRIVATE 
+                ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN 
                 : GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_GLOBAL,
                 ch,
                 add,
@@ -1005,6 +1018,65 @@ run_external_ip (void *cls)
 }
 
 
+/**
+ * We got a connection reversal request from another peer.
+ * Notify applicable clients.
+ *
+ * @param cls closure with the `struct LocalAddressList` 
+ * @param ra IP address of the peer who wants us to connect to it 
+ */
+static void
+reversal_callback (void *cls,
+                  const struct sockaddr_in *ra)
+{
+  struct LocalAddressList *lal = cls;
+  const struct sockaddr_in *l4;
+
+  GNUNET_assert (AF_INET == lal->af);
+  l4 = (const struct sockaddr_in *) &lal->addr;
+  for (struct ClientHandle *ch = ch_head;
+       NULL != ch;
+       ch = ch->next)
+  {    
+    struct GNUNET_NAT_ConnectionReversalRequestedMessage *crrm;
+    struct GNUNET_MQ_Envelope *env;
+    int match;
+
+    /* Check if client is in applicable range for ICMP NAT traversal
+       for this local address */
+    if (! ch->natted_address)
+      continue;
+    match = GNUNET_NO;
+    for (unsigned int i=0;i<ch->num_caddrs;i++)
+    {
+      struct ClientAddress *ca = &ch->caddrs[i];
+      const struct sockaddr_in *c4;
+      
+      if (AF_INET != ca->ss.ss_family)
+       continue;
+      c4 = (const struct sockaddr_in *) &ca->ss;
+      if ( (0 != c4->sin_addr.s_addr) &&
+          (l4->sin_addr.s_addr != c4->sin_addr.s_addr) )
+       continue;
+      match = GNUNET_YES;
+      break;
+    }
+    if (! match)
+      continue;
+
+    /* Notify applicable client about connection reversal request */
+    env = GNUNET_MQ_msg_extra (crrm,
+                              sizeof (struct sockaddr_in),
+                              GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED);
+    GNUNET_memcpy (&crrm[1],
+                  ra,
+                  sizeof (struct sockaddr_in));
+    GNUNET_MQ_send (ch->mq,
+                   env);
+  }
+}
+
+
 /**
  * Task we run periodically to scan for network interfaces.
  *
@@ -1041,7 +1113,11 @@ run_scan (void *cls)
                         (AF_INET == lal->af)
                         ? sizeof (struct sockaddr_in)
                         : sizeof (struct sockaddr_in6))) )
+      {
        found = GNUNET_YES;
+       pos->hc = lal->hc;
+       lal->hc = NULL;
+      }
     }
     if (GNUNET_NO == found)
       notify_clients (lal,
@@ -1072,6 +1148,17 @@ run_scan (void *cls)
     if (GNUNET_NO == found)
       notify_clients (pos,
                      GNUNET_YES);
+    if ( (AF_INET == pos->af) &&
+        (NULL == pos->hc) &&
+        (0 != (GNUNET_NAT_AC_LAN & pos->ac)) )
+    {
+      const struct sockaddr_in *s4
+       = (const struct sockaddr_in *) &pos->addr;
+      
+      pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
+                                            &reversal_callback,
+                                            pos);
+    }
   }
   if ( (GNUNET_YES == have_nat) &&
        (GNUNET_YES == enable_upnp) &&
@@ -1164,12 +1251,12 @@ upnp_addr_change_cb (void *cls,
   {
   case AF_INET:
     ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
-      ? GNUNET_NAT_AC_LAN_PRIVATE
+      ? GNUNET_NAT_AC_LAN
       : GNUNET_NAT_AC_EXTERN;
     break;
   case AF_INET6:
     ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
-      ? GNUNET_NAT_AC_LAN_PRIVATE
+      ? GNUNET_NAT_AC_LAN
       : GNUNET_NAT_AC_EXTERN;
     break;
   default:
index 379603ae27654a70049ecb210b29616b3e36c89e..febc3c2dd4db570198fc1250c4b5e4c2bd8413f7 100644 (file)
@@ -39,7 +39,7 @@ struct HelperContext
   /**
    * IP address we pass to the NAT helper.
    */
-  const char *internal_address;
+  struct in_addr internal_address;
 
   /**
    * Function to call if we receive a reversal request.
@@ -220,6 +220,7 @@ restart_nat_server (void *cls)
 {
   struct HelperContext *h = cls;
   char *binary;
+  char ia[INET_ADDRSTRLEN];
   
   h->server_read_task = NULL;
   h->server_stdout 
@@ -232,10 +233,15 @@ restart_nat_server (void *cls)
     try_again (h);
     return;
   }
+  GNUNET_assert (NULL !=
+                inet_ntop (AF_INET,
+                           &h->internal_address,
+                           ia,
+                           sizeof (ia)));
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Starting `%s' at `%s'\n",
        "gnunet-helper-nat-server",
-       h->internal_address);
+       ia);
   /* Start the server process */
   binary
     = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-server");
@@ -247,7 +253,7 @@ restart_nat_server (void *cls)
                               NULL,
                               binary,
                               "gnunet-helper-nat-server",
-                              h->internal_address,
+                              ia,
                               NULL);
   GNUNET_free (binary);
   if (NULL == h->server_proc)
@@ -285,7 +291,7 @@ restart_nat_server (void *cls)
  * @return NULL on error
  */
 struct HelperContext *
-GN_start_gnunet_nat_server_ (const char *internal_address,
+GN_start_gnunet_nat_server_ (const struct in_addr *internal_address,
                             GN_ReversalCallback cb,
                             void *cb_cls)
 {
@@ -294,8 +300,7 @@ GN_start_gnunet_nat_server_ (const char *internal_address,
   h = GNUNET_new (struct HelperContext);
   h->cb = cb;
   h->cb_cls = cb_cls;
-  h->internal_address
-    = internal_address;
+  h->internal_address = *internal_address;
   if (NULL == h->server_stdout)
   {
     GN_stop_gnunet_nat_server_ (h);
index d3f1a757c7cae85a18b81a85e349f32f272ef656..026526b05579e2f8fb1992f534d93349dbf98526 100644 (file)
@@ -56,7 +56,7 @@ typedef void
  * @return NULL on error
  */
 struct HelperContext *
-GN_start_gnunet_nat_server_ (const char *internal_address,
+GN_start_gnunet_nat_server_ (const struct in_addr *internal_address,
                             GN_ReversalCallback cb,
                             void *cb_cls);
 
index 3356b19ceeb0323c822cf9766bcb5b802a9d9b04..5cb1c105004ee9b46c5a762630066088f9428595 100644 (file)
@@ -191,19 +191,7 @@ struct GNUNET_NAT_ConnectionReversalRequestedMessage
    */
   struct GNUNET_MessageHeader header;
 
-  /**
-   * Size of the local address where we received the request, in NBO.
-   */
-  uint16_t local_addr_size;
-
-  /**
-   * Size of the remote address making the request, in NBO.
-   */
-  uint16_t remote_addr_size;
-
-  /* followed by a `struct sockaddr` of @e local_addr_size bytes */
-
-  /* followed by a `struct sockaddr` of @e remote_addr_size bytes */
+  /* followed by a `struct sockaddr_in` */
   
 };
 
index 481bc6fded54b95ada0476ca93b7542926f97b00..ab36d6162aa1ba05fcc37b8787d621f84461b5e1 100644 (file)
@@ -176,14 +176,7 @@ check_connection_reversal_request (void *cls,
 {
   if (ntohs (crm->header.size) !=
       sizeof (*crm) +
-      ntohs (crm->local_addr_size) +
-      ntohs (crm->remote_addr_size) )
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  if ( (sizeof (struct sockaddr_in) != ntohs (crm->local_addr_size)) ||
-       (sizeof (struct sockaddr_in) != ntohs (crm->remote_addr_size)) )
+      sizeof (struct sockaddr_in) )
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
@@ -203,13 +196,9 @@ handle_connection_reversal_request (void *cls,
                                    const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm)
 {
   struct GNUNET_NAT_Handle *nh = cls;
-  const struct sockaddr_in *local_sa = (const struct sockaddr_in *) &crm[1];
-  const struct sockaddr_in *remote_sa = &local_sa[1];
 
   nh->reversal_callback (nh->callback_cls,
-                        (const struct sockaddr *) local_sa,
-                        sizeof (struct sockaddr_in),
-                        (const struct sockaddr *) remote_sa,
+                        (const struct sockaddr *) &crm[1],
                         sizeof (struct sockaddr_in));
 }