preparations for proper manual hole punching support in new NAT API
authorChristian Grothoff <christian@grothoff.org>
Mon, 2 Jan 2017 18:15:51 +0000 (19:15 +0100)
committerChristian Grothoff <christian@grothoff.org>
Mon, 2 Jan 2017 18:15:51 +0000 (19:15 +0100)
doc/man/gnunet-nat.1
src/include/gnunet_nat_service.h
src/nat/gnunet-nat.c
src/nat/gnunet-service-nat.c
src/nat/nat.h
src/nat/nat_api.c

index 2ba2363998ae8e8f7016e76348edfb42086e1b4a..5bdbb21eb33fc6d12a0d84aa8b06907995b49728 100644 (file)
@@ -39,8 +39,8 @@ Assuming we are listening at ADDRESS for connection reversal requests.
 Ask the peer at ADDRESS for connection reversal, using the local address for the target address of the reversal.
 
 .B
-.IP "\-p PORT,  \-\-port=PORT"
-Use PORT as our external port for advertising for incoming requests.
+.IP "\-p ADDRESS,  \-\-punch=ADDRESS"
+A hole was punched manually through the NAT. We should use ADDRESS as our external hostname and port for advertising for incoming requests. The special hostname 'AUTO' can be used to indicate that GNUnet should determine the external IP address by other means (such as upnpc), and just take the port number from ADDRESS.
 
 .B
 .IP "\-s,  \-\-stun"
@@ -89,6 +89,12 @@ Initiate connection reversal request:
 
   # gnunet-nat FIXME
 
+\fBManual hole punching:\fR
+
+Assume manually punched NAT, but determine external IP automatically:
+
+  # gnunet-nat -t -p AUTO:8080
+
 \fBSTUN-based XXX:\fR
 
 XXX:
index d9ce0e6f9dedd8c4b7fdc8a840995e39d39e6146..1620c9433fd5644bdd12cd5a8a4de16852a8c772 100644 (file)
@@ -180,8 +180,7 @@ struct GNUNET_NAT_Handle;
  *
  * @param cfg configuration to use
  * @param proto protocol this is about, IPPROTO_TCP or IPPROTO_UDP
- * @param adv_port advertised port (port we are either bound to or that our OS
- *                 locally performs redirection from to our bound port).
+ * @param hole_external hostname and port of manually punched hole in NAT, otherwise NULL (or empty string)
  * @param num_addrs number of addresses in @a addrs
  * @param addrs list of local addresses packets should be redirected to
  * @param addrlens actual lengths of the addresses in @a addrs
@@ -194,7 +193,7 @@ struct GNUNET_NAT_Handle;
 struct GNUNET_NAT_Handle *
 GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
                      uint8_t proto,
-                     uint16_t adv_port,
+                     const char *hole_external,
                      unsigned int num_addrs,
                      const struct sockaddr **addrs,
                      const socklen_t *addrlens,
index a145dc800363b2bb7c3e92504216bad125d4d557..81e4549b5d2763c07e6c566a6ff8d200543a5895 100644 (file)
@@ -39,9 +39,10 @@ static int global_ret;
 static struct GNUNET_NAT_AutoHandle *ah;
 
 /**
- * Port we advertise.
+ * External hostname and port, if user manually punched
+ * the NAT.  
  */ 
-static unsigned int adv_port;
+static char *hole_external;
 
 /**
  * Flag set to 1 if we use IPPROTO_UDP.
@@ -568,7 +569,7 @@ run (void *cls,
   {
     nh = GNUNET_NAT_register (c,
                              proto,
-                             (uint16_t) adv_port,
+                             hole_external,
                              1,
                              (const struct sockaddr **) &local_sa,
                              &local_len,
@@ -697,9 +698,9 @@ main (int argc,
     {'r', "remote", "ADDRESS",
      gettext_noop ("which remote IP and port should be asked for connection reversal"),
      GNUNET_YES, &GNUNET_GETOPT_set_string, &remote_addr },
-    {'p', "port", NULL,
-     gettext_noop ("port to use to advertise"),
-     GNUNET_YES, &GNUNET_GETOPT_set_uint, &adv_port },
+    {'p', "punched", NULL,
+     gettext_noop ("external hostname and port of NAT, if punched manually; use AUTO for hostname for automatic determination of the external IP"),
+     GNUNET_YES, &GNUNET_GETOPT_set_string, &hole_external },
     {'s', "stun", NULL,
      gettext_noop ("enable STUN processing"),
      GNUNET_NO, &GNUNET_GETOPT_set_one, &do_stun },
index b547e773a131a2ad274b531280b27dda0e42897a..f432eca186de070c8d5314994a9c1664e84cba9c 100644 (file)
  * knowledge about the local network topology.
  *
  * TODO:
- * - test ICMP based NAT traversal
+ * - test and document (!) ICMP based NAT traversal
+ * - implement manual hole punching support (incl. DNS
+ *   lookup for DynDNS setups!)
  * - implement "more" autoconfig:
  *   re-work gnunet-nat-server & integrate!
+ *   + test manually punched NAT (how?)
  * - implement & test STUN processing to classify NAT;
  *   basically, open port & try different methods.
  * - implement NEW logic for external IP detection
@@ -129,6 +132,16 @@ struct ClientHandle
    * Array of addresses used by the service.
    */
   struct ClientAddress *caddrs;
+
+  /**
+   * External DNS name and port given by user due to manual
+   * hole punching.  Special DNS name 'AUTO' is used to indicate
+   * desire for automatic determination of the external IP 
+   * (instead of DNS or manual configuration, i.e. to be used 
+   * if the IP keeps changing and we have no DynDNS, but we do
+   * have a hole punched).
+   */
+  char *hole_external;
   
   /**
    * What does this client care about?
@@ -140,12 +153,6 @@ struct ClientHandle
    */
   int natted_address;
   
-  /**
-   * Port we would like as we are configured to use this one for
-   * advertising (in addition to the one we are binding to).
-   */
-  uint16_t adv_port;
-
   /**
    * Number of addresses that this service is bound to.
    * Length of the @e caddrs array.
@@ -459,7 +466,14 @@ check_register (void *cls,
       GNUNET_break (0);
       return GNUNET_SYSERR;      
     }
-  }  
+    off += alen;
+    left -= alen;
+  }
+  if (left != ntohs (message->hole_external_len))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;      
+  }
   return GNUNET_OK; 
 }
 
@@ -870,36 +884,33 @@ check_notify_client_external_ipv4_change (const struct in_addr *v4,
                                          int add)
 {
   struct sockaddr_in sa;
-  uint16_t port;
-  uint16_t bport;
+  int have_v4;
 
   /* (1) check if client cares. */
   if (! ch->natted_address)
     return;
   if (0 == (GNUNET_NAT_RF_ADDRESSES & ch->flags))
     return;
-  bport = 0;
+  have_v4 = GNUNET_NO;
   for (unsigned int i=0;i<ch->num_caddrs;i++)
   {
     const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
 
     if (AF_INET != ss->ss_family)
       continue;
-    bport = ntohs (((const struct sockaddr_in *) ss)->sin_port);
+    have_v4 = GNUNET_YES;
+    break;
   }
-  if (0 == bport)
+  if (GNUNET_NO == have_v4)
     return; /* IPv6-only */
-  
-  /* (2) figure out external port, build sockaddr */
-  port = ch->adv_port;
-  if (0 == port)
-    port = bport;
+
+  /* build address info */
   memset (&sa,
          0,
          sizeof (sa));
   sa.sin_family = AF_INET;
   sa.sin_addr = *v4;
-  sa.sin_port = htons (port);
+  sa.sin_port = htons (0);
   
   /* (3) notify client of change */
   notify_client (is_nat_v4 (v4)
@@ -1303,7 +1314,6 @@ handle_register (void *cls,
              "Received REGISTER message from client\n");
   ch->flags = message->flags;
   ch->proto = message->proto;
-  ch->adv_port = ntohs (message->adv_port);
   ch->num_caddrs = ntohs (message->num_addrs);
   ch->caddrs = GNUNET_new_array (ch->num_caddrs,
                                 struct ClientAddress);
@@ -1379,6 +1389,11 @@ handle_register (void *cls,
 
     off += alen;
   }
+
+  ch->hole_external
+    = GNUNET_strndup (off,
+                     ntohs (message->hole_external_len));
+    
   /* Actually send IP address list to client */
   for (struct LocalAddressList *lal = lal_head;
        NULL != lal;
@@ -1450,7 +1465,7 @@ notify_clients_stun_change (const struct sockaddr_in *ip,
     if (! ch->natted_address)
       continue;
     v4 = *ip;
-    v4.sin_port = htons (ch->adv_port);
+    v4.sin_port = htons (0);
     env = GNUNET_MQ_msg_extra (msg,
                               sizeof (v4),
                               GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
@@ -2132,6 +2147,7 @@ client_disconnect_cb (void *cls,
     }
   }
   GNUNET_free_non_null (ch->caddrs);
+  GNUNET_free (ch->hole_external);
   GNUNET_free (ch);
 }
 
index 5cb1c105004ee9b46c5a762630066088f9428595..af418c7c248bc15b7fcd1de81b36f53b1f461fad 100644 (file)
@@ -110,10 +110,11 @@ struct GNUNET_NAT_RegisterMessage
   uint8_t proto;
 
   /**
-   * Port we would like as we are configured to use this one for
-   * advertising (in addition to the one we are binding to).
+   * Number of bytes in the string that follow which
+   * specify the hostname and port of a manually punched
+   * hole for this client.
    */
-  uint16_t adv_port GNUNET_PACKED;
+  uint16_t hole_external_len GNUNET_PACKED;
 
   /**
    * Number of addresses that this service is bound to that follow.
@@ -124,6 +125,9 @@ struct GNUNET_NAT_RegisterMessage
 
   /* Followed by @e num_addrs addresses of type 'struct
      sockaddr' */
+
+  /* Followed by @e hole_external_len bytes giving a hostname
+     and port */
   
 };
 
index ab36d6162aa1ba05fcc37b8787d621f84461b5e1..e4dfc1629e77ec6be1c50c785b1bf4815662234a 100644 (file)
@@ -369,8 +369,7 @@ do_connect (void *cls)
  *
  * @param cfg configuration to use
  * @param proto protocol this is about, IPPROTO_TCP or IPPROTO_UDP
- * @param adv_port advertised port (port we are either bound to or that our OS
- *                 locally performs redirection from to our bound port).
+ * @param hole_external hostname and port of manually punched hole in NAT, otherwise NULL (or empty string)
  * @param num_addrs number of addresses in @a addrs
  * @param addrs list of local addresses packets should be redirected to
  * @param addrlens actual lengths of the addresses in @a addrs
@@ -383,7 +382,7 @@ do_connect (void *cls)
 struct GNUNET_NAT_Handle *
 GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
                      uint8_t proto,
-                     uint16_t adv_port,
+                     const char *hole_external,
                      unsigned int num_addrs,
                      const struct sockaddr **addrs,
                      const socklen_t *addrlens,
@@ -394,11 +393,17 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
   struct GNUNET_NAT_Handle *nh;
   struct GNUNET_NAT_RegisterMessage *rm;
   size_t len;
+  size_t hole_external_len;
   char *off;
   
   len = 0;
   for (unsigned int i=0;i<num_addrs;i++)
     len += addrlens[i];
+  hole_external_len
+    = (NULL == hole_external)
+    ? 0
+    : strlen (hole_external);
+  len += hole_external_len;
   if ( (len > GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*rm)) ||
        (num_addrs > UINT16_MAX) )
   {
@@ -414,7 +419,7 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
   if (NULL != reversal_callback)
     rm->flags |= GNUNET_NAT_RF_REVERSAL;
   rm->proto = proto;
-  rm->adv_port = htons (adv_port);
+  rm->hole_external_len = htons (hole_external_len);
   rm->num_addrs = htons ((uint16_t) num_addrs);
   off = (char *) &rm[1];
   for (unsigned int i=0;i<num_addrs;i++)
@@ -453,6 +458,9 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
                   addrlens[i]);
     off += addrlens[i];
   }
+  GNUNET_memcpy (off,
+                hole_external,
+                hole_external_len);
 
   nh = GNUNET_new (struct GNUNET_NAT_Handle);
   nh->reg = &rm->header;