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"
35 static struct GNUNET_SERVER_Handle *server;
40 static const struct GNUNET_CONFIGURATION_Handle *cfg;
43 * Try contacting the peer using autonomous
44 * NAT traveral method.
46 * @param dst_ipv4 IPv4 address to send the fake ICMP message
47 * @param dport destination port to include in ICMP message
48 * @param is_tcp mark for TCP (GNUNET_YES) or UDP (GNUNET_NO)
51 try_anat (uint32_t dst_ipv4,
55 struct GNUNET_NAT_Handle *h;
56 struct sockaddr_in sa;
58 h = GNUNET_NAT_register (cfg,
63 memset (&sa, 0, sizeof (sa));
64 #if HAVE_SOCKADDR_IN_SIN_LEN
65 sa.sin_len = sizeof (sa);
67 sa.sin_addr.s_addr = dst_ipv4;
68 GNUNET_NAT_run_client (h, &sa);
69 GNUNET_NAT_unregister (h);
74 * Closure for 'tcp_send'.
81 struct GNUNET_NETWORK_Handle *s;
91 * Task called by the scheduler once we can do the TCP send
92 * (or once we failed to connect...).
94 * @param ctx the 'struct TcpContext'
95 * @param tc scheduler context
99 const struct GNUNET_SCHEDULER_TaskContext *tc)
101 struct TcpContext *ctx = cls;
103 if ( (NULL != tc->write_ready) &&
104 (GNUNET_NETWORK_fdset_isset (tc->write_ready,
107 if (-1 == GNUNET_NETWORK_socket_send (ctx->s, &ctx->data, sizeof (ctx->data)))
108 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
109 GNUNET_NETWORK_socket_shutdown (ctx->s, SHUT_RDWR);
111 GNUNET_NETWORK_socket_close (ctx->s);
117 * Try to send 'data' to the
118 * IP 'dst_ipv4' at port 'dport' via TCP.
120 * @param dst_ivp4 target IP
121 * @param dport target port
122 * @param data data to send
125 try_send_tcp (uint32_t dst_ipv4,
129 struct GNUNET_NETWORK_Handle *s;
130 struct sockaddr_in sa;
131 struct TcpContext *ctx;
133 s = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
136 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket");
139 memset (&sa, 0, sizeof (sa));
140 #if HAVE_SOCKADDR_IN_SIN_LEN
141 sa.sin_len = sizeof (sa);
143 sa.sin_addr.s_addr = dst_ipv4;
144 sa.sin_port = htons (dport);
146 GNUNET_NETWORK_socket_connect (s,
147 (const struct sockaddr*) &sa, sizeof (sa))) &&
148 (errno != EINPROGRESS) )
150 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect");
151 GNUNET_NETWORK_socket_close (s);
154 ctx = GNUNET_malloc (sizeof (struct TcpContext));
157 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_SECONDS,
164 * Try to send 'data' to the
165 * IP 'dst_ipv4' at port 'dport' via UDP.
167 * @param dst_ivp4 target IP
168 * @param dport target port
169 * @param data data to send
172 try_send_udp (uint32_t dst_ipv4,
176 struct GNUNET_NETWORK_Handle *s;
177 struct sockaddr_in sa;
179 s = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_DGRAM, 0);
182 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket");
185 memset (&sa, 0, sizeof (sa));
186 #if HAVE_SOCKADDR_IN_SIN_LEN
187 sa.sin_len = sizeof (sa);
189 sa.sin_addr.s_addr = dst_ipv4;
190 sa.sin_port = htons (dport);
191 if (-1 == GNUNET_NETWORK_socket_sendto (s, &data, sizeof(data), (const struct sockaddr*) &sa, sizeof (sa)))
192 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "sendto");
193 GNUNET_NETWORK_socket_close (s);
198 * We've received a request to probe a NAT
202 * @param client handle to client (we always close)
203 * @param msg message with details about what to test
207 struct GNUNET_SERVER_Client *client,
208 const struct GNUNET_MessageHeader *msg)
210 const struct GNUNET_NAT_TestMessage *tm;
213 tm = (const struct GNUNET_NAT_TestMessage*) msg;
214 dport = ntohs (tm->dport);
216 try_anat (tm->dst_ipv4,
218 (int) ntohl (tm->is_tcp));
219 else if (GNUNET_YES == ntohl (tm->is_tcp))
220 try_send_tcp (tm->dst_ipv4, dport, tm->data);
222 try_send_udp (tm->dst_ipv4, dport, tm->data);
223 GNUNET_SERVER_receive_done (client,
229 * Task run during shutdown.
232 * @param tc scheduler context
235 shutdown_task (void *cls,
236 const struct GNUNET_SCHEDULER_TaskContext *tc)
238 GNUNET_SERVER_destroy (server);
244 * Main function that will be run.
247 * @param args remaining command-line arguments
248 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
249 * @param c configuration
255 const struct GNUNET_CONFIGURATION_Handle *c)
257 static const struct GNUNET_SERVER_MessageHandler handlers[] =
259 { &test, NULL, GNUNET_MESSAGE_TYPE_NAT_TEST, sizeof (struct GNUNET_NAT_TestMessage) },
263 struct sockaddr_in in4;
264 struct sockaddr_in6 in6;
271 struct sockaddr *sa[] =
273 (struct sockaddr*) &in4,
274 (struct sockaddr*) &in6,
279 if ( (args[0] == NULL) ||
280 (1 != SSCANF (args[0], "%u", &port)) ||
285 _("Please pass valid port number as the first argument!\n"));
288 memset (&in4, 0, sizeof (in4));
289 memset (&in6, 0, sizeof (in6));
290 in4.sin_port = htons ((uint16_t) port);
291 in6.sin6_port = htons ((uint16_t) port);
292 #if HAVE_SOCKADDR_IN_SIN_LEN
293 in4.sin_len = sizeof (in);
294 in6.sin6_len = sizeof (in6);
296 server = GNUNET_SERVER_create (NULL, NULL,
297 (struct sockaddr*const*) sa,
299 GNUNET_TIME_UNIT_SECONDS,
301 GNUNET_SERVER_add_handlers (server,
303 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
310 * Main function of gnunet-nat-server.
312 * @param argc number of command-line arguments
313 * @param argv command line
314 * @return 0 on success, -1 on error
317 main (int argc, char *const argv[])
319 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
320 GNUNET_GETOPT_OPTION_END
324 GNUNET_PROGRAM_run (argc, argv,
325 "gnunet-nat-server [options] PORT",
326 _("GNUnet NAT traversal test helper daemon"),
334 /* end of gnunet-nat-server.c */