2 This file is part of GNUnet.
3 (C) 2010 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file src/transport/gnunet-nat-server-udp.c
23 * @brief Test for NAT traversal using ICMP method.
24 * @author Christian Grothoff
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <arpa/inet.h>
29 #include <sys/types.h>
36 #include <netinet/in.h>
42 * How often do we send our UDP messages to keep ports open (and to
43 * try to connect, of course). Assuming the NAT closes UDP ports
44 * after 60s, we need at least about 100ms here for 512 ports;
45 * however, we should open the ports quickly (and we don't yet
46 * differentiate between the first round and later rounds), so we pick
47 * a much lower value here for now.
49 #define UDP_SEND_FREQUENCY_MS 50
52 * Port we always try to use.
54 #define NAT_TRAV_PORT 22225
57 * Number of UDP ports to keep open at the same time (typically >= 256).
58 * Should be less than FD_SETSIZE.
60 #define NUM_UDP_PORTS 1000
63 * How often do we retry to open and bind a UDP socket before giving up?
65 #define MAX_BIND_TRIES 10
68 * How long do we try at most? We expect the other side to give
69 * up after about one minute for now.
71 #define MAX_DURATION 60000
73 #define LOW_PORT 32768
76 * create a random port number that is not totally
77 * unlikely to be chosen by the nat box.
82 return LOW_PORT + ( (unsigned int)rand ()) % (64 * 1024 - LOW_PORT - 2);
87 * create a fresh udp socket bound to a random local port,
88 * or, if the argument is zero, to the NAT_TRAV_PORT.
94 make_udp_socket (int i)
98 struct sockaddr_in src;
100 for (tries=0;tries<MAX_BIND_TRIES;tries++)
102 ret = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
106 "Error opening udp socket: %s\n",
110 if (ret >= FD_SETSIZE)
113 "Socket number too large (%d > %u)\n",
115 (unsigned int) FD_SETSIZE);
119 memset (&src, 0, sizeof (src));
120 src.sin_family = AF_INET;
122 src.sin_port = htons (NAT_TRAV_PORT);
124 src.sin_port = htons (make_port ());
125 if (0 != bind (ret, (struct sockaddr*) &src, sizeof (src)))
133 "Error binding udp socket: %s\n",
140 main (int argc, char *const *argv)
142 int udpsocks[NUM_UDP_PORTS];
144 struct in_addr external;
145 struct in_addr target;
150 struct sockaddr_in dst;
151 struct sockaddr_in src;
153 char dummybuf[65536];
163 "This program must be started with our IP and the targets external IP as arguments.\n");
166 if ( (1 != inet_pton (AF_INET, argv[1], &external)) ||
167 (1 != inet_pton (AF_INET, argv[2], &target)) )
170 "Error parsing IPv4 address: %s\n",
175 "Trying to connect to %s\n",
177 srand (stime = time(NULL));
178 for (i=0;i<NUM_UDP_PORTS;i++)
179 udpsocks[i] = make_udp_socket (i);
180 memset (&dst, 0, sizeof (dst));
181 dst.sin_family = AF_INET;
182 dst.sin_addr = target;
185 while (stime + MAX_DURATION >= time (NULL))
189 for (i=0;i<NUM_UDP_PORTS;i++)
191 if (udpsocks[i] != -1)
192 FD_SET (udpsocks[i], &rs);
193 if (udpsocks[i] > max)
197 tv.tv_usec = UDP_SEND_FREQUENCY_MS * 1000;
198 select (max + 1, &rs, NULL, NULL, &tv);
199 for (i=0;i<NUM_UDP_PORTS;i++)
201 if (udpsocks[i] == -1)
203 if (! FD_ISSET (udpsocks[i], &rs))
206 recvfrom (udpsocks[i],
207 dummybuf, sizeof (dummybuf), 0,
208 (struct sockaddr*) &src,
210 if (slen != sizeof (src))
213 "Unexpected size of address.\n");
216 if (0 != memcmp (&src.sin_addr,
221 "Unexpected sender IP\n");
224 /* discovered port! */
228 ntohs (src.sin_port));
229 dst.sin_port = src.sin_port;
230 if (-1 == sendto (udpsocks[i],
232 (struct sockaddr*) &dst, sizeof (dst)))
235 "sendto failed: %s\n",
241 "Succeeded after %u packets.\n",
245 if (udpsocks[pos] == -1)
247 udpsocks[pos] = make_udp_socket (pos);
250 if ( (0 == ((unsigned int)rand() % NUM_UDP_PORTS)) ||
252 dst.sin_port = htons (NAT_TRAV_PORT);
254 dst.sin_port = htons (make_port ());
256 "Sending UDP packet to `%s:%u'\n",
258 ntohs (dst.sin_port));
260 if (-1 == sendto (udpsocks[pos],
262 (struct sockaddr*) &dst, sizeof (dst)))
265 "sendto failed: %s\n",
267 close (udpsocks[pos]);
268 udpsocks[pos] = make_udp_socket (pos);
270 pos = (pos+1) % NUM_UDP_PORTS;
273 "Giving up after %u tries.\n",
278 /* end of server-test.c */