aboutsummaryrefslogtreecommitdiff
path: root/src/nat-auto
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2017-01-06 13:26:38 +0100
committerChristian Grothoff <christian@grothoff.org>2017-01-06 13:26:38 +0100
commit80e1315b56f559db60499f5373e90c293c5ab065 (patch)
tree3b279e6ac8e6298d7d9d96d12868f628a413939b /src/nat-auto
parent1b7f6eea0a06abab9b75b30f021aa6313fccfcd4 (diff)
downloadgnunet-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/.gitignore3
-rw-r--r--src/nat-auto/Makefile.am58
-rw-r--r--src/nat-auto/gnunet-nat-auto.c428
-rw-r--r--src/nat-auto/gnunet-nat-server.c384
-rw-r--r--src/nat-auto/gnunet-service-nat-auto.c481
-rw-r--r--src/nat-auto/nat-auto.conf.in15
-rw-r--r--src/nat-auto/nat-auto.h110
-rw-r--r--src/nat-auto/nat_auto_api.c274
-rw-r--r--src/nat-auto/nat_auto_api_test.c644
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 @@
1gnunet-service-nat-auto
2gnunet-nat-auto
3gnunet-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
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4libexecdir= $(pkglibdir)/libexec/
5
6pkgcfgdir= $(pkgdatadir)/config.d/
7
8pkgcfg_DATA = \
9 nat-auto.conf
10
11bin_PROGRAMS = \
12 gnunet-nat-auto \
13 gnunet-nat-server
14
15libexec_PROGRAMS = \
16 gnunet-service-nat-auto
17
18gnunet_nat_server_SOURCES = \
19 gnunet-nat-server.c nat-auto.h
20gnunet_nat_server_LDADD = \
21 $(top_builddir)/src/nat/libgnunetnat.la \
22 $(top_builddir)/src/util/libgnunetutil.la
23
24gnunet_nat_auto_SOURCES = \
25 gnunet-nat-auto.c nat-auto.h
26gnunet_nat_auto_LDADD = \
27 libgnunetnatauto.la \
28 $(top_builddir)/src/util/libgnunetutil.la
29
30
31if USE_COVERAGE
32 AM_CFLAGS = -fprofile-arcs -ftest-coverage
33endif
34
35lib_LTLIBRARIES = \
36 libgnunetnatauto.la
37
38libgnunetnatauto_la_SOURCES = \
39 nat_auto_api.c \
40 nat_auto_api_test.c
41libgnunetnatauto_la_LIBADD = \
42 $(top_builddir)/src/nat/libgnunetnatnew.la \
43 $(top_builddir)/src/util/libgnunetutil.la \
44 $(GN_LIBINTL) @EXT_LIBS@
45libgnunetnatauto_la_LDFLAGS = \
46 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
47 -version-info 0:0:0
48
49gnunet_service_nat_auto_SOURCES = \
50 gnunet-service-nat-auto.c
51gnunet_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 */
35static int global_ret;
36
37/**
38 * Handle to ongoing autoconfiguration.
39 */
40static struct GNUNET_NAT_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 * Address we are bound to (in test), or should bind to
60 * (if #do_stun is set).
61 */
62static char *bind_addr;
63
64/**
65 * External IP address and port to use for the test.
66 * If not set, use #bind_addr.
67 */
68static char *extern_addr;
69
70/**
71 * Should we run autoconfiguration?
72 */
73static unsigned int do_auto;
74
75/**
76 * Handle to a NAT test operation.
77 */
78static struct GNUNET_NAT_Test *nt;
79
80/**
81 * Flag set to 1 if we use IPPROTO_UDP.
82 */
83static int use_udp;
84
85/**
86 * Flag set to 1 if we use IPPROTO_TCP.
87 */
88static int use_tcp;
89
90/**
91 * Protocol to use.
92 */
93static uint8_t proto;
94
95/**
96 * Test if all activities have finished, and if so,
97 * terminate.
98 */
99static void
100test_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 */
118static void
119auto_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 */
146static void
147auto_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 */
253static void
254test_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 */
269static void
270do_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 */
293static void
294run (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 */
383int
384main (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 */
36static struct GNUNET_SERVER_Handle *server;
37
38/**
39 * Our configuration.
40 */
41static 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 */
51static void
52try_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 */
82struct 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 */
102static void
103tcp_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 */
132static void
133try_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 */
190static void
191try_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 */
238static void
239test (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 */
272static void
273shutdown_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 */
288static void
289run (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 */
355int
356main (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 */
53struct 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 */
81struct 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 */
135static struct ClientHandle *ch_head;
136
137/**
138 * Tail of client DLL.
139 */
140static struct ClientHandle *ch_tail;
141
142/**
143 * DLL of our autoconfiguration operations.
144 */
145static struct AutoconfigContext *ac_head;
146
147/**
148 * DLL of our autoconfiguration operations.
149 */
150static struct AutoconfigContext *ac_tail;
151
152/**
153 * Handle to our current configuration.
154 */
155static const struct GNUNET_CONFIGURATION_Handle *cfg;
156
157/**
158 * Handle to the statistics service.
159 */
160static 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 */
171static int
172check_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 */
184static void
185terminate_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 */
201static void
202conclude_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 */
250static void
251check_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 */
265static void
266update_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 */
296static void
297handle_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 */
361static void
362shutdown_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 */
390static void
391run (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 */
411static void *
412client_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 */
435static void
436client_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 */
452GNUNET_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 */
472void __attribute__ ((constructor))
473GNUNET_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]
2AUTOSTART = @AUTOSTART@
3@UNIXONLY@ PORT = 2124
4HOSTNAME = localhost
5BINARY = gnunet-service-nat-auto
6ACCEPT_FROM = 127.0.0.1;
7ACCEPT_FROM6 = ::1;
8UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-nat-auto.sock
9UNIX_MATCH_UID = YES
10UNIX_MATCH_GID = YES
11
12[gnunet-nat-server]
13HOSTNAME = gnunet.org
14PORT = 5724
15NOARMBIND = 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
33GNUNET_NETWORK_STRUCT_BEGIN
34
35/**
36 * Request to test NAT traversal, sent to the gnunet-nat-server
37 * (not the service!).
38 */
39struct 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 */
72struct 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 */
87struct 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
108GNUNET_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 */
39struct 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 */
71const char *
72GNUNET_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 */
127static int
128check_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 */
141static void
142handle_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 */
185static void
186ah_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 */
208struct GNUNET_NAT_AutoHandle *
209GNUNET_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 */
267void
268GNUNET_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 */
37struct 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 */
69struct 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 */
97struct 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 */
185static void
186reversal_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 */
214static void
215do_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 */
254static void
255do_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 */
297static void
298do_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 */
340static void
341mq_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 */
364static void
365addr_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 */
428static void
429do_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 */
456struct GNUNET_NAT_Test *
457GNUNET_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 */
596void
597GNUNET_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 */