aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2010-02-08 12:52:43 +0000
committerChristian Grothoff <christian@grothoff.org>2010-02-08 12:52:43 +0000
commit19b13a33872cef3616e188daade61fc8b662ea35 (patch)
treee8ece8d018912d126d3af3297a7956bee8146b8a /src
parent0cc9e15f6613fa10058b429de0350e5632d38695 (diff)
downloadgnunet-19b13a33872cef3616e188daade61fc8b662ea35.tar.gz
gnunet-19b13a33872cef3616e188daade61fc8b662ea35.zip
more
Diffstat (limited to 'src')
-rwxr-xr-xsrc/transport/gnunet-nat-client-script.sh4
-rw-r--r--src/transport/gnunet-nat-client-udp.c298
-rwxr-xr-xsrc/transport/gnunet-nat-server-script.sh4
-rw-r--r--src/transport/gnunet-nat-server-udp.c278
4 files changed, 584 insertions, 0 deletions
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 @@
1#!/bin/sh
2IP=`ifconfig | grep inet | head -n1 | awk '{print $2}' | sed -e "s/addr://"`
3echo "Using IP $IP, trying to connect to $1"
4./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 @@
1/*
2 This file is part of GNUnet.
3 (C) 2010 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19*/
20
21/**
22 * @file src/transport/client-test.c
23 * @brief Test for NAT traversal using ICMP method.
24 * @author Christian Grothoff
25 */
26#include <sys/types.h>
27#include <sys/socket.h>
28#include <arpa/inet.h>
29#include <sys/types.h>
30#include <unistd.h>
31#include <stdio.h>
32#include <string.h>
33#include <errno.h>
34#include <stdlib.h>
35#include <stdint.h>
36#include <netinet/in.h>
37#include <time.h>
38
39/**
40 * How often do we send our UDP messages to keep ports open (and to
41 * try to connect, of course). Use small value since we are the
42 * initiator and should hence be rather aggressive.
43 */
44#define UDP_SEND_FREQUENCY_MS 5
45
46/**
47 * Port we always try to use.
48 */
49#define NAT_TRAV_PORT 22223
50
51/**
52 * Number of UDP ports to keep open at the same time (typically >= 256).
53 * Should be less than FD_SETSIZE.
54 */
55#define NUM_UDP_PORTS 1000
56
57/**
58 * How often do we retry to open and bind a UDP socket before giving up?
59 */
60#define MAX_BIND_TRIES 10
61
62/**
63 * How often do we try at most? We expect to need (for the worst kind
64 * of NAT) on average 64512 / 512 = 126 attempts to have the right
65 * destination port and we then need to also (in the worst case) have
66 * the right source port (so 126 * 64512 = 8128512 packets on
67 * average!). That's obviously a bit much, so we give up earlier. The
68 * given value corresponds to about 1 minute of runtime (for a send
69 * frequency of one packet per ms).
70 *
71 * NOW: if the *server* would listen for Linux-generated ICMP
72 * "Destination unreachables" we *might* increase our chances since
73 * maybe the firewall has some older/other UDP rules (this was
74 * the case during testing for me), but obviously that would mean
75 * more SUID'ed code. Yuck.
76 */
77#define MAX_TRIES 62500
78
79#define LOW_PORT 32768
80
81/**
82 * create a random port number that is not totally
83 * unlikely to be chosen by the nat box.
84 */
85static uint16_t
86make_port ()
87{
88 return LOW_PORT + ( (unsigned int)rand ()) % (64 * 1024 - LOW_PORT);
89}
90
91
92/**
93 * create a fresh udp socket bound to a random local port,
94 * or, if the argument is zero, to the NAT_TRAV_PORT.
95 *
96 * @param i counter
97 * @return -1 on error
98 */
99static int
100make_udp_socket (int i)
101{
102 int ret;
103 int tries;
104 struct sockaddr_in src;
105
106 for (tries=0;tries<MAX_BIND_TRIES;tries++)
107 {
108 ret = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
109 if (-1 == ret)
110 {
111 fprintf (stderr,
112 "Error opening udp socket: %s\n",
113 strerror (errno));
114 return -1;
115 }
116 if (ret >= FD_SETSIZE)
117 {
118 fprintf (stderr,
119 "Socket number too large (%d > %u)\n",
120 ret,
121 (unsigned int) FD_SETSIZE);
122 close (ret);
123 return -1;
124 }
125 memset (&src, 0, sizeof (src));
126 src.sin_family = AF_INET;
127 if (i == 0)
128 src.sin_port = htons (NAT_TRAV_PORT);
129 else
130 src.sin_port = htons (make_port ());
131 if (0 != bind (ret, (struct sockaddr*) &src, sizeof (src)))
132 {
133 close (ret);
134 continue;
135 }
136 return ret;
137 }
138 fprintf (stderr,
139 "Error binding udp socket: %s\n",
140 strerror (errno));
141 return -1;
142}
143
144
145
146
147int
148main (int argc, char *const *argv)
149{
150 int udpsocks[NUM_UDP_PORTS];
151 char command[512];
152 struct in_addr external;
153 struct in_addr target;
154 int ret;
155 unsigned int pos;
156 int i;
157 int max;
158 struct sockaddr_in dst;
159 struct sockaddr_in src;
160 int first_round = 1;
161 char dummybuf[65536];
162 unsigned int tries;
163 struct timeval tv;
164 socklen_t slen;
165 fd_set rs;
166
167 if (argc != 3)
168 {
169 fprintf (stderr,
170 "This program must be started with our IP and the targets external IP as arguments.\n");
171 return 1;
172 }
173 if ( (1 != inet_pton (AF_INET, argv[1], &external)) ||
174 (1 != inet_pton (AF_INET, argv[2], &target)) )
175 {
176 fprintf (stderr,
177 "Error parsing IPv4 address: %s\n",
178 strerror (errno));
179 return 1;
180 }
181 snprintf (command,
182 sizeof (command),
183 "gnunet-nat-client %s %s",
184 argv[1],
185 argv[2]);
186 if (0 != (ret = system (command)))
187 {
188 if (ret == -1)
189 fprintf (stderr,
190 "Error running `%s': %s\n",
191 command,
192 strerror (errno));
193 return 1;
194 }
195 fprintf (stderr,
196 "Trying to connect to `%s'\n",
197 argv[2]);
198 srand (time(NULL));
199 for (i=0;i<NUM_UDP_PORTS;i++)
200 udpsocks[i] = make_udp_socket (i);
201 memset (&dst, 0, sizeof (dst));
202 dst.sin_family = AF_INET;
203 dst.sin_addr = target;
204 pos = 0;
205 tries = 0;
206 while (MAX_TRIES > tries++)
207 {
208 FD_ZERO (&rs);
209 for (i=0;i<NUM_UDP_PORTS;i++)
210 {
211 if (udpsocks[i] != -1)
212 FD_SET (udpsocks[i], &rs);
213 if (udpsocks[i] > max)
214 max = udpsocks[i];
215 }
216 tv.tv_sec = 0;
217 tv.tv_usec = UDP_SEND_FREQUENCY_MS * 1000;
218 select (max + 1, &rs, NULL, NULL, &tv);
219 for (i=0;i<NUM_UDP_PORTS;i++)
220 {
221 if (udpsocks[i] == -1)
222 continue;
223 if (! FD_ISSET (udpsocks[i], &rs))
224 continue;
225 slen = sizeof (src);
226 recvfrom (udpsocks[i],
227 dummybuf, sizeof (dummybuf), 0,
228 (struct sockaddr*) &src,
229 &slen);
230 if (slen != sizeof (src))
231 {
232 fprintf (stderr,
233 "Unexpected size of address.\n");
234 continue;
235 }
236 if (0 != memcmp (&src.sin_addr,
237 &target,
238 sizeof (external)))
239 {
240 fprintf (stderr,
241 "Unexpected sender IP\n");
242 continue;
243 }
244 /* discovered port! */
245 fprintf (stdout,
246 "%s:%u\n",
247 argv[2],
248 ntohs (src.sin_port));
249 dst.sin_port = src.sin_port;
250 if (-1 == sendto (udpsocks[i],
251 NULL, 0, 0,
252 (struct sockaddr*) &dst, sizeof (dst)))
253 {
254 fprintf (stderr,
255 "sendto failed: %s\n",
256 strerror (errno));
257 return 2; /* oops */
258 }
259 /* success! */
260 fprintf (stderr,
261 "Succeeded after %u packets.\n",
262 tries);
263 return 0;
264 }
265 if (udpsocks[pos] == -1)
266 {
267 udpsocks[pos] = make_udp_socket (pos);
268 continue;
269 }
270 if ( (0 == ((unsigned int)rand() % NUM_UDP_PORTS)) ||
271 (1 == first_round) )
272 dst.sin_port = htons (NAT_TRAV_PORT);
273 else
274 dst.sin_port = htons (make_port ());
275 fprintf (stderr,
276 "Sending UDP packet to `%s:%u'\n",
277 argv[2],
278 ntohs (dst.sin_port));
279 first_round = 0;
280 if (-1 == sendto (udpsocks[pos],
281 NULL, 0, 0,
282 (struct sockaddr*) &dst, sizeof (dst)))
283 {
284 fprintf (stderr,
285 "sendto failed: %s\n",
286 strerror (errno));
287 close (udpsocks[pos]);
288 udpsocks[pos] = make_udp_socket (pos);
289 }
290 pos = (pos+1) % NUM_UDP_PORTS;
291 }
292 fprintf (stderr,
293 "Giving up after %u tries.\n",
294 tries);
295 return 3;
296}
297
298/* end of client-test.c */
diff --git a/src/transport/gnunet-nat-server-script.sh b/src/transport/gnunet-nat-server-script.sh
new file mode 100755
index 000000000..42a8e639a
--- /dev/null
+++ b/src/transport/gnunet-nat-server-script.sh
@@ -0,0 +1,4 @@
1#!/bin/sh
2IP=`ifconfig | grep inet | head -n1 | awk '{print $2}' | sed -e "s/addr://"`
3echo "Using IP $IP"
4./gnunet-nat-server $IP | sed -u -e "s/.*/.\/gnunet-nat-server-udp $IP &\&/" | sh
diff --git a/src/transport/gnunet-nat-server-udp.c b/src/transport/gnunet-nat-server-udp.c
new file mode 100644
index 000000000..693adbcf5
--- /dev/null
+++ b/src/transport/gnunet-nat-server-udp.c
@@ -0,0 +1,278 @@
1/*
2 This file is part of GNUnet.
3 (C) 2010 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19*/
20
21/**
22 * @file src/transport/server-test.c
23 * @brief Test for NAT traversal using ICMP method.
24 * @author Christian Grothoff
25 */
26#include <sys/types.h>
27#include <sys/socket.h>
28#include <arpa/inet.h>
29#include <sys/types.h>
30#include <unistd.h>
31#include <stdio.h>
32#include <string.h>
33#include <errno.h>
34#include <stdlib.h>
35#include <stdint.h>
36#include <netinet/in.h>
37#include <time.h>
38
39
40
41/**
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.
48 */
49#define UDP_SEND_FREQUENCY_MS 50
50
51/**
52 * Port we always try to use.
53 */
54#define NAT_TRAV_PORT 22225
55
56/**
57 * Number of UDP ports to keep open at the same time (typically >= 256).
58 * Should be less than FD_SETSIZE.
59 */
60#define NUM_UDP_PORTS 1000
61
62/**
63 * How often do we retry to open and bind a UDP socket before giving up?
64 */
65#define MAX_BIND_TRIES 10
66
67/**
68 * How long do we try at most? We expect the other side to give
69 * up after about one minute for now.
70 */
71#define MAX_DURATION 60000
72
73#define LOW_PORT 32768
74
75/**
76 * create a random port number that is not totally
77 * unlikely to be chosen by the nat box.
78 */
79static uint16_t
80make_port ()
81{
82 return LOW_PORT + ( (unsigned int)rand ()) % (64 * 1024 - LOW_PORT - 2);
83}
84
85
86/**
87 * create a fresh udp socket bound to a random local port,
88 * or, if the argument is zero, to the NAT_TRAV_PORT.
89 *
90 * @param i counter
91 * @return -1 on error
92 */
93static int
94make_udp_socket (int i)
95{
96 int ret;
97 int tries;
98 struct sockaddr_in src;
99
100 for (tries=0;tries<MAX_BIND_TRIES;tries++)
101 {
102 ret = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
103 if (-1 == ret)
104 {
105 fprintf (stderr,
106 "Error opening udp socket: %s\n",
107 strerror (errno));
108 return -1;
109 }
110 if (ret >= FD_SETSIZE)
111 {
112 fprintf (stderr,
113 "Socket number too large (%d > %u)\n",
114 ret,
115 (unsigned int) FD_SETSIZE);
116 close (ret);
117 return -1;
118 }
119 memset (&src, 0, sizeof (src));
120 src.sin_family = AF_INET;
121 if (i == 0)
122 src.sin_port = htons (NAT_TRAV_PORT);
123 else
124 src.sin_port = htons (make_port ());
125 if (0 != bind (ret, (struct sockaddr*) &src, sizeof (src)))
126 {
127 close (ret);
128 continue;
129 }
130 return ret;
131 }
132 fprintf (stderr,
133 "Error binding udp socket: %s\n",
134 strerror (errno));
135 return -1;
136}
137
138
139int
140main (int argc, char *const *argv)
141{
142 int udpsocks[NUM_UDP_PORTS];
143 char command[512];
144 struct in_addr external;
145 struct in_addr target;
146 int ret;
147 unsigned int pos;
148 int i;
149 int max;
150 struct sockaddr_in dst;
151 struct sockaddr_in src;
152 int first_round = 1;
153 char dummybuf[65536];
154 unsigned int tries;
155 struct timeval tv;
156 socklen_t slen;
157 fd_set rs;
158 time_t stime;
159
160 if (argc != 3)
161 {
162 fprintf (stderr,
163 "This program must be started with our IP and the targets external IP as arguments.\n");
164 return 1;
165 }
166 if ( (1 != inet_pton (AF_INET, argv[1], &external)) ||
167 (1 != inet_pton (AF_INET, argv[2], &target)) )
168 {
169 fprintf (stderr,
170 "Error parsing IPv4 address: %s\n",
171 strerror (errno));
172 return 1;
173 }
174 fprintf (stderr,
175 "Trying to connect to %s\n",
176 argv[2]);
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;
183 pos = 0;
184 tries = 0;
185 while (stime + MAX_DURATION >= time (NULL))
186 {
187 tries++;
188 FD_ZERO (&rs);
189 for (i=0;i<NUM_UDP_PORTS;i++)
190 {
191 if (udpsocks[i] != -1)
192 FD_SET (udpsocks[i], &rs);
193 if (udpsocks[i] > max)
194 max = udpsocks[i];
195 }
196 tv.tv_sec = 0;
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++)
200 {
201 if (udpsocks[i] == -1)
202 continue;
203 if (! FD_ISSET (udpsocks[i], &rs))
204 continue;
205 slen = sizeof (src);
206 recvfrom (udpsocks[i],
207 dummybuf, sizeof (dummybuf), 0,
208 (struct sockaddr*) &src,
209 &slen);
210 if (slen != sizeof (src))
211 {
212 fprintf (stderr,
213 "Unexpected size of address.\n");
214 continue;
215 }
216 if (0 != memcmp (&src.sin_addr,
217 &target,
218 sizeof (external)))
219 {
220 fprintf (stderr,
221 "Unexpected sender IP\n");
222 continue;
223 }
224 /* discovered port! */
225 fprintf (stdout,
226 "%s:%u\n",
227 argv[2],
228 ntohs (src.sin_port));
229 dst.sin_port = src.sin_port;
230 if (-1 == sendto (udpsocks[i],
231 NULL, 0, 0,
232 (struct sockaddr*) &dst, sizeof (dst)))
233 {
234 fprintf (stderr,
235 "sendto failed: %s\n",
236 strerror (errno));
237 return 2; /* oops */
238 }
239 /* success! */
240 fprintf (stderr,
241 "Succeeded after %u packets.\n",
242 tries);
243 return 0;
244 }
245 if (udpsocks[pos] == -1)
246 {
247 udpsocks[pos] = make_udp_socket (pos);
248 continue;
249 }
250 if ( (0 == ((unsigned int)rand() % NUM_UDP_PORTS)) ||
251 (1 == first_round) )
252 dst.sin_port = htons (NAT_TRAV_PORT);
253 else
254 dst.sin_port = htons (make_port ());
255 fprintf (stderr,
256 "Sending UDP packet to `%s:%u'\n",
257 argv[2],
258 ntohs (dst.sin_port));
259 first_round = 0;
260 if (-1 == sendto (udpsocks[pos],
261 NULL, 0, 0,
262 (struct sockaddr*) &dst, sizeof (dst)))
263 {
264 fprintf (stderr,
265 "sendto failed: %s\n",
266 strerror (errno));
267 close (udpsocks[pos]);
268 udpsocks[pos] = make_udp_socket (pos);
269 }
270 pos = (pos+1) % NUM_UDP_PORTS;
271 }
272 fprintf (stderr,
273 "Giving up after %u tries.\n",
274 tries);
275 return 3;
276}
277
278/* end of server-test.c */