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