-remove debug message
[oweals/gnunet.git] / src / nat-auto / gnunet-nat-auto.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2015, 2016, 2017 GNUnet e.V.
4
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.
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      Affero General Public License for more details.
14
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/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
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
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_nat_service.h"
30 #include "gnunet_nat_auto_service.h"
31
32 /**
33  * Value to return from #main().
34  */
35 static int global_ret;
36
37 /**
38  * Handle to ongoing autoconfiguration.
39  */
40 static struct GNUNET_NAT_AUTO_AutoHandle *ah;
41
42 /**
43  * If we do auto-configuration, should we write the result
44  * to a file?
45  */
46 static int write_cfg;
47
48 /**
49  * Configuration filename.
50  */
51 static const char *cfg_file;
52
53 /**
54  * Original configuration.
55  */
56 static const struct GNUNET_CONFIGURATION_Handle *cfg;
57
58 /**
59  * Adapter we are supposed to test.
60  */
61 static char *section_name;
62
63 /**
64  * Should we run autoconfiguration?
65  */
66 static int do_auto;
67
68 /**
69  * Handle to a NAT test operation.
70  */
71 static struct GNUNET_NAT_AUTO_Test *nt;
72
73 /**
74  * Flag set to 1 if we use IPPROTO_UDP.
75  */
76 static int use_udp;
77
78 /**
79  * Flag set to 1 if we use IPPROTO_TCP.
80  */
81 static int use_tcp;
82
83 /**
84  * Protocol to use.
85  */
86 static uint8_t proto;
87
88 /**
89  * Test if all activities have finished, and if so,
90  * terminate.
91  */
92 static void
93 test_finished ()
94 {
95   if (NULL != ah)
96     return;
97   if (NULL != nt)
98     return;
99   GNUNET_SCHEDULER_shutdown ();
100 }
101
102
103 /**
104  * Function to iterate over sugested changes options
105  *
106  * @param cls closure
107  * @param section name of the section
108  * @param option name of the option
109  * @param value value of the option
110  */
111 static void
112 auto_conf_iter (void *cls,
113                 const char *section,
114                 const char *option,
115                 const char *value)
116 {
117   struct GNUNET_CONFIGURATION_Handle *new_cfg = cls;
118
119   printf ("%s: %s\n", option, value);
120   if (NULL != new_cfg)
121     GNUNET_CONFIGURATION_set_value_string (new_cfg, section, option, value);
122 }
123
124
125 /**
126  * Function called with the result from the autoconfiguration.
127  *
128  * @param cls closure
129  * @param diff minimal suggested changes to the original configuration
130  *             to make it work (as best as we can)
131  * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
132  * @param type what the situation of the NAT
133  */
134 static void
135 auto_config_cb (void *cls,
136                 const struct GNUNET_CONFIGURATION_Handle *diff,
137                 enum GNUNET_NAT_StatusCode result,
138                 enum GNUNET_NAT_Type type)
139 {
140   const char *nat_type;
141   char unknown_type[64];
142   struct GNUNET_CONFIGURATION_Handle *new_cfg;
143
144   ah = NULL;
145   switch (type)
146   {
147   case GNUNET_NAT_TYPE_NO_NAT:
148     nat_type = "NO NAT";
149     break;
150
151   case GNUNET_NAT_TYPE_UNREACHABLE_NAT:
152     nat_type = "NAT but we can traverse";
153     break;
154
155   case GNUNET_NAT_TYPE_STUN_PUNCHED_NAT:
156     nat_type = "NAT but STUN is able to identify the correct information";
157     break;
158
159   case GNUNET_NAT_TYPE_UPNP_NAT:
160     nat_type = "NAT but UPNP opened the ports";
161     break;
162
163   default:
164     sprintf (unknown_type, "NAT unknown, type %u", type);
165     nat_type = unknown_type;
166     break;
167   }
168
169   GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
170               "NAT status: %s/%s\n",
171               GNUNET_NAT_AUTO_status2string (result),
172               nat_type);
173
174   if (NULL == diff)
175     return;
176
177   /* Shortcut: if there are no changes suggested, bail out early. */
178   if (GNUNET_NO == GNUNET_CONFIGURATION_is_dirty (diff))
179   {
180     test_finished ();
181     return;
182   }
183
184   /* Apply diff to original configuration and show changes
185      to the user */
186   new_cfg = write_cfg ? GNUNET_CONFIGURATION_dup (cfg) : NULL;
187
188   GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
189               _ ("Suggested configuration changes:\n"));
190   GNUNET_CONFIGURATION_iterate_section_values (diff,
191                                                "nat",
192                                                &auto_conf_iter,
193                                                new_cfg);
194
195   /* If desired, write configuration to file; we write only the
196      changes to the defaults to keep things compact. */
197   if (write_cfg)
198   {
199     struct GNUNET_CONFIGURATION_Handle *def_cfg;
200
201     GNUNET_CONFIGURATION_set_value_string (new_cfg, "ARM", "CONFIG", NULL);
202     def_cfg = GNUNET_CONFIGURATION_create ();
203     GNUNET_break (GNUNET_OK == GNUNET_CONFIGURATION_load (def_cfg, NULL));
204     if (GNUNET_OK !=
205         GNUNET_CONFIGURATION_write_diffs (def_cfg, new_cfg, cfg_file))
206     {
207       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
208                   _ ("Failed to write configuration to `%s'\n"),
209                   cfg_file);
210       global_ret = 1;
211     }
212     else
213     {
214       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
215                   _ ("Wrote updated configuration to `%s'\n"),
216                   cfg_file);
217     }
218     GNUNET_CONFIGURATION_destroy (def_cfg);
219   }
220
221   if (NULL != new_cfg)
222     GNUNET_CONFIGURATION_destroy (new_cfg);
223   test_finished ();
224 }
225
226
227 /**
228  * Function called to report success or failure for
229  * NAT configuration test.
230  *
231  * @param cls closure
232  * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
233  */
234 static void
235 test_report_cb (void *cls, enum GNUNET_NAT_StatusCode result)
236 {
237   nt = NULL;
238   printf ("NAT test result: %s\n", GNUNET_NAT_AUTO_status2string (result));
239   test_finished ();
240 }
241
242
243 /**
244  * Task run on shutdown.
245  *
246  * @param cls NULL
247  */
248 static void
249 do_shutdown (void *cls)
250 {
251   if (NULL != ah)
252   {
253     GNUNET_NAT_AUTO_autoconfig_cancel (ah);
254     ah = NULL;
255   }
256   if (NULL != nt)
257   {
258     GNUNET_NAT_AUTO_test_stop (nt);
259     nt = NULL;
260   }
261 }
262
263
264 /**
265  * Main function that will be run.
266  *
267  * @param cls closure
268  * @param args remaining command-line arguments
269  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
270  * @param c configuration
271  */
272 static void
273 run (void *cls,
274      char *const *args,
275      const char *cfgfile,
276      const struct GNUNET_CONFIGURATION_Handle *c)
277 {
278   cfg_file = cfgfile;
279   cfg = c;
280
281   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
282
283   if (do_auto)
284   {
285     ah = GNUNET_NAT_AUTO_autoconfig_start (c, &auto_config_cb, NULL);
286   }
287
288   if (use_tcp && use_udp)
289   {
290     if (do_auto)
291       return;
292     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Cannot use TCP and UDP\n");
293     global_ret = 1;
294     return;
295   }
296   proto = 0;
297   if (use_tcp)
298     proto = IPPROTO_TCP;
299   if (use_udp)
300     proto = IPPROTO_UDP;
301
302   if (NULL != section_name)
303   {
304     nt = GNUNET_NAT_AUTO_test_start (c,
305                                      proto,
306                                      section_name,
307                                      &test_report_cb,
308                                      NULL);
309   }
310   test_finished ();
311 }
312
313
314 /**
315  * Main function of gnunet-nat-auto
316  *
317  * @param argc number of command-line arguments
318  * @param argv command line
319  * @return 0 on success, -1 on error
320  */
321 int
322 main (int argc, char *const argv[])
323 {
324   struct GNUNET_GETOPT_CommandLineOption options[] =
325   { GNUNET_GETOPT_option_flag ('a',
326                                "auto",
327                                gettext_noop ("run autoconfiguration"),
328                                &do_auto),
329
330     GNUNET_GETOPT_option_string (
331       'S',
332       "section",
333       "NAME",
334       gettext_noop (
335         "section name providing the configuration for the adapter"),
336       &section_name),
337
338     GNUNET_GETOPT_option_flag ('t', "tcp", gettext_noop ("use TCP"), &use_tcp),
339
340     GNUNET_GETOPT_option_flag ('u', "udp", gettext_noop ("use UDP"), &use_udp),
341
342     GNUNET_GETOPT_option_flag (
343       'w',
344       "write",
345       gettext_noop ("write configuration file (for autoconfiguration)"),
346       &write_cfg),
347     GNUNET_GETOPT_OPTION_END };
348
349   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
350     return 2;
351   if (GNUNET_OK !=
352       GNUNET_PROGRAM_run (argc,
353                           argv,
354                           "gnunet-nat-auto [options]",
355                           _ ("GNUnet NAT traversal autoconfiguration"),
356                           options,
357                           &run,
358                           NULL))
359   {
360     global_ret = 1;
361   }
362   GNUNET_free_nz ((void *) argv);
363   return global_ret;
364 }
365
366
367 /* end of gnunet-nat-auto.c */