gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r10253 - gnunet/src/transport


From: gnunet
Subject: [GNUnet-SVN] r10253 - gnunet/src/transport
Date: Mon, 8 Feb 2010 13:52:43 +0100

Author: grothoff
Date: 2010-02-08 13:52:43 +0100 (Mon, 08 Feb 2010)
New Revision: 10253

Added:
   gnunet/src/transport/gnunet-nat-client-script.sh
   gnunet/src/transport/gnunet-nat-client-udp.c
   gnunet/src/transport/gnunet-nat-server-script.sh
   gnunet/src/transport/gnunet-nat-server-udp.c
Log:
more

Added: gnunet/src/transport/gnunet-nat-client-script.sh
===================================================================
--- gnunet/src/transport/gnunet-nat-client-script.sh                            
(rev 0)
+++ gnunet/src/transport/gnunet-nat-client-script.sh    2010-02-08 12:52:43 UTC 
(rev 10253)
@@ -0,0 +1,4 @@
+#!/bin/sh
+IP=`ifconfig | grep inet | head -n1 | awk '{print $2}' | sed -e "s/addr://"`
+echo "Using IP $IP, trying to connect to $1"
+./gnunet-nat-client-udp $IP $1


Property changes on: gnunet/src/transport/gnunet-nat-client-script.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: gnunet/src/transport/gnunet-nat-client-udp.c
===================================================================
--- gnunet/src/transport/gnunet-nat-client-udp.c                                
(rev 0)
+++ gnunet/src/transport/gnunet-nat-client-udp.c        2010-02-08 12:52:43 UTC 
(rev 10253)
@@ -0,0 +1,298 @@
+/*
+     This file is part of GNUnet.
+     (C) 2010 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file src/transport/client-test.c
+ * @brief Test for NAT traversal using ICMP method.
+ * @author Christian Grothoff
+ */
+#include <sys/types.h> 
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <netinet/in.h> 
+#include <time.h>
+
+/**
+ * How often do we send our UDP messages to keep ports open (and to
+ * try to connect, of course).  Use small value since we are the
+ * initiator and should hence be rather aggressive.
+ */
+#define UDP_SEND_FREQUENCY_MS 5
+
+/**
+ * Port we always try to use.
+ */
+#define NAT_TRAV_PORT 22223
+
+/**
+ * Number of UDP ports to keep open at the same time (typically >= 256).
+ * Should be less than FD_SETSIZE.
+ */
+#define NUM_UDP_PORTS 1000
+
+/**
+ * How often do we retry to open and bind a UDP socket before giving up?
+ */
+#define MAX_BIND_TRIES 10
+
+/**
+ * How often do we try at most?  We expect to need (for the worst kind
+ * of NAT) on average 64512 / 512 = 126 attempts to have the right
+ * destination port and we then need to also (in the worst case) have
+ * the right source port (so 126 * 64512 = 8128512 packets on
+ * average!).  That's obviously a bit much, so we give up earlier.  The
+ * given value corresponds to about 1 minute of runtime (for a send
+ * frequency of one packet per ms).
+ *
+ * NOW: if the *server* would listen for Linux-generated ICMP 
+ * "Destination unreachables" we *might* increase our chances since
+ * maybe the firewall has some older/other UDP rules (this was
+ * the case during testing for me), but obviously that would mean
+ * more SUID'ed code. Yuck.
+ */
+#define MAX_TRIES 62500
+
+#define LOW_PORT 32768
+
+/**
+ * create a random port number that is not totally
+ * unlikely to be chosen by the nat box.
+ */
+static uint16_t 
+make_port ()
+{
+  return LOW_PORT + ( (unsigned int)rand ()) % (64 * 1024 - LOW_PORT);
+}
+
+
+/**
+ * create a fresh udp socket bound to a random local port,
+ * or, if the argument is zero, to the NAT_TRAV_PORT.
+ *
+ * @param i counter
+ * @return -1 on error
+ */
+static int
+make_udp_socket (int i)
+{
+  int ret;
+  int tries;
+  struct sockaddr_in src;
+
+  for (tries=0;tries<MAX_BIND_TRIES;tries++)
+    {
+      ret = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+      if (-1 == ret)
+        {
+          fprintf (stderr,
+                   "Error opening udp socket: %s\n",
+                   strerror (errno));
+          return -1;
+        }
+      if (ret >= FD_SETSIZE)
+        {
+          fprintf (stderr,
+                   "Socket number too large (%d > %u)\n",
+                   ret,
+                   (unsigned int) FD_SETSIZE);
+          close (ret);
+          return -1;
+        }
+      memset (&src, 0, sizeof (src));
+      src.sin_family = AF_INET;
+      if (i == 0)
+       src.sin_port = htons (NAT_TRAV_PORT);
+      else
+       src.sin_port = htons (make_port ());
+      if (0 != bind (ret, (struct sockaddr*) &src, sizeof (src)))
+        {
+          close (ret);
+          continue;
+        }
+      return ret;
+    }
+  fprintf (stderr,
+           "Error binding udp socket: %s\n",
+           strerror (errno));
+  return -1;
+}
+
+
+
+
+int
+main (int argc, char *const *argv)
+{
+  int udpsocks[NUM_UDP_PORTS];
+  char command[512];
+  struct in_addr external;
+  struct in_addr target;
+  int ret;
+  unsigned int pos;
+  int i;
+  int max;
+  struct sockaddr_in dst;
+  struct sockaddr_in src;
+  int first_round = 1;
+  char dummybuf[65536];
+  unsigned int tries;
+  struct timeval tv;
+  socklen_t slen;
+  fd_set rs;
+ 
+  if (argc != 3)
+    {
+      fprintf (stderr,
+              "This program must be started with our IP and the targets 
external IP as arguments.\n");
+      return 1;
+    }
+  if ( (1 != inet_pton (AF_INET, argv[1], &external)) ||
+       (1 != inet_pton (AF_INET, argv[2], &target)) )
+    {
+      fprintf (stderr,
+              "Error parsing IPv4 address: %s\n",
+              strerror (errno));
+      return 1;
+    }
+  snprintf (command, 
+           sizeof (command),
+           "gnunet-nat-client %s %s",
+           argv[1],
+           argv[2]);
+  if (0 != (ret = system (command)))
+    {
+      if (ret == -1)
+       fprintf (stderr,
+                "Error running `%s': %s\n",
+                command,
+                strerror (errno));
+      return 1;
+    }
+  fprintf (stderr,
+          "Trying to connect to `%s'\n",
+          argv[2]);
+  srand (time(NULL));
+  for (i=0;i<NUM_UDP_PORTS;i++)
+    udpsocks[i] = make_udp_socket (i); 
+  memset (&dst, 0, sizeof (dst));
+  dst.sin_family = AF_INET;
+  dst.sin_addr = target;
+  pos = 0;
+  tries = 0;
+  while (MAX_TRIES > tries++)
+    {
+      FD_ZERO (&rs);
+      for (i=0;i<NUM_UDP_PORTS;i++)
+       {
+         if (udpsocks[i] != -1)
+           FD_SET (udpsocks[i], &rs);
+         if (udpsocks[i] > max)
+           max = udpsocks[i];
+       }
+      tv.tv_sec = 0;
+      tv.tv_usec = UDP_SEND_FREQUENCY_MS * 1000;
+      select (max + 1, &rs, NULL, NULL, &tv);
+      for (i=0;i<NUM_UDP_PORTS;i++)
+       {
+         if (udpsocks[i] == -1)
+           continue;
+         if (! FD_ISSET (udpsocks[i], &rs))
+           continue;
+         slen = sizeof (src);
+         recvfrom (udpsocks[i], 
+                   dummybuf, sizeof (dummybuf), 0,
+                   (struct sockaddr*) &src,
+                   &slen);
+         if (slen != sizeof (src))
+           {
+             fprintf (stderr,
+                      "Unexpected size of address.\n");
+             continue;
+           }
+         if (0 != memcmp (&src.sin_addr,
+                          &target,
+                          sizeof (external)))
+           {
+             fprintf (stderr,
+                      "Unexpected sender IP\n");
+             continue;
+           }
+         /* discovered port! */
+         fprintf (stdout,
+                  "%s:%u\n",
+                  argv[2],
+                  ntohs (src.sin_port));
+         dst.sin_port = src.sin_port;
+         if (-1 == sendto (udpsocks[i],
+                           NULL, 0, 0,
+                           (struct sockaddr*) &dst, sizeof (dst)))
+           {
+             fprintf (stderr,
+                      "sendto failed: %s\n",
+                      strerror (errno));             
+             return 2; /* oops */
+           }     
+         /* success! */
+         fprintf (stderr,
+                  "Succeeded after %u packets.\n",
+                  tries);
+         return 0;
+        }
+      if (udpsocks[pos] == -1)
+       {
+          udpsocks[pos] = make_udp_socket (pos);
+         continue;
+       }
+      if ( (0 == ((unsigned int)rand() % NUM_UDP_PORTS)) ||
+          (1 == first_round) )
+       dst.sin_port = htons (NAT_TRAV_PORT);
+      else
+       dst.sin_port = htons (make_port ());
+      fprintf (stderr,
+              "Sending UDP packet to `%s:%u'\n",
+              argv[2],
+              ntohs (dst.sin_port));
+      first_round = 0;
+      if (-1 == sendto (udpsocks[pos],
+                        NULL, 0, 0,
+                        (struct sockaddr*) &dst, sizeof (dst)))
+        {
+          fprintf (stderr,
+                   "sendto failed: %s\n",
+                   strerror (errno));
+          close (udpsocks[pos]);
+          udpsocks[pos] = make_udp_socket (pos);
+        }
+      pos = (pos+1) % NUM_UDP_PORTS;
+    }
+  fprintf (stderr,
+          "Giving up after %u tries.\n",
+          tries);
+  return 3;
+}
+
+/* end of client-test.c */

Added: gnunet/src/transport/gnunet-nat-server-script.sh
===================================================================
--- gnunet/src/transport/gnunet-nat-server-script.sh                            
(rev 0)
+++ gnunet/src/transport/gnunet-nat-server-script.sh    2010-02-08 12:52:43 UTC 
(rev 10253)
@@ -0,0 +1,4 @@
+#!/bin/sh
+IP=`ifconfig | grep inet | head -n1 | awk '{print $2}' | sed -e "s/addr://"`
+echo "Using IP $IP"
+./gnunet-nat-server $IP | sed -u -e "s/.*/.\/gnunet-nat-server-udp $IP &\&/" | 
sh


Property changes on: gnunet/src/transport/gnunet-nat-server-script.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: gnunet/src/transport/gnunet-nat-server-udp.c
===================================================================
--- gnunet/src/transport/gnunet-nat-server-udp.c                                
(rev 0)
+++ gnunet/src/transport/gnunet-nat-server-udp.c        2010-02-08 12:52:43 UTC 
(rev 10253)
@@ -0,0 +1,278 @@
+/*
+     This file is part of GNUnet.
+     (C) 2010 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file src/transport/server-test.c
+ * @brief Test for NAT traversal using ICMP method.
+ * @author Christian Grothoff
+ */
+#include <sys/types.h> 
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <netinet/in.h> 
+#include <time.h>
+
+
+
+/**
+ * How often do we send our UDP messages to keep ports open (and to
+ * try to connect, of course).  Assuming the NAT closes UDP ports
+ * after 60s, we need at least about 100ms here for 512 ports;
+ * however, we should open the ports quickly (and we don't yet
+ * differentiate between the first round and later rounds), so we pick
+ * a much lower value here for now.
+ */
+#define UDP_SEND_FREQUENCY_MS 50
+
+/**
+ * Port we always try to use.
+ */
+#define NAT_TRAV_PORT 22225
+
+/**
+ * Number of UDP ports to keep open at the same time (typically >= 256).
+ * Should be less than FD_SETSIZE.
+ */
+#define NUM_UDP_PORTS 1000
+
+/**
+ * How often do we retry to open and bind a UDP socket before giving up?
+ */
+#define MAX_BIND_TRIES 10
+
+/**
+ * How long do we try at most?  We expect the other side to give
+ * up after about one minute for now.
+ */
+#define MAX_DURATION 60000
+
+#define LOW_PORT 32768
+
+/**
+ * create a random port number that is not totally
+ * unlikely to be chosen by the nat box.
+ */
+static uint16_t 
+make_port ()
+{
+  return LOW_PORT + ( (unsigned int)rand ()) % (64 * 1024 - LOW_PORT - 2);
+}
+
+
+/**
+ * create a fresh udp socket bound to a random local port,
+ * or, if the argument is zero, to the NAT_TRAV_PORT.
+ *
+ * @param i counter
+ * @return -1 on error
+ */
+static int
+make_udp_socket (int i)
+{
+  int ret;
+  int tries;
+  struct sockaddr_in src;
+
+  for (tries=0;tries<MAX_BIND_TRIES;tries++)
+    {
+      ret = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+      if (-1 == ret)
+        {
+          fprintf (stderr,
+                   "Error opening udp socket: %s\n",
+                   strerror (errno));
+          return -1;
+        }
+      if (ret >= FD_SETSIZE)
+        {
+          fprintf (stderr,
+                   "Socket number too large (%d > %u)\n",
+                   ret,
+                   (unsigned int) FD_SETSIZE);
+          close (ret);
+          return -1;
+        }
+      memset (&src, 0, sizeof (src));
+      src.sin_family = AF_INET;
+      if (i == 0)
+       src.sin_port = htons (NAT_TRAV_PORT);
+      else
+       src.sin_port = htons (make_port ());
+      if (0 != bind (ret, (struct sockaddr*) &src, sizeof (src)))
+        {
+          close (ret);
+          continue;
+        }
+      return ret;
+    }
+  fprintf (stderr,
+           "Error binding udp socket: %s\n",
+           strerror (errno));
+  return -1;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+  int udpsocks[NUM_UDP_PORTS];
+  char command[512];
+  struct in_addr external;
+  struct in_addr target;
+  int ret;
+  unsigned int pos;
+  int i;
+  int max;
+  struct sockaddr_in dst;
+  struct sockaddr_in src;
+  int first_round = 1;
+  char dummybuf[65536];
+  unsigned int tries;
+  struct timeval tv;
+  socklen_t slen;
+  fd_set rs;
+  time_t stime;
+ 
+  if (argc != 3)
+    {
+      fprintf (stderr,
+              "This program must be started with our IP and the targets 
external IP as arguments.\n");
+      return 1;
+    }
+  if ( (1 != inet_pton (AF_INET, argv[1], &external)) ||
+       (1 != inet_pton (AF_INET, argv[2], &target)) )
+    {
+      fprintf (stderr,
+              "Error parsing IPv4 address: %s\n",
+              strerror (errno));
+      return 1;
+    }
+  fprintf (stderr,
+          "Trying to connect to %s\n",
+          argv[2]);
+  srand (stime = time(NULL));
+  for (i=0;i<NUM_UDP_PORTS;i++)
+    udpsocks[i] = make_udp_socket (i); 
+  memset (&dst, 0, sizeof (dst));
+  dst.sin_family = AF_INET;
+  dst.sin_addr = target;
+  pos = 0;
+  tries = 0;
+  while (stime + MAX_DURATION >= time (NULL))
+    {
+      tries++;
+      FD_ZERO (&rs);
+      for (i=0;i<NUM_UDP_PORTS;i++)
+       {
+         if (udpsocks[i] != -1)
+           FD_SET (udpsocks[i], &rs);
+         if (udpsocks[i] > max)
+           max = udpsocks[i];
+       }
+      tv.tv_sec = 0;
+      tv.tv_usec = UDP_SEND_FREQUENCY_MS * 1000;
+      select (max + 1, &rs, NULL, NULL, &tv);
+      for (i=0;i<NUM_UDP_PORTS;i++)
+       {
+         if (udpsocks[i] == -1)
+           continue;
+         if (! FD_ISSET (udpsocks[i], &rs))
+           continue;
+         slen = sizeof (src);
+         recvfrom (udpsocks[i], 
+                   dummybuf, sizeof (dummybuf), 0,
+                   (struct sockaddr*) &src,
+                   &slen);
+         if (slen != sizeof (src))
+           {
+             fprintf (stderr,
+                      "Unexpected size of address.\n");
+             continue;
+           }
+         if (0 != memcmp (&src.sin_addr,
+                          &target,
+                          sizeof (external)))
+           {
+             fprintf (stderr,
+                      "Unexpected sender IP\n");
+             continue;
+           }
+         /* discovered port! */
+         fprintf (stdout,
+                  "%s:%u\n",
+                  argv[2],
+                  ntohs (src.sin_port));
+         dst.sin_port = src.sin_port;
+         if (-1 == sendto (udpsocks[i],
+                           NULL, 0, 0,
+                           (struct sockaddr*) &dst, sizeof (dst)))
+           {
+             fprintf (stderr,
+                      "sendto failed: %s\n",
+                      strerror (errno));             
+             return 2; /* oops */
+           }     
+         /* success! */
+         fprintf (stderr,
+                  "Succeeded after %u packets.\n",
+                  tries);
+         return 0;
+        }
+      if (udpsocks[pos] == -1)
+       {
+          udpsocks[pos] = make_udp_socket (pos);
+         continue;
+       }
+      if ( (0 == ((unsigned int)rand() % NUM_UDP_PORTS)) ||
+          (1 == first_round) )
+       dst.sin_port = htons (NAT_TRAV_PORT);
+      else
+       dst.sin_port = htons (make_port ());
+      fprintf (stderr,
+              "Sending UDP packet to `%s:%u'\n",
+              argv[2],
+              ntohs (dst.sin_port));
+      first_round = 0;
+      if (-1 == sendto (udpsocks[pos],
+                        NULL, 0, 0,
+                        (struct sockaddr*) &dst, sizeof (dst)))
+        {
+          fprintf (stderr,
+                   "sendto failed: %s\n",
+                   strerror (errno));
+          close (udpsocks[pos]);
+          udpsocks[pos] = make_udp_socket (pos);
+        }
+      pos = (pos+1) % NUM_UDP_PORTS;
+    }
+  fprintf (stderr,
+          "Giving up after %u tries.\n",
+          tries);
+  return 3;
+}
+
+/* end of server-test.c */





reply via email to

[Prev in Thread] Current Thread [Next in Thread]