From 19b13a33872cef3616e188daade61fc8b662ea35 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 8 Feb 2010 12:52:43 +0000 Subject: more --- src/transport/gnunet-nat-client-script.sh | 4 + src/transport/gnunet-nat-client-udp.c | 298 ++++++++++++++++++++++++++++++ src/transport/gnunet-nat-server-script.sh | 4 + src/transport/gnunet-nat-server-udp.c | 278 ++++++++++++++++++++++++++++ 4 files changed, 584 insertions(+) create mode 100755 src/transport/gnunet-nat-client-script.sh create mode 100644 src/transport/gnunet-nat-client-udp.c create mode 100755 src/transport/gnunet-nat-server-script.sh create mode 100644 src/transport/gnunet-nat-server-udp.c (limited to 'src') diff --git a/src/transport/gnunet-nat-client-script.sh b/src/transport/gnunet-nat-client-script.sh new file mode 100755 index 000000000..4e4ccafad --- /dev/null +++ b/src/transport/gnunet-nat-client-script.sh @@ -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 diff --git a/src/transport/gnunet-nat-client-udp.c b/src/transport/gnunet-nat-client-udp.c new file mode 100644 index 000000000..c17710b61 --- /dev/null +++ b/src/transport/gnunet-nat-client-udp.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * 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= 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 tries++) + { + FD_ZERO (&rs); + for (i=0;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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +/** + * 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= 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= time (NULL)) + { + tries++; + FD_ZERO (&rs); + for (i=0;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