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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file src/nat/gnunet-nat.c
23 * @brief Command-line tool to interact with the NAT service
24 * @author Christian Grothoff
25 * @author Bruno Cabral
28 #include "gnunet_util_lib.h"
29 #include "gnunet_nat_service.h"
32 * Value to return from #main().
34 static int global_ret;
37 * Name of section in configuration file to use for
40 static char *section_name;
43 * Flag set to 1 if we use IPPROTO_UDP.
48 * Flag set to 1 if we are to listen for connection reversal requests.
50 static int listen_reversal;
53 * Flag set to 1 if we use IPPROTO_TCP.
63 * Local address to use for connection reversal request.
65 static char *local_addr;
68 * Remote address to use for connection reversal request.
70 static char *remote_addr;
73 * Should we actually bind to #bind_addr and receive and process STUN requests?
78 * Handle to NAT operation.
80 static struct GNUNET_NAT_Handle *nh;
83 * Listen socket for STUN processing.
85 static struct GNUNET_NETWORK_Handle *ls;
88 * Task for reading STUN packets.
90 static struct GNUNET_SCHEDULER_Task *rtask;
94 * Test if all activities have finished, and if so,
104 GNUNET_SCHEDULER_shutdown ();
109 * Signature of the callback passed to #GNUNET_NAT_register() for
110 * a function to call whenever our set of 'valid' addresses changes.
112 * @param cls closure, NULL
113 * @param app_ctx[in,out] location where the app can store stuff
114 * on add and retrieve it on remove
115 * @param add_remove #GNUNET_YES to add a new public IP address,
116 * #GNUNET_NO to remove a previous (now invalid) one
117 * @param ac address class the address belongs to
118 * @param addr either the previous or the new public IP address
119 * @param addrlen actual length of the @a addr
122 address_cb (void *cls,
125 enum GNUNET_NAT_AddressClass ac,
126 const struct sockaddr *addr,
134 add_remove ? "+" : "-",
135 GNUNET_a2s (addr, addrlen),
141 * Signature of the callback passed to #GNUNET_NAT_register().
142 * for a function to call whenever someone asks us to do connection
145 * @param cls closure, NULL
146 * @param remote_addr public IP address of the other peer
147 * @param remote_addrlen actual length of the @a remote_addr
150 reversal_cb (void *cls,
151 const struct sockaddr *remote_addr,
152 socklen_t remote_addrlen)
154 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
155 "Connection reversal requested by %s\n",
156 GNUNET_a2s (remote_addr, remote_addrlen));
161 * Task run on shutdown.
166 do_shutdown (void *cls)
170 GNUNET_NAT_unregister (nh);
175 GNUNET_NETWORK_socket_close (ls);
180 GNUNET_SCHEDULER_cancel (rtask);
187 * Task to receive incoming packets for STUN processing.
190 stun_read_task (void *cls)
194 rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
198 size = GNUNET_NETWORK_socket_recvfrom_amount (ls);
202 GNUNET_SCHEDULER_shutdown ();
208 struct sockaddr_storage sa;
209 socklen_t salen = sizeof(sa);
212 ret = GNUNET_NETWORK_socket_recvfrom (ls,
215 (struct sockaddr *) &sa,
220 GNUNET_SCHEDULER_shutdown ();
224 (void) GNUNET_NAT_stun_handle_packet (nh,
225 (const struct sockaddr *) &sa,
234 * Main function that will be run.
237 * @param args remaining command-line arguments
238 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
239 * @param c configuration
245 const struct GNUNET_CONFIGURATION_Handle *c)
248 struct sockaddr *local_sa;
249 struct sockaddr *remote_sa;
253 if (use_tcp && use_udp)
255 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Cannot use TCP and UDP\n");
265 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
269 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Must specify either TCP or UDP\n");
277 if (NULL != local_addr)
280 (socklen_t) GNUNET_STRINGS_parse_socket_addr (local_addr, &af, &local_sa);
283 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
284 "Invalid socket address `%s'\n",
286 goto fail_and_shutdown;
290 if (NULL != remote_addr)
293 GNUNET_STRINGS_parse_socket_addr (remote_addr, &af, &remote_sa);
296 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
297 "Invalid socket address `%s'\n",
299 goto fail_and_shutdown;
303 if (NULL != local_addr)
305 if (NULL == section_name)
306 section_name = GNUNET_strdup ("undefined");
307 nh = GNUNET_NAT_register (c,
311 (const struct sockaddr **) &local_sa,
314 (listen_reversal) ? &reversal_cb : NULL,
317 else if (listen_reversal)
319 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
320 "Use of `-W` only effective in combination with `-i`\n");
321 goto fail_and_shutdown;
324 if (NULL != remote_addr)
328 if ((NULL == nh) || (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");
353 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
354 "Connection reversal unavailable\n");
358 /* operation in progress */
365 if (NULL == local_addr)
367 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
368 "Require local address to support STUN requests\n");
369 goto fail_and_shutdown;
371 if (IPPROTO_UDP != proto)
373 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "STUN only supported over UDP\n");
374 goto fail_and_shutdown;
376 ls = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, IPPROTO_UDP);
379 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Failed to create socket\n");
380 goto fail_and_shutdown;
382 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ls, local_sa, local_len))
384 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
385 "Failed to bind to %s: %s\n",
386 GNUNET_a2s (local_sa, local_len),
388 goto fail_and_shutdown;
390 rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
395 GNUNET_free_non_null (remote_sa);
396 GNUNET_free_non_null (local_sa);
401 GNUNET_SCHEDULER_shutdown ();
402 GNUNET_free_non_null (remote_sa);
403 GNUNET_free_non_null (local_sa);
408 * Main function of gnunet-nat
410 * @param argc number of command-line arguments
411 * @param argv command line
412 * @return 0 on success, -1 on error
415 main (int argc, char *const argv[])
417 struct GNUNET_GETOPT_CommandLineOption options[] = {
418 GNUNET_GETOPT_option_string (
422 gettext_noop ("which IP and port are we locally using to bind/listen to"),
425 GNUNET_GETOPT_option_string (
430 "which remote IP and port should be asked for connection reversal"),
433 GNUNET_GETOPT_option_string (
438 "name of configuration section to find additional options, such as manual host punching data"),
441 GNUNET_GETOPT_option_flag ('s',
443 gettext_noop ("enable STUN processing"),
446 GNUNET_GETOPT_option_flag ('t', "tcp", gettext_noop ("use TCP"), &use_tcp),
448 GNUNET_GETOPT_option_flag ('u', "udp", gettext_noop ("use UDP"), &use_udp),
450 GNUNET_GETOPT_option_flag ('W',
453 "watch for connection reversal requests"),
455 GNUNET_GETOPT_OPTION_END
458 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
461 GNUNET_PROGRAM_run (argc,
463 "gnunet-nat [options]",
464 _ ("GNUnet NAT traversal autoconfigure daemon"),
471 GNUNET_free ((void *) argv);
476 /* end of gnunet-nat.c */