2 This file is part of GNUnet.
3 (C) 2011 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/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_lib.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
46 * NAT traveral method.
48 * @param dst_ipv4 IPv4 address to send the fake ICMP message
49 * @param dport destination port to include in ICMP message
50 * @param is_tcp mark for TCP (GNUNET_YES) or UDP (GNUNET_NO)
53 try_anat (uint32_t dst_ipv4, uint16_t dport, int is_tcp)
55 struct GNUNET_NAT_Handle *h;
56 struct sockaddr_in sa;
59 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
60 "Asking for connection reversal with %x and code %u\n",
61 (unsigned int) dst_ipv4, (unsigned int) dport);
63 h = GNUNET_NAT_register (cfg, is_tcp, dport, 0, NULL, NULL, NULL, NULL, NULL);
64 memset (&sa, 0, sizeof (sa));
65 sa.sin_family = AF_INET;
66 #if HAVE_SOCKADDR_IN_SIN_LEN
67 sa.sin_len = sizeof (sa);
69 sa.sin_addr.s_addr = dst_ipv4;
70 GNUNET_NAT_run_client (h, &sa);
71 GNUNET_NAT_unregister (h);
76 * Closure for 'tcp_send'.
83 struct GNUNET_NETWORK_Handle *s;
93 * Task called by the scheduler once we can do the TCP send
94 * (or once we failed to connect...).
96 * @param cls the 'struct TcpContext'
97 * @param tc scheduler context
100 tcp_send (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
102 struct TcpContext *ctx = cls;
104 if ((NULL != tc->write_ready) &&
105 (GNUNET_NETWORK_fdset_isset (tc->write_ready, ctx->s)))
108 GNUNET_NETWORK_socket_send (ctx->s, &ctx->data, sizeof (ctx->data)))
111 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send");
114 GNUNET_NETWORK_socket_shutdown (ctx->s, SHUT_RDWR);
116 GNUNET_NETWORK_socket_close (ctx->s);
122 * Try to send 'data' to the
123 * IP 'dst_ipv4' at port 'dport' via TCP.
125 * @param dst_ipv4 target IP
126 * @param dport target port
127 * @param data data to send
130 try_send_tcp (uint32_t dst_ipv4, uint16_t dport, uint16_t data)
132 struct GNUNET_NETWORK_Handle *s;
133 struct sockaddr_in sa;
134 struct TcpContext *ctx;
136 s = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
139 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket");
142 memset (&sa, 0, sizeof (sa));
143 sa.sin_family = AF_INET;
144 #if HAVE_SOCKADDR_IN_SIN_LEN
145 sa.sin_len = sizeof (sa);
147 sa.sin_addr.s_addr = dst_ipv4;
148 sa.sin_port = htons (dport);
150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending TCP message to `%s'\n",
151 GNUNET_a2s ((struct sockaddr *) &sa, sizeof (sa)));
154 GNUNET_NETWORK_socket_connect (s, (const struct sockaddr *) &sa,
155 sizeof (sa))) && (errno != EINPROGRESS))
157 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect");
158 GNUNET_NETWORK_socket_close (s);
161 ctx = GNUNET_malloc (sizeof (struct TcpContext));
164 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_SECONDS, s, &tcp_send, ctx);
169 * Try to send 'data' to the
170 * IP 'dst_ipv4' at port 'dport' via UDP.
172 * @param dst_ipv4 target IP
173 * @param dport target port
174 * @param data data to send
177 try_send_udp (uint32_t dst_ipv4, uint16_t dport, uint16_t data)
179 struct GNUNET_NETWORK_Handle *s;
180 struct sockaddr_in sa;
182 s = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
185 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket");
188 memset (&sa, 0, sizeof (sa));
189 sa.sin_family = AF_INET;
190 #if HAVE_SOCKADDR_IN_SIN_LEN
191 sa.sin_len = sizeof (sa);
193 sa.sin_addr.s_addr = dst_ipv4;
194 sa.sin_port = htons (dport);
196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending UDP packet to `%s'\n",
197 GNUNET_a2s ((struct sockaddr *) &sa, sizeof (sa)));
200 GNUNET_NETWORK_socket_sendto (s, &data, sizeof (data),
201 (const struct sockaddr *) &sa, sizeof (sa)))
202 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "sendto");
203 GNUNET_NETWORK_socket_close (s);
208 * We've received a request to probe a NAT
212 * @param client handle to client (we always close)
213 * @param msg message with details about what to test
216 test (void *cls, struct GNUNET_SERVER_Client *client,
217 const struct GNUNET_MessageHeader *msg)
219 const struct GNUNET_NAT_TestMessage *tm;
223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received test request\n");
225 tm = (const struct GNUNET_NAT_TestMessage *) msg;
226 dport = ntohs (tm->dport);
228 try_anat (tm->dst_ipv4, ntohs (tm->data), (int) ntohl (tm->is_tcp));
229 else if (GNUNET_YES == ntohl (tm->is_tcp))
230 try_send_tcp (tm->dst_ipv4, dport, tm->data);
232 try_send_udp (tm->dst_ipv4, dport, tm->data);
233 GNUNET_SERVER_receive_done (client, GNUNET_NO);
238 * Task run during shutdown.
241 * @param tc scheduler context
244 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
246 GNUNET_SERVER_destroy (server);
252 * Main function that will be run.
255 * @param args remaining command-line arguments
256 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
257 * @param c configuration
260 run (void *cls, char *const *args, const char *cfgfile,
261 const struct GNUNET_CONFIGURATION_Handle *c)
263 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
264 {&test, NULL, GNUNET_MESSAGE_TYPE_NAT_TEST,
265 sizeof (struct GNUNET_NAT_TestMessage)},
269 struct sockaddr_in in4;
270 struct sockaddr_in6 in6;
277 struct sockaddr *sa[] = {
278 (struct sockaddr *) &in4,
279 (struct sockaddr *) &in6,
284 if ((args[0] == NULL) || (1 != SSCANF (args[0], "%u", &port)) || (0 == port)
289 ("Please pass valid port number as the first argument! (got `%s')\n"),
293 memset (&in4, 0, sizeof (in4));
294 memset (&in6, 0, sizeof (in6));
295 in4.sin_family = AF_INET;
296 in4.sin_port = htons ((uint16_t) port);
297 in6.sin6_family = AF_INET6;
298 in6.sin6_port = htons ((uint16_t) port);
299 #if HAVE_SOCKADDR_IN_SIN_LEN
300 in4.sin_len = sizeof (in4);
301 in6.sin6_len = sizeof (in6);
304 GNUNET_SERVER_create (NULL, NULL, (struct sockaddr * const *) sa, slen,
305 GNUNET_TIME_UNIT_SECONDS, GNUNET_YES);
306 GNUNET_SERVER_add_handlers (server, handlers);
307 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
313 * Main function of gnunet-nat-server.
315 * @param argc number of command-line arguments
316 * @param argv command line
317 * @return 0 on success, -1 on error
320 main (int argc, char *const argv[])
322 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
323 GNUNET_GETOPT_OPTION_END
327 GNUNET_PROGRAM_run (argc, argv, "gnunet-nat-server [options] PORT",
328 _("GNUnet NAT traversal test helper daemon"), options,
335 /* end of gnunet-nat-server.c */