2 This file is part of GNUnet.
3 Copyright (C) 2011 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
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
27 #include "gnunet_util_lib.h"
28 #include "gnunet_nat_service.h"
29 #include "gnunet_protocols.h"
36 static struct GNUNET_SERVER_Handle *server;
41 static const struct GNUNET_CONFIGURATION_Handle *cfg;
45 * Try contacting the peer using autonomous NAT traveral method.
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)
52 try_anat (uint32_t dst_ipv4,
56 struct GNUNET_NAT_Handle *h;
57 struct sockaddr_in lsa;
58 struct sockaddr_in rsa;
59 const struct sockaddr *sa;
62 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
63 "Asking for connection reversal with %x and code %u\n",
64 (unsigned int) dst_ipv4,
65 (unsigned int) dport);
66 memset (&lsa, 0, sizeof (lsa));
67 lsa.sin_family = AF_INET;
68 #if HAVE_SOCKADDR_IN_SIN_LEN
69 lsa.sin_len = sizeof (sa);
71 lsa.sin_addr.s_addr = 0;
72 lsa.sin_port = htons (dport);
73 memset (&rsa, 0, sizeof (rsa));
74 rsa.sin_family = AF_INET;
75 #if HAVE_SOCKADDR_IN_SIN_LEN
76 rsa.sin_len = sizeof (sa);
78 rsa.sin_addr.s_addr = dst_ipv4;
79 rsa.sin_port = htons (dport);
80 sa_len = sizeof (lsa);
81 sa = (const struct sockaddr *) &lsa;
82 h = GNUNET_NAT_register (cfg,
84 is_tcp ? IPPROTO_TCP : IPPROTO_UDP,
89 GNUNET_NAT_request_reversal (h,
92 GNUNET_NAT_unregister (h);
97 * Closure for #tcp_send.
104 struct GNUNET_NETWORK_Handle *s;
114 * Task called by the scheduler once we can do the TCP send
115 * (or once we failed to connect...).
117 * @param cls the `struct TcpContext`
122 struct TcpContext *ctx = cls;
123 const struct GNUNET_SCHEDULER_TaskContext *tc;
125 tc = GNUNET_SCHEDULER_get_task_context ();
126 if ((NULL != tc->write_ready) &&
127 (GNUNET_NETWORK_fdset_isset (tc->write_ready, ctx->s)))
130 GNUNET_NETWORK_socket_send (ctx->s, &ctx->data, sizeof (ctx->data)))
132 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send");
134 GNUNET_NETWORK_socket_shutdown (ctx->s, SHUT_RDWR);
136 GNUNET_NETWORK_socket_close (ctx->s);
142 * Try to send @a data to the
143 * IP @a dst_ipv4' at port @a dport via TCP.
145 * @param dst_ipv4 target IP
146 * @param dport target port
147 * @param data data to send
150 try_send_tcp (uint32_t dst_ipv4,
154 struct GNUNET_NETWORK_Handle *s;
155 struct sockaddr_in sa;
156 struct TcpContext *ctx;
158 s = GNUNET_NETWORK_socket_create (AF_INET,
163 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
167 memset (&sa, 0, sizeof (sa));
168 sa.sin_family = AF_INET;
169 #if HAVE_SOCKADDR_IN_SIN_LEN
170 sa.sin_len = sizeof (sa);
172 sa.sin_addr.s_addr = dst_ipv4;
173 sa.sin_port = htons (dport);
174 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
175 "Sending TCP message to `%s'\n",
176 GNUNET_a2s ((struct sockaddr *) &sa,
179 GNUNET_NETWORK_socket_connect (s,
180 (const struct sockaddr *) &sa,
182 (errno != EINPROGRESS) )
184 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
186 GNUNET_NETWORK_socket_close (s);
189 ctx = GNUNET_new (struct TcpContext);
192 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_SECONDS,
200 * Try to send @a data to the
201 * IP @a dst_ipv4 at port @a dport via UDP.
203 * @param dst_ipv4 target IP
204 * @param dport target port
205 * @param data data to send
208 try_send_udp (uint32_t dst_ipv4,
212 struct GNUNET_NETWORK_Handle *s;
213 struct sockaddr_in sa;
215 s = GNUNET_NETWORK_socket_create (AF_INET,
220 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
224 memset (&sa, 0, sizeof (sa));
225 sa.sin_family = AF_INET;
226 #if HAVE_SOCKADDR_IN_SIN_LEN
227 sa.sin_len = sizeof (sa);
229 sa.sin_addr.s_addr = dst_ipv4;
230 sa.sin_port = htons (dport);
231 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
232 "Sending UDP packet to `%s'\n",
233 GNUNET_a2s ((struct sockaddr *) &sa,
236 GNUNET_NETWORK_socket_sendto (s,
239 (const struct sockaddr *) &sa,
241 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
243 GNUNET_NETWORK_socket_close (s);
248 * We've received a request to probe a NAT
252 * @param client handle to client (we always close)
253 * @param msg message with details about what to test
257 struct GNUNET_SERVER_Client *client,
258 const struct GNUNET_MessageHeader *msg)
260 const struct GNUNET_NAT_AUTO_TestMessage *tm;
263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
264 "Received test request\n");
265 tm = (const struct GNUNET_NAT_AUTO_TestMessage *) msg;
266 dport = ntohs (tm->dport);
268 try_anat (tm->dst_ipv4,
270 (int) ntohl (tm->is_tcp));
271 else if (GNUNET_YES == ntohl (tm->is_tcp))
272 try_send_tcp (tm->dst_ipv4,
276 try_send_udp (tm->dst_ipv4,
279 GNUNET_SERVER_receive_done (client,
285 * Task run during shutdown.
290 shutdown_task (void *cls)
292 GNUNET_SERVER_destroy (server);
298 * Main function that will be run.
301 * @param args remaining command-line arguments
302 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
303 * @param c configuration
309 const struct GNUNET_CONFIGURATION_Handle *c)
311 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
312 {&test, NULL, GNUNET_MESSAGE_TYPE_NAT_TEST,
313 sizeof (struct GNUNET_NAT_AUTO_TestMessage)},
317 struct sockaddr_in in4;
318 struct sockaddr_in6 in6;
325 struct sockaddr *sa[] = {
326 (struct sockaddr *) &in4,
327 (struct sockaddr *) &in6,
332 if ( (NULL == args[0]) ||
333 (1 != SSCANF (args[0], "%u", &port)) ||
338 _("Please pass valid port number as the first argument! (got `%s')\n"),
342 memset (&in4, 0, sizeof (in4));
343 memset (&in6, 0, sizeof (in6));
344 in4.sin_family = AF_INET;
345 in4.sin_port = htons ((uint16_t) port);
346 in6.sin6_family = AF_INET6;
347 in6.sin6_port = htons ((uint16_t) port);
348 #if HAVE_SOCKADDR_IN_SIN_LEN
349 in4.sin_len = sizeof (in4);
350 in6.sin6_len = sizeof (in6);
352 server = GNUNET_SERVER_create (NULL,
354 (struct sockaddr * const *) sa,
356 GNUNET_TIME_UNIT_SECONDS,
358 GNUNET_SERVER_add_handlers (server,
360 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
366 * Main function of gnunet-nat-server.
368 * @param argc number of command-line arguments
369 * @param argv command line
370 * @return 0 on success, -1 on error
373 main (int argc, char *const argv[])
375 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
376 GNUNET_GETOPT_OPTION_END
380 GNUNET_STRINGS_get_utf8_args (argc, argv,
385 GNUNET_PROGRAM_run (argc,
387 "gnunet-nat-server [options] PORT",
388 _("GNUnet NAT traversal test helper daemon"),
393 GNUNET_free ((void*) argv);
396 GNUNET_free ((void*) argv);
401 /* end of gnunet-nat-server.c */