aboutsummaryrefslogtreecommitdiff
path: root/src/nat-auto/gnunet-nat-server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nat-auto/gnunet-nat-server.c')
-rw-r--r--src/nat-auto/gnunet-nat-server.c399
1 files changed, 399 insertions, 0 deletions
diff --git a/src/nat-auto/gnunet-nat-server.c b/src/nat-auto/gnunet-nat-server.c
new file mode 100644
index 000000000..dd08f8d36
--- /dev/null
+++ b/src/nat-auto/gnunet-nat-server.c
@@ -0,0 +1,399 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file src/nat/gnunet-nat-server.c
23 * @brief Daemon to run on 'gnunet.org' to help test NAT traversal code
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_nat_service.h"
29#include "gnunet_protocols.h"
30#include "nat-auto.h"
31
32
33/**
34 * Our server.
35 */
36static struct GNUNET_SERVER_Handle *server;
37
38/**
39 * Our configuration.
40 */
41static const struct GNUNET_CONFIGURATION_Handle *cfg;
42
43
44/**
45 * Try contacting the peer using autonomous NAT traveral method.
46 *
47 * @param dst_ipv4 IPv4 address to send the fake ICMP message
48 * @param dport destination port to include in ICMP message
49 * @param is_tcp mark for TCP (#GNUNET_YES) or UDP (#GNUNET_NO)
50 */
51static void
52try_anat (uint32_t dst_ipv4,
53 uint16_t dport,
54 int is_tcp)
55{
56 struct GNUNET_NAT_Handle *h;
57 struct sockaddr_in lsa;
58 struct sockaddr_in rsa;
59 socklen_t sa_len;
60
61 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
62 "Asking for connection reversal with %x and code %u\n",
63 (unsigned int) dst_ipv4,
64 (unsigned int) dport);
65 memset (&lsa, 0, sizeof (lsa));
66 lsa.sin_family = AF_INET;
67#if HAVE_SOCKADDR_IN_SIN_LEN
68 lsa.sin_len = sizeof (sa);
69#endif
70 lsa.sin_addr.s_addr = 0;
71 lsa.sin_port = htons (dport);
72 memset (&rsa, 0, sizeof (rsa));
73 rsa.sin_family = AF_INET;
74#if HAVE_SOCKADDR_IN_SIN_LEN
75 rsa.sin_len = sizeof (sa);
76#endif
77 rsa.sin_addr.s_addr = dst_ipv4;
78 rsa.sin_port = htons (dport);
79 sa_len = sizeof (lsa);
80 h = GNUNET_NAT_register (cfg,
81 "none",
82 is_tcp ? IPPROTO_TCP : IPPROTO_UDP,
83 1,
84 (const struct sockaddr **) &lsa,
85 &sa_len,
86 NULL, NULL, NULL);
87 GNUNET_NAT_request_reversal (h,
88 &lsa,
89 &rsa);
90 GNUNET_NAT_unregister (h);
91}
92
93
94/**
95 * Closure for #tcp_send.
96 */
97struct TcpContext
98{
99 /**
100 * TCP socket.
101 */
102 struct GNUNET_NETWORK_Handle *s;
103
104 /**
105 * Data to transmit.
106 */
107 uint16_t data;
108};
109
110
111/**
112 * Task called by the scheduler once we can do the TCP send
113 * (or once we failed to connect...).
114 *
115 * @param cls the `struct TcpContext`
116 */
117static void
118tcp_send (void *cls)
119{
120 struct TcpContext *ctx = cls;
121 const struct GNUNET_SCHEDULER_TaskContext *tc;
122
123 tc = GNUNET_SCHEDULER_get_task_context ();
124 if ((NULL != tc->write_ready) &&
125 (GNUNET_NETWORK_fdset_isset (tc->write_ready, ctx->s)))
126 {
127 if (-1 ==
128 GNUNET_NETWORK_socket_send (ctx->s, &ctx->data, sizeof (ctx->data)))
129 {
130 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send");
131 }
132 GNUNET_NETWORK_socket_shutdown (ctx->s, SHUT_RDWR);
133 }
134 GNUNET_NETWORK_socket_close (ctx->s);
135 GNUNET_free (ctx);
136}
137
138
139/**
140 * Try to send @a data to the
141 * IP @a dst_ipv4' at port @a dport via TCP.
142 *
143 * @param dst_ipv4 target IP
144 * @param dport target port
145 * @param data data to send
146 */
147static void
148try_send_tcp (uint32_t dst_ipv4,
149 uint16_t dport,
150 uint16_t data)
151{
152 struct GNUNET_NETWORK_Handle *s;
153 struct sockaddr_in sa;
154 struct TcpContext *ctx;
155
156 s = GNUNET_NETWORK_socket_create (AF_INET,
157 SOCK_STREAM,
158 0);
159 if (NULL == s)
160 {
161 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
162 "socket");
163 return;
164 }
165 memset (&sa, 0, sizeof (sa));
166 sa.sin_family = AF_INET;
167#if HAVE_SOCKADDR_IN_SIN_LEN
168 sa.sin_len = sizeof (sa);
169#endif
170 sa.sin_addr.s_addr = dst_ipv4;
171 sa.sin_port = htons (dport);
172 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
173 "Sending TCP message to `%s'\n",
174 GNUNET_a2s ((struct sockaddr *) &sa,
175 sizeof (sa)));
176 if ( (GNUNET_OK !=
177 GNUNET_NETWORK_socket_connect (s,
178 (const struct sockaddr *) &sa,
179 sizeof (sa))) &&
180 (errno != EINPROGRESS) )
181 {
182 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
183 "connect");
184 GNUNET_NETWORK_socket_close (s);
185 return;
186 }
187 ctx = GNUNET_new (struct TcpContext);
188 ctx->s = s;
189 ctx->data = data;
190 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_SECONDS,
191 s,
192 &tcp_send,
193 ctx);
194}
195
196
197/**
198 * Try to send @a data to the
199 * IP @a dst_ipv4 at port @a dport via UDP.
200 *
201 * @param dst_ipv4 target IP
202 * @param dport target port
203 * @param data data to send
204 */
205static void
206try_send_udp (uint32_t dst_ipv4,
207 uint16_t dport,
208 uint16_t data)
209{
210 struct GNUNET_NETWORK_Handle *s;
211 struct sockaddr_in sa;
212
213 s = GNUNET_NETWORK_socket_create (AF_INET,
214 SOCK_DGRAM,
215 0);
216 if (NULL == s)
217 {
218 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
219 "socket");
220 return;
221 }
222 memset (&sa, 0, sizeof (sa));
223 sa.sin_family = AF_INET;
224#if HAVE_SOCKADDR_IN_SIN_LEN
225 sa.sin_len = sizeof (sa);
226#endif
227 sa.sin_addr.s_addr = dst_ipv4;
228 sa.sin_port = htons (dport);
229 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
230 "Sending UDP packet to `%s'\n",
231 GNUNET_a2s ((struct sockaddr *) &sa,
232 sizeof (sa)));
233 if (-1 ==
234 GNUNET_NETWORK_socket_sendto (s,
235 &data,
236 sizeof (data),
237 (const struct sockaddr *) &sa,
238 sizeof (sa)))
239 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
240 "sendto");
241 GNUNET_NETWORK_socket_close (s);
242}
243
244
245/**
246 * We've received a request to probe a NAT
247 * traversal. Do it.
248 *
249 * @param cls unused
250 * @param client handle to client (we always close)
251 * @param msg message with details about what to test
252 */
253static void
254test (void *cls,
255 struct GNUNET_SERVER_Client *client,
256 const struct GNUNET_MessageHeader *msg)
257{
258 const struct GNUNET_NAT_AUTO_TestMessage *tm;
259 uint16_t dport;
260
261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
262 "Received test request\n");
263 tm = (const struct GNUNET_NAT_AUTO_TestMessage *) msg;
264 dport = ntohs (tm->dport);
265 if (0 == dport)
266 try_anat (tm->dst_ipv4,
267 ntohs (tm->data),
268 (int) ntohl (tm->is_tcp));
269 else if (GNUNET_YES == ntohl (tm->is_tcp))
270 try_send_tcp (tm->dst_ipv4,
271 dport,
272 tm->data);
273 else
274 try_send_udp (tm->dst_ipv4,
275 dport,
276 tm->data);
277 GNUNET_SERVER_receive_done (client,
278 GNUNET_NO);
279}
280
281
282/**
283 * Task run during shutdown.
284 *
285 * @param cls unused
286 */
287static void
288shutdown_task (void *cls)
289{
290 GNUNET_SERVER_destroy (server);
291 server = NULL;
292}
293
294
295/**
296 * Main function that will be run.
297 *
298 * @param cls closure
299 * @param args remaining command-line arguments
300 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
301 * @param c configuration
302 */
303static void
304run (void *cls,
305 char *const *args,
306 const char *cfgfile,
307 const struct GNUNET_CONFIGURATION_Handle *c)
308{
309 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
310 {&test, NULL, GNUNET_MESSAGE_TYPE_NAT_TEST,
311 sizeof (struct GNUNET_NAT_AUTO_TestMessage)},
312 {NULL, NULL, 0, 0}
313 };
314 unsigned int port;
315 struct sockaddr_in in4;
316 struct sockaddr_in6 in6;
317
318 socklen_t slen[] = {
319 sizeof (in4),
320 sizeof (in6),
321 0
322 };
323 struct sockaddr *sa[] = {
324 (struct sockaddr *) &in4,
325 (struct sockaddr *) &in6,
326 NULL
327 };
328
329 cfg = c;
330 if ( (NULL == args[0]) ||
331 (1 != SSCANF (args[0], "%u", &port)) ||
332 (0 == port) ||
333 (65536 <= port) )
334 {
335 FPRINTF (stderr,
336 _("Please pass valid port number as the first argument! (got `%s')\n"),
337 args[0]);
338 return;
339 }
340 memset (&in4, 0, sizeof (in4));
341 memset (&in6, 0, sizeof (in6));
342 in4.sin_family = AF_INET;
343 in4.sin_port = htons ((uint16_t) port);
344 in6.sin6_family = AF_INET6;
345 in6.sin6_port = htons ((uint16_t) port);
346#if HAVE_SOCKADDR_IN_SIN_LEN
347 in4.sin_len = sizeof (in4);
348 in6.sin6_len = sizeof (in6);
349#endif
350 server = GNUNET_SERVER_create (NULL,
351 NULL,
352 (struct sockaddr * const *) sa,
353 slen,
354 GNUNET_TIME_UNIT_SECONDS,
355 GNUNET_YES);
356 GNUNET_SERVER_add_handlers (server,
357 handlers);
358 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
359 NULL);
360}
361
362
363/**
364 * Main function of gnunet-nat-server.
365 *
366 * @param argc number of command-line arguments
367 * @param argv command line
368 * @return 0 on success, -1 on error
369 */
370int
371main (int argc, char *const argv[])
372{
373 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
374 GNUNET_GETOPT_OPTION_END
375 };
376
377 if (GNUNET_OK !=
378 GNUNET_STRINGS_get_utf8_args (argc, argv,
379 &argc, &argv))
380 return 2;
381
382 if (GNUNET_OK !=
383 GNUNET_PROGRAM_run (argc,
384 argv,
385 "gnunet-nat-server [options] PORT",
386 _("GNUnet NAT traversal test helper daemon"),
387 options,
388 &run,
389 NULL))
390 {
391 GNUNET_free ((void*) argv);
392 return 1;
393 }
394 GNUNET_free ((void*) argv);
395 return 0;
396}
397
398
399/* end of gnunet-nat-server.c */