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