diff options
author | Christian Grothoff <christian@grothoff.org> | 2017-01-06 13:26:38 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2017-01-06 13:26:38 +0100 |
commit | 80e1315b56f559db60499f5373e90c293c5ab065 (patch) | |
tree | 3b279e6ac8e6298d7d9d96d12868f628a413939b /src/nat-auto | |
parent | 1b7f6eea0a06abab9b75b30f021aa6313fccfcd4 (diff) | |
download | gnunet-80e1315b56f559db60499f5373e90c293c5ab065.tar.gz gnunet-80e1315b56f559db60499f5373e90c293c5ab065.zip |
separate service for autoconfiguration from NAT traversal
Diffstat (limited to 'src/nat-auto')
-rw-r--r-- | src/nat-auto/.gitignore | 3 | ||||
-rw-r--r-- | src/nat-auto/Makefile.am | 58 | ||||
-rw-r--r-- | src/nat-auto/gnunet-nat-auto.c | 428 | ||||
-rw-r--r-- | src/nat-auto/gnunet-nat-server.c | 384 | ||||
-rw-r--r-- | src/nat-auto/gnunet-service-nat-auto.c | 481 | ||||
-rw-r--r-- | src/nat-auto/nat-auto.conf.in | 15 | ||||
-rw-r--r-- | src/nat-auto/nat-auto.h | 110 | ||||
-rw-r--r-- | src/nat-auto/nat_auto_api.c | 274 | ||||
-rw-r--r-- | src/nat-auto/nat_auto_api_test.c | 644 |
9 files changed, 2397 insertions, 0 deletions
diff --git a/src/nat-auto/.gitignore b/src/nat-auto/.gitignore new file mode 100644 index 000000000..6ba53d72f --- /dev/null +++ b/src/nat-auto/.gitignore | |||
@@ -0,0 +1,3 @@ | |||
1 | gnunet-service-nat-auto | ||
2 | gnunet-nat-auto | ||
3 | gnunet-nat-server | ||
diff --git a/src/nat-auto/Makefile.am b/src/nat-auto/Makefile.am new file mode 100644 index 000000000..dbe910306 --- /dev/null +++ b/src/nat-auto/Makefile.am | |||
@@ -0,0 +1,58 @@ | |||
1 | # This Makefile.am is in the public domain | ||
2 | AM_CPPFLAGS = -I$(top_srcdir)/src/include | ||
3 | |||
4 | libexecdir= $(pkglibdir)/libexec/ | ||
5 | |||
6 | pkgcfgdir= $(pkgdatadir)/config.d/ | ||
7 | |||
8 | pkgcfg_DATA = \ | ||
9 | nat-auto.conf | ||
10 | |||
11 | bin_PROGRAMS = \ | ||
12 | gnunet-nat-auto \ | ||
13 | gnunet-nat-server | ||
14 | |||
15 | libexec_PROGRAMS = \ | ||
16 | gnunet-service-nat-auto | ||
17 | |||
18 | gnunet_nat_server_SOURCES = \ | ||
19 | gnunet-nat-server.c nat-auto.h | ||
20 | gnunet_nat_server_LDADD = \ | ||
21 | $(top_builddir)/src/nat/libgnunetnat.la \ | ||
22 | $(top_builddir)/src/util/libgnunetutil.la | ||
23 | |||
24 | gnunet_nat_auto_SOURCES = \ | ||
25 | gnunet-nat-auto.c nat-auto.h | ||
26 | gnunet_nat_auto_LDADD = \ | ||
27 | libgnunetnatauto.la \ | ||
28 | $(top_builddir)/src/util/libgnunetutil.la | ||
29 | |||
30 | |||
31 | if USE_COVERAGE | ||
32 | AM_CFLAGS = -fprofile-arcs -ftest-coverage | ||
33 | endif | ||
34 | |||
35 | lib_LTLIBRARIES = \ | ||
36 | libgnunetnatauto.la | ||
37 | |||
38 | libgnunetnatauto_la_SOURCES = \ | ||
39 | nat_auto_api.c \ | ||
40 | nat_auto_api_test.c | ||
41 | libgnunetnatauto_la_LIBADD = \ | ||
42 | $(top_builddir)/src/nat/libgnunetnatnew.la \ | ||
43 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
44 | $(GN_LIBINTL) @EXT_LIBS@ | ||
45 | libgnunetnatauto_la_LDFLAGS = \ | ||
46 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ | ||
47 | -version-info 0:0:0 | ||
48 | |||
49 | gnunet_service_nat_auto_SOURCES = \ | ||
50 | gnunet-service-nat-auto.c | ||
51 | gnunet_service_nat_auto_LDADD = \ | ||
52 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
53 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
54 | $(top_builddir)/src/nat/libgnunetnatnew.la \ | ||
55 | $(LIBGCRYPT_LIBS) \ | ||
56 | -lgcrypt \ | ||
57 | $(GN_LIBINTL) | ||
58 | |||
diff --git a/src/nat-auto/gnunet-nat-auto.c b/src/nat-auto/gnunet-nat-auto.c new file mode 100644 index 000000000..3b9a5fa94 --- /dev/null +++ b/src/nat-auto/gnunet-nat-auto.c | |||
@@ -0,0 +1,428 @@ | |||
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_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 | * Address we are bound to (in test), or should bind to | ||
60 | * (if #do_stun is set). | ||
61 | */ | ||
62 | static char *bind_addr; | ||
63 | |||
64 | /** | ||
65 | * External IP address and port to use for the test. | ||
66 | * If not set, use #bind_addr. | ||
67 | */ | ||
68 | static char *extern_addr; | ||
69 | |||
70 | /** | ||
71 | * Should we run autoconfiguration? | ||
72 | */ | ||
73 | static unsigned int do_auto; | ||
74 | |||
75 | /** | ||
76 | * Handle to a NAT test operation. | ||
77 | */ | ||
78 | static struct GNUNET_NAT_Test *nt; | ||
79 | |||
80 | /** | ||
81 | * Flag set to 1 if we use IPPROTO_UDP. | ||
82 | */ | ||
83 | static int use_udp; | ||
84 | |||
85 | /** | ||
86 | * Flag set to 1 if we use IPPROTO_TCP. | ||
87 | */ | ||
88 | static int use_tcp; | ||
89 | |||
90 | /** | ||
91 | * Protocol to use. | ||
92 | */ | ||
93 | static uint8_t proto; | ||
94 | |||
95 | /** | ||
96 | * Test if all activities have finished, and if so, | ||
97 | * terminate. | ||
98 | */ | ||
99 | static void | ||
100 | test_finished () | ||
101 | { | ||
102 | if (NULL != ah) | ||
103 | return; | ||
104 | if (NULL != nt) | ||
105 | return; | ||
106 | GNUNET_SCHEDULER_shutdown (); | ||
107 | } | ||
108 | |||
109 | |||
110 | /** | ||
111 | * Function to iterate over sugested changes options | ||
112 | * | ||
113 | * @param cls closure | ||
114 | * @param section name of the section | ||
115 | * @param option name of the option | ||
116 | * @param value value of the option | ||
117 | */ | ||
118 | static void | ||
119 | auto_conf_iter (void *cls, | ||
120 | const char *section, | ||
121 | const char *option, | ||
122 | const char *value) | ||
123 | { | ||
124 | struct GNUNET_CONFIGURATION_Handle *new_cfg = cls; | ||
125 | |||
126 | PRINTF ("%s: %s\n", | ||
127 | option, | ||
128 | value); | ||
129 | if (NULL != new_cfg) | ||
130 | GNUNET_CONFIGURATION_set_value_string (new_cfg, | ||
131 | section, | ||
132 | option, | ||
133 | value); | ||
134 | } | ||
135 | |||
136 | |||
137 | /** | ||
138 | * Function called with the result from the autoconfiguration. | ||
139 | * | ||
140 | * @param cls closure | ||
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 | ||
145 | */ | ||
146 | static void | ||
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) | ||
151 | { | ||
152 | const char *nat_type; | ||
153 | char unknown_type[64]; | ||
154 | struct GNUNET_CONFIGURATION_Handle *new_cfg; | ||
155 | |||
156 | ah = NULL; | ||
157 | switch (type) | ||
158 | { | ||
159 | case GNUNET_NAT_TYPE_NO_NAT: | ||
160 | nat_type = "NO NAT"; | ||
161 | break; | ||
162 | case GNUNET_NAT_TYPE_UNREACHABLE_NAT: | ||
163 | nat_type = "NAT but we can traverse"; | ||
164 | break; | ||
165 | case GNUNET_NAT_TYPE_STUN_PUNCHED_NAT: | ||
166 | nat_type = "NAT but STUN is able to identify the correct information"; | ||
167 | break; | ||
168 | case GNUNET_NAT_TYPE_UPNP_NAT: | ||
169 | nat_type = "NAT but UPNP opened the ports"; | ||
170 | break; | ||
171 | default: | ||
172 | SPRINTF (unknown_type, | ||
173 | "NAT unknown, type %u", | ||
174 | type); | ||
175 | nat_type = unknown_type; | ||
176 | break; | ||
177 | } | ||
178 | |||
179 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
180 | "NAT status: %s/%s\n", | ||
181 | GNUNET_NAT_status2string (result), | ||
182 | nat_type); | ||
183 | |||
184 | /* Shortcut: if there are no changes suggested, bail out early. */ | ||
185 | if (GNUNET_NO == | ||
186 | GNUNET_CONFIGURATION_is_dirty (diff)) | ||
187 | { | ||
188 | test_finished (); | ||
189 | return; | ||
190 | } | ||
191 | |||
192 | /* Apply diff to original configuration and show changes | ||
193 | to the user */ | ||
194 | new_cfg = write_cfg ? GNUNET_CONFIGURATION_dup (cfg) : NULL; | ||
195 | |||
196 | if (NULL != diff) | ||
197 | { | ||
198 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
199 | _("Suggested configuration changes:\n")); | ||
200 | GNUNET_CONFIGURATION_iterate_section_values (diff, | ||
201 | "nat", | ||
202 | &auto_conf_iter, | ||
203 | new_cfg); | ||
204 | } | ||
205 | |||
206 | /* If desired, write configuration to file; we write only the | ||
207 | changes to the defaults to keep things compact. */ | ||
208 | if ( (write_cfg) && | ||
209 | (NULL != diff) ) | ||
210 | { | ||
211 | struct GNUNET_CONFIGURATION_Handle *def_cfg; | ||
212 | |||
213 | GNUNET_CONFIGURATION_set_value_string (new_cfg, | ||
214 | "ARM", | ||
215 | "CONFIG", | ||
216 | NULL); | ||
217 | def_cfg = GNUNET_CONFIGURATION_create (); | ||
218 | GNUNET_break (GNUNET_OK == | ||
219 | GNUNET_CONFIGURATION_load (def_cfg, | ||
220 | NULL)); | ||
221 | if (GNUNET_OK != | ||
222 | GNUNET_CONFIGURATION_write_diffs (def_cfg, | ||
223 | new_cfg, | ||
224 | cfg_file)) | ||
225 | { | ||
226 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
227 | _("Failed to write configuration to `%s'\n"), | ||
228 | cfg_file); | ||
229 | global_ret = 1; | ||
230 | } | ||
231 | else | ||
232 | { | ||
233 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
234 | _("Wrote updated configuration to `%s'\n"), | ||
235 | cfg_file); | ||
236 | } | ||
237 | GNUNET_CONFIGURATION_destroy (def_cfg); | ||
238 | } | ||
239 | |||
240 | if (NULL != new_cfg) | ||
241 | GNUNET_CONFIGURATION_destroy (new_cfg); | ||
242 | test_finished (); | ||
243 | } | ||
244 | |||
245 | |||
246 | /** | ||
247 | * Function called to report success or failure for | ||
248 | * NAT configuration test. | ||
249 | * | ||
250 | * @param cls closure | ||
251 | * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code | ||
252 | */ | ||
253 | static void | ||
254 | test_report_cb (void *cls, | ||
255 | enum GNUNET_NAT_StatusCode result) | ||
256 | { | ||
257 | nt = NULL; | ||
258 | PRINTF ("NAT test result: %s\n", | ||
259 | GNUNET_NAT_status2string (result)); | ||
260 | test_finished (); | ||
261 | } | ||
262 | |||
263 | |||
264 | /** | ||
265 | * Task run on shutdown. | ||
266 | * | ||
267 | * @param cls NULL | ||
268 | */ | ||
269 | static void | ||
270 | do_shutdown (void *cls) | ||
271 | { | ||
272 | if (NULL != ah) | ||
273 | { | ||
274 | GNUNET_NAT_autoconfig_cancel (ah); | ||
275 | ah = NULL; | ||
276 | } | ||
277 | if (NULL != nt) | ||
278 | { | ||
279 | GNUNET_NAT_test_stop (nt); | ||
280 | nt = NULL; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | |||
285 | /** | ||
286 | * Main function that will be run. | ||
287 | * | ||
288 | * @param cls closure | ||
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 | ||
292 | */ | ||
293 | static void | ||
294 | run (void *cls, | ||
295 | char *const *args, | ||
296 | const char *cfgfile, | ||
297 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
298 | { | ||
299 | struct sockaddr_in bind_sa; | ||
300 | struct sockaddr_in extern_sa; | ||
301 | |||
302 | cfg_file = cfgfile; | ||
303 | cfg = c; | ||
304 | |||
305 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, | ||
306 | NULL); | ||
307 | |||
308 | if (do_auto) | ||
309 | { | ||
310 | ah = GNUNET_NAT_autoconfig_start (c, | ||
311 | &auto_config_cb, | ||
312 | NULL); | ||
313 | } | ||
314 | |||
315 | if (use_tcp && use_udp) | ||
316 | { | ||
317 | if (do_auto) | ||
318 | return; | ||
319 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
320 | "Cannot use TCP and UDP\n"); | ||
321 | global_ret = 1; | ||
322 | return; | ||
323 | } | ||
324 | proto = 0; | ||
325 | if (use_tcp) | ||
326 | proto = IPPROTO_TCP; | ||
327 | if (use_udp) | ||
328 | proto = IPPROTO_UDP; | ||
329 | |||
330 | if (NULL != bind_addr) | ||
331 | { | ||
332 | if (GNUNET_OK != | ||
333 | GNUNET_STRINGS_to_address_ipv4 (bind_addr, | ||
334 | strlen (bind_addr), | ||
335 | &bind_sa)) | ||
336 | { | ||
337 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
338 | "Invalid socket address `%s'\n", | ||
339 | bind_addr); | ||
340 | global_ret = 1; | ||
341 | return; | ||
342 | } | ||
343 | } | ||
344 | if (NULL != extern_addr) | ||
345 | { | ||
346 | if (GNUNET_OK != | ||
347 | GNUNET_STRINGS_to_address_ipv4 (extern_addr, | ||
348 | strlen (extern_addr), | ||
349 | &extern_sa)) | ||
350 | { | ||
351 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
352 | "Invalid socket address `%s'\n", | ||
353 | extern_addr); | ||
354 | global_ret = 1; | ||
355 | return; | ||
356 | } | ||
357 | } | ||
358 | |||
359 | if (NULL != bind_addr) | ||
360 | { | ||
361 | if (NULL == extern_addr) | ||
362 | extern_sa = bind_sa; | ||
363 | nt = GNUNET_NAT_test_start (c, | ||
364 | proto, | ||
365 | bind_sa.sin_addr, | ||
366 | ntohs (bind_sa.sin_port), | ||
367 | extern_sa.sin_addr, | ||
368 | ntohs (extern_sa.sin_port), | ||
369 | &test_report_cb, | ||
370 | NULL); | ||
371 | } | ||
372 | test_finished (); | ||
373 | } | ||
374 | |||
375 | |||
376 | /** | ||
377 | * Main function of gnunet-nat | ||
378 | * | ||
379 | * @param argc number of command-line arguments | ||
380 | * @param argv command line | ||
381 | * @return 0 on success, -1 on error | ||
382 | */ | ||
383 | int | ||
384 | main (int argc, | ||
385 | char *const argv[]) | ||
386 | { | ||
387 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
388 | {'a', "auto", NULL, | ||
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 }, | ||
397 | {'t', "tcp", NULL, | ||
398 | gettext_noop ("use TCP"), | ||
399 | GNUNET_NO, &GNUNET_GETOPT_set_one, &use_tcp }, | ||
400 | {'u', "udp", NULL, | ||
401 | gettext_noop ("use UDP"), | ||
402 | GNUNET_NO, &GNUNET_GETOPT_set_one, &use_udp }, | ||
403 | {'w', "write", NULL, | ||
404 | gettext_noop ("write configuration file (for autoconfiguration)"), | ||
405 | GNUNET_NO, &GNUNET_GETOPT_set_one, &write_cfg }, | ||
406 | GNUNET_GETOPT_OPTION_END | ||
407 | }; | ||
408 | |||
409 | if (GNUNET_OK != | ||
410 | GNUNET_STRINGS_get_utf8_args (argc, argv, | ||
411 | &argc, &argv)) | ||
412 | return 2; | ||
413 | if (GNUNET_OK != | ||
414 | GNUNET_PROGRAM_run (argc, argv, | ||
415 | "gnunet-nat-auto [options]", | ||
416 | _("GNUnet NAT traversal autoconfiguration"), | ||
417 | options, | ||
418 | &run, | ||
419 | NULL)) | ||
420 | { | ||
421 | global_ret = 1; | ||
422 | } | ||
423 | GNUNET_free ((void*) argv); | ||
424 | return global_ret; | ||
425 | } | ||
426 | |||
427 | |||
428 | /* end of gnunet-nat-auto.c */ | ||
diff --git a/src/nat-auto/gnunet-nat-server.c b/src/nat-auto/gnunet-nat-server.c new file mode 100644 index 000000000..93352f5f0 --- /dev/null +++ b/src/nat-auto/gnunet-nat-server.c | |||
@@ -0,0 +1,384 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011 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-server.c | ||
23 | * @brief Daemon to run on 'gnunet.org' to help test NAT traversal code | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_nat_lib.h" | ||
29 | #include "gnunet_protocols.h" | ||
30 | #include "nat-auto.h" | ||
31 | |||
32 | |||
33 | /** | ||
34 | * Our server. | ||
35 | */ | ||
36 | static struct GNUNET_SERVER_Handle *server; | ||
37 | |||
38 | /** | ||
39 | * Our configuration. | ||
40 | */ | ||
41 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
42 | |||
43 | |||
44 | /** | ||
45 | * Try contacting the peer using autonomous NAT traveral method. | ||
46 | * | ||
47 | * @param dst_ipv4 IPv4 address to send the fake ICMP message | ||
48 | * @param dport destination port to include in ICMP message | ||
49 | * @param is_tcp mark for TCP (#GNUNET_YES) or UDP (#GNUNET_NO) | ||
50 | */ | ||
51 | static void | ||
52 | try_anat (uint32_t dst_ipv4, | ||
53 | uint16_t dport, | ||
54 | int is_tcp) | ||
55 | { | ||
56 | struct GNUNET_NAT_Handle *h; | ||
57 | struct sockaddr_in sa; | ||
58 | |||
59 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
60 | "Asking for connection reversal with %x and code %u\n", | ||
61 | (unsigned int) dst_ipv4, | ||
62 | (unsigned int) dport); | ||
63 | h = GNUNET_NAT_register (cfg, | ||
64 | is_tcp, | ||
65 | dport, | ||
66 | 0, | ||
67 | NULL, NULL, NULL, NULL, NULL, NULL); | ||
68 | memset (&sa, 0, sizeof (sa)); | ||
69 | sa.sin_family = AF_INET; | ||
70 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
71 | sa.sin_len = sizeof (sa); | ||
72 | #endif | ||
73 | sa.sin_addr.s_addr = dst_ipv4; | ||
74 | GNUNET_NAT_run_client (h, &sa); | ||
75 | GNUNET_NAT_unregister (h); | ||
76 | } | ||
77 | |||
78 | |||
79 | /** | ||
80 | * Closure for #tcp_send. | ||
81 | */ | ||
82 | struct TcpContext | ||
83 | { | ||
84 | /** | ||
85 | * TCP socket. | ||
86 | */ | ||
87 | struct GNUNET_NETWORK_Handle *s; | ||
88 | |||
89 | /** | ||
90 | * Data to transmit. | ||
91 | */ | ||
92 | uint16_t data; | ||
93 | }; | ||
94 | |||
95 | |||
96 | /** | ||
97 | * Task called by the scheduler once we can do the TCP send | ||
98 | * (or once we failed to connect...). | ||
99 | * | ||
100 | * @param cls the `struct TcpContext` | ||
101 | */ | ||
102 | static void | ||
103 | tcp_send (void *cls) | ||
104 | { | ||
105 | struct TcpContext *ctx = cls; | ||
106 | const struct GNUNET_SCHEDULER_TaskContext *tc; | ||
107 | |||
108 | tc = GNUNET_SCHEDULER_get_task_context (); | ||
109 | if ((NULL != tc->write_ready) && | ||
110 | (GNUNET_NETWORK_fdset_isset (tc->write_ready, ctx->s))) | ||
111 | { | ||
112 | if (-1 == | ||
113 | GNUNET_NETWORK_socket_send (ctx->s, &ctx->data, sizeof (ctx->data))) | ||
114 | { | ||
115 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send"); | ||
116 | } | ||
117 | GNUNET_NETWORK_socket_shutdown (ctx->s, SHUT_RDWR); | ||
118 | } | ||
119 | GNUNET_NETWORK_socket_close (ctx->s); | ||
120 | GNUNET_free (ctx); | ||
121 | } | ||
122 | |||
123 | |||
124 | /** | ||
125 | * Try to send @a data to the | ||
126 | * IP @a dst_ipv4' at port @a dport via TCP. | ||
127 | * | ||
128 | * @param dst_ipv4 target IP | ||
129 | * @param dport target port | ||
130 | * @param data data to send | ||
131 | */ | ||
132 | static void | ||
133 | try_send_tcp (uint32_t dst_ipv4, | ||
134 | uint16_t dport, | ||
135 | uint16_t data) | ||
136 | { | ||
137 | struct GNUNET_NETWORK_Handle *s; | ||
138 | struct sockaddr_in sa; | ||
139 | struct TcpContext *ctx; | ||
140 | |||
141 | s = GNUNET_NETWORK_socket_create (AF_INET, | ||
142 | SOCK_STREAM, | ||
143 | 0); | ||
144 | if (NULL == s) | ||
145 | { | ||
146 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
147 | "socket"); | ||
148 | return; | ||
149 | } | ||
150 | memset (&sa, 0, sizeof (sa)); | ||
151 | sa.sin_family = AF_INET; | ||
152 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
153 | sa.sin_len = sizeof (sa); | ||
154 | #endif | ||
155 | sa.sin_addr.s_addr = dst_ipv4; | ||
156 | sa.sin_port = htons (dport); | ||
157 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
158 | "Sending TCP message to `%s'\n", | ||
159 | GNUNET_a2s ((struct sockaddr *) &sa, | ||
160 | sizeof (sa))); | ||
161 | if ( (GNUNET_OK != | ||
162 | GNUNET_NETWORK_socket_connect (s, | ||
163 | (const struct sockaddr *) &sa, | ||
164 | sizeof (sa))) && | ||
165 | (errno != EINPROGRESS) ) | ||
166 | { | ||
167 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
168 | "connect"); | ||
169 | GNUNET_NETWORK_socket_close (s); | ||
170 | return; | ||
171 | } | ||
172 | ctx = GNUNET_new (struct TcpContext); | ||
173 | ctx->s = s; | ||
174 | ctx->data = data; | ||
175 | GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_SECONDS, | ||
176 | s, | ||
177 | &tcp_send, | ||
178 | ctx); | ||
179 | } | ||
180 | |||
181 | |||
182 | /** | ||
183 | * Try to send @a data to the | ||
184 | * IP @a dst_ipv4 at port @a dport via UDP. | ||
185 | * | ||
186 | * @param dst_ipv4 target IP | ||
187 | * @param dport target port | ||
188 | * @param data data to send | ||
189 | */ | ||
190 | static void | ||
191 | try_send_udp (uint32_t dst_ipv4, | ||
192 | uint16_t dport, | ||
193 | uint16_t data) | ||
194 | { | ||
195 | struct GNUNET_NETWORK_Handle *s; | ||
196 | struct sockaddr_in sa; | ||
197 | |||
198 | s = GNUNET_NETWORK_socket_create (AF_INET, | ||
199 | SOCK_DGRAM, | ||
200 | 0); | ||
201 | if (NULL == s) | ||
202 | { | ||
203 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
204 | "socket"); | ||
205 | return; | ||
206 | } | ||
207 | memset (&sa, 0, sizeof (sa)); | ||
208 | sa.sin_family = AF_INET; | ||
209 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
210 | sa.sin_len = sizeof (sa); | ||
211 | #endif | ||
212 | sa.sin_addr.s_addr = dst_ipv4; | ||
213 | sa.sin_port = htons (dport); | ||
214 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
215 | "Sending UDP packet to `%s'\n", | ||
216 | GNUNET_a2s ((struct sockaddr *) &sa, | ||
217 | sizeof (sa))); | ||
218 | if (-1 == | ||
219 | GNUNET_NETWORK_socket_sendto (s, | ||
220 | &data, | ||
221 | sizeof (data), | ||
222 | (const struct sockaddr *) &sa, | ||
223 | sizeof (sa))) | ||
224 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
225 | "sendto"); | ||
226 | GNUNET_NETWORK_socket_close (s); | ||
227 | } | ||
228 | |||
229 | |||
230 | /** | ||
231 | * We've received a request to probe a NAT | ||
232 | * traversal. Do it. | ||
233 | * | ||
234 | * @param cls unused | ||
235 | * @param client handle to client (we always close) | ||
236 | * @param msg message with details about what to test | ||
237 | */ | ||
238 | static void | ||
239 | test (void *cls, | ||
240 | struct GNUNET_SERVER_Client *client, | ||
241 | const struct GNUNET_MessageHeader *msg) | ||
242 | { | ||
243 | const struct GNUNET_NAT_TestMessage *tm; | ||
244 | uint16_t dport; | ||
245 | |||
246 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
247 | "Received test request\n"); | ||
248 | tm = (const struct GNUNET_NAT_TestMessage *) msg; | ||
249 | dport = ntohs (tm->dport); | ||
250 | if (0 == dport) | ||
251 | try_anat (tm->dst_ipv4, | ||
252 | ntohs (tm->data), | ||
253 | (int) ntohl (tm->is_tcp)); | ||
254 | else if (GNUNET_YES == ntohl (tm->is_tcp)) | ||
255 | try_send_tcp (tm->dst_ipv4, | ||
256 | dport, | ||
257 | tm->data); | ||
258 | else | ||
259 | try_send_udp (tm->dst_ipv4, | ||
260 | dport, | ||
261 | tm->data); | ||
262 | GNUNET_SERVER_receive_done (client, | ||
263 | GNUNET_NO); | ||
264 | } | ||
265 | |||
266 | |||
267 | /** | ||
268 | * Task run during shutdown. | ||
269 | * | ||
270 | * @param cls unused | ||
271 | */ | ||
272 | static void | ||
273 | shutdown_task (void *cls) | ||
274 | { | ||
275 | GNUNET_SERVER_destroy (server); | ||
276 | server = NULL; | ||
277 | } | ||
278 | |||
279 | |||
280 | /** | ||
281 | * Main function that will be run. | ||
282 | * | ||
283 | * @param cls closure | ||
284 | * @param args remaining command-line arguments | ||
285 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
286 | * @param c configuration | ||
287 | */ | ||
288 | static void | ||
289 | run (void *cls, | ||
290 | char *const *args, | ||
291 | const char *cfgfile, | ||
292 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
293 | { | ||
294 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { | ||
295 | {&test, NULL, GNUNET_MESSAGE_TYPE_NAT_TEST, | ||
296 | sizeof (struct GNUNET_NAT_TestMessage)}, | ||
297 | {NULL, NULL, 0, 0} | ||
298 | }; | ||
299 | unsigned int port; | ||
300 | struct sockaddr_in in4; | ||
301 | struct sockaddr_in6 in6; | ||
302 | |||
303 | socklen_t slen[] = { | ||
304 | sizeof (in4), | ||
305 | sizeof (in6), | ||
306 | 0 | ||
307 | }; | ||
308 | struct sockaddr *sa[] = { | ||
309 | (struct sockaddr *) &in4, | ||
310 | (struct sockaddr *) &in6, | ||
311 | NULL | ||
312 | }; | ||
313 | |||
314 | cfg = c; | ||
315 | if ( (NULL == args[0]) || | ||
316 | (1 != SSCANF (args[0], "%u", &port)) || | ||
317 | (0 == port) || | ||
318 | (65536 <= port) ) | ||
319 | { | ||
320 | FPRINTF (stderr, | ||
321 | _("Please pass valid port number as the first argument! (got `%s')\n"), | ||
322 | args[0]); | ||
323 | return; | ||
324 | } | ||
325 | memset (&in4, 0, sizeof (in4)); | ||
326 | memset (&in6, 0, sizeof (in6)); | ||
327 | in4.sin_family = AF_INET; | ||
328 | in4.sin_port = htons ((uint16_t) port); | ||
329 | in6.sin6_family = AF_INET6; | ||
330 | in6.sin6_port = htons ((uint16_t) port); | ||
331 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
332 | in4.sin_len = sizeof (in4); | ||
333 | in6.sin6_len = sizeof (in6); | ||
334 | #endif | ||
335 | server = GNUNET_SERVER_create (NULL, | ||
336 | NULL, | ||
337 | (struct sockaddr * const *) sa, | ||
338 | slen, | ||
339 | GNUNET_TIME_UNIT_SECONDS, | ||
340 | GNUNET_YES); | ||
341 | GNUNET_SERVER_add_handlers (server, | ||
342 | handlers); | ||
343 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
344 | NULL); | ||
345 | } | ||
346 | |||
347 | |||
348 | /** | ||
349 | * Main function of gnunet-nat-server. | ||
350 | * | ||
351 | * @param argc number of command-line arguments | ||
352 | * @param argv command line | ||
353 | * @return 0 on success, -1 on error | ||
354 | */ | ||
355 | int | ||
356 | main (int argc, char *const argv[]) | ||
357 | { | ||
358 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
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 | |||
367 | if (GNUNET_OK != | ||
368 | GNUNET_PROGRAM_run (argc, | ||
369 | argv, | ||
370 | "gnunet-nat-server [options] PORT", | ||
371 | _("GNUnet NAT traversal test helper daemon"), | ||
372 | options, | ||
373 | &run, | ||
374 | NULL)) | ||
375 | { | ||
376 | GNUNET_free ((void*) argv); | ||
377 | return 1; | ||
378 | } | ||
379 | GNUNET_free ((void*) argv); | ||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | |||
384 | /* end of gnunet-nat-server.c */ | ||
diff --git a/src/nat-auto/gnunet-service-nat-auto.c b/src/nat-auto/gnunet-service-nat-auto.c new file mode 100644 index 000000000..897d6feb2 --- /dev/null +++ b/src/nat-auto/gnunet-service-nat-auto.c | |||
@@ -0,0 +1,481 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 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 nat-auto/gnunet-service-nat-auto.c | ||
23 | * @brief NAT autoconfiguration service | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | * TODO: | ||
27 | * - merge client handle and autoconfig context | ||
28 | * - implement "more" autoconfig: | ||
29 | * + re-work gnunet-nat-server & integrate! | ||
30 | * + test manually punched NAT (how?) | ||
31 | */ | ||
32 | #include "platform.h" | ||
33 | #include <math.h> | ||
34 | #include "gnunet_util_lib.h" | ||
35 | #include "gnunet_protocols.h" | ||
36 | #include "gnunet_signatures.h" | ||
37 | #include "gnunet_nat_service.h" | ||
38 | #include "gnunet_statistics_service.h" | ||
39 | #include "gnunet_resolver_service.h" | ||
40 | #include "nat-auto.h" | ||
41 | #include <gcrypt.h> | ||
42 | |||
43 | |||
44 | /** | ||
45 | * How long do we wait until we forcefully terminate autoconfiguration? | ||
46 | */ | ||
47 | #define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) | ||
48 | |||
49 | |||
50 | /** | ||
51 | * Internal data structure we track for each of our clients. | ||
52 | */ | ||
53 | struct ClientHandle | ||
54 | { | ||
55 | |||
56 | /** | ||
57 | * Kept in a DLL. | ||
58 | */ | ||
59 | struct ClientHandle *next; | ||
60 | |||
61 | /** | ||
62 | * Kept in a DLL. | ||
63 | */ | ||
64 | struct ClientHandle *prev; | ||
65 | |||
66 | /** | ||
67 | * Underlying handle for this client with the service. | ||
68 | */ | ||
69 | struct GNUNET_SERVICE_Client *client; | ||
70 | |||
71 | /** | ||
72 | * Message queue for communicating with the client. | ||
73 | */ | ||
74 | struct GNUNET_MQ_Handle *mq; | ||
75 | }; | ||
76 | |||
77 | |||
78 | /** | ||
79 | * Context for autoconfiguration operations. | ||
80 | */ | ||
81 | struct AutoconfigContext | ||
82 | { | ||
83 | /** | ||
84 | * Kept in a DLL. | ||
85 | */ | ||
86 | struct AutoconfigContext *prev; | ||
87 | |||
88 | /** | ||
89 | * Kept in a DLL. | ||
90 | */ | ||
91 | struct AutoconfigContext *next; | ||
92 | |||
93 | /** | ||
94 | * Which client asked the question. | ||
95 | */ | ||
96 | struct ClientHandle *ch; | ||
97 | |||
98 | /** | ||
99 | * Configuration we are creating. | ||
100 | */ | ||
101 | struct GNUNET_CONFIGURATION_Handle *c; | ||
102 | |||
103 | /** | ||
104 | * Original configuration (for diffing). | ||
105 | */ | ||
106 | struct GNUNET_CONFIGURATION_Handle *orig; | ||
107 | |||
108 | /** | ||
109 | * Timeout task to force termination. | ||
110 | */ | ||
111 | struct GNUNET_SCHEDULER_Task *timeout_task; | ||
112 | |||
113 | /** | ||
114 | * #GNUNET_YES if upnpc should be used, | ||
115 | * #GNUNET_NO if upnpc should not be used, | ||
116 | * #GNUNET_SYSERR if we should simply not change the option. | ||
117 | */ | ||
118 | int enable_upnpc; | ||
119 | |||
120 | /** | ||
121 | * Status code to return to the client. | ||
122 | */ | ||
123 | enum GNUNET_NAT_StatusCode status_code; | ||
124 | |||
125 | /** | ||
126 | * NAT type to return to the client. | ||
127 | */ | ||
128 | enum GNUNET_NAT_Type type; | ||
129 | }; | ||
130 | |||
131 | |||
132 | /** | ||
133 | * Head of client DLL. | ||
134 | */ | ||
135 | static struct ClientHandle *ch_head; | ||
136 | |||
137 | /** | ||
138 | * Tail of client DLL. | ||
139 | */ | ||
140 | static struct ClientHandle *ch_tail; | ||
141 | |||
142 | /** | ||
143 | * DLL of our autoconfiguration operations. | ||
144 | */ | ||
145 | static struct AutoconfigContext *ac_head; | ||
146 | |||
147 | /** | ||
148 | * DLL of our autoconfiguration operations. | ||
149 | */ | ||
150 | static struct AutoconfigContext *ac_tail; | ||
151 | |||
152 | /** | ||
153 | * Handle to our current configuration. | ||
154 | */ | ||
155 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
156 | |||
157 | /** | ||
158 | * Handle to the statistics service. | ||
159 | */ | ||
160 | static struct GNUNET_STATISTICS_Handle *stats; | ||
161 | |||
162 | |||
163 | /** | ||
164 | * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message | ||
165 | * from client. | ||
166 | * | ||
167 | * @param cls client who sent the message | ||
168 | * @param message the message received | ||
169 | * @return #GNUNET_OK if message is well-formed | ||
170 | */ | ||
171 | static int | ||
172 | check_autoconfig_request (void *cls, | ||
173 | const struct GNUNET_NAT_AutoconfigRequestMessage *message) | ||
174 | { | ||
175 | return GNUNET_OK; /* checked later */ | ||
176 | } | ||
177 | |||
178 | |||
179 | /** | ||
180 | * Stop all pending activities with respect to the @a ac | ||
181 | * | ||
182 | * @param ac autoconfiguration to terminate activities for | ||
183 | */ | ||
184 | static void | ||
185 | terminate_ac_activities (struct AutoconfigContext *ac) | ||
186 | { | ||
187 | if (NULL != ac->timeout_task) | ||
188 | { | ||
189 | GNUNET_SCHEDULER_cancel (ac->timeout_task); | ||
190 | ac->timeout_task = NULL; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | |||
195 | /** | ||
196 | * Finish handling the autoconfiguration request and send | ||
197 | * the response to the client. | ||
198 | * | ||
199 | * @param cls the `struct AutoconfigContext` to conclude | ||
200 | */ | ||
201 | static void | ||
202 | conclude_autoconfig_request (void *cls) | ||
203 | { | ||
204 | struct AutoconfigContext *ac = cls; | ||
205 | struct ClientHandle *ch = ac->ch; | ||
206 | struct GNUNET_NAT_AutoconfigResultMessage *arm; | ||
207 | struct GNUNET_MQ_Envelope *env; | ||
208 | size_t c_size; | ||
209 | char *buf; | ||
210 | struct GNUNET_CONFIGURATION_Handle *diff; | ||
211 | |||
212 | ac->timeout_task = NULL; | ||
213 | terminate_ac_activities (ac); | ||
214 | |||
215 | /* Send back response */ | ||
216 | diff = GNUNET_CONFIGURATION_get_diff (ac->orig, | ||
217 | ac->c); | ||
218 | buf = GNUNET_CONFIGURATION_serialize (diff, | ||
219 | &c_size); | ||
220 | GNUNET_CONFIGURATION_destroy (diff); | ||
221 | env = GNUNET_MQ_msg_extra (arm, | ||
222 | c_size, | ||
223 | GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT); | ||
224 | arm->status_code = htonl ((uint32_t) ac->status_code); | ||
225 | arm->type = htonl ((uint32_t) ac->type); | ||
226 | GNUNET_memcpy (&arm[1], | ||
227 | buf, | ||
228 | c_size); | ||
229 | GNUNET_free (buf); | ||
230 | GNUNET_MQ_send (ch->mq, | ||
231 | env); | ||
232 | |||
233 | /* clean up */ | ||
234 | GNUNET_CONFIGURATION_destroy (ac->orig); | ||
235 | GNUNET_CONFIGURATION_destroy (ac->c); | ||
236 | GNUNET_CONTAINER_DLL_remove (ac_head, | ||
237 | ac_tail, | ||
238 | ac); | ||
239 | GNUNET_free (ac); | ||
240 | GNUNET_SERVICE_client_continue (ch->client); | ||
241 | } | ||
242 | |||
243 | |||
244 | /** | ||
245 | * Check if all autoconfiguration operations have concluded, | ||
246 | * and if they have, send the result back to the client. | ||
247 | * | ||
248 | * @param ac autoconfiguation context to check | ||
249 | */ | ||
250 | static void | ||
251 | check_autoconfig_finished (struct AutoconfigContext *ac) | ||
252 | { | ||
253 | GNUNET_SCHEDULER_cancel (ac->timeout_task); | ||
254 | ac->timeout_task | ||
255 | = GNUNET_SCHEDULER_add_now (&conclude_autoconfig_request, | ||
256 | ac); | ||
257 | } | ||
258 | |||
259 | |||
260 | /** | ||
261 | * Update ENABLE_UPNPC configuration option. | ||
262 | * | ||
263 | * @param ac autoconfiguration to update | ||
264 | */ | ||
265 | static void | ||
266 | update_enable_upnpc_option (struct AutoconfigContext *ac) | ||
267 | { | ||
268 | switch (ac->enable_upnpc) | ||
269 | { | ||
270 | case GNUNET_YES: | ||
271 | GNUNET_CONFIGURATION_set_value_string (ac->c, | ||
272 | "NAT", | ||
273 | "ENABLE_UPNP", | ||
274 | "YES"); | ||
275 | break; | ||
276 | case GNUNET_NO: | ||
277 | GNUNET_CONFIGURATION_set_value_string (ac->c, | ||
278 | "NAT", | ||
279 | "ENABLE_UPNP", | ||
280 | "NO"); | ||
281 | break; | ||
282 | case GNUNET_SYSERR: | ||
283 | /* We are unsure, do not change option */ | ||
284 | break; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | |||
289 | /** | ||
290 | * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from | ||
291 | * client. | ||
292 | * | ||
293 | * @param cls client who sent the message | ||
294 | * @param message the message received | ||
295 | */ | ||
296 | static void | ||
297 | handle_autoconfig_request (void *cls, | ||
298 | const struct GNUNET_NAT_AutoconfigRequestMessage *message) | ||
299 | { | ||
300 | struct ClientHandle *ch = cls; | ||
301 | size_t left = ntohs (message->header.size) - sizeof (*message); | ||
302 | struct AutoconfigContext *ac; | ||
303 | |||
304 | ac = GNUNET_new (struct AutoconfigContext); | ||
305 | ac->status_code = GNUNET_NAT_ERROR_SUCCESS; | ||
306 | ac->ch = ch; | ||
307 | ac->c = GNUNET_CONFIGURATION_create (); | ||
308 | if (GNUNET_OK != | ||
309 | GNUNET_CONFIGURATION_deserialize (ac->c, | ||
310 | (const char *) &message[1], | ||
311 | left, | ||
312 | GNUNET_NO)) | ||
313 | { | ||
314 | GNUNET_break (0); | ||
315 | GNUNET_SERVICE_client_drop (ch->client); | ||
316 | GNUNET_CONFIGURATION_destroy (ac->c); | ||
317 | GNUNET_free (ac); | ||
318 | return; | ||
319 | } | ||
320 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
321 | "Received REQUEST_AUTO_CONFIG message from client\n"); | ||
322 | |||
323 | GNUNET_CONTAINER_DLL_insert (ac_head, | ||
324 | ac_tail, | ||
325 | ac); | ||
326 | ac->orig | ||
327 | = GNUNET_CONFIGURATION_dup (ac->c); | ||
328 | ac->timeout_task | ||
329 | = GNUNET_SCHEDULER_add_delayed (AUTOCONFIG_TIMEOUT, | ||
330 | &conclude_autoconfig_request, | ||
331 | ac); | ||
332 | ac->enable_upnpc = GNUNET_SYSERR; /* undecided */ | ||
333 | |||
334 | /* Probe for upnpc */ | ||
335 | if (GNUNET_SYSERR == | ||
336 | GNUNET_OS_check_helper_binary ("upnpc", | ||
337 | GNUNET_NO, | ||
338 | NULL)) | ||
339 | { | ||
340 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
341 | _("UPnP client `upnpc` command not found, disabling UPnP\n")); | ||
342 | ac->enable_upnpc = GNUNET_NO; | ||
343 | } | ||
344 | else | ||
345 | { | ||
346 | /* We might at some point be behind NAT, try upnpc */ | ||
347 | ac->enable_upnpc = GNUNET_YES; | ||
348 | } | ||
349 | update_enable_upnpc_option (ac); | ||
350 | |||
351 | /* Finally, check if we are already done */ | ||
352 | check_autoconfig_finished (ac); | ||
353 | } | ||
354 | |||
355 | |||
356 | /** | ||
357 | * Task run during shutdown. | ||
358 | * | ||
359 | * @param cls unused | ||
360 | */ | ||
361 | static void | ||
362 | shutdown_task (void *cls) | ||
363 | { | ||
364 | struct AutoconfigContext *ac; | ||
365 | |||
366 | while (NULL != (ac = ac_head)) | ||
367 | { | ||
368 | GNUNET_CONTAINER_DLL_remove (ac_head, | ||
369 | ac_tail, | ||
370 | ac); | ||
371 | terminate_ac_activities (ac); | ||
372 | GNUNET_free (ac); | ||
373 | } | ||
374 | if (NULL != stats) | ||
375 | { | ||
376 | GNUNET_STATISTICS_destroy (stats, | ||
377 | GNUNET_NO); | ||
378 | stats = NULL; | ||
379 | } | ||
380 | } | ||
381 | |||
382 | |||
383 | /** | ||
384 | * Setup NAT service. | ||
385 | * | ||
386 | * @param cls closure | ||
387 | * @param c configuration to use | ||
388 | * @param service the initialized service | ||
389 | */ | ||
390 | static void | ||
391 | run (void *cls, | ||
392 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
393 | struct GNUNET_SERVICE_Handle *service) | ||
394 | { | ||
395 | cfg = c; | ||
396 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
397 | NULL); | ||
398 | stats = GNUNET_STATISTICS_create ("nat-auto", | ||
399 | cfg); | ||
400 | } | ||
401 | |||
402 | |||
403 | /** | ||
404 | * Callback called when a client connects to the service. | ||
405 | * | ||
406 | * @param cls closure for the service | ||
407 | * @param c the new client that connected to the service | ||
408 | * @param mq the message queue used to send messages to the client | ||
409 | * @return a `struct ClientHandle` | ||
410 | */ | ||
411 | static void * | ||
412 | client_connect_cb (void *cls, | ||
413 | struct GNUNET_SERVICE_Client *c, | ||
414 | struct GNUNET_MQ_Handle *mq) | ||
415 | { | ||
416 | struct ClientHandle *ch; | ||
417 | |||
418 | ch = GNUNET_new (struct ClientHandle); | ||
419 | ch->mq = mq; | ||
420 | ch->client = c; | ||
421 | GNUNET_CONTAINER_DLL_insert (ch_head, | ||
422 | ch_tail, | ||
423 | ch); | ||
424 | return ch; | ||
425 | } | ||
426 | |||
427 | |||
428 | /** | ||
429 | * Callback called when a client disconnected from the service | ||
430 | * | ||
431 | * @param cls closure for the service | ||
432 | * @param c the client that disconnected | ||
433 | * @param internal_cls a `struct ClientHandle *` | ||
434 | */ | ||
435 | static void | ||
436 | client_disconnect_cb (void *cls, | ||
437 | struct GNUNET_SERVICE_Client *c, | ||
438 | void *internal_cls) | ||
439 | { | ||
440 | struct ClientHandle *ch = internal_cls; | ||
441 | |||
442 | GNUNET_CONTAINER_DLL_remove (ch_head, | ||
443 | ch_tail, | ||
444 | ch); | ||
445 | GNUNET_free (ch); | ||
446 | } | ||
447 | |||
448 | |||
449 | /** | ||
450 | * Define "main" method using service macro. | ||
451 | */ | ||
452 | GNUNET_SERVICE_MAIN | ||
453 | ("nat", | ||
454 | GNUNET_SERVICE_OPTION_NONE, | ||
455 | &run, | ||
456 | &client_connect_cb, | ||
457 | &client_disconnect_cb, | ||
458 | NULL, | ||
459 | GNUNET_MQ_hd_var_size (autoconfig_request, | ||
460 | GNUNET_MESSAGE_TYPE_NAT_AUTO_REQUEST_CFG, | ||
461 | struct GNUNET_NAT_AutoconfigRequestMessage, | ||
462 | NULL), | ||
463 | GNUNET_MQ_handler_end ()); | ||
464 | |||
465 | |||
466 | #if defined(LINUX) && defined(__GLIBC__) | ||
467 | #include <malloc.h> | ||
468 | |||
469 | /** | ||
470 | * MINIMIZE heap size (way below 128k) since this process doesn't need much. | ||
471 | */ | ||
472 | void __attribute__ ((constructor)) | ||
473 | GNUNET_ARM_memory_init () | ||
474 | { | ||
475 | mallopt (M_TRIM_THRESHOLD, 4 * 1024); | ||
476 | mallopt (M_TOP_PAD, 1 * 1024); | ||
477 | malloc_trim (0); | ||
478 | } | ||
479 | #endif | ||
480 | |||
481 | /* end of gnunet-service-nat.c */ | ||
diff --git a/src/nat-auto/nat-auto.conf.in b/src/nat-auto/nat-auto.conf.in new file mode 100644 index 000000000..daa3e389d --- /dev/null +++ b/src/nat-auto/nat-auto.conf.in | |||
@@ -0,0 +1,15 @@ | |||
1 | [nat] | ||
2 | AUTOSTART = @AUTOSTART@ | ||
3 | @UNIXONLY@ PORT = 2124 | ||
4 | HOSTNAME = localhost | ||
5 | BINARY = gnunet-service-nat-auto | ||
6 | ACCEPT_FROM = 127.0.0.1; | ||
7 | ACCEPT_FROM6 = ::1; | ||
8 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-nat-auto.sock | ||
9 | UNIX_MATCH_UID = YES | ||
10 | UNIX_MATCH_GID = YES | ||
11 | |||
12 | [gnunet-nat-server] | ||
13 | HOSTNAME = gnunet.org | ||
14 | PORT = 5724 | ||
15 | NOARMBIND = YES | ||
diff --git a/src/nat-auto/nat-auto.h b/src/nat-auto/nat-auto.h new file mode 100644 index 000000000..150dc32c2 --- /dev/null +++ b/src/nat-auto/nat-auto.h | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011, 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-auto/nat-auto.h | ||
23 | * @brief Messages for interaction with gnunet-nat-auto-service | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | */ | ||
27 | #ifndef NAT_AUTO_H | ||
28 | #define NAT_AUTO_H | ||
29 | #include "gnunet_util_lib.h" | ||
30 | |||
31 | |||
32 | |||
33 | GNUNET_NETWORK_STRUCT_BEGIN | ||
34 | |||
35 | /** | ||
36 | * Request to test NAT traversal, sent to the gnunet-nat-server | ||
37 | * (not the service!). | ||
38 | */ | ||
39 | struct GNUNET_NAT_TestMessage | ||
40 | { | ||
41 | /** | ||
42 | * Header with type #GNUNET_MESSAGE_TYPE_NAT_TEST | ||
43 | */ | ||
44 | struct GNUNET_MessageHeader header; | ||
45 | |||
46 | /** | ||
47 | * IPv4 target IP address | ||
48 | */ | ||
49 | uint32_t dst_ipv4; | ||
50 | |||
51 | /** | ||
52 | * Port to use, 0 to send dummy ICMP response. | ||
53 | */ | ||
54 | uint16_t dport; | ||
55 | |||
56 | /** | ||
57 | * Data to send OR advertised-port (in NBO) to use for dummy ICMP. | ||
58 | */ | ||
59 | uint16_t data; | ||
60 | |||
61 | /** | ||
62 | * #GNUNET_YES for TCP, #GNUNET_NO for UDP. | ||
63 | */ | ||
64 | int32_t is_tcp; | ||
65 | |||
66 | }; | ||
67 | |||
68 | |||
69 | /** | ||
70 | * Client requesting automatic configuration. | ||
71 | */ | ||
72 | struct GNUNET_NAT_AutoconfigRequestMessage | ||
73 | { | ||
74 | /** | ||
75 | * Header with type #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG | ||
76 | */ | ||
77 | struct GNUNET_MessageHeader header; | ||
78 | |||
79 | /* Followed by configuration (diff, serialized, compressed) */ | ||
80 | |||
81 | }; | ||
82 | |||
83 | |||
84 | /** | ||
85 | * Service responding with proposed configuration. | ||
86 | */ | ||
87 | struct GNUNET_NAT_AutoconfigResultMessage | ||
88 | { | ||
89 | /** | ||
90 | * Header with type #GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT | ||
91 | */ | ||
92 | struct GNUNET_MessageHeader header; | ||
93 | |||
94 | /** | ||
95 | * An `enum GNUNET_NAT_StatusCode` in NBO. | ||
96 | */ | ||
97 | int32_t status_code GNUNET_PACKED; | ||
98 | |||
99 | /** | ||
100 | * An `enum GNUNET_NAT_Type` in NBO. | ||
101 | */ | ||
102 | int32_t type GNUNET_PACKED; | ||
103 | |||
104 | /* Followed by configuration (diff, serialized, compressed) */ | ||
105 | }; | ||
106 | |||
107 | |||
108 | GNUNET_NETWORK_STRUCT_END | ||
109 | |||
110 | #endif | ||
diff --git a/src/nat-auto/nat_auto_api.c b/src/nat-auto/nat_auto_api.c new file mode 100644 index 000000000..e6b0512c6 --- /dev/null +++ b/src/nat-auto/nat_auto_api.c | |||
@@ -0,0 +1,274 @@ | |||
1 | |||
2 | /* | ||
3 | This file is part of GNUnet. | ||
4 | Copyright (C) 2007-2016 GNUnet e.V. | ||
5 | |||
6 | GNUnet is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published | ||
8 | by the Free Software Foundation; either version 3, or (at your | ||
9 | option) any later version. | ||
10 | |||
11 | GNUnet is distributed in the hope that it will be useful, but | ||
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with GNUnet; see the file COPYING. If not, write to the | ||
18 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
19 | Boston, MA 02110-1301, USA. | ||
20 | */ | ||
21 | |||
22 | /** | ||
23 | * @author Christian Grothoff | ||
24 | * @author Milan Bouchet-Valat | ||
25 | * | ||
26 | * @file nat/nat_auto_api.c | ||
27 | * Routines for NAT auto configuration. | ||
28 | */ | ||
29 | #include "platform.h" | ||
30 | #include "gnunet_nat_service.h" | ||
31 | #include "gnunet_nat_auto_service.h" | ||
32 | #include "nat-auto.h" | ||
33 | |||
34 | |||
35 | |||
36 | /** | ||
37 | * Handle to auto-configuration in progress. | ||
38 | */ | ||
39 | struct GNUNET_NAT_AutoHandle | ||
40 | { | ||
41 | |||
42 | /** | ||
43 | * Configuration we use. | ||
44 | */ | ||
45 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
46 | |||
47 | /** | ||
48 | * Message queue for communicating with the NAT service. | ||
49 | */ | ||
50 | struct GNUNET_MQ_Handle *mq; | ||
51 | |||
52 | /** | ||
53 | * Function called with the result from the autoconfiguration. | ||
54 | */ | ||
55 | GNUNET_NAT_AutoResultCallback arc; | ||
56 | |||
57 | /** | ||
58 | * Closure for @e arc. | ||
59 | */ | ||
60 | void *arc_cls; | ||
61 | |||
62 | }; | ||
63 | |||
64 | |||
65 | /** | ||
66 | * Converts `enum GNUNET_NAT_StatusCode` to string | ||
67 | * | ||
68 | * @param err error code to resolve to a string | ||
69 | * @return point to a static string containing the error code | ||
70 | */ | ||
71 | const char * | ||
72 | GNUNET_NAT_status2string (enum GNUNET_NAT_StatusCode err) | ||
73 | { | ||
74 | switch (err) | ||
75 | { | ||
76 | case GNUNET_NAT_ERROR_SUCCESS: | ||
77 | return _ ("Operation Successful"); | ||
78 | case GNUNET_NAT_ERROR_IPC_FAILURE: | ||
79 | return _ ("IPC failure"); | ||
80 | case GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR: | ||
81 | return _ ("Failure in network subsystem, check permissions."); | ||
82 | case GNUNET_NAT_ERROR_TIMEOUT: | ||
83 | return _ ("Encountered timeout while performing operation"); | ||
84 | case GNUNET_NAT_ERROR_NOT_ONLINE: | ||
85 | return _ ("detected that we are offline"); | ||
86 | case GNUNET_NAT_ERROR_UPNPC_NOT_FOUND: | ||
87 | return _ ("`upnpc` command not found"); | ||
88 | case GNUNET_NAT_ERROR_UPNPC_FAILED: | ||
89 | return _ ("Failed to run `upnpc` command"); | ||
90 | case GNUNET_NAT_ERROR_UPNPC_TIMEOUT: | ||
91 | return _ ("`upnpc' command took too long, process killed"); | ||
92 | case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED: | ||
93 | return _ ("`upnpc' command failed to establish port mapping"); | ||
94 | case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND: | ||
95 | return _ ("`external-ip' command not found"); | ||
96 | case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED: | ||
97 | return _ ("Failed to run `external-ip` command"); | ||
98 | case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID: | ||
99 | return _ ("`external-ip' command output invalid"); | ||
100 | case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID: | ||
101 | return _ ("no valid address was returned by `external-ip'"); | ||
102 | case GNUNET_NAT_ERROR_NO_VALID_IF_IP_COMBO: | ||
103 | return _ ("Could not determine interface with internal/local network address"); | ||
104 | case GNUNET_NAT_ERROR_HELPER_NAT_SERVER_NOT_FOUND: | ||
105 | return _ ("No functioning gnunet-helper-nat-server installation found"); | ||
106 | case GNUNET_NAT_ERROR_NAT_TEST_START_FAILED: | ||
107 | return _ ("NAT test could not be initialized"); | ||
108 | case GNUNET_NAT_ERROR_NAT_TEST_TIMEOUT: | ||
109 | return _ ("NAT test timeout reached"); | ||
110 | case GNUNET_NAT_ERROR_NAT_REGISTER_FAILED: | ||
111 | return _ ("could not register NAT"); | ||
112 | case GNUNET_NAT_ERROR_HELPER_NAT_CLIENT_NOT_FOUND: | ||
113 | return _ ("No working gnunet-helper-nat-client installation found"); | ||
114 | default: | ||
115 | return "unknown status code"; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | |||
120 | /** | ||
121 | * Check result from autoconfiguration attempt. | ||
122 | * | ||
123 | * @param cls the `struct GNUNET_NAT_AutoHandle` | ||
124 | * @param res the result | ||
125 | * @return #GNUNET_OK if @a res is well-formed (always for now) | ||
126 | */ | ||
127 | static int | ||
128 | check_auto_result (void *cls, | ||
129 | const struct GNUNET_NAT_AutoconfigResultMessage *res) | ||
130 | { | ||
131 | return GNUNET_OK; | ||
132 | } | ||
133 | |||
134 | |||
135 | /** | ||
136 | * Handle result from autoconfiguration attempt. | ||
137 | * | ||
138 | * @param cls the `struct GNUNET_NAT_AutoHandle` | ||
139 | * @param res the result | ||
140 | */ | ||
141 | static void | ||
142 | handle_auto_result (void *cls, | ||
143 | const struct GNUNET_NAT_AutoconfigResultMessage *res) | ||
144 | { | ||
145 | struct GNUNET_NAT_AutoHandle *ah = cls; | ||
146 | size_t left; | ||
147 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
148 | enum GNUNET_NAT_Type type | ||
149 | = (enum GNUNET_NAT_Type) ntohl (res->type); | ||
150 | enum GNUNET_NAT_StatusCode status | ||
151 | = (enum GNUNET_NAT_StatusCode) ntohl (res->status_code); | ||
152 | |||
153 | left = ntohs (res->header.size) - sizeof (*res); | ||
154 | cfg = GNUNET_CONFIGURATION_create (); | ||
155 | if (GNUNET_OK != | ||
156 | GNUNET_CONFIGURATION_deserialize (cfg, | ||
157 | (const char *) &res[1], | ||
158 | left, | ||
159 | GNUNET_NO)) | ||
160 | { | ||
161 | GNUNET_break (0); | ||
162 | ah->arc (ah->arc_cls, | ||
163 | NULL, | ||
164 | GNUNET_NAT_ERROR_IPC_FAILURE, | ||
165 | type); | ||
166 | } | ||
167 | else | ||
168 | { | ||
169 | ah->arc (ah->arc_cls, | ||
170 | cfg, | ||
171 | status, | ||
172 | type); | ||
173 | } | ||
174 | GNUNET_CONFIGURATION_destroy (cfg); | ||
175 | GNUNET_NAT_autoconfig_cancel (ah); | ||
176 | } | ||
177 | |||
178 | |||
179 | /** | ||
180 | * Handle queue errors by reporting autoconfiguration failure. | ||
181 | * | ||
182 | * @param cls the `struct GNUNET_NAT_AutoHandle *` | ||
183 | * @param error details about the error | ||
184 | */ | ||
185 | static void | ||
186 | ah_error_handler (void *cls, | ||
187 | enum GNUNET_MQ_Error error) | ||
188 | { | ||
189 | struct GNUNET_NAT_AutoHandle *ah = cls; | ||
190 | |||
191 | ah->arc (ah->arc_cls, | ||
192 | NULL, | ||
193 | GNUNET_NAT_ERROR_IPC_FAILURE, | ||
194 | GNUNET_NAT_TYPE_UNKNOWN); | ||
195 | GNUNET_NAT_autoconfig_cancel (ah); | ||
196 | } | ||
197 | |||
198 | |||
199 | /** | ||
200 | * Start auto-configuration routine. The transport adapters should | ||
201 | * be stopped while this function is called. | ||
202 | * | ||
203 | * @param cfg initial configuration | ||
204 | * @param cb function to call with autoconfiguration result | ||
205 | * @param cb_cls closure for @a cb | ||
206 | * @return handle to cancel operation | ||
207 | */ | ||
208 | struct GNUNET_NAT_AutoHandle * | ||
209 | GNUNET_NAT_autoconfig_start (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
210 | GNUNET_NAT_AutoResultCallback cb, | ||
211 | void *cb_cls) | ||
212 | { | ||
213 | struct GNUNET_NAT_AutoHandle *ah = GNUNET_new (struct GNUNET_NAT_AutoHandle); | ||
214 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
215 | GNUNET_MQ_hd_var_size (auto_result, | ||
216 | GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT, | ||
217 | struct GNUNET_NAT_AutoconfigResultMessage, | ||
218 | ah), | ||
219 | GNUNET_MQ_handler_end () | ||
220 | }; | ||
221 | struct GNUNET_MQ_Envelope *env; | ||
222 | struct GNUNET_NAT_AutoconfigRequestMessage *req; | ||
223 | char *buf; | ||
224 | size_t size; | ||
225 | |||
226 | buf = GNUNET_CONFIGURATION_serialize (cfg, | ||
227 | &size); | ||
228 | if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*req)) | ||
229 | { | ||
230 | GNUNET_break (0); | ||
231 | GNUNET_free (buf); | ||
232 | GNUNET_free (ah); | ||
233 | return NULL; | ||
234 | } | ||
235 | ah->arc = cb; | ||
236 | ah->arc_cls = cb_cls; | ||
237 | ah->mq = GNUNET_CLIENT_connecT (cfg, | ||
238 | "nat", | ||
239 | handlers, | ||
240 | &ah_error_handler, | ||
241 | ah); | ||
242 | if (NULL == ah->mq) | ||
243 | { | ||
244 | GNUNET_break (0); | ||
245 | GNUNET_free (buf); | ||
246 | GNUNET_free (ah); | ||
247 | return NULL; | ||
248 | } | ||
249 | env = GNUNET_MQ_msg_extra (req, | ||
250 | size, | ||
251 | GNUNET_MESSAGE_TYPE_NAT_AUTO_REQUEST_CFG); | ||
252 | GNUNET_memcpy (&req[1], | ||
253 | buf, | ||
254 | size); | ||
255 | GNUNET_free (buf); | ||
256 | GNUNET_MQ_send (ah->mq, | ||
257 | env); | ||
258 | return ah; | ||
259 | } | ||
260 | |||
261 | |||
262 | /** | ||
263 | * Abort autoconfiguration. | ||
264 | * | ||
265 | * @param ah handle for operation to abort | ||
266 | */ | ||
267 | void | ||
268 | GNUNET_NAT_autoconfig_cancel (struct GNUNET_NAT_AutoHandle *ah) | ||
269 | { | ||
270 | GNUNET_MQ_destroy (ah->mq); | ||
271 | GNUNET_free (ah); | ||
272 | } | ||
273 | |||
274 | /* end of nat_api_auto.c */ | ||
diff --git a/src/nat-auto/nat_auto_api_test.c b/src/nat-auto/nat_auto_api_test.c new file mode 100644 index 000000000..056d2a2bf --- /dev/null +++ b/src/nat-auto/nat_auto_api_test.c | |||
@@ -0,0 +1,644 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011, 2016 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 | * @file nat/nat_auto_api_test.c | ||
22 | * @brief functions to test if the NAT configuration is successful at achieving NAT traversal (with the help of a gnunet-nat-server) | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_util_lib.h" | ||
27 | #include "gnunet_nat_lib.h" | ||
28 | #include "nat-auto.h" | ||
29 | |||
30 | #define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__) | ||
31 | |||
32 | #define NAT_SERVER_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) | ||
33 | |||
34 | /** | ||
35 | * Entry we keep for each incoming connection. | ||
36 | */ | ||
37 | struct NatActivity | ||
38 | { | ||
39 | /** | ||
40 | * This is a doubly-linked list. | ||
41 | */ | ||
42 | struct NatActivity *next; | ||
43 | |||
44 | /** | ||
45 | * This is a doubly-linked list. | ||
46 | */ | ||
47 | struct NatActivity *prev; | ||
48 | |||
49 | /** | ||
50 | * Socket of the incoming connection. | ||
51 | */ | ||
52 | struct GNUNET_NETWORK_Handle *sock; | ||
53 | |||
54 | /** | ||
55 | * Handle of the master context. | ||
56 | */ | ||
57 | struct GNUNET_NAT_Test *h; | ||
58 | |||
59 | /** | ||
60 | * Task reading from the incoming connection. | ||
61 | */ | ||
62 | struct GNUNET_SCHEDULER_Task *rtask; | ||
63 | }; | ||
64 | |||
65 | |||
66 | /** | ||
67 | * Entry we keep for each connection to the gnunet-nat-service. | ||
68 | */ | ||
69 | struct ClientActivity | ||
70 | { | ||
71 | /** | ||
72 | * This is a doubly-linked list. | ||
73 | */ | ||
74 | struct ClientActivity *next; | ||
75 | |||
76 | /** | ||
77 | * This is a doubly-linked list. | ||
78 | */ | ||
79 | struct ClientActivity *prev; | ||
80 | |||
81 | /** | ||
82 | * Socket of the incoming connection. | ||
83 | */ | ||
84 | struct GNUNET_MQ_Handle *mq; | ||
85 | |||
86 | /** | ||
87 | * Handle to overall NAT test. | ||
88 | */ | ||
89 | struct GNUNET_NAT_Test *h; | ||
90 | |||
91 | }; | ||
92 | |||
93 | |||
94 | /** | ||
95 | * Handle to a NAT test. | ||
96 | */ | ||
97 | struct GNUNET_NAT_Test | ||
98 | { | ||
99 | |||
100 | /** | ||
101 | * Configuration used | ||
102 | */ | ||
103 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
104 | |||
105 | /** | ||
106 | * Function to call with success report | ||
107 | */ | ||
108 | GNUNET_NAT_TestCallback report; | ||
109 | |||
110 | /** | ||
111 | * Closure for @e report. | ||
112 | */ | ||
113 | void *report_cls; | ||
114 | |||
115 | /** | ||
116 | * Handle to NAT traversal in use | ||
117 | */ | ||
118 | struct GNUNET_NAT_Handle *nat; | ||
119 | |||
120 | /** | ||
121 | * Handle to listen socket, or NULL | ||
122 | */ | ||
123 | struct GNUNET_NETWORK_Handle *lsock; | ||
124 | |||
125 | /** | ||
126 | * Head of list of nat activities. | ||
127 | */ | ||
128 | struct NatActivity *na_head; | ||
129 | |||
130 | /** | ||
131 | * Tail of list of nat activities. | ||
132 | */ | ||
133 | struct NatActivity *na_tail; | ||
134 | |||
135 | /** | ||
136 | * Head of list of client activities. | ||
137 | */ | ||
138 | struct ClientActivity *ca_head; | ||
139 | |||
140 | /** | ||
141 | * Tail of list of client activities. | ||
142 | */ | ||
143 | struct ClientActivity *ca_tail; | ||
144 | |||
145 | /** | ||
146 | * Identity of task for the listen socket (if any) | ||
147 | */ | ||
148 | struct GNUNET_SCHEDULER_Task *ltask; | ||
149 | |||
150 | /** | ||
151 | * Task identifier for the timeout (if any) | ||
152 | */ | ||
153 | struct GNUNET_SCHEDULER_Task *ttask; | ||
154 | |||
155 | /** | ||
156 | * #GNUNET_YES if we're testing TCP | ||
157 | */ | ||
158 | int is_tcp; | ||
159 | |||
160 | /** | ||
161 | * Data that should be transmitted or source-port. | ||
162 | */ | ||
163 | uint16_t data; | ||
164 | |||
165 | /** | ||
166 | * Advertised port to the other peer. | ||
167 | */ | ||
168 | uint16_t adv_port; | ||
169 | |||
170 | /** | ||
171 | * Status code to be reported to the timeout/status call | ||
172 | */ | ||
173 | enum GNUNET_NAT_StatusCode status; | ||
174 | }; | ||
175 | |||
176 | |||
177 | /** | ||
178 | * Function called from #GNUNET_NAT_register whenever someone asks us | ||
179 | * to do connection reversal. | ||
180 | * | ||
181 | * @param cls closure, our `struct GNUNET_NAT_Handle` | ||
182 | * @param addr public IP address of the other peer | ||
183 | * @param addrlen actual lenght of the @a addr | ||
184 | */ | ||
185 | static void | ||
186 | reversal_cb (void *cls, | ||
187 | const struct sockaddr *addr, | ||
188 | socklen_t addrlen) | ||
189 | { | ||
190 | struct GNUNET_NAT_Test *h = cls; | ||
191 | const struct sockaddr_in *sa; | ||
192 | |||
193 | if (sizeof (struct sockaddr_in) != addrlen) | ||
194 | return; | ||
195 | sa = (const struct sockaddr_in *) addr; | ||
196 | if (h->data != sa->sin_port) | ||
197 | { | ||
198 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
199 | "Received connection reversal request for wrong port\n"); | ||
200 | return; /* wrong port */ | ||
201 | } | ||
202 | /* report success */ | ||
203 | h->report (h->report_cls, | ||
204 | GNUNET_NAT_ERROR_SUCCESS); | ||
205 | } | ||
206 | |||
207 | |||
208 | /** | ||
209 | * Activity on our incoming socket. Read data from the | ||
210 | * incoming connection. | ||
211 | * | ||
212 | * @param cls the `struct GNUNET_NAT_Test` | ||
213 | */ | ||
214 | static void | ||
215 | do_udp_read (void *cls) | ||
216 | { | ||
217 | struct GNUNET_NAT_Test *tst = cls; | ||
218 | uint16_t data; | ||
219 | const struct GNUNET_SCHEDULER_TaskContext *tc; | ||
220 | |||
221 | tc = GNUNET_SCHEDULER_get_task_context (); | ||
222 | tst->ltask = | ||
223 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
224 | tst->lsock, | ||
225 | &do_udp_read, | ||
226 | tst); | ||
227 | if ((NULL != tc->write_ready) && | ||
228 | (GNUNET_NETWORK_fdset_isset (tc->read_ready, | ||
229 | tst->lsock)) && | ||
230 | (sizeof (data) == | ||
231 | GNUNET_NETWORK_socket_recv (tst->lsock, | ||
232 | &data, | ||
233 | sizeof (data)))) | ||
234 | { | ||
235 | if (data == tst->data) | ||
236 | tst->report (tst->report_cls, | ||
237 | GNUNET_NAT_ERROR_SUCCESS); | ||
238 | else | ||
239 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
240 | "Received data mismatches expected value\n"); | ||
241 | } | ||
242 | else | ||
243 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
244 | "Failed to receive data from inbound connection\n"); | ||
245 | } | ||
246 | |||
247 | |||
248 | /** | ||
249 | * Activity on our incoming socket. Read data from the | ||
250 | * incoming connection. | ||
251 | * | ||
252 | * @param cls the `struct NatActivity` | ||
253 | */ | ||
254 | static void | ||
255 | do_read (void *cls) | ||
256 | { | ||
257 | struct NatActivity *na = cls; | ||
258 | struct GNUNET_NAT_Test *tst; | ||
259 | uint16_t data; | ||
260 | const struct GNUNET_SCHEDULER_TaskContext *tc; | ||
261 | |||
262 | tc = GNUNET_SCHEDULER_get_task_context (); | ||
263 | na->rtask = NULL; | ||
264 | tst = na->h; | ||
265 | GNUNET_CONTAINER_DLL_remove (tst->na_head, | ||
266 | tst->na_tail, | ||
267 | na); | ||
268 | if ((NULL != tc->write_ready) && | ||
269 | (GNUNET_NETWORK_fdset_isset (tc->read_ready, | ||
270 | na->sock)) && | ||
271 | (sizeof (data) == | ||
272 | GNUNET_NETWORK_socket_recv (na->sock, | ||
273 | &data, | ||
274 | sizeof (data)))) | ||
275 | { | ||
276 | if (data == tst->data) | ||
277 | tst->report (tst->report_cls, | ||
278 | GNUNET_NAT_ERROR_SUCCESS); | ||
279 | else | ||
280 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
281 | "Received data does not match expected value\n"); | ||
282 | } | ||
283 | else | ||
284 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
285 | "Failed to receive data from inbound connection\n"); | ||
286 | GNUNET_NETWORK_socket_close (na->sock); | ||
287 | GNUNET_free (na); | ||
288 | } | ||
289 | |||
290 | |||
291 | /** | ||
292 | * Activity on our listen socket. Accept the | ||
293 | * incoming connection. | ||
294 | * | ||
295 | * @param cls the `struct GNUNET_NAT_Test` | ||
296 | */ | ||
297 | static void | ||
298 | do_accept (void *cls) | ||
299 | { | ||
300 | struct GNUNET_NAT_Test *tst = cls; | ||
301 | struct GNUNET_NETWORK_Handle *s; | ||
302 | struct NatActivity *wl; | ||
303 | |||
304 | tst->ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
305 | tst->lsock, | ||
306 | &do_accept, | ||
307 | tst); | ||
308 | s = GNUNET_NETWORK_socket_accept (tst->lsock, | ||
309 | NULL, | ||
310 | NULL); | ||
311 | if (NULL == s) | ||
312 | { | ||
313 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, | ||
314 | "accept"); | ||
315 | return; /* odd error */ | ||
316 | } | ||
317 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
318 | "Got an inbound connection, waiting for data\n"); | ||
319 | wl = GNUNET_new (struct NatActivity); | ||
320 | wl->sock = s; | ||
321 | wl->h = tst; | ||
322 | wl->rtask = | ||
323 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
324 | wl->sock, | ||
325 | &do_read, | ||
326 | wl); | ||
327 | GNUNET_CONTAINER_DLL_insert (tst->na_head, | ||
328 | tst->na_tail, | ||
329 | wl); | ||
330 | } | ||
331 | |||
332 | |||
333 | /** | ||
334 | * We got disconnected from the NAT server. Stop | ||
335 | * waiting for a reply. | ||
336 | * | ||
337 | * @param cls the `struct ClientActivity` | ||
338 | * @param error error code | ||
339 | */ | ||
340 | static void | ||
341 | mq_error_handler (void *cls, | ||
342 | enum GNUNET_MQ_Error error) | ||
343 | { | ||
344 | struct ClientActivity *ca = cls; | ||
345 | struct GNUNET_NAT_Test *tst = ca->h; | ||
346 | |||
347 | GNUNET_CONTAINER_DLL_remove (tst->ca_head, | ||
348 | tst->ca_tail, | ||
349 | ca); | ||
350 | GNUNET_MQ_destroy (ca->mq); | ||
351 | GNUNET_free (ca); | ||
352 | } | ||
353 | |||
354 | |||
355 | /** | ||
356 | * Address-callback, used to send message to gnunet-nat-server. | ||
357 | * | ||
358 | * @param cls closure | ||
359 | * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean | ||
360 | * the previous (now invalid) one | ||
361 | * @param addr either the previous or the new public IP address | ||
362 | * @param addrlen actual length of the @a addr | ||
363 | */ | ||
364 | static void | ||
365 | addr_cb (void *cls, | ||
366 | int add_remove, | ||
367 | const struct sockaddr *addr, | ||
368 | socklen_t addrlen) | ||
369 | { | ||
370 | struct GNUNET_NAT_Test *h = cls; | ||
371 | struct ClientActivity *ca; | ||
372 | struct GNUNET_MQ_Envelope *env; | ||
373 | struct GNUNET_NAT_TestMessage *msg; | ||
374 | const struct sockaddr_in *sa; | ||
375 | |||
376 | if (GNUNET_YES != add_remove) | ||
377 | return; | ||
378 | if (addrlen != sizeof (struct sockaddr_in)) | ||
379 | { | ||
380 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
381 | "NAT test ignores IPv6 address `%s' returned from NAT library\n", | ||
382 | GNUNET_a2s (addr, | ||
383 | addrlen)); | ||
384 | return; /* ignore IPv6 here */ | ||
385 | } | ||
386 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
387 | "Asking gnunet-nat-server to connect to `%s'\n", | ||
388 | GNUNET_a2s (addr, | ||
389 | addrlen)); | ||
390 | |||
391 | ca = GNUNET_new (struct ClientActivity); | ||
392 | ca->h = h; | ||
393 | ca->mq = GNUNET_CLIENT_connecT (h->cfg, | ||
394 | "gnunet-nat-server", | ||
395 | NULL, | ||
396 | &mq_error_handler, | ||
397 | ca); | ||
398 | if (NULL == ca->mq) | ||
399 | { | ||
400 | GNUNET_free (ca); | ||
401 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
402 | _("Failed to connect to `gnunet-nat-server'\n")); | ||
403 | return; | ||
404 | } | ||
405 | GNUNET_CONTAINER_DLL_insert (h->ca_head, | ||
406 | h->ca_tail, | ||
407 | ca); | ||
408 | sa = (const struct sockaddr_in *) addr; | ||
409 | env = GNUNET_MQ_msg (msg, | ||
410 | GNUNET_MESSAGE_TYPE_NAT_TEST); | ||
411 | msg->dst_ipv4 = sa->sin_addr.s_addr; | ||
412 | msg->dport = sa->sin_port; | ||
413 | msg->data = h->data; | ||
414 | msg->is_tcp = htonl ((uint32_t) h->is_tcp); | ||
415 | GNUNET_MQ_send (ca->mq, | ||
416 | env); | ||
417 | } | ||
418 | |||
419 | |||
420 | /** | ||
421 | * Timeout task for a nat test. | ||
422 | * Calls the report-callback with a timeout return value | ||
423 | * | ||
424 | * Destroys the nat handle after the callback has been processed. | ||
425 | * | ||
426 | * @param cls handle to the timed out NAT test | ||
427 | */ | ||
428 | static void | ||
429 | do_timeout (void *cls) | ||
430 | { | ||
431 | struct GNUNET_NAT_Test *nh = cls; | ||
432 | |||
433 | nh->ttask = NULL; | ||
434 | nh->report (nh->report_cls, | ||
435 | (GNUNET_NAT_ERROR_SUCCESS == nh->status) | ||
436 | ? GNUNET_NAT_ERROR_TIMEOUT | ||
437 | : nh->status); | ||
438 | } | ||
439 | |||
440 | |||
441 | /** | ||
442 | * Start testing if NAT traversal works using the | ||
443 | * given configuration (IPv4-only). | ||
444 | * | ||
445 | * ALL failures are reported directly to the report callback | ||
446 | * | ||
447 | * @param cfg configuration for the NAT traversal | ||
448 | * @param is_tcp #GNUNET_YES to test TCP, #GNUNET_NO to test UDP | ||
449 | * @param bnd_port port to bind to, 0 for connection reversal | ||
450 | * @param adv_port externally advertised port to use | ||
451 | * @param timeout delay after which the test should be aborted | ||
452 | * @param report function to call with the result of the test | ||
453 | * @param report_cls closure for @a report | ||
454 | * @return handle to cancel NAT test or NULL. The error is always indicated via the report callback | ||
455 | */ | ||
456 | struct GNUNET_NAT_Test * | ||
457 | GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
458 | int is_tcp, | ||
459 | uint16_t bnd_port, | ||
460 | uint16_t adv_port, | ||
461 | struct GNUNET_TIME_Relative timeout, | ||
462 | GNUNET_NAT_TestCallback report, | ||
463 | void *report_cls) | ||
464 | { | ||
465 | struct GNUNET_NAT_Test *nh; | ||
466 | struct sockaddr_in sa; | ||
467 | const struct sockaddr *addrs[] = { | ||
468 | (const struct sockaddr *) &sa | ||
469 | }; | ||
470 | const socklen_t addrlens[] = { | ||
471 | sizeof (sa) | ||
472 | }; | ||
473 | |||
474 | memset (&sa, 0, sizeof (sa)); | ||
475 | sa.sin_family = AF_INET; | ||
476 | sa.sin_port = htons (bnd_port); | ||
477 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
478 | sa.sin_len = sizeof (sa); | ||
479 | #endif | ||
480 | |||
481 | nh = GNUNET_new (struct GNUNET_NAT_Test); | ||
482 | nh->cfg = cfg; | ||
483 | nh->is_tcp = is_tcp; | ||
484 | nh->data = bnd_port; | ||
485 | nh->adv_port = adv_port; | ||
486 | nh->report = report; | ||
487 | nh->report_cls = report_cls; | ||
488 | nh->status = GNUNET_NAT_ERROR_SUCCESS; | ||
489 | if (0 == bnd_port) | ||
490 | { | ||
491 | nh->nat | ||
492 | = GNUNET_NAT_register (cfg, | ||
493 | is_tcp, | ||
494 | 0, | ||
495 | 0, | ||
496 | NULL, | ||
497 | NULL, | ||
498 | &addr_cb, | ||
499 | &reversal_cb, | ||
500 | nh, | ||
501 | NULL); | ||
502 | } | ||
503 | else | ||
504 | { | ||
505 | nh->lsock = | ||
506 | GNUNET_NETWORK_socket_create (AF_INET, | ||
507 | (is_tcp == | ||
508 | GNUNET_YES) ? SOCK_STREAM : SOCK_DGRAM, | ||
509 | 0); | ||
510 | if ((nh->lsock == NULL) || | ||
511 | (GNUNET_OK != | ||
512 | GNUNET_NETWORK_socket_bind (nh->lsock, | ||
513 | (const struct sockaddr *) &sa, | ||
514 | sizeof (sa)))) | ||
515 | { | ||
516 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
517 | _("Failed to create listen socket bound to `%s' for NAT test: %s\n"), | ||
518 | GNUNET_a2s ((const struct sockaddr *) &sa, | ||
519 | sizeof (sa)), | ||
520 | STRERROR (errno)); | ||
521 | if (NULL != nh->lsock) | ||
522 | { | ||
523 | GNUNET_NETWORK_socket_close (nh->lsock); | ||
524 | nh->lsock = NULL; | ||
525 | } | ||
526 | nh->status = GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR; | ||
527 | nh->ttask = GNUNET_SCHEDULER_add_now (&do_timeout, | ||
528 | nh); | ||
529 | return nh; | ||
530 | } | ||
531 | if (GNUNET_YES == is_tcp) | ||
532 | { | ||
533 | GNUNET_break (GNUNET_OK == | ||
534 | GNUNET_NETWORK_socket_listen (nh->lsock, | ||
535 | 5)); | ||
536 | nh->ltask = | ||
537 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
538 | nh->lsock, | ||
539 | &do_accept, | ||
540 | nh); | ||
541 | } | ||
542 | else | ||
543 | { | ||
544 | nh->ltask = | ||
545 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
546 | nh->lsock, | ||
547 | &do_udp_read, | ||
548 | nh); | ||
549 | } | ||
550 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
551 | "NAT test listens on port %u (%s)\n", | ||
552 | bnd_port, | ||
553 | (GNUNET_YES == is_tcp) ? "tcp" : "udp"); | ||
554 | nh->nat = GNUNET_NAT_register (cfg, | ||
555 | is_tcp, | ||
556 | adv_port, | ||
557 | 1, | ||
558 | addrs, | ||
559 | addrlens, | ||
560 | &addr_cb, | ||
561 | NULL, | ||
562 | nh, | ||
563 | NULL); | ||
564 | if (NULL == nh->nat) | ||
565 | { | ||
566 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
567 | _("NAT test failed to start NAT library\n")); | ||
568 | if (NULL != nh->ltask) | ||
569 | { | ||
570 | GNUNET_SCHEDULER_cancel (nh->ltask); | ||
571 | nh->ltask = NULL; | ||
572 | } | ||
573 | if (NULL != nh->lsock) | ||
574 | { | ||
575 | GNUNET_NETWORK_socket_close (nh->lsock); | ||
576 | nh->lsock = NULL; | ||
577 | } | ||
578 | nh->status = GNUNET_NAT_ERROR_NAT_REGISTER_FAILED; | ||
579 | nh->ttask = GNUNET_SCHEDULER_add_now (&do_timeout, | ||
580 | nh); | ||
581 | return nh; | ||
582 | } | ||
583 | } | ||
584 | nh->ttask = GNUNET_SCHEDULER_add_delayed (timeout, | ||
585 | &do_timeout, | ||
586 | nh); | ||
587 | return nh; | ||
588 | } | ||
589 | |||
590 | |||
591 | /** | ||
592 | * Stop an active NAT test. | ||
593 | * | ||
594 | * @param tst test to stop. | ||
595 | */ | ||
596 | void | ||
597 | GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst) | ||
598 | { | ||
599 | struct NatActivity *pos; | ||
600 | struct ClientActivity *cpos; | ||
601 | |||
602 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
603 | "Stopping NAT test\n"); | ||
604 | while (NULL != (cpos = tst->ca_head)) | ||
605 | { | ||
606 | GNUNET_CONTAINER_DLL_remove (tst->ca_head, | ||
607 | tst->ca_tail, | ||
608 | cpos); | ||
609 | GNUNET_MQ_destroy (cpos->mq); | ||
610 | GNUNET_free (cpos); | ||
611 | } | ||
612 | while (NULL != (pos = tst->na_head)) | ||
613 | { | ||
614 | GNUNET_CONTAINER_DLL_remove (tst->na_head, | ||
615 | tst->na_tail, | ||
616 | pos); | ||
617 | GNUNET_SCHEDULER_cancel (pos->rtask); | ||
618 | GNUNET_NETWORK_socket_close (pos->sock); | ||
619 | GNUNET_free (pos); | ||
620 | } | ||
621 | if (NULL != tst->ttask) | ||
622 | { | ||
623 | GNUNET_SCHEDULER_cancel (tst->ttask); | ||
624 | tst->ttask = NULL; | ||
625 | } | ||
626 | if (NULL != tst->ltask) | ||
627 | { | ||
628 | GNUNET_SCHEDULER_cancel (tst->ltask); | ||
629 | tst->ltask = NULL; | ||
630 | } | ||
631 | if (NULL != tst->lsock) | ||
632 | { | ||
633 | GNUNET_NETWORK_socket_close (tst->lsock); | ||
634 | tst->lsock = NULL; | ||
635 | } | ||
636 | if (NULL != tst->nat) | ||
637 | { | ||
638 | GNUNET_NAT_unregister (tst->nat); | ||
639 | tst->nat = NULL; | ||
640 | } | ||
641 | GNUNET_free (tst); | ||
642 | } | ||
643 | |||
644 | /* end of nat_test.c */ | ||