2 This file is part of GNUnet.
3 Copyright (C) 2015, 2016 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * @file src/nat/gnunet-nat.c
21 * @brief Command-line tool to interact with the NAT service
22 * @author Christian Grothoff
23 * @author Bruno Cabral
26 #include "gnunet_util_lib.h"
27 #include "gnunet_nat_service.h"
30 * Value to return from #main().
32 static int global_ret;
35 * Name of section in configuration file to use for
38 static char *section_name;
41 * Flag set to 1 if we use IPPROTO_UDP.
46 * Flag set to 1 if we are to listen for connection reversal requests.
48 static int listen_reversal;
51 * Flag set to 1 if we use IPPROTO_TCP.
61 * Local address to use for connection reversal request.
63 static char *local_addr;
66 * Remote address to use for connection reversal request.
68 static char *remote_addr;
71 * Should we actually bind to #bind_addr and receive and process STUN requests?
76 * Handle to NAT operation.
78 static struct GNUNET_NAT_Handle *nh;
81 * Listen socket for STUN processing.
83 static struct GNUNET_NETWORK_Handle *ls;
86 * Task for reading STUN packets.
88 static struct GNUNET_SCHEDULER_Task *rtask;
92 * Test if all activities have finished, and if so,
102 GNUNET_SCHEDULER_shutdown ();
107 * Signature of the callback passed to #GNUNET_NAT_register() for
108 * a function to call whenever our set of 'valid' addresses changes.
110 * @param cls closure, NULL
111 * @param add_remove #GNUNET_YES to add a new public IP address,
112 * #GNUNET_NO to remove a previous (now invalid) one
113 * @param ac address class the address belongs to
114 * @param addr either the previous or the new public IP address
115 * @param addrlen actual length of the @a addr
118 address_cb (void *cls,
120 enum GNUNET_NAT_AddressClass ac,
121 const struct sockaddr *addr,
126 add_remove ? "+" : "-",
134 * Signature of the callback passed to #GNUNET_NAT_register().
135 * for a function to call whenever someone asks us to do connection
138 * @param cls closure, NULL
139 * @param remote_addr public IP address of the other peer
140 * @param remote_addrlen actual length of the @a remote_addr
143 reversal_cb (void *cls,
144 const struct sockaddr *remote_addr,
145 socklen_t remote_addrlen)
147 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
148 "Connection reversal requested by %s\n",
149 GNUNET_a2s (remote_addr,
155 * Task run on shutdown.
160 do_shutdown (void *cls)
164 GNUNET_NAT_unregister (nh);
169 GNUNET_NETWORK_socket_close (ls);
174 GNUNET_SCHEDULER_cancel (rtask);
181 * Task to receive incoming packets for STUN processing.
184 stun_read_task (void *cls)
188 rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
192 size = GNUNET_NETWORK_socket_recvfrom_amount (ls);
196 GNUNET_SCHEDULER_shutdown ();
202 struct sockaddr_storage sa;
203 socklen_t salen = sizeof (sa);
206 ret = GNUNET_NETWORK_socket_recvfrom (ls,
209 (struct sockaddr *) &sa,
214 GNUNET_SCHEDULER_shutdown ();
218 (void) GNUNET_NAT_stun_handle_packet (nh,
219 (const struct sockaddr *) &sa,
228 * Main function that will be run.
231 * @param args remaining command-line arguments
232 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
233 * @param c configuration
239 const struct GNUNET_CONFIGURATION_Handle *c)
242 struct sockaddr *local_sa;
243 struct sockaddr *remote_sa;
247 if (use_tcp && use_udp)
249 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
250 "Cannot use TCP and UDP\n");
260 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
265 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
266 "Must specify either TCP or UDP\n");
274 if (NULL != local_addr)
276 local_len = (socklen_t) GNUNET_STRINGS_parse_socket_addr (local_addr,
281 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
282 "Invalid socket address `%s'\n",
284 goto fail_and_shutdown;
288 if (NULL != remote_addr)
290 remote_len = GNUNET_STRINGS_parse_socket_addr (remote_addr,
295 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
296 "Invalid socket address `%s'\n",
298 goto fail_and_shutdown;
302 if (NULL != local_addr)
304 if (NULL == section_name)
305 section_name = GNUNET_strdup ("undefined");
306 nh = GNUNET_NAT_register (c,
310 (const struct sockaddr **) &local_sa,
313 (listen_reversal) ? &reversal_cb : NULL,
316 else if (listen_reversal)
318 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
319 "Use of `-W` only effective in combination with `-i`\n");
320 goto fail_and_shutdown;
323 if (NULL != remote_addr)
328 (sizeof (struct sockaddr_in) != local_len) )
330 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
331 "Require IPv4 local address to initiate connection reversal\n");
332 goto fail_and_shutdown;
334 if (sizeof (struct sockaddr_in) != remote_len)
336 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
337 "Require IPv4 reversal target address\n");
338 goto fail_and_shutdown;
340 GNUNET_assert (AF_INET == local_sa->sa_family);
341 GNUNET_assert (AF_INET == remote_sa->sa_family);
342 ret = GNUNET_NAT_request_reversal (nh,
343 (const struct sockaddr_in *) local_sa,
344 (const struct sockaddr_in *) remote_sa);
348 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
349 "Connection reversal internal error\n");
352 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
353 "Connection reversal unavailable\n");
356 /* operation in progress */
363 if (NULL == local_addr)
365 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
366 "Require local address to support STUN requests\n");
367 goto fail_and_shutdown;
369 if (IPPROTO_UDP != proto)
371 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
372 "STUN only supported over UDP\n");
373 goto fail_and_shutdown;
375 ls = GNUNET_NETWORK_socket_create (af,
380 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
381 "Failed to create socket\n");
382 goto fail_and_shutdown;
385 GNUNET_NETWORK_socket_bind (ls,
389 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
390 "Failed to bind to %s: %s\n",
391 GNUNET_a2s (local_sa,
394 goto fail_and_shutdown;
396 rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
401 GNUNET_free_non_null (remote_sa);
402 GNUNET_free_non_null (local_sa);
407 GNUNET_SCHEDULER_shutdown ();
408 GNUNET_free_non_null (remote_sa);
409 GNUNET_free_non_null (local_sa);
414 * Main function of gnunet-nat
416 * @param argc number of command-line arguments
417 * @param argv command line
418 * @return 0 on success, -1 on error
424 struct GNUNET_GETOPT_CommandLineOption options[] = {
426 GNUNET_GETOPT_option_string ('i',
429 gettext_noop ("which IP and port are we locally using to bind/listen to"),
432 GNUNET_GETOPT_option_string ('r',
435 gettext_noop ("which remote IP and port should be asked for connection reversal"),
438 GNUNET_GETOPT_option_string ('S',
441 gettext_noop ("name of configuration section to find additional options, such as manual host punching data"),
444 GNUNET_GETOPT_option_flag ('s',
446 gettext_noop ("enable STUN processing"),
449 GNUNET_GETOPT_option_flag ('t',
451 gettext_noop ("use TCP"),
454 GNUNET_GETOPT_option_flag ('u',
456 gettext_noop ("use UDP"),
459 GNUNET_GETOPT_option_flag ('W',
461 gettext_noop ("watch for connection reversal requests"),
463 GNUNET_GETOPT_OPTION_END
467 GNUNET_STRINGS_get_utf8_args (argc, argv,
471 GNUNET_PROGRAM_run (argc, argv,
472 "gnunet-nat [options]",
473 _("GNUnet NAT traversal autoconfigure daemon"),
480 GNUNET_free ((void*) argv);
485 /* end of gnunet-nat.c */