fix misc compilation issues in nat-auto
[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
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-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 unsigned 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",
120           option,
121           value);
122   if (NULL != new_cfg)
123     GNUNET_CONFIGURATION_set_value_string (new_cfg,
124                                            section,
125                                            option,
126                                            value);
127 }
128
129
130 /**
131  * Function called with the result from the autoconfiguration.
132  *
133  * @param cls closure
134  * @param diff minimal suggested changes to the original configuration
135  *             to make it work (as best as we can)
136  * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
137  * @param type what the situation of the NAT
138  */
139 static void
140 auto_config_cb (void *cls,
141                 const struct GNUNET_CONFIGURATION_Handle *diff,
142                 enum GNUNET_NAT_StatusCode result,
143                 enum GNUNET_NAT_Type type)
144 {
145   const char *nat_type;
146   char unknown_type[64];
147   struct GNUNET_CONFIGURATION_Handle *new_cfg;
148
149   ah = NULL;
150   switch (type)
151   {
152   case GNUNET_NAT_TYPE_NO_NAT:
153     nat_type = "NO NAT";
154     break;
155   case GNUNET_NAT_TYPE_UNREACHABLE_NAT:
156     nat_type = "NAT but we can traverse";
157     break;
158   case GNUNET_NAT_TYPE_STUN_PUNCHED_NAT:
159     nat_type = "NAT but STUN is able to identify the correct information";
160     break;
161   case GNUNET_NAT_TYPE_UPNP_NAT:
162     nat_type = "NAT but UPNP opened the ports";
163     break;
164   default:
165     SPRINTF (unknown_type,
166              "NAT unknown, type %u",
167              type);
168     nat_type = unknown_type;
169     break;
170   }
171
172   GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
173               "NAT status: %s/%s\n",
174               GNUNET_NAT_AUTO_status2string (result),
175               nat_type);
176
177   /* Shortcut: if there are no changes suggested, bail out early. */
178   if (GNUNET_NO ==
179       GNUNET_CONFIGURATION_is_dirty (diff))
180   {
181     test_finished ();
182     return;
183   }
184
185   /* Apply diff to original configuration and show changes
186      to the user */
187   new_cfg = write_cfg ? GNUNET_CONFIGURATION_dup (cfg) : NULL;
188
189   if (NULL != diff)
190   {
191     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
192                 _("Suggested configuration changes:\n"));
193     GNUNET_CONFIGURATION_iterate_section_values (diff,
194                                                  "nat",
195                                                  &auto_conf_iter,
196                                                  new_cfg);
197   }
198
199   /* If desired, write configuration to file; we write only the
200      changes to the defaults to keep things compact. */
201   if ( (write_cfg) &&
202        (NULL != diff) )
203   {
204     struct GNUNET_CONFIGURATION_Handle *def_cfg;
205
206     GNUNET_CONFIGURATION_set_value_string (new_cfg,
207                                            "ARM",
208                                            "CONFIG",
209                                            NULL);
210     def_cfg = GNUNET_CONFIGURATION_create ();
211     GNUNET_break (GNUNET_OK ==
212                   GNUNET_CONFIGURATION_load (def_cfg,
213                                              NULL));
214     if (GNUNET_OK !=
215         GNUNET_CONFIGURATION_write_diffs (def_cfg,
216                                           new_cfg,
217                                           cfg_file))
218     {
219       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
220                   _("Failed to write configuration to `%s'\n"),
221                   cfg_file);
222       global_ret = 1;
223     }
224     else
225     {
226       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
227                   _("Wrote updated configuration to `%s'\n"),
228                   cfg_file);
229     }
230     GNUNET_CONFIGURATION_destroy (def_cfg);
231   }
232
233   if (NULL != new_cfg)
234     GNUNET_CONFIGURATION_destroy (new_cfg);
235   test_finished ();
236 }
237
238
239 /**
240  * Function called to report success or failure for
241  * NAT configuration test.
242  *
243  * @param cls closure
244  * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
245  */
246 static void
247 test_report_cb (void *cls,
248                 enum GNUNET_NAT_StatusCode result)
249 {
250   nt = NULL;
251   PRINTF ("NAT test result: %s\n",
252           GNUNET_NAT_AUTO_status2string (result));
253   test_finished ();
254 }
255
256
257 /**
258  * Task run on shutdown.
259  *
260  * @param cls NULL
261  */
262 static void
263 do_shutdown (void *cls)
264 {
265   if (NULL != ah)
266   {
267     GNUNET_NAT_AUTO_autoconfig_cancel (ah);
268     ah = NULL;
269   }
270   if (NULL != nt)
271   {
272     GNUNET_NAT_AUTO_test_stop (nt);
273     nt = NULL;
274   }
275 }
276
277
278 /**
279  * Main function that will be run.
280  *
281  * @param cls closure
282  * @param args remaining command-line arguments
283  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
284  * @param c configuration
285  */
286 static void
287 run (void *cls,
288      char *const *args,
289      const char *cfgfile,
290      const struct GNUNET_CONFIGURATION_Handle *c)
291 {
292   cfg_file = cfgfile;
293   cfg = c;
294
295   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
296                                  NULL);
297
298   if (do_auto)
299   {
300     ah = GNUNET_NAT_AUTO_autoconfig_start (c,
301                                       &auto_config_cb,
302                                       NULL);
303   }
304
305   if (use_tcp && use_udp)
306   {
307     if (do_auto)
308       return;
309     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
310                 "Cannot use TCP and UDP\n");
311     global_ret = 1;
312     return;
313   }
314   proto = 0;
315   if (use_tcp)
316     proto = IPPROTO_TCP;
317   if (use_udp)
318     proto = IPPROTO_UDP;
319
320   if (NULL != section_name)
321   {
322     nt = GNUNET_NAT_AUTO_test_start (c,
323                                      proto,
324                                      section_name,
325                                      &test_report_cb,
326                                      NULL);
327   }
328   test_finished ();
329 }
330
331
332 /**
333  * Main function of gnunet-nat-auto
334  *
335  * @param argc number of command-line arguments
336  * @param argv command line
337  * @return 0 on success, -1 on error
338  */
339 int
340 main (int argc,
341       char *const argv[])
342 {
343   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
344     {'a', "auto", NULL,
345      gettext_noop ("run autoconfiguration"),
346      GNUNET_NO, &GNUNET_GETOPT_set_one, &do_auto },
347     {'S', "section", "NAME",
348      gettext_noop ("section name providing the configuration for the adapter"),
349      GNUNET_YES, &GNUNET_GETOPT_set_string, &section_name },
350     {'t', "tcp", NULL,
351      gettext_noop ("use TCP"),
352      GNUNET_NO, &GNUNET_GETOPT_set_one, &use_tcp },
353     {'u', "udp", NULL,
354      gettext_noop ("use UDP"),
355      GNUNET_NO, &GNUNET_GETOPT_set_one, &use_udp },
356     {'w', "write", NULL,
357      gettext_noop ("write configuration file (for autoconfiguration)"),
358      GNUNET_NO, &GNUNET_GETOPT_set_one, &write_cfg },
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   if (GNUNET_OK !=
367       GNUNET_PROGRAM_run (argc, argv,
368                           "gnunet-nat-auto [options]",
369                           _("GNUnet NAT traversal autoconfiguration"),
370                           options,
371                           &run,
372                           NULL))
373   {
374     global_ret = 1;
375   }
376   GNUNET_free ((void*) argv);
377   return global_ret;
378 }
379
380
381 /* end of gnunet-nat-auto.c */