2 This file is part of GNUnet.
3 Copyright (C) 2015, 2016, 2017 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file src/nat/gnunet-nat-auto.c
23 * @brief Command-line tool for testing and autoconfiguration of NAT traversal
24 * @author Christian Grothoff
25 * @author Bruno Cabral
28 #include "gnunet_util_lib.h"
29 #include "gnunet_nat_service.h"
30 #include "gnunet_nat_auto_service.h"
33 * Value to return from #main().
35 static int global_ret;
38 * Handle to ongoing autoconfiguration.
40 static struct GNUNET_NAT_AUTO_AutoHandle *ah;
43 * If we do auto-configuration, should we write the result
49 * Configuration filename.
51 static const char *cfg_file;
54 * Original configuration.
56 static const struct GNUNET_CONFIGURATION_Handle *cfg;
59 * Address we are bound to (in test), or should bind to
60 * (if #do_stun is set).
62 static char *bind_addr;
65 * External IP address and port to use for the test.
66 * If not set, use #bind_addr.
68 static char *extern_addr;
71 * Should we run autoconfiguration?
73 static unsigned int do_auto;
76 * Handle to a NAT test operation.
78 static struct GNUNET_NAT_AUTO_Test *nt;
81 * Flag set to 1 if we use IPPROTO_UDP.
86 * Flag set to 1 if we use IPPROTO_TCP.
96 * Test if all activities have finished, and if so,
106 GNUNET_SCHEDULER_shutdown ();
111 * Function to iterate over sugested changes options
114 * @param section name of the section
115 * @param option name of the option
116 * @param value value of the option
119 auto_conf_iter (void *cls,
124 struct GNUNET_CONFIGURATION_Handle *new_cfg = cls;
130 GNUNET_CONFIGURATION_set_value_string (new_cfg,
138 * Function called with the result from the autoconfiguration.
141 * @param diff minimal suggested changes to the original configuration
142 * to make it work (as best as we can)
143 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
144 * @param type what the situation of the NAT
147 auto_config_cb (void *cls,
148 const struct GNUNET_CONFIGURATION_Handle *diff,
149 enum GNUNET_NAT_StatusCode result,
150 enum GNUNET_NAT_Type type)
152 const char *nat_type;
153 char unknown_type[64];
154 struct GNUNET_CONFIGURATION_Handle *new_cfg;
159 case GNUNET_NAT_TYPE_NO_NAT:
162 case GNUNET_NAT_TYPE_UNREACHABLE_NAT:
163 nat_type = "NAT but we can traverse";
165 case GNUNET_NAT_TYPE_STUN_PUNCHED_NAT:
166 nat_type = "NAT but STUN is able to identify the correct information";
168 case GNUNET_NAT_TYPE_UPNP_NAT:
169 nat_type = "NAT but UPNP opened the ports";
172 SPRINTF (unknown_type,
173 "NAT unknown, type %u",
175 nat_type = unknown_type;
179 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
180 "NAT status: %s/%s\n",
181 GNUNET_NAT_AUTO_status2string (result),
184 /* Shortcut: if there are no changes suggested, bail out early. */
186 GNUNET_CONFIGURATION_is_dirty (diff))
192 /* Apply diff to original configuration and show changes
194 new_cfg = write_cfg ? GNUNET_CONFIGURATION_dup (cfg) : NULL;
198 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
199 _("Suggested configuration changes:\n"));
200 GNUNET_CONFIGURATION_iterate_section_values (diff,
206 /* If desired, write configuration to file; we write only the
207 changes to the defaults to keep things compact. */
211 struct GNUNET_CONFIGURATION_Handle *def_cfg;
213 GNUNET_CONFIGURATION_set_value_string (new_cfg,
217 def_cfg = GNUNET_CONFIGURATION_create ();
218 GNUNET_break (GNUNET_OK ==
219 GNUNET_CONFIGURATION_load (def_cfg,
222 GNUNET_CONFIGURATION_write_diffs (def_cfg,
226 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
227 _("Failed to write configuration to `%s'\n"),
233 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
234 _("Wrote updated configuration to `%s'\n"),
237 GNUNET_CONFIGURATION_destroy (def_cfg);
241 GNUNET_CONFIGURATION_destroy (new_cfg);
247 * Function called to report success or failure for
248 * NAT configuration test.
251 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
254 test_report_cb (void *cls,
255 enum GNUNET_NAT_StatusCode result)
258 PRINTF ("NAT test result: %s\n",
259 GNUNET_NAT_AUTO_status2string (result));
265 * Task run on shutdown.
270 do_shutdown (void *cls)
274 GNUNET_NAT_AUTO_autoconfig_cancel (ah);
279 GNUNET_NAT_AUTO_test_stop (nt);
286 * Main function that will be run.
289 * @param args remaining command-line arguments
290 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
291 * @param c configuration
297 const struct GNUNET_CONFIGURATION_Handle *c)
299 struct sockaddr_in bind_sa;
300 struct sockaddr_in extern_sa;
305 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
310 ah = GNUNET_NAT_AUTO_autoconfig_start (c,
315 if (use_tcp && use_udp)
319 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
320 "Cannot use TCP and UDP\n");
330 if (NULL != bind_addr)
333 GNUNET_STRINGS_to_address_ipv4 (bind_addr,
337 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
338 "Invalid socket address `%s'\n",
344 if (NULL != extern_addr)
347 GNUNET_STRINGS_to_address_ipv4 (extern_addr,
348 strlen (extern_addr),
351 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
352 "Invalid socket address `%s'\n",
359 if (NULL != bind_addr)
361 if (NULL == extern_addr)
363 nt = GNUNET_NAT_AUTO_test_start (c,
366 ntohs (bind_sa.sin_port),
368 ntohs (extern_sa.sin_port),
377 * Main function of gnunet-nat
379 * @param argc number of command-line arguments
380 * @param argv command line
381 * @return 0 on success, -1 on error
387 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
389 gettext_noop ("run autoconfiguration"),
390 GNUNET_NO, &GNUNET_GETOPT_set_one, &do_auto },
391 {'b', "bind", "ADDRESS",
392 gettext_noop ("which IP and port are we bound to"),
393 GNUNET_YES, &GNUNET_GETOPT_set_string, &bind_addr },
394 {'e', "external", "ADDRESS",
395 gettext_noop ("which external IP and port should be used to test"),
396 GNUNET_YES, &GNUNET_GETOPT_set_string, &extern_addr },
398 gettext_noop ("use TCP"),
399 GNUNET_NO, &GNUNET_GETOPT_set_one, &use_tcp },
401 gettext_noop ("use UDP"),
402 GNUNET_NO, &GNUNET_GETOPT_set_one, &use_udp },
404 gettext_noop ("write configuration file (for autoconfiguration)"),
405 GNUNET_NO, &GNUNET_GETOPT_set_one, &write_cfg },
406 GNUNET_GETOPT_OPTION_END
410 GNUNET_STRINGS_get_utf8_args (argc, argv,
414 GNUNET_PROGRAM_run (argc, argv,
415 "gnunet-nat-auto [options]",
416 _("GNUnet NAT traversal autoconfiguration"),
423 GNUNET_free ((void*) argv);
428 /* end of gnunet-nat-auto.c */