aboutsummaryrefslogtreecommitdiff
path: root/src/nat-auto/gnunet-nat-auto.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nat-auto/gnunet-nat-auto.c')
-rw-r--r--src/nat-auto/gnunet-nat-auto.c381
1 files changed, 381 insertions, 0 deletions
diff --git a/src/nat-auto/gnunet-nat-auto.c b/src/nat-auto/gnunet-nat-auto.c
new file mode 100644
index 000000000..9ba81eb5f
--- /dev/null
+++ b/src/nat-auto/gnunet-nat-auto.c
@@ -0,0 +1,381 @@
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 */
35static int global_ret;
36
37/**
38 * Handle to ongoing autoconfiguration.
39 */
40static struct GNUNET_NAT_AUTO_AutoHandle *ah;
41
42/**
43 * If we do auto-configuration, should we write the result
44 * to a file?
45 */
46static int write_cfg;
47
48/**
49 * Configuration filename.
50 */
51static const char *cfg_file;
52
53/**
54 * Original configuration.
55 */
56static const struct GNUNET_CONFIGURATION_Handle *cfg;
57
58/**
59 * Adapter we are supposed to test.
60 */
61static char *section_name;
62
63/**
64 * Should we run autoconfiguration?
65 */
66static unsigned int do_auto;
67
68/**
69 * Handle to a NAT test operation.
70 */
71static struct GNUNET_NAT_AUTO_Test *nt;
72
73/**
74 * Flag set to 1 if we use IPPROTO_UDP.
75 */
76static int use_udp;
77
78/**
79 * Flag set to 1 if we use IPPROTO_TCP.
80 */
81static int use_tcp;
82
83/**
84 * Protocol to use.
85 */
86static uint8_t proto;
87
88/**
89 * Test if all activities have finished, and if so,
90 * terminate.
91 */
92static void
93test_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 */
111static void
112auto_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 */
139static void
140auto_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 */
246static void
247test_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 */
262static void
263do_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 */
286static void
287run (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 */
339int
340main (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 */